diff options
| -rw-r--r-- | ImageMagick7.spec | 12 | ||||
| -rw-r--r-- | heif.patch | 1005 | 
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);  | 
