bool JPEGReader::Extract( ICCProfile& icc ) { icc.Clear(); if ( !IsOpen() ) return false; if ( jpeg_decompressor->marker_list == nullptr ) return true; ByteArray iccData; uint32 iccSize = 0; uint32 iccChunkOffset = 0; const ::jpeg_marker_struct* m = jpeg_decompressor->marker_list; do { if ( !STRNCASECMP( (const char*)m->data, "ICC_PROFILE", 11 ) ) { // // ICC_PROFILE 0 i N ddddddddddddd...ddd // ----------- // iCC id // // 0 = nul character // i = index number of this chunk // N = total number of chunks // d = data bytes in this chunk // void* iccChunkData = m->data + 14; // Allocate ICC data block when we see the first chunk. if ( iccChunkOffset == 0 ) { // iccChunkData points now to an ICC profile header. // The first field in an ICC profile header is the uint32 // profile length in bytes. ICC profiles are encoded using // big endian byte order. iccSize = BigToLittleEndian( *(const uint32*)iccChunkData ); if ( iccSize == 0 ) return true; iccData = ByteArray( size_type( iccSize ) ); } uint32 iccChunkSize = m->data_length - 14; // Guard us against insane ICC profile data. if ( iccChunkOffset+iccChunkSize > iccSize ) return true; ::memcpy( iccData.At( iccChunkOffset ), iccChunkData, iccChunkSize ); iccChunkOffset += iccChunkSize; // More chunks ? if ( m->data[12] >= m->data[13] ) break; } } while ( (m = m->next) != nullptr ); icc.Set( iccData ); return true; }