summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ImageMagick7.spec12
-rw-r--r--heif.patch1005
2 files changed, 1016 insertions, 1 deletions
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 <remi@remirepo.net> - 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 <remi@remirepo.net> - 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 <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
+
+---
+ 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 <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
+ 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);