Commit 1e2e12e76 for imagemagick.org
commit 1e2e12e76d0f454b88421467110ef91b27af2b60
Author: Dirk Lemstra <dirk@lemstra.org>
Date: Sun Oct 11 19:09:12 2026 +0200
Preserve source depth when decoding HEIC sequences
diff --git a/coders/heic.c b/coders/heic.c
index faec9283c..0e40cda64 100644
--- a/coders/heic.c
+++ b/coders/heic.c
@@ -702,28 +702,26 @@ static MagickBooleanType ReadHEICSequenceFrames(const ImageInfo *image_info,
Image *image,struct heif_context *heif_context,ExceptionInfo *exception)
{
const uint8_t
- *p,
- *pixels;
-
- enum heif_channel
- channel;
+ *pixels[4];
- enum heif_chroma
- chroma;
+ const enum heif_channel
+ channels[4] = { heif_channel_R, heif_channel_G, heif_channel_B,
+ heif_channel_Alpha };
heif_track
*track;
int
- bits_per_pixel,
+ bits_per_pixel[4],
has_alpha = 0,
- shift,
- stride = 0;
+ stride[4];
MagickBooleanType
status;
size_t
+ c,
+ number_channels,
scene;
struct heif_decoding_options
@@ -789,14 +787,8 @@ static MagickBooleanType ReadHEICSequenceFrames(const ImageInfo *image_info,
}
heif_image=(struct heif_image *) NULL;
- image->depth=10;
- if (image->alpha_trait != UndefinedPixelTrait)
- chroma=heif_chroma_interleaved_RRGGBBAA_LE;
- else
- chroma=heif_chroma_interleaved_RRGGBB_LE;
-
error=heif_track_decode_next_image(track,&heif_image,heif_colorspace_RGB,
- chroma,decode_options);
+ heif_chroma_444,decode_options);
if (error.code == heif_error_End_of_sequence)
break;
if (error.code != heif_error_Ok)
@@ -872,14 +864,27 @@ static MagickBooleanType ReadHEICSequenceFrames(const ImageInfo *image_info,
/*
Set image dimensions from the decoded frame.
*/
- 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);
- bits_per_pixel=heif_image_get_bits_per_pixel_range(heif_image,channel);
- if (bits_per_pixel > 0)
- image->depth=(size_t) bits_per_pixel;
- else
- image->depth=8;
+ image->columns=(size_t) heif_image_get_width(heif_image,heif_channel_R);
+ image->rows=(size_t) heif_image_get_height(heif_image,heif_channel_R);
+ has_alpha=heif_image_has_channel(heif_image,heif_channel_Alpha);
+ number_channels=has_alpha != 0 ? 4 : 3;
+ for (c=0; c < number_channels; c++)
+ {
+ bits_per_pixel[c]=heif_image_get_bits_per_pixel_range(heif_image,
+ channels[c]);
+ if ((bits_per_pixel[c] <= 0) || (bits_per_pixel[c] > 16))
+ break;
+ }
+ if (c != number_channels)
+ {
+ (void) ThrowMagickException(exception,GetMagickModule(),
+ CorruptImageError,"ImproperImageHeader","`%s'",image->filename);
+ heif_image_release(heif_image);
+ status=MagickFalse;
+ break;
+ }
+ image->depth=(size_t) bits_per_pixel[0];
+ image->alpha_trait=UndefinedPixelTrait;
if (has_alpha != 0)
{
image->alpha_trait=BlendPixelTrait;
@@ -901,42 +906,26 @@ static MagickBooleanType ReadHEICSequenceFrames(const ImageInfo *image_info,
heif_image_release(heif_image);
break;
}
- pixels=heif_image_get_plane_readonly(heif_image,channel,&stride);
- if (pixels == (const uint8_t *) NULL)
+ for (c=0; c < number_channels; c++)
{
+ pixels[c]=heif_image_get_plane_readonly(heif_image,channels[c],
+ &stride[c]);
+ if (pixels[c] == (const uint8_t *) NULL)
+ break;
+ }
+ if (c != number_channels)
+ {
+ (void) ThrowMagickException(exception,GetMagickModule(),
+ CorruptImageError,"ImproperImageHeader","`%s'",image->filename);
heif_image_release(heif_image);
status=MagickFalse;
break;
}
- shift=(int) (16-image->depth);
- if (image->depth <= 8)
- for (y=0; y < (ssize_t) image->rows; y++)
+ for (y=0; y < (ssize_t) image->rows; y++)
{
- Quantum
- *q;
+ const uint8_t
+ *p[4];
- ssize_t
- x;
-
- 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+=(ptrdiff_t) GetPixelChannels(image);
- }
- if (SyncAuthenticPixels(image,exception) == MagickFalse)
- break;
- }
- else
- for (y=0; y < (ssize_t) image->rows; y++)
- {
Quantum
*q;
@@ -945,28 +934,51 @@ static MagickBooleanType ReadHEICSequenceFrames(const ImageInfo *image_info,
q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
if (q == (Quantum *) NULL)
- break;
- p=pixels+(y*stride);
+ {
+ status=MagickFalse;
+ break;
+ }
+ for (c=0; c < number_channels; c++)
+ p[c]=pixels[c]+y*stride[c];
for (x=0; x < (ssize_t) image->columns; x++)
{
- unsigned short pixel = (((unsigned short) *(p+1) << 8) |
- (*(p+0))) << shift; p+=(ptrdiff_t) 2;
- SetPixelRed(image,ScaleShortToQuantum(pixel),q);
- pixel=(((unsigned short) *(p+1) << 8) | (*(p+0))) << shift; p+=(ptrdiff_t) 2;
- SetPixelGreen(image,ScaleShortToQuantum(pixel),q);
- pixel=(((unsigned short) *(p+1) << 8) | (*(p+0))) << shift; p+=(ptrdiff_t) 2;
- SetPixelBlue(image,ScaleShortToQuantum(pixel),q);
- if (image->alpha_trait != UndefinedPixelTrait)
+ Quantum
+ values[4];
+
+ for (c=0; c < number_channels; c++)
{
- pixel=(((unsigned short) *(p+1) << 8) | (*(p+0))) << shift; p+=(ptrdiff_t) 2;
- SetPixelAlpha(image,ScaleShortToQuantum(pixel),q);
+ if (bits_per_pixel[c] <= 8)
+ values[c]=ScaleCharToQuantum(*p[c]++);
+ else
+ {
+ uint16_t
+ pixel;
+
+ /*
+ Planar samples use native byte order.
+ */
+ (void) memcpy(&pixel,p[c],sizeof(pixel));
+ p[c]+=(ptrdiff_t) sizeof(pixel);
+ values[c]=ScaleShortToQuantum((unsigned short)
+ (pixel << (16-bits_per_pixel[c])));
+ }
}
+ SetPixelRed(image,values[0],q);
+ SetPixelGreen(image,values[1],q);
+ SetPixelBlue(image,values[2],q);
+ if (has_alpha != 0)
+ SetPixelAlpha(image,values[3],q);
q+=(ptrdiff_t) GetPixelChannels(image);
}
if (SyncAuthenticPixels(image,exception) == MagickFalse)
- break;
+ {
+ status=MagickFalse;
+ break;
+ }
}
heif_image_release(heif_image);
+ if (status == MagickFalse)
+ break;
scene++;
if (image_info->number_scenes != 0)
if (image->scene >= (image_info->scene+image_info->number_scenes-1))