Пример #1
0
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;
}