diff options
Diffstat (limited to 'coders/heic.c')
-rw-r--r-- | coders/heic.c | 280 |
1 files changed, 151 insertions, 129 deletions
diff --git a/coders/heic.c b/coders/heic.c index 56273315e..7910247ca 100644 --- a/coders/heic.c +++ b/coders/heic.c @@ -22,7 +22,7 @@ % % % Copyright 2017-2018 YANDEX LLC. % % % -% Copyright 1999-2020 ImageMagick Studio LLC, a non-profit organization % +% Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization % % dedicated to making software imaging solutions freely available. % % % % You may not use this file except in compliance with the License. You may % @@ -126,7 +126,8 @@ static MagickBooleanType % o exception: return any errors or warnings in this structure. % */ -static MagickBooleanType IsHeifSuccess(struct heif_error *error,Image *image, + +static MagickBooleanType IsHeifSuccess(Image *image,struct heif_error *error, ExceptionInfo *exception) { if (error->code == 0) @@ -140,6 +141,9 @@ static MagickBooleanType ReadHEICColorProfile(Image *image, size_t length; + /* + Read color profile. + */ #if LIBHEIF_NUMERIC_VERSION >= 0x01040000 length=heif_image_handle_get_raw_color_profile_size(image_handle); if (length > 0) @@ -147,9 +151,6 @@ static MagickBooleanType ReadHEICColorProfile(Image *image, unsigned char *color_buffer; - /* - Read color profile. - */ if ((MagickSizeType) length > GetBlobSize(image)) ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile", image->filename); @@ -189,6 +190,9 @@ static MagickBooleanType ReadHEICExifProfile(Image *image, int count; + /* + Read Exif profile. + */ count=heif_image_handle_get_list_of_metadata_block_IDs(image_handle,"Exif", &exif_id,1); if (count > 0) @@ -199,9 +203,6 @@ static MagickBooleanType ReadHEICExifProfile(Image *image, unsigned char *exif_buffer; - /* - Read Exif profile. - */ exif_size=heif_image_handle_get_metadata_size(image_handle,exif_id); if ((MagickSizeType) exif_size > GetBlobSize(image)) ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile", @@ -220,8 +221,7 @@ static MagickBooleanType ReadHEICExifProfile(Image *image, *profile; /* - The first 4 byte should be skipped since they indicate the - offset to the start of the TIFF header of the Exif data. + Skip first 4 bytes, the offset to the TIFF header. */ profile=(StringInfo*) NULL; if (exif_size > 8) @@ -253,14 +253,20 @@ static inline MagickBooleanType HEICSkipImage(const ImageInfo *image_info, } static MagickBooleanType ReadHEICImageByID(const ImageInfo *image_info, - Image *image,struct heif_context *heif_context,heif_item_id image_id, + Image *image,struct heif_image_handle *image_handle, ExceptionInfo *exception) { + const uint8_t + *p_y, + *p_cb, + *p_cr, + *p_a; + int - stride_y, - stride_cb, - stride_cr, - stride_a; + stride_y = 0, + stride_cb = 0, + stride_cr = 0, + stride_a = 0; MagickBooleanType preserve_orientation, @@ -278,65 +284,36 @@ static MagickBooleanType ReadHEICImageByID(const ImageInfo *image_info, struct heif_image *heif_image; - struct heif_image_handle - *image_handle; - - const uint8_t - *p_y, - *p_cb, - *p_cr, - *p_a; - - error=heif_context_get_image_handle(heif_context,image_id,&image_handle); - if (IsHeifSuccess(&error,image,exception) == MagickFalse) - return(MagickFalse); - if (ReadHEICColorProfile(image,image_handle,exception) == MagickFalse) - { - heif_image_handle_release(image_handle); - return(MagickFalse); - } - if (ReadHEICExifProfile(image,image_handle,exception) == MagickFalse) - { - heif_image_handle_release(image_handle); - return(MagickFalse); - } /* - Set image size. + Read HEIC image from container. */ image->columns=(size_t) heif_image_handle_get_width(image_handle); image->rows=(size_t) heif_image_handle_get_height(image_handle); + image->depth=8; #if LIBHEIF_NUMERIC_VERSION > 0x01040000 image->depth=(size_t) heif_image_handle_get_luma_bits_per_pixel(image_handle); -#else - image->depth=8; #endif + image->colorspace=YCbCrColorspace; if (heif_image_handle_has_alpha_channel(image_handle)) image->alpha_trait=BlendPixelTrait; preserve_orientation=IsStringTrue(GetImageOption(image_info, "heic:preserve-orientation")); if (preserve_orientation == MagickFalse) (void) SetImageProperty(image,"exif:Orientation","1",exception); + if (ReadHEICColorProfile(image,image_handle,exception) == MagickFalse) + return(MagickFalse); + if (ReadHEICExifProfile(image,image_handle,exception) == MagickFalse) + return(MagickFalse); if (image_info->ping != MagickFalse) - { - image->colorspace=YCbCrColorspace; - heif_image_handle_release(image_handle); - return(MagickTrue); - } + return(MagickTrue); if (HEICSkipImage(image_info,image) != MagickFalse) - { - heif_image_handle_release(image_handle); - return(MagickTrue); - } + return(MagickTrue); status=SetImageExtent(image,image->columns,image->rows,exception); if (status == MagickFalse) - { - heif_image_handle_release(image_handle); - return(MagickFalse); - } + return(MagickFalse); /* - Copy HEIF image into ImageMagick data structures. + Convert HEIC format to ImageMagick YCrCb image. */ - (void) SetImageColorspace(image,YCbCrColorspace,exception); decode_options=heif_decoding_options_alloc(); #if LIBHEIF_NUMERIC_VERSION > 0x01070000 decode_options->convert_hdr_to_8bit=1; @@ -346,28 +323,20 @@ static MagickBooleanType ReadHEICImageByID(const ImageInfo *image_info, error=heif_decode_image(image_handle,&heif_image,heif_colorspace_YCbCr, heif_chroma_420,decode_options); heif_decoding_options_free(decode_options); - if (IsHeifSuccess(&error,image,exception) == MagickFalse) - { - heif_image_handle_release(image_handle); - return(MagickFalse); - } - /* - Correct the width and height of the image. - */ + if (IsHeifSuccess(image,&error,exception) == MagickFalse) + return(MagickFalse); image->columns=(size_t) heif_image_get_width(heif_image,heif_channel_Y); image->rows=(size_t) heif_image_get_height(heif_image,heif_channel_Y); status=SetImageExtent(image,image->columns,image->rows,exception); if (status == MagickFalse) { heif_image_release(heif_image); - heif_image_handle_release(image_handle); return(MagickFalse); } p_y=heif_image_get_plane_readonly(heif_image,heif_channel_Y,&stride_y); p_cb=heif_image_get_plane_readonly(heif_image,heif_channel_Cb,&stride_cb); p_cr=heif_image_get_plane_readonly(heif_image,heif_channel_Cr,&stride_cr); p_a=(const uint8_t *) NULL; - stride_a=0; if (image->alpha_trait != UndefinedPixelTrait) p_a=heif_image_get_plane_readonly(heif_image,heif_channel_Alpha,&stride_a); for (y=0; y < (ssize_t) image->rows; y++) @@ -375,7 +344,7 @@ static MagickBooleanType ReadHEICImageByID(const ImageInfo *image_info, Quantum *q; - register ssize_t + ssize_t x; q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); @@ -383,22 +352,21 @@ static MagickBooleanType ReadHEICImageByID(const ImageInfo *image_info, break; for (x=0; x < (ssize_t) image->columns; x++) { - SetPixelRed(image,ScaleCharToQuantum((unsigned char) p_y[y* - stride_y+x]),q); - SetPixelGreen(image,ScaleCharToQuantum((unsigned char) p_cb[(y/2)* - stride_cb+x/2]),q); - SetPixelBlue(image,ScaleCharToQuantum((unsigned char) p_cr[(y/2)* - stride_cr+x/2]),q); + SetPixelRed(image,ScaleCharToQuantum((unsigned char) + p_y[y*stride_y+x]),q); + SetPixelGreen(image,ScaleCharToQuantum((unsigned char) + p_cb[(y/2)*stride_cb+x/2]),q); + SetPixelBlue(image,ScaleCharToQuantum((unsigned char) + p_cr[(y/2)*stride_cr+x/2]),q); if (p_a != (const uint8_t *) NULL) - SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) p_a[y* - stride_a+x]),q); + SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) + p_a[y*stride_a+x]),q); q+=GetPixelChannels(image); } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } heif_image_release(heif_image); - heif_image_handle_release(image_handle); return(MagickTrue); } @@ -428,6 +396,9 @@ static Image *ReadHEICImage(const ImageInfo *image_info, struct heif_error error; + struct heif_image_handle + *image_handle; + void *file_data; @@ -445,7 +416,7 @@ static Image *ReadHEICImage(const ImageInfo *image_info, status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) return(DestroyImageList(image)); - if (GetBlobSize(image) > (MagickSizeType) SSIZE_MAX) + if (GetBlobSize(image) > (MagickSizeType) LONG_MAX) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); length=(size_t) GetBlobSize(image); file_data=AcquireMagickMemory(length); @@ -457,39 +428,48 @@ static Image *ReadHEICImage(const ImageInfo *image_info, ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile"); } /* - Decode HEIF file + Decode HEIF image. */ heif_context=heif_context_alloc(); error=heif_context_read_from_memory_without_copy(heif_context,file_data, length,NULL); - if (IsHeifSuccess(&error,image,exception) == MagickFalse) + if (IsHeifSuccess(image,&error,exception) == MagickFalse) { heif_context_free(heif_context); file_data=RelinquishMagickMemory(file_data); return(DestroyImageList(image)); } error=heif_context_get_primary_image_ID(heif_context,&primary_image_id); - if (IsHeifSuccess(&error,image,exception) == MagickFalse) + if (IsHeifSuccess(image,&error,exception) == MagickFalse) + { + heif_context_free(heif_context); + file_data=RelinquishMagickMemory(file_data); + return(DestroyImageList(image)); + } + error=heif_context_get_image_handle(heif_context,primary_image_id, + &image_handle); + if (IsHeifSuccess(image,&error,exception) == MagickFalse) { heif_context_free(heif_context); file_data=RelinquishMagickMemory(file_data); return(DestroyImageList(image)); } - status=ReadHEICImageByID(image_info,image,heif_context,primary_image_id, - exception); + status=ReadHEICImageByID(image_info,image,image_handle,exception); image_ids=(heif_item_id *) NULL; count=(size_t) heif_context_get_number_of_top_level_images(heif_context); if ((status != MagickFalse) && (count > 1)) { - register size_t + size_t i; image_ids=(heif_item_id *) AcquireQuantumMemory((size_t) count, sizeof(*image_ids)); if (image_ids == (heif_item_id *) NULL) { + heif_image_handle_release(image_handle); heif_context_free(heif_context); - ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); + file_data=RelinquishMagickMemory(file_data); + return(DestroyImageList(image)); } (void) heif_context_get_list_of_top_level_image_IDs(heif_context, image_ids,(int) count); @@ -507,8 +487,14 @@ static Image *ReadHEICImage(const ImageInfo *image_info, break; } image=SyncNextImageInList(image); - status=ReadHEICImageByID(image_info,image,heif_context,image_ids[i], - exception); + error=heif_context_get_image_handle(heif_context,primary_image_id, + &image_handle); + if (IsHeifSuccess(image,&error,exception) == MagickFalse) + { + status=MagickFalse; + break; + } + status=ReadHEICImageByID(image_info,image,image_handle,exception); if (status == MagickFalse) break; if (image_info->number_scenes != 0) @@ -516,15 +502,54 @@ static Image *ReadHEICImage(const ImageInfo *image_info, break; } } + heif_image_handle_release(image_handle); + error=heif_context_get_image_handle(heif_context,primary_image_id, + &image_handle); + if (IsHeifSuccess(image,&error,exception) == MagickFalse) + { + heif_context_free(heif_context); + file_data=RelinquishMagickMemory(file_data); + return(DestroyImageList(image)); + } + if (heif_image_handle_has_depth_image(image_handle) != 0) + { + heif_item_id + depth_id; + + int + number_images; + + /* + Read depth image. + */ + number_images=heif_image_handle_get_list_of_depth_image_IDs(image_handle, + &depth_id,1); + if (number_images > 0) + { + struct heif_image_handle + *depth_handle; + + error=heif_image_handle_get_depth_image_handle(image_handle,depth_id, + &depth_handle); + if (IsHeifSuccess(image,&error,exception) != MagickFalse) + { + AcquireNextImage(image_info,image,exception); + if (GetNextImageInList(image) == (Image *) NULL) + status=MagickFalse; + image=SyncNextImageInList(image); + status=ReadHEICImageByID(image_info,image,depth_handle, + exception); + heif_image_handle_release(depth_handle); + } + } + } + heif_image_handle_release(image_handle); if (image_ids != (heif_item_id *) NULL) (void) RelinquishMagickMemory(image_ids); heif_context_free(heif_context); file_data=RelinquishMagickMemory(file_data); if (status == MagickFalse) return(DestroyImageList(image)); - /* - Change image colorspace if it contains a color profile. - */ image=GetFirstImageInList(image); profile=GetImageProfile(image,"icc"); if (profile != (const StringInfo *) NULL) @@ -532,9 +557,10 @@ static Image *ReadHEICImage(const ImageInfo *image_info, Image *next; - next=image; - while (next != (Image *) NULL) - { + /* + Change image colorspace if it contains a color profile. + */ + for (next=image; next != (Image *) NULL; next=GetNextImageInList(next)) if (HEICSkipImage(image_info,next) != MagickFalse) { if (image_info->ping == MagickFalse) @@ -542,8 +568,6 @@ static Image *ReadHEICImage(const ImageInfo *image_info, else next->colorspace=sRGBColorspace; } - next=GetNextImageInList(next); - } } return(image); } @@ -736,7 +760,7 @@ static void WriteProfile(struct heif_context *context,Image *image, const StringInfo *profile; - register ssize_t + ssize_t i; size_t @@ -773,8 +797,8 @@ static void WriteProfile(struct heif_context *context,Image *image, image->filename); length=65533L; } - (void) heif_context_add_exif_metadata(context,image_handle, - (void*) GetStringInfoDatum(profile),(int) length); + (void) heif_context_add_exif_metadata(context,image_handle, + (void*) GetStringInfoDatum(profile),(int) length); } if (LocaleCompare(name,"XMP") == 0) { @@ -828,20 +852,17 @@ static struct heif_error heif_write_func(struct heif_context *context, static MagickBooleanType WriteHEICImageYCbCr(Image *image, struct heif_image *heif_image,ExceptionInfo *exception) { + int + p_y, + p_cb, + p_cr; + MagickBooleanType status; ssize_t y; - const Quantum - *p; - - int - p_y, - p_cb, - p_cr; - struct heif_error error; @@ -851,22 +872,21 @@ static MagickBooleanType WriteHEICImageYCbCr(Image *image, *q_cr; status=MagickTrue; - error=heif_image_add_plane(heif_image,heif_channel_Y,(int) image->columns, (int) image->rows,8); - status=IsHeifSuccess(&error,image,exception); + status=IsHeifSuccess(image,&error,exception); if (status == MagickFalse) - return status; + return(status); error=heif_image_add_plane(heif_image,heif_channel_Cb, ((int) image->columns+1)/2,((int) image->rows+1)/2,8); - status=IsHeifSuccess(&error,image,exception); + status=IsHeifSuccess(image,&error,exception); if (status == MagickFalse) - return status; + return(status); error=heif_image_add_plane(heif_image,heif_channel_Cr, ((int) image->columns+1)/2,((int) image->rows+1)/2,8); - status=IsHeifSuccess(&error,image,exception); + status=IsHeifSuccess(image,&error,exception); if (status == MagickFalse) - return status; + 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); @@ -875,7 +895,10 @@ static MagickBooleanType WriteHEICImageYCbCr(Image *image, */ for (y=0; y < (ssize_t) image->rows; y++) { - register ssize_t + const Quantum + *p; + + ssize_t x; p=GetVirtualPixels(image,0,y,image->columns,1,exception); @@ -884,7 +907,13 @@ static MagickBooleanType WriteHEICImageYCbCr(Image *image, status=MagickFalse; break; } - if ((y & 0x01) == 0) + if ((y & 0x01) != 0) + for (x=0; x < (ssize_t) image->columns; x++) + { + q_y[y*p_y+x]=ScaleQuantumToChar(GetPixelRed(image,p)); + p+=GetPixelChannels(image); + } + else for (x=0; x < (ssize_t) image->columns; x+=2) { q_y[y*p_y+x]=ScaleQuantumToChar(GetPixelRed(image,p)); @@ -897,12 +926,6 @@ static MagickBooleanType WriteHEICImageYCbCr(Image *image, p+=GetPixelChannels(image); } } - else - for (x=0; x < (ssize_t) image->columns; x++) - { - q_y[y*p_y+x]=ScaleQuantumToChar(GetPixelRed(image,p)); - p+=GetPixelChannels(image); - } if (image->previous == (Image *) NULL) { status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, @@ -939,7 +962,7 @@ static MagickBooleanType WriteHEICImageRGBA(Image *image, status=MagickTrue; error=heif_image_add_plane(heif_image,heif_channel_interleaved, (int) image->columns,(int) image->rows,8); - status=IsHeifSuccess(&error,image,exception); + status=IsHeifSuccess(image,&error,exception); if (status == MagickFalse) return status; plane=heif_image_get_plane(heif_image,heif_channel_interleaved,&stride); @@ -948,7 +971,7 @@ static MagickBooleanType WriteHEICImageRGBA(Image *image, */ for (y=0; y < (ssize_t) image->rows; y++) { - register ssize_t + ssize_t x; p=GetVirtualPixels(image,0,y,image->columns,1,exception); @@ -1019,7 +1042,6 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, heif_context=heif_context_alloc(); heif_image=(struct heif_image*) NULL; heif_encoder=(struct heif_encoder*) NULL; - do { #if LIBHEIF_NUMERIC_VERSION >= 0x01040000 @@ -1054,7 +1076,7 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, #endif error=heif_context_get_encoder_for_format(heif_context, heif_compression_HEVC,&heif_encoder); - status=IsHeifSuccess(&error,image,exception); + status=IsHeifSuccess(image,&error,exception); if (status == MagickFalse) break; if ((colorspace == heif_colorspace_YCbCr) && @@ -1067,9 +1089,9 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, /* Initialize HEIF encoder context. */ - error=heif_image_create((int) image->columns,(int) image->rows, - colorspace,chroma,&heif_image); - status=IsHeifSuccess(&error,image,exception); + error=heif_image_create((int) image->columns,(int) image->rows,colorspace, + chroma,&heif_image); + status=IsHeifSuccess(image,&error,exception); if (status == MagickFalse) break; #if LIBHEIF_NUMERIC_VERSION >= 0x01040000 @@ -1091,14 +1113,14 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, { error=heif_encoder_set_lossy_quality(heif_encoder,(int) image_info->quality); - status=IsHeifSuccess(&error,image,exception); + status=IsHeifSuccess(image,&error,exception); if (status == MagickFalse) break; } error=heif_context_encode_image(heif_context,heif_image,heif_encoder, (const struct heif_encoding_options *) NULL, (struct heif_image_handle **) NULL); - status=IsHeifSuccess(&error,image,exception); + status=IsHeifSuccess(image,&error,exception); if (status == MagickFalse) break; #if LIBHEIF_NUMERIC_VERSION >= 0x01030000 @@ -1125,7 +1147,7 @@ static MagickBooleanType WriteHEICImage(const ImageInfo *image_info, WriteProfile(heif_context,image,exception); #endif error=heif_context_write(heif_context,&writer,image); - status=IsHeifSuccess(&error,image,exception); + status=IsHeifSuccess(image,&error,exception); if (heif_encoder != (struct heif_encoder*) NULL) heif_encoder_release(heif_encoder); if (heif_image != (struct heif_image*) NULL) |