diff options
Diffstat (limited to 'heif.patch')
-rw-r--r-- | heif.patch | 1031 |
1 files changed, 45 insertions, 986 deletions
@@ -1,1005 +1,64 @@ -From 418e3f40dc7302dae664eaaf0ea4cd4b7b59f852 Mon Sep 17 00:00:00 2001 +From ffc2aaae543dcd60c6cc7e5a426f66dbc51df560 Mon Sep 17 00:00:00 2001 From: Cristy <urban-warrior@imagemagick.org> -Date: Sat, 19 Mar 2022 11:26:52 -0400 -Subject: [PATCH] Coders: support 10-bit AVIF per - https://github.com/ImageMagick/ImageMagick/discussions/4932 +Date: Mon, 21 Mar 2022 21:53:40 -0400 +Subject: [PATCH] https://github.com/ImageMagick/ImageMagick/issues/4972 --- - coders/heic.c | 606 ++++++++++++++++++++++++++++++++------------------ - 1 file changed, 388 insertions(+), 218 deletions(-) + coders/heic.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) diff --git a/coders/heic.c b/coders/heic.c -index f7961b3a62..c85c214189 100644 +index 96b4e218fc..846f5c7575 100644 --- a/coders/heic.c +++ b/coders/heic.c -@@ -80,13 +80,13 @@ - #include <libheif/heif.h> - #endif - #endif -- -+ - #if defined(MAGICKCORE_HEIC_DELEGATE) - /* - Define declarations. - */ - #define XmpNamespaceExtent 28 -- -+ - /* - Const declarations. - */ -@@ -127,12 +127,14 @@ static MagickBooleanType - % - */ - --static MagickBooleanType IsHeifSuccess(Image *image,struct heif_error *error, -- ExceptionInfo *exception) -+static inline MagickBooleanType IsHEIFSuccess(Image *image, -+ struct heif_error *error,ExceptionInfo *exception) - { - if (error->code == 0) - return(MagickTrue); -- ThrowBinaryException(CorruptImageError,error->message,image->filename); -+ (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError, -+ error->message,"(%d.%d) `%s'",error->code,error->subcode,image->filename); -+ return(MagickFalse); - } - - static MagickBooleanType ReadHEICColorProfile(Image *image, -@@ -142,41 +144,38 @@ static MagickBooleanType ReadHEICColorProfile(Image *image, - size_t - length; - -+ struct heif_error -+ error; -+ -+ unsigned char -+ *color_profile; -+ - /* - Read color profile. - */ - length=heif_image_handle_get_raw_color_profile_size(image_handle); -- if (length > 0) -+ if (length == 0) -+ return(MagickTrue); -+ if ((MagickSizeType) length > GetBlobSize(image)) -+ ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile", -+ image->filename); -+ color_profile=(unsigned char *) AcquireQuantumMemory(1,length); -+ if (color_profile == (unsigned char *) NULL) -+ return(MagickFalse); -+ error=heif_image_handle_get_raw_color_profile(image_handle,color_profile); -+ if (IsHEIFSuccess(image,&error,exception) != MagickFalse) - { -- unsigned char -- *color_buffer; -- -- if ((MagickSizeType) length > GetBlobSize(image)) -- ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile", -- image->filename); -- color_buffer=(unsigned char *) AcquireQuantumMemory(1,length); -- if (color_buffer != (unsigned char *) NULL) -- { -- struct heif_error -- error; -+ StringInfo -+ *profile; - -- 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); -- } -- } -+ profile=BlobToStringInfo(color_profile,length); -+ if (profile != (StringInfo*) NULL) -+ { -+ (void) SetImageProfile(image,"icc",profile,exception); -+ profile=DestroyStringInfo(profile); - } -- color_buffer=(unsigned char *) RelinquishMagickMemory(color_buffer); - } -+ color_profile=(unsigned char *) RelinquishMagickMemory(color_profile); - #endif - return(MagickTrue); - } -@@ -185,56 +184,53 @@ static MagickBooleanType ReadHEICExifProfile(Image *image, - struct heif_image_handle *image_handle,ExceptionInfo *exception) - { - heif_item_id -- exif_id; -+ id; - - int - count; - -+ size_t -+ extent; -+ -+ struct heif_error -+ error; -+ -+ unsigned char -+ *exif_profile; -+ - /* - Read Exif profile. - */ - count=heif_image_handle_get_list_of_metadata_block_IDs(image_handle,"Exif", -- &exif_id,1); -- if (count > 0) -+ &id,1); -+ if (count != 1) -+ return(MagickTrue); -+ extent=heif_image_handle_get_metadata_size(image_handle,id); -+ if ((MagickSizeType) extent > GetBlobSize(image)) -+ ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile", -+ image->filename); -+ exif_profile=(unsigned char *) AcquireQuantumMemory(1,extent); -+ if (exif_profile == (unsigned char *) NULL) -+ return(MagickFalse); -+ error=heif_image_handle_get_metadata(image_handle,id,exif_profile); -+ if (IsHEIFSuccess(image,&error,exception) != MagickFalse) - { -- size_t -- exif_size; -- -- unsigned char -- *exif_buffer; -- -- exif_size=heif_image_handle_get_metadata_size(image_handle,exif_id); -- if ((MagickSizeType) exif_size > GetBlobSize(image)) -- ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile", -- image->filename); -- exif_buffer=(unsigned char *) AcquireQuantumMemory(1,exif_size); -- if (exif_buffer != (unsigned char *) NULL) -+ StringInfo -+ *profile; -+ -+ /* -+ Skip first 4 bytes, the offset to the TIFF header. -+ */ -+ profile=(StringInfo*) NULL; -+ if (extent > 8) -+ profile=BlobToStringInfo(exif_profile+4,(size_t) extent-4); -+ if (profile != (StringInfo*) NULL) - { -- struct heif_error -- error; -- -- error=heif_image_handle_get_metadata(image_handle, -- exif_id,exif_buffer); -- if (error.code == 0) -- { -- StringInfo -- *profile; -- -- /* -- Skip first 4 bytes, the offset to the TIFF header. -- */ -- profile=(StringInfo*) NULL; -- if (exif_size > 8) -- profile=BlobToStringInfo(exif_buffer+4,(size_t) exif_size-4); -- if (profile != (StringInfo*) NULL) -- { -- (void) SetImageProfile(image,"exif",profile,exception); -- profile=DestroyStringInfo(profile); -- } -- } -+ (void) SetImageProfile(image,"exif",profile,exception); -+ profile=DestroyStringInfo(profile); - } -- exif_buffer=(unsigned char *) RelinquishMagickMemory(exif_buffer); -- } -+ } -+ exif_profile=(unsigned char *) RelinquishMagickMemory(exif_profile); - return(MagickTrue); - } - -@@ -253,13 +249,20 @@ static inline MagickBooleanType HEICSkipImage(const ImageInfo *image_info, - } - - static MagickBooleanType ReadHEICImageHandle(const ImageInfo *image_info, -- Image *image,struct heif_image_handle *image_handle, -- ExceptionInfo *exception) -+ Image *image,struct heif_image_handle *image_handle,ExceptionInfo *exception) - { - const uint8_t -- *p; -+ *p, -+ *pixels; -+ -+ enum heif_channel -+ channel; -+ -+ enum heif_chroma -+ chroma; - - int -+ shift, - stride = 0; - - MagickBooleanType -@@ -312,54 +315,102 @@ static MagickBooleanType ReadHEICImageHandle(const ImageInfo *image_info, - if (status == MagickFalse) - return(MagickFalse); - decode_options=heif_decoding_options_alloc(); --#if LIBHEIF_NUMERIC_VERSION > 0x01070000 -- decode_options->convert_hdr_to_8bit=1; --#endif +@@ -318,13 +318,17 @@ static MagickBooleanType ReadHEICImageHandle(const ImageInfo *image_info, if (preserve_orientation == MagickTrue) decode_options->ignore_transformations=1; -- error=heif_decode_image(image_handle,&heif_image,heif_colorspace_RGB, -- image->alpha_trait != UndefinedPixelTrait ? heif_chroma_interleaved_RGBA : -- heif_chroma_interleaved_RGB,decode_options); -+ chroma=heif_chroma_interleaved_RGB; -+ if (image->depth > 8) -+ chroma=heif_chroma_interleaved_RRGGBB_LE; -+ if (image->alpha_trait != UndefinedPixelTrait) -+ { -+ chroma=heif_chroma_interleaved_RGBA; -+ if (image->depth > 8) -+ chroma=heif_chroma_interleaved_RRGGBBAA_LE; -+ } -+ error=heif_decode_image(image_handle,&heif_image,heif_colorspace_RGB,chroma, -+ decode_options); -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) -+ return(MagickFalse); - heif_decoding_options_free(decode_options); -- if (IsHeifSuccess(image,&error,exception) == MagickFalse) -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) - return(MagickFalse); -- image->columns=(size_t) heif_image_get_width(heif_image, -- heif_channel_interleaved); -- image->rows=(size_t) heif_image_get_height(heif_image, -- heif_channel_interleaved); -+ channel=heif_channel_interleaved; -+ image->columns=(size_t) heif_image_get_width(heif_image,channel); -+ image->rows=(size_t) heif_image_get_height(heif_image,channel); - status=SetImageExtent(image,image->columns,image->rows,exception); - if (status == MagickFalse) - { - heif_image_release(heif_image); - return(MagickFalse); - } -- p=heif_image_get_plane_readonly(heif_image,heif_channel_interleaved,&stride); -- stride-=(int) (image->columns * (image->alpha_trait != UndefinedPixelTrait ? -- 4 : 3)); -- for (y=0; y < (ssize_t) image->rows; y++) -- { -- Quantum -- *q; -+ pixels=heif_image_get_plane_readonly(heif_image,channel,&stride); -+ if (pixels == (const uint8_t *) NULL) -+ { -+ heif_image_release(heif_image); -+ return(MagickFalse); -+ } -+ shift=(int) (16-image->depth); -+ if (image->depth <= 8) -+ for (y=0; y < (ssize_t) image->rows; y++) -+ { -+ Quantum -+ *q; - -- ssize_t -- x; -+ ssize_t -+ x; - -- q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); -- if (q == (Quantum *) NULL) -- break; -- for (x=0; x < (ssize_t) image->columns; x++) -+ /* -+ Transform 8-bit image. -+ */ -+ q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); -+ if (q == (Quantum *) NULL) -+ break; -+ p=pixels+(y*stride); -+ for (x=0; x < (ssize_t) image->columns; x++) -+ { -+ SetPixelRed(image,ScaleCharToQuantum((unsigned char) *(p++)),q); -+ SetPixelGreen(image,ScaleCharToQuantum((unsigned char) *(p++)),q); -+ SetPixelBlue(image,ScaleCharToQuantum((unsigned char) *(p++)),q); -+ if (image->alpha_trait != UndefinedPixelTrait) -+ SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) *(p++)),q); -+ q+=GetPixelChannels(image); -+ } -+ if (SyncAuthenticPixels(image,exception) == MagickFalse) -+ break; -+ } -+ else -+ for (y=0; y < (ssize_t) image->rows; y++) - { -- SetPixelRed(image,ScaleCharToQuantum((unsigned char) *(p++)),q); -- SetPixelGreen(image,ScaleCharToQuantum((unsigned char) *(p++)),q); -- SetPixelBlue(image,ScaleCharToQuantum((unsigned char) *(p++)),q); -- if (image->alpha_trait != UndefinedPixelTrait) -- SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) *(p++)),q); -- q+=GetPixelChannels(image); -+ Quantum -+ *q; -+ -+ ssize_t -+ x; -+ -+ /* -+ Transform 10-bit or 12-bit image. -+ */ -+ q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); -+ if (q == (Quantum *) NULL) -+ break; -+ p=pixels+(y*stride); -+ for (x=0; x < (ssize_t) image->columns; x++) -+ { -+ unsigned short pixel = ((*(p+1) << 8) | (*(p+0))) << shift; p+=2; -+ SetPixelRed(image,ScaleShortToQuantum(pixel),q); -+ pixel=((*(p+1) << 8) | (*(p+0))) << shift; p+=2; -+ SetPixelGreen(image,ScaleShortToQuantum(pixel),q); -+ pixel=((*(p+1) << 8) | (*(p+0))) << shift; p+=2; -+ SetPixelBlue(image,ScaleShortToQuantum(pixel),q); -+ if (image->alpha_trait != UndefinedPixelTrait) -+ { -+ pixel=((*(p+1) << 8) | (*(p+0))) << shift; p+=2; -+ SetPixelAlpha(image,ScaleShortToQuantum(pixel),q); -+ } -+ q+=GetPixelChannels(image); -+ } -+ if (SyncAuthenticPixels(image,exception) == MagickFalse) -+ break; - } -- p+=stride; -- if (SyncAuthenticPixels(image,exception) == MagickFalse) -- break; -- } - heif_image_release(heif_image); - return(MagickTrue); - } -@@ -382,6 +433,9 @@ static void ReadHEICDepthImage(const ImageInfo *image_info,Image *image, - struct heif_image_handle - *depth_handle; - -+ /* -+ Read HEIF depth image. -+ */ - option=GetImageOption(image_info,"heic:depth-image"); - if (IsStringTrue(option) == MagickFalse) - return; -@@ -393,7 +447,7 @@ static void ReadHEICDepthImage(const ImageInfo *image_info,Image *image, - return; - error=heif_image_handle_get_depth_image_handle(image_handle,depth_id, - &depth_handle); -- if (IsHeifSuccess(image,&error,exception) == MagickFalse) -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) - return; - AcquireNextImage(image_info,image,exception); - if (GetNextImageInList(image) != (Image *) NULL) -@@ -430,7 +484,7 @@ static Image *ReadHEICImage(const ImageInfo *image_info, - *image_handle; - - void -- *file_data; -+ *container; - - /* - Open image file. -@@ -449,43 +503,43 @@ static Image *ReadHEICImage(const ImageInfo *image_info, - if (GetBlobSize(image) > (MagickSizeType) MAGICK_SSIZE_MAX) - ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); - length=(size_t) GetBlobSize(image); -- file_data=AcquireMagickMemory(length); -- if (file_data == (void *) NULL) -+ container=AcquireMagickMemory(length); -+ if (container == (void *) NULL) - ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); -- if (ReadBlob(image,length,file_data) != (ssize_t) length) -+ if (ReadBlob(image,length,container) != (ssize_t) length) - { -- file_data=RelinquishMagickMemory(file_data); -+ container=RelinquishMagickMemory(container); - ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile"); - } - #if LIBHEIF_NUMERIC_VERSION >= 0x010b0000 -- if (heif_has_compatible_brand((unsigned char *) file_data,(int) length,"avif") != MagickFalse) -+ if (heif_has_compatible_brand((unsigned char *) container,(int) length,"avif") != MagickFalse) - (void) CopyMagickString(image->magick,"AVIF",MagickPathExtent); - #endif - /* - Decode HEIF image. - */ - heif_context=heif_context_alloc(); -- error=heif_context_read_from_memory_without_copy(heif_context,file_data, -+ error=heif_context_read_from_memory_without_copy(heif_context,container, - length,NULL); -- if (IsHeifSuccess(image,&error,exception) == MagickFalse) -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) - { - heif_context_free(heif_context); -- file_data=RelinquishMagickMemory(file_data); -+ container=RelinquishMagickMemory(container); - return(DestroyImageList(image)); - } - error=heif_context_get_primary_image_ID(heif_context,&primary_image_id); -- if (IsHeifSuccess(image,&error,exception) == MagickFalse) -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) - { - heif_context_free(heif_context); -- file_data=RelinquishMagickMemory(file_data); -+ container=RelinquishMagickMemory(container); - return(DestroyImageList(image)); - } - error=heif_context_get_image_handle(heif_context,primary_image_id, - &image_handle); -- if (IsHeifSuccess(image,&error,exception) == MagickFalse) -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) - { - heif_context_free(heif_context); -- file_data=RelinquishMagickMemory(file_data); -+ container=RelinquishMagickMemory(container); - return(DestroyImageList(image)); - } - status=ReadHEICImageHandle(image_info,image,image_handle,exception); -@@ -494,24 +548,23 @@ static Image *ReadHEICImage(const ImageInfo *image_info, - if ((status != MagickFalse) && (count > 1)) - { - heif_item_id -- *image_ids; -+ *ids; - - size_t - i; - -- image_ids=(heif_item_id *) AcquireQuantumMemory((size_t) count, -- sizeof(*image_ids)); -- if (image_ids == (heif_item_id *) NULL) -+ ids=(heif_item_id *) AcquireQuantumMemory((size_t) count,sizeof(*ids)); -+ if (ids == (heif_item_id *) NULL) - { - heif_context_free(heif_context); -- file_data=RelinquishMagickMemory(file_data); -+ container=RelinquishMagickMemory(container); - return(DestroyImageList(image)); - } -- (void) heif_context_get_list_of_top_level_image_IDs(heif_context, -- image_ids,(int) count); -+ (void) heif_context_get_list_of_top_level_image_IDs(heif_context,ids, -+ (int) count); - for (i=0; i < count; i++) - { -- if (image_ids[i] == primary_image_id) -+ if (ids[i] == primary_image_id) - continue; - /* - Allocate next image structure. -@@ -523,9 +576,8 @@ static Image *ReadHEICImage(const ImageInfo *image_info, - break; - } - image=SyncNextImageInList(image); -- error=heif_context_get_image_handle(heif_context,image_ids[i], -- &image_handle); -- if (IsHeifSuccess(image,&error,exception) == MagickFalse) -+ error=heif_context_get_image_handle(heif_context,ids[i],&image_handle); -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) - { - status=MagickFalse; - break; -@@ -538,20 +590,20 @@ static Image *ReadHEICImage(const ImageInfo *image_info, - if (image->scene >= (image_info->scene+image_info->number_scenes-1)) - break; - } -- image_ids=(heif_item_id *) RelinquishMagickMemory(image_ids); -+ ids=(heif_item_id *) RelinquishMagickMemory(ids); - } - error=heif_context_get_image_handle(heif_context,primary_image_id, - &image_handle); -- if (IsHeifSuccess(image,&error,exception) == MagickFalse) -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) + chroma=heif_chroma_interleaved_RGB; ++#if LIBHEIF_NUMERIC_VERSION > 0x01040000 + if (image->depth > 8) + chroma=heif_chroma_interleaved_RRGGBB_LE; ++#endif + if (image->alpha_trait != UndefinedPixelTrait) { - heif_context_free(heif_context); -- file_data=RelinquishMagickMemory(file_data); -+ container=RelinquishMagickMemory(container); - return(DestroyImageList(image)); - } - ReadHEICDepthImage(image_info,image,image_handle,exception); - heif_image_handle_release(image_handle); - heif_context_free(heif_context); -- file_data=RelinquishMagickMemory(file_data); -+ container=RelinquishMagickMemory(container); - if (status == MagickFalse) - return(DestroyImageList(image)); - (void) CloseBlob(image); -@@ -589,12 +641,12 @@ static MagickBooleanType IsHEIC(const unsigned char *magick,const size_t length) - #if defined(MAGICKCORE_HEIC_DELEGATE) - #if LIBHEIF_NUMERIC_VERSION >= 0x01040000 - enum heif_filetype_result -- heif_filetype; -+ type; - - if (length < 12) - return(MagickFalse); -- heif_filetype=heif_check_filetype(magick,(int) length); -- if (heif_filetype == heif_filetype_yes_supported) -+ type=heif_check_filetype(magick,(int) length); -+ if (type == heif_filetype_yes_supported) - return(MagickTrue); - #endif - #endif -@@ -748,12 +800,12 @@ static void WriteProfile(struct heif_context *context,Image *image, - const StringInfo - *profile; - -- ssize_t -- i; -- - size_t - length; - -+ ssize_t -+ i; -+ - struct heif_error - error; - -@@ -765,7 +817,7 @@ static void WriteProfile(struct heif_context *context,Image *image, - */ - image_handle=(struct heif_image_handle *) NULL; - error=heif_context_get_primary_image_handle(context,&image_handle); -- if (error.code != 0) -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) - return; - /* - Save image profile as a APP marker. -@@ -804,7 +856,7 @@ static void WriteProfile(struct heif_context *context,Image *image, - length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L); - error=heif_context_add_XMP_metadata(context,image_handle, - (void*) (GetStringInfoDatum(xmp_profile)+i),(int) length); -- if (error.code != 0) -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) - break; - } - xmp_profile=DestroyStringInfo(xmp_profile); -@@ -841,10 +893,9 @@ static MagickBooleanType WriteHEICImageYCbCr(Image *image, - struct heif_image *heif_image,ExceptionInfo *exception) - { - int -- bit_depth, -- p_y, - p_cb, -- p_cr; -+ p_cr, -+ p_y; - - MagickBooleanType - status; -@@ -856,33 +907,32 @@ static MagickBooleanType WriteHEICImageYCbCr(Image *image, - error; - - uint8_t -- *q_y, - *q_cb, -- *q_cr; -+ *q_cr, -+ *q_y; - -+ /* -+ Transform HEIF YCbCr image. -+ */ - status=MagickTrue; -- bit_depth=8; - error=heif_image_add_plane(heif_image,heif_channel_Y,(int) image->columns, -- (int) image->rows,bit_depth); -- status=IsHeifSuccess(image,&error,exception); -+ (int) image->rows,8); -+ status=IsHEIFSuccess(image,&error,exception); - if (status == MagickFalse) - return(status); - error=heif_image_add_plane(heif_image,heif_channel_Cb, -- ((int) image->columns+1)/2,((int) image->rows+1)/2,bit_depth); -- status=IsHeifSuccess(image,&error,exception); -+ ((int) image->columns+1)/2,((int) image->rows+1)/2,8); -+ status=IsHEIFSuccess(image,&error,exception); - if (status == MagickFalse) - return(status); - error=heif_image_add_plane(heif_image,heif_channel_Cr, -- ((int) image->columns+1)/2,((int) image->rows+1)/2,bit_depth); -- status=IsHeifSuccess(image,&error,exception); -+ ((int) image->columns+1)/2,((int) image->rows+1)/2,8); -+ status=IsHEIFSuccess(image,&error,exception); - if (status == MagickFalse) - return(status); - q_y=heif_image_get_plane(heif_image,heif_channel_Y,&p_y); - q_cb=heif_image_get_plane(heif_image,heif_channel_Cb,&p_cb); - q_cr=heif_image_get_plane(heif_image,heif_channel_Cr,&p_cr); -- /* -- Copy image to heif_image -- */ - for (y=0; y < (ssize_t) image->rows; y++) - { - const Quantum -@@ -930,35 +980,124 @@ static MagickBooleanType WriteHEICImageYCbCr(Image *image, - static MagickBooleanType WriteHEICImageRGBA(Image *image, - struct heif_image *heif_image,ExceptionInfo *exception) - { -+ const Quantum -+ *p; -+ -+ enum heif_channel -+ channel; -+ -+ int -+ stride; -+ - MagickBooleanType - status; - - ssize_t - y; - -+ struct heif_error -+ error; -+ -+ uint8_t -+ *pixels, -+ *q; -+ -+ /* -+ Transform HEIF RGBA image. -+ */ -+ status=MagickTrue; -+ channel=heif_channel_interleaved; -+ if (GetPixelChannels(image) == 1) -+ channel=heif_channel_Y; -+ error=heif_image_add_plane(heif_image,channel,(int) image->columns, -+ (int) image->rows,8); -+ status=IsHEIFSuccess(image,&error,exception); -+ if (status == MagickFalse) -+ return(status); -+ pixels=heif_image_get_plane(heif_image,channel,&stride); -+ if (pixels == (uint8_t *) NULL) -+ return(MagickFalse); -+ for (y=0; y < (ssize_t) image->rows; y++) -+ { -+ ssize_t -+ x; -+ -+ p=GetVirtualPixels(image,0,y,image->columns,1,exception); -+ if (p == (const Quantum *) NULL) -+ { -+ status=MagickFalse; -+ break; -+ } -+ q=pixels+(y*stride); -+ for (x=0; x < (ssize_t) image->columns; x++) -+ { -+ *(q++)=ScaleQuantumToChar(GetPixelRed(image,p)); -+ if (GetPixelChannels(image) > 1) -+ { -+ *(q++)=ScaleQuantumToChar(GetPixelGreen(image,p)); -+ *(q++)=ScaleQuantumToChar(GetPixelBlue(image,p)); -+ if (image->alpha_trait != UndefinedPixelTrait) -+ *(q++)=ScaleQuantumToChar(GetPixelAlpha(image,p)); -+ } -+ p+=GetPixelChannels(image); -+ } -+ if (image->previous == (Image *) NULL) -+ { -+ status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, -+ image->rows); -+ if (status == MagickFalse) -+ break; -+ } -+ } -+ return(status); -+} -+ -+static MagickBooleanType WriteHEICImageRRGGBBAA(Image *image, -+ struct heif_image *heif_image,ExceptionInfo *exception) -+{ - const Quantum - *p; - -+ enum heif_channel -+ channel; -+ - int -+ depth, -+ shift, - stride; - -+ MagickBooleanType -+ status; -+ -+ ssize_t -+ y; -+ - struct heif_error - error; - - uint8_t -- *q, -- *plane; -+ *pixels, -+ *q; - -- status=MagickTrue; -- error=heif_image_add_plane(heif_image,heif_channel_interleaved, -- (int) image->columns,(int) image->rows,8); -- status=IsHeifSuccess(image,&error,exception); -- if (status == MagickFalse) -- return status; -- plane=heif_image_get_plane(heif_image,heif_channel_interleaved,&stride); - /* -- Copy image to heif_image -+ Transform HEIF RGBA image with depth > 8. - */ -+ status=MagickTrue; -+ depth=image->depth > 10 ? 12 : 10; -+ channel=heif_channel_interleaved; -+ if (GetPixelChannels(image) == 1) -+ channel=heif_channel_Y; -+ error=heif_image_add_plane(heif_image,channel,(int) image->columns, -+ (int) image->rows,depth); -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) -+ return(MagickFalse); -+ status=IsHEIFSuccess(image,&error,exception); -+ if (status == MagickFalse) -+ return(status); -+ pixels=heif_image_get_plane(heif_image,channel,&stride); -+ if (pixels == (uint8_t *) NULL) -+ return(MagickFalse); -+ shift=(int) (16-depth); - for (y=0; y < (ssize_t) image->rows; y++) - { - ssize_t -@@ -970,17 +1109,29 @@ static MagickBooleanType WriteHEICImageRGBA(Image *image, - status=MagickFalse; - break; - } -- q=plane+(y*stride); -+ q=pixels+(y*stride); - for (x=0; x < (ssize_t) image->columns; x++) -- { -- *(q++)=ScaleQuantumToChar(GetPixelRed(image,p)); -- *(q++)=ScaleQuantumToChar(GetPixelGreen(image,p)); -- *(q++)=ScaleQuantumToChar(GetPixelBlue(image,p)); -- if (image->alpha_trait != UndefinedPixelTrait) -- *(q++)=ScaleQuantumToChar(GetPixelAlpha(image,p)); -- -- p+=GetPixelChannels(image); -- } -+ { -+ int pixel=ScaleQuantumToShort(GetPixelRed(image,p)) >> shift; -+ *(q++)=(uint8_t) (pixel & 0xff); -+ *(q++)=(uint8_t) (pixel >> 8); -+ if (GetPixelChannels(image) > 1) -+ { -+ pixel=ScaleQuantumToShort(GetPixelGreen(image,p)) >> shift; -+ *(q++)=(uint8_t) (pixel & 0xff); -+ *(q++)=(uint8_t) (pixel >> 8); -+ pixel=ScaleQuantumToShort(GetPixelBlue(image,p)) >> shift; -+ *(q++)=(uint8_t) (pixel & 0xff); -+ *(q++)=(uint8_t) (pixel >> 8); -+ if (image->alpha_trait != UndefinedPixelTrait) -+ { -+ pixel=ScaleQuantumToShort(GetPixelAlpha(image,p)) >> shift; -+ *(q++)=(uint8_t) (pixel & 0xff); -+ *(q++)=(uint8_t) (pixel >> 8); -+ } -+ } -+ p+=GetPixelChannels(image); -+ } - if (image->previous == (Image *) NULL) - { - status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, -@@ -996,6 +1147,9 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, - Image *image,ExceptionInfo *exception) - { - MagickBooleanType -+#if LIBHEIF_NUMERIC_VERSION > 0x01060200 -+ encode_avif, + chroma=heif_chroma_interleaved_RGBA; ++#if LIBHEIF_NUMERIC_VERSION > 0x01040000 + if (image->depth > 8) + chroma=heif_chroma_interleaved_RRGGBBAA_LE; +#endif - status; - - MagickOffsetType -@@ -1005,22 +1159,17 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, - *heif_context; - - struct heif_encoder -- *heif_encoder; -+ *heif_encoder = (struct heif_encoder*) NULL; - - struct heif_error - error; - - struct heif_image -- *heif_image; -+ *heif_image = (struct heif_image*) NULL; - - struct heif_writer - writer; - --#if LIBHEIF_NUMERIC_VERSION > 0x01060200 -- MagickBooleanType -- encode_avif; --#endif -- - /* - Open output image file. - */ -@@ -1035,11 +1184,9 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, - return(status); - scene=0; - heif_context=heif_context_alloc(); -- heif_image=(struct heif_image*) NULL; -- heif_encoder=(struct heif_encoder*) NULL; - #if LIBHEIF_NUMERIC_VERSION > 0x01060200 -- encode_avif=(LocaleCompare(image_info->magick,"AVIF") == 0) ? -- MagickTrue : MagickFalse; -+ encode_avif=(LocaleCompare(image_info->magick,"AVIF") == 0) ? MagickTrue : -+ MagickFalse; - #endif - do - { -@@ -1048,18 +1195,15 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, - *profile; - #endif - -- enum heif_colorspace -- colorspace; -- - enum heif_chroma - chroma; - -+ enum heif_colorspace -+ colorspace = heif_colorspace_YCbCr; -+ - MagickBooleanType -- lossless; -+ lossless = image_info->quality >= 100 ? MagickTrue : MagickFalse; - -- colorspace=heif_colorspace_YCbCr; -- lossless=image_info->quality == 100 ? MagickTrue : MagickFalse; -- chroma=lossless ? heif_chroma_444 : heif_chroma_420; - /* - Get encoder for the specified format. - */ -@@ -1071,23 +1215,37 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, - #endif - error=heif_context_get_encoder_for_format(heif_context, - heif_compression_HEVC,&heif_encoder); -- status=IsHeifSuccess(image,&error,exception); -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) -+ break; -+ status=IsHEIFSuccess(image,&error,exception); - if (status == MagickFalse) - break; -+ chroma=lossless != MagickFalse ? heif_chroma_444 : heif_chroma_420; - if (image->alpha_trait == BlendPixelTrait) - { -- colorspace=heif_colorspace_RGB; -- chroma=heif_chroma_interleaved_RGBA; - if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) + } + error=heif_decode_image(image_handle,&heif_image,heif_colorspace_RGB,chroma, + decode_options); +@@ -1225,16 +1229,20 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, status=TransformImageColorspace(image,sRGBColorspace,exception); -- } -- else if (IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) -- { colorspace=heif_colorspace_RGB; -- chroma=heif_chroma_interleaved_RGB; -+ chroma=heif_chroma_interleaved_RGBA; -+ if (image->depth > 8) -+ chroma=heif_chroma_interleaved_RRGGBBAA_LE; + chroma=heif_chroma_interleaved_RGBA; ++#if LIBHEIF_NUMERIC_VERSION > 0x01040000 + if (image->depth > 8) + chroma=heif_chroma_interleaved_RRGGBBAA_LE; ++#endif } -- else if (image->colorspace != YCbCrColorspace) -- status=TransformImageColorspace(image,YCbCrColorspace,exception); -+ else -+ if (IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) -+ { -+ colorspace=heif_colorspace_RGB; -+ chroma=heif_chroma_interleaved_RGB; -+ if (image->depth > 8) -+ chroma=heif_chroma_interleaved_RRGGBB_LE; -+ if (GetPixelChannels(image) == 1) -+ { -+ colorspace=heif_colorspace_monochrome; -+ chroma=heif_chroma_monochrome; -+ } -+ } -+ else -+ if (image->colorspace != YCbCrColorspace) -+ status=TransformImageColorspace(image,YCbCrColorspace,exception); - if (status == MagickFalse) - break; - /* -@@ -1095,7 +1253,9 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, - */ - error=heif_image_create((int) image->columns,(int) image->rows,colorspace, - chroma,&heif_image); -- status=IsHeifSuccess(image,&error,exception); -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) -+ break; -+ status=IsHEIFSuccess(image,&error,exception); - if (status == MagickFalse) - break; - #if LIBHEIF_NUMERIC_VERSION >= 0x01040000 -@@ -1107,18 +1267,26 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, + else + if (IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) + { + colorspace=heif_colorspace_RGB; + chroma=heif_chroma_interleaved_RGB; ++#if LIBHEIF_NUMERIC_VERSION > 0x01040000 + if (image->depth > 8) + chroma=heif_chroma_interleaved_RRGGBB_LE; ++#endif + if (GetPixelChannels(image) == 1) + { + colorspace=heif_colorspace_monochrome; +@@ -1265,9 +1273,11 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, if (colorspace == heif_colorspace_YCbCr) status=WriteHEICImageYCbCr(image,heif_image,exception); else -- status=WriteHEICImageRGBA(image,heif_image,exception); -+ if (image->depth > 8) -+ status=WriteHEICImageRRGGBBAA(image,heif_image,exception); -+ else -+ status=WriteHEICImageRGBA(image,heif_image,exception); - if (status == MagickFalse) - break; - /* -- Code and actually write the HEIC image -+ Encode HEIC image. - */ - if (lossless != MagickFalse) - error=heif_encoder_set_lossless(heif_encoder,1); -- else if (image_info->quality != UndefinedCompressionQuality) -- error=heif_encoder_set_lossy_quality(heif_encoder,(int) -- image_info->quality); -- status=IsHeifSuccess(image,&error,exception); -+ else -+ if (image_info->quality == UndefinedCompressionQuality) -+ error=heif_encoder_set_lossy_quality(heif_encoder,50); -+ else -+ error=heif_encoder_set_lossy_quality(heif_encoder,(int) -+ image_info->quality); -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) -+ break; -+ status=IsHEIFSuccess(image,&error,exception); - if (status == MagickFalse) - break; - #if LIBHEIF_NUMERIC_VERSION > 0x01060200 -@@ -1131,7 +1299,7 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, - if (option != (char *) NULL) - { - error=heif_encoder_set_parameter(heif_encoder,"speed",option); -- status=IsHeifSuccess(image,&error,exception); -+ status=IsHEIFSuccess(image,&error,exception); - if (status == MagickFalse) - break; - } -@@ -1139,7 +1307,7 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, - if (option != (char *) NULL) - { - error=heif_encoder_set_parameter(heif_encoder,"chroma",option); -- status=IsHeifSuccess(image,&error,exception); -+ status=IsHEIFSuccess(image,&error,exception); - if (status == MagickFalse) - break; - } -@@ -1148,7 +1316,9 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, - error=heif_context_encode_image(heif_context,heif_image,heif_encoder, - (const struct heif_encoding_options *) NULL, - (struct heif_image_handle **) NULL); -- status=IsHeifSuccess(image,&error,exception); -+ if (IsHEIFSuccess(image,&error,exception) == MagickFalse) -+ break; -+ status=IsHEIFSuccess(image,&error,exception); ++#if LIBHEIF_NUMERIC_VERSION > 0x01040000 + if (image->depth > 8) + status=WriteHEICImageRRGGBBAA(image,heif_image,exception); + else ++#endif + status=WriteHEICImageRGBA(image,heif_image,exception); if (status == MagickFalse) break; - #if LIBHEIF_NUMERIC_VERSION >= 0x01030000 -@@ -1177,7 +1347,7 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, - WriteProfile(heif_context,image,exception); - #endif - error=heif_context_write(heif_context,&writer,image); -- status=IsHeifSuccess(image,&error,exception); -+ status=IsHEIFSuccess(image,&error,exception); - } - if (heif_encoder != (struct heif_encoder*) NULL) - heif_encoder_release(heif_encoder); |