From: Cristy Date: Wed, 8 May 2019 00:21:15 +0000 (-0400) Subject: Support HEIC color profiles X-Git-Tag: 7.0.8-45~15 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e95d2faa62015c0c3c1ba7aa2dd1d10c7543e463;p=imagemagick Support HEIC color profiles --- diff --git a/coders/heic.c b/coders/heic.c index 3c5d8e9bf..0b951fa37 100644 --- a/coders/heic.c +++ b/coders/heic.c @@ -81,20 +81,22 @@ #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/ "; +#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 - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -391,7 +435,7 @@ static MagickBooleanType IsHEIC(const unsigned char *magick,const size_t length) return(MagickTrue); return(MagickFalse); } - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -436,7 +480,7 @@ ModuleExport size_t RegisterHEICImage(void) (void) RegisterMagickInfo(entry); return(MagickImageCoderSignature); } - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -460,7 +504,7 @@ ModuleExport void UnregisterHEICImage(void) { (void) UnregisterMagickInfo("HEIC"); } - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -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); }