]> granicus.if.org Git - imagemagick/commitdiff
Support HEIC color profiles
authorCristy <mikayla-grace@urban-warrior.org>
Wed, 8 May 2019 00:21:15 +0000 (20:21 -0400)
committerCristy <mikayla-grace@urban-warrior.org>
Wed, 8 May 2019 00:21:15 +0000 (20:21 -0400)
coders/heic.c

index 3c5d8e9bfe3a9a9c714114aba76677f626a67758..0b951fa3752a55363cba79d4885e7f97dce82bb2 100644 (file)
 #endif
 #endif
 
-
 #if defined(MAGICKCORE_HEIC_DELEGATE)
+/*
+  Define declarations.
+*/
+#define XmpNamespaceExtent  28
 
 /*
   Const declarations.
 */
-static const char *xmp_namespace = "http://ns.adobe.com/xap/1.0/ ";
-#define XmpNamespaceExtent 28
+static const char
+  *xmp_namespace = "http://ns.adobe.com/xap/1.0/ ";
 \f
+#if !defined(MAGICKCORE_WINDOWS_SUPPORT)
 /*
   Forward declarations.
 */
-
-#if !defined(MAGICKCORE_WINDOWS_SUPPORT)
 static MagickBooleanType
   WriteHEICImage(const ImageInfo *,Image *,ExceptionInfo *);
 #endif
@@ -131,13 +133,15 @@ static MagickBooleanType IsHeifSuccess(struct heif_error *error,Image *image,
 {
   if (error->code == 0)
     return(MagickTrue);
-
   ThrowBinaryException(CorruptImageError,error->message,image->filename);
 }
 
 static Image *ReadHEICImage(const ImageInfo *image_info,
   ExceptionInfo *exception)
 {
+  const char
+    *option;
+
   heif_item_id
     exif_id;
 
@@ -153,7 +157,7 @@ static Image *ReadHEICImage(const ImageInfo *image_info,
   MagickBooleanType
     status;
 
-  MagickSizeType
+  size_t
     length;
 
   ssize_t
@@ -162,6 +166,9 @@ static Image *ReadHEICImage(const ImageInfo *image_info,
   struct heif_context
     *heif_context;
 
+  struct heif_decoding_options
+    *decode_options;
+
   struct heif_error
     error;
 
@@ -171,9 +178,6 @@ static Image *ReadHEICImage(const ImageInfo *image_info,
   struct heif_image_handle
     *image_handle;
 
-  struct heif_decoding_options
-    *decode_options;
-
   uint8_t
     *p_y,
     *p_cb,
@@ -182,9 +186,6 @@ static Image *ReadHEICImage(const ImageInfo *image_info,
   void
     *file_data;
 
-  const char
-    *option;
-
   /*
     Open image file.
   */
@@ -199,7 +200,9 @@ static Image *ReadHEICImage(const ImageInfo *image_info,
   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
   if (status == MagickFalse)
     return(DestroyImageList(image));
-  length=GetBlobSize(image);
+  if (GetBlobSize(image) > (MagickSizeType) SSIZE_MAX)
+    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+  length=(size_t) GetBlobSize(image);
   file_data=AcquireMagickMemory(length);
   if (file_data == (void *) NULL)
     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
@@ -226,9 +229,41 @@ static Image *ReadHEICImage(const ImageInfo *image_info,
       heif_context_free(heif_context);
       return(DestroyImageList(image));
     }
-  /*
-    Read Exif data from HEIC file
-  */
+  length=heif_image_handle_get_raw_color_profile_size(image_handle);
+  if (length > 0)
+    {
+      unsigned char
+        *color_buffer;
+
+      /*
+        Read color profile.
+      */
+      if ((MagickSizeType) length > GetBlobSize(image))
+        {
+          heif_image_handle_release(image_handle);
+          heif_context_free(heif_context);
+          ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
+        }
+      color_buffer=(unsigned char *) AcquireMagickMemory(length);
+      if (color_buffer != (unsigned char *) NULL)
+        {
+          error=heif_image_handle_get_raw_color_profile(image_handle,
+            color_buffer);
+          if (error.code == 0)
+            {
+              StringInfo
+                *profile;
+
+              profile=BlobToStringInfo(color_buffer,length);
+              if (profile != (StringInfo*) NULL)
+                {
+                  (void) SetImageProfile(image,"icc",profile,exception);
+                  profile=DestroyStringInfo(profile);
+                }
+            }
+        }
+      color_buffer=(unsigned char *) RelinquishMagickMemory(color_buffer);
+    }
   count=heif_image_handle_get_list_of_metadata_block_IDs(image_handle,"Exif",
     &exif_id,1);
   if (count > 0)
@@ -239,16 +274,18 @@ static Image *ReadHEICImage(const ImageInfo *image_info,
       unsigned char
         *exif_buffer;
 
+      /*
+        Read Exif profile.
+      */
       exif_size=heif_image_handle_get_metadata_size(image_handle,exif_id);
-      if (exif_size > GetBlobSize(image))
+      if ((MagickSizeType) exif_size > GetBlobSize(image))
         {
           heif_image_handle_release(image_handle);
           heif_context_free(heif_context);
-          ThrowReaderException(CorruptImageError,
-            "InsufficientImageDataInFile");
+          ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
         }
       exif_buffer=(unsigned char *) AcquireMagickMemory(exif_size);
-      if (exif_buffer !=(unsigned char *) NULL)
+      if (exif_buffer != (unsigned char *) NULL)
         {
           error=heif_image_handle_get_metadata(image_handle,
             exif_id,exif_buffer);
@@ -257,14 +294,16 @@ static Image *ReadHEICImage(const ImageInfo *image_info,
               StringInfo
                 *profile;
 
-              // The first 4 byte should be skipped since they indicate the
-              // offset to the start of the TIFF header of the Exif data.
+              /*
+                The first 4 byte should be skipped since they indicate the
+                offset to the start of the TIFF header of the Exif data.
+              */
               profile=(StringInfo*) NULL;
               if (exif_size > 8)
-                profile=BlobToStringInfo(exif_buffer+4,exif_size-4);
+                profile=BlobToStringInfo(exif_buffer+4,(size_t) exif_size-4);
               if (profile != (StringInfo*) NULL)
                 {
-                  SetImageProfile(image,"exif",profile,exception);
+                  (void) SetImageProfile(image,"exif",profile,exception);
                   profile=DestroyStringInfo(profile);
                 }
             }
@@ -272,8 +311,8 @@ static Image *ReadHEICImage(const ImageInfo *image_info,
       exif_buffer=(unsigned char *) RelinquishMagickMemory(exif_buffer);
   }
   /*
-    Set image size
-   */
+    Set image size.
+  */
   image->depth=8;
   image->columns=(size_t) heif_image_handle_get_width(image_handle);
   image->rows=(size_t) heif_image_handle_get_height(image_handle);
@@ -292,7 +331,7 @@ static Image *ReadHEICImage(const ImageInfo *image_info,
       return(DestroyImageList(image));
     }
   /*
-    Copy HEIF image into ImageMagick data structures
+    Copy HEIF image into ImageMagick data structures.
   */
   (void) SetImageColorspace(image,YCbCrColorspace,exception);
   decode_options=(struct heif_decoding_options *) NULL;
@@ -303,12 +342,14 @@ static Image *ReadHEICImage(const ImageInfo *image_info,
       decode_options->ignore_transformations=1;
     }
   else
-    SetImageProperty(image,"exif:Orientation","1",exception);
+    (void) SetImageProperty(image,"exif:Orientation","1",exception);
   error=heif_decode_image(image_handle,&heif_image,heif_colorspace_YCbCr,
     heif_chroma_420,decode_options);
   if (decode_options != (struct heif_decoding_options *) NULL)
     {
-      /* Correct the width and height of the image */
+      /*
+        Correct the width and height of the image.
+      */
       image->columns=(size_t) heif_image_get_width(heif_image,heif_channel_Y);
       image->rows=(size_t) heif_image_get_height(heif_image,heif_channel_Y);
       status=SetImageExtent(image,image->columns,image->rows,exception);
@@ -335,11 +376,14 @@ static Image *ReadHEICImage(const ImageInfo *image_info,
     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
     if (q == (Quantum *) NULL)
       break;
-    for (x=0; x < (long) image->columns; x++)
+    for (x=0; x < (ssize_t) image->columns; x++)
     {
-      SetPixelRed(image,ScaleCharToQuantum(p_y[y*stride_y + x]),q);
-      SetPixelGreen(image,ScaleCharToQuantum(p_cb[(y/2)*stride_cb + x/2]),q);
-      SetPixelBlue(image,ScaleCharToQuantum(p_cr[(y/2)*stride_cr + x/2]),q);
+      SetPixelRed(image,ScaleCharToQuantum((unsigned char) p_y[y*
+        stride_y+x]),q);
+      SetPixelGreen(image,ScaleCharToQuantum((unsigned char) p_cb[(y/2)*
+        stride_cb+x/2]),q);
+      SetPixelBlue(image,ScaleCharToQuantum((unsigned char) p_cr[(y/2)*
+        stride_cr+x/2]),q);
       q+=GetPixelChannels(image);
     }
     if (SyncAuthenticPixels(image,exception) == MagickFalse)
@@ -351,7 +395,7 @@ static Image *ReadHEICImage(const ImageInfo *image_info,
   return(GetFirstImageInList(image));
 }
 #endif
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -391,7 +435,7 @@ static MagickBooleanType IsHEIC(const unsigned char *magick,const size_t length)
     return(MagickTrue);
   return(MagickFalse);
 }
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -436,7 +480,7 @@ ModuleExport size_t RegisterHEICImage(void)
   (void) RegisterMagickInfo(entry);
   return(MagickImageCoderSignature);
 }
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -460,7 +504,7 @@ ModuleExport void UnregisterHEICImage(void)
 {
   (void) UnregisterMagickInfo("HEIC");
 }
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -488,8 +532,9 @@ ModuleExport void UnregisterHEICImage(void)
 %    o exception:  return any errors or warnings in this structure.
 %
 */
+
 #if defined(MAGICKCORE_HEIC_DELEGATE) && !defined(MAGICKCORE_WINDOWS_SUPPORT)
-static void WriteProfile(struct heif_context* ctx,Image *image,
+static void WriteProfile(struct heif_context *context,Image *image,
   ExceptionInfo *exception)
 {
   const char
@@ -498,9 +543,6 @@ static void WriteProfile(struct heif_context* ctx,Image *image,
   const StringInfo
     *profile;
 
-  MagickBooleanType
-    iptc;
-
   register ssize_t
     i;
 
@@ -516,23 +558,22 @@ static void WriteProfile(struct heif_context* ctx,Image *image,
   struct heif_image_handle
     *image_handle;
 
-  /*Get image handle*/
+  /*
+    Get image handle.
+  */
   image_handle=(struct heif_image_handle *) NULL;
-  error=heif_context_get_primary_image_handle(ctx,&image_handle);
+  error=heif_context_get_primary_image_handle(context,&image_handle);
   if (error.code != 0)
     return;
-
   /*
     Save image profile as a APP marker.
   */
-  iptc=MagickFalse;
   custom_profile=AcquireStringInfo(65535L);
   ResetImageProfileIterator(image);
   for (name=GetNextImageProfile(image); name != (const char *) NULL; )
   {
     profile=GetImageProfile(image,name);
     length=GetStringInfoLength(profile);
-
     if (LocaleCompare(name,"EXIF") == 0)
       {
         length=GetStringInfoLength(profile);
@@ -543,10 +584,9 @@ static void WriteProfile(struct heif_context* ctx,Image *image,
               image->filename);
             length=65533L;
           }
-          (void) heif_context_add_exif_metadata(ctx,image_handle,
+          (void) heif_context_add_exif_metadata(context,image_handle,
             (void*) GetStringInfoDatum(profile),length);
       }
-
     if (LocaleCompare(name,"XMP") == 0)
       {
         StringInfo
@@ -561,7 +601,7 @@ static void WriteProfile(struct heif_context* ctx,Image *image,
             for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
             {
               length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
-              error=heif_context_add_XMP_metadata(ctx,image_handle,
+              error=heif_context_add_XMP_metadata(context,image_handle,
                 (void*) (GetStringInfoDatum(xmp_profile)+i),length);
               if (error.code != 0)
                 break;
@@ -578,8 +618,8 @@ static void WriteProfile(struct heif_context* ctx,Image *image,
   heif_image_handle_release(image_handle);
 }
 
-static struct heif_error heif_write_func(struct heif_context *ctx,const void* data,
-  size_t size,void* userdata)
+static struct heif_error heif_write_func(struct heif_context *context,
+  const void* data,size_t size,void* userdata)
 {
   Image
     *image;
@@ -587,7 +627,7 @@ static struct heif_error heif_write_func(struct heif_context *ctx,const void* da
   struct heif_error
     error_ok;
 
-  (void) ctx;
+  (void) context;
   image=(Image*) userdata;
   (void) WriteBlob(image,size,(const unsigned char *) data);
   error_ok.code=heif_error_Ok;
@@ -596,19 +636,18 @@ static struct heif_error heif_write_func(struct heif_context *ctx,const void* da
   return(error_ok);
 }
 
-static MagickBooleanType WriteHEICImage(const ImageInfo *image_info,Image *image,
-  ExceptionInfo *exception)
+static MagickBooleanType WriteHEICImage(const ImageInfo *image_info,
+  Image *image,ExceptionInfo *exception)
 {
-  long
-    x,
-    y;
-
   MagickBooleanType
     status;
 
   MagickOffsetType
     scene;
 
+  ssize_t
+    y;
+
   struct heif_context
     *heif_context;
 
@@ -639,6 +678,9 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info,Image *image
     const Quantum
       *p;
 
+    const StringInfo
+      *profile;
+
     int
       stride_y,
       stride_cb,
@@ -663,13 +705,17 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info,Image *image
     if (status == MagickFalse)
       break;
     /*
-      Initialize HEIF encoder context
+      Initialize HEIF encoder context.
     */
     error=heif_image_create((int) image->columns,(int) image->rows,
       heif_colorspace_YCbCr,heif_chroma_420,&heif_image);
     status=IsHeifSuccess(&error,image,exception);
     if (status == MagickFalse)
       break;
+    profile=GetImageProfile(image,"icc");
+    if (profile != (StringInfo *) NULL)
+      (void) heif_image_set_raw_color_profile(heif_image,"prof",
+        GetStringInfoDatum(profile),GetStringInfoLength(profile));
     error=heif_image_add_plane(heif_image,heif_channel_Y,(int) image->columns,
       (int) image->rows,8);
     status=IsHeifSuccess(&error,image,exception);
@@ -691,40 +737,35 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info,Image *image
     /*
       Copy image to heif_image
     */
-    for (y=0; y < (long) image->rows; y++)
+    for (y=0; y < (ssize_t) image->rows; y++)
     {
+      register ssize_t
+        x;
+
       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
       if (p == (const Quantum *) NULL)
         {
           status=MagickFalse;
           break;
         }
-      if ((y & 1)==0)
+      if ((y & 0x01) == 0)
+        for (x=0; x < (ssize_t) image->columns; x+=2)
         {
-          for (x=0; x < (long) image->columns; x+=2)
+          p_y[y*stride_y+x]=ScaleQuantumToChar(GetPixelRed(image,p));
+          p_cb[y/2*stride_cb+x/2]=ScaleQuantumToChar(GetPixelGreen(image,p));
+          p_cr[y/2*stride_cr+x/2]=ScaleQuantumToChar(GetPixelBlue(image,p));
+          p+=GetPixelChannels(image);
+          if ((x+1) < (ssize_t) image->columns)
             {
-              p_y[y*stride_y+x]=ScaleQuantumToChar(GetPixelRed(image,p));
-              p_cb[y/2*stride_cb+x/2]=ScaleQuantumToChar(GetPixelGreen(image,
-                p));
-              p_cr[y/2*stride_cr+x/2]=ScaleQuantumToChar(GetPixelBlue(image,
-                p));
+              p_y[y*stride_y+x+1]=ScaleQuantumToChar(GetPixelRed(image,p));
               p+=GetPixelChannels(image);
-
-              if ((x+1) < (ssize_t) image->columns)
-                {
-                  p_y[y*stride_y + x+1]=ScaleQuantumToChar(GetPixelRed(image,
-                    p));
-                  p+=GetPixelChannels(image);
-                }
             }
         }
       else
+        for (x=0; x < (ssize_t) image->columns; x++)
         {
-          for (x=0; x < (long) image->columns; x++)
-          {
-            p_y[y*stride_y + x]=ScaleQuantumToChar(GetPixelRed(image,p));
-            p+=GetPixelChannels(image);
-          }
+          p_y[y*stride_y+x]=ScaleQuantumToChar(GetPixelRed(image,p));
+          p+=GetPixelChannels(image);
         }
       if (image->previous == (Image *) NULL)
         {
@@ -746,30 +787,28 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info,Image *image
       break;
     if (image_info->quality != UndefinedCompressionQuality)
       {
-        error=heif_encoder_set_lossy_quality(heif_encoder,
-          (int) image_info->quality);
+        error=heif_encoder_set_lossy_quality(heif_encoder,(int)
+          image_info->quality);
         status=IsHeifSuccess(&error,image,exception);
         if (status == MagickFalse)
           break;
       }
     error=heif_context_encode_image(heif_context,heif_image,heif_encoder,
-      (const struct heif_encoding_options*) NULL,
-      (struct heif_image_handle**) NULL);
+      (const struct heif_encoding_options *) NULL,
+      (struct heif_image_handle **) NULL);
     status=IsHeifSuccess(&error,image,exception);
     if (status == MagickFalse)
       break;
     writer.writer_api_version=1;
     writer.write=heif_write_func;
-
        if (image->profiles != (void *) NULL)
        WriteProfile(heif_context, image, exception);
-
     error=heif_context_write(heif_context,&writer,image);
     status=IsHeifSuccess(&error,image,exception);
     if (status == MagickFalse)
       break;
     if (GetNextImageInList(image) == (Image *) NULL)
-        break;
+      break;
     image=SyncNextImageInList(image);
     status=SetImageProgress(image,SaveImagesTag,scene,
       GetImageListLength(image));
@@ -781,13 +820,11 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info,Image *image
     heif_image=(struct heif_image*) NULL;
     scene++;
   } while (image_info->adjoin != MagickFalse);
-
   if (heif_encoder != (struct heif_encoder*) NULL)
     heif_encoder_release(heif_encoder);
   if (heif_image != (struct heif_image*) NULL)
     heif_image_release(heif_image);
   heif_context_free(heif_context);
-
   (void) CloseBlob(image);
   return(status);
 }