From 645837193429af4f13bf70df3c9b3b96901d901e Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Mon, 21 Mar 2022 10:40:10 +0100 Subject: update to version 7.1.0 patch level 28 open https://github.com/ImageMagick/ImageMagick/issues/4972 Build failure with old libheif (El-7) --- ImageMagick7.spec | 12 +- heif.patch | 1005 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1016 insertions(+), 1 deletion(-) create mode 100644 heif.patch diff --git a/ImageMagick7.spec b/ImageMagick7.spec index 451ded7..c3ebe95 100644 --- a/ImageMagick7.spec +++ b/ImageMagick7.spec @@ -9,7 +9,7 @@ # Please preserve changelog entries # %global VER 7.1.0 -%global Patchlevel 27 +%global Patchlevel 28 %global incsuffixe -7 %global libsuffixe -7.Q16HDRI %bcond_without tests @@ -54,6 +54,8 @@ Url: http://www.imagemagick.org/ #Source0: ftp://ftp.imagemagick.org/pub/ImageMagick/releases/ImageMagick-%%{VER}-%%{Patchlevel}.tar.xz Source0: https://www.imagemagick.org/download/ImageMagick-%{VER}-%{Patchlevel}.tar.xz +Patch0: heif.patch + BuildRequires: gcc BuildRequires: gcc-c++ %if 0%{?fedora} >= 27 || 0%{?rhel} >= 8 @@ -361,6 +363,9 @@ however. %prep %setup -q -n %{libname}-%{VER}-%{Patchlevel} +%if 0%{?rhel} == 7 +%patch0 -p1 -R +%endif # for %%doc mkdir Magick++/examples @@ -611,6 +616,11 @@ fi %changelog +* Mon Mar 21 2022 Remi Collet - 7.1.0.28-1 +- update to version 7.1.0 patch level 28 +- open https://github.com/ImageMagick/ImageMagick/issues/4972 + Build failure with old libheif (El-7) + * Mon Mar 7 2022 Remi Collet - 7.1.0.27-1 - update to version 7.1.0 patch level 27 diff --git a/heif.patch b/heif.patch new file mode 100644 index 0000000..315a301 --- /dev/null +++ b/heif.patch @@ -0,0 +1,1005 @@ +From 418e3f40dc7302dae664eaaf0ea4cd4b7b59f852 Mon Sep 17 00:00:00 2001 +From: Cristy +Date: Sat, 19 Mar 2022 11:26:52 -0400 +Subject: [PATCH] Coders: support 10-bit AVIF per + https://github.com/ImageMagick/ImageMagick/discussions/4932 + +--- + coders/heic.c | 606 ++++++++++++++++++++++++++++++++------------------ + 1 file changed, 388 insertions(+), 218 deletions(-) + +diff --git a/coders/heic.c b/coders/heic.c +index f7961b3a62..c85c214189 100644 +--- a/coders/heic.c ++++ b/coders/heic.c +@@ -80,13 +80,13 @@ + #include + #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 + 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) + { + 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, ++#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) + 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; + } +- 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, + 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 (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); -- cgit