From 41fa21a2eabdeee0202a5f32c081ee968784c265 Mon Sep 17 00:00:00 2001 From: Sergii Rudchenko Date: Mon, 3 Sep 2018 20:33:15 +0200 Subject: [PATCH] Align pixel orientation with exif:Orientation in HEIC decoder (#1233) * Align pixel orientation with exif:Orientation in HEIC decoder It turns out that in HEIC the pixels are never rotated and the metadata only indicates the orientation of the sensor when the photo was taken. Hence, there was a discrepancy between `Image->orientation` and actual pixel orientation in images loaded with the `heic` coder. Particularly, this led to incorrect behavior of the `-auto-orient` which in this case tried to compensate non-existing pixel rotation. https://github.com/ImageMagick/ImageMagick/issues/1232 --- coders/heic.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/coders/heic.c b/coders/heic.c index 419ca9845..83e2a3a80 100644 --- a/coders/heic.c +++ b/coders/heic.c @@ -59,6 +59,7 @@ #include "MagickCore/monitor-private.h" #include "MagickCore/montage.h" #include "MagickCore/transform.h" +#include "MagickCore/distort.h" #include "MagickCore/memory_.h" #include "MagickCore/memory-private.h" #include "MagickCore/option.h" @@ -121,6 +122,55 @@ static MagickBooleanType IsHeifSuccess(struct heif_error *error,Image *image, ThrowBinaryException(CorruptImageError,error->message,image->filename); } +/* An inverse of AutoOrientImage */ +static Image *CompensateOrientation(Image *image, ExceptionInfo *exception) +{ + const char + *value; + + value=GetImageProperty(image,"exif:Orientation",exception); + if (value == NULL) + { + return image; + } + + Image + *new_image = image; + + switch((OrientationType) StringToLong(value)) + { + case UndefinedOrientation: + case TopLeftOrientation: + default: + return image; + + case TopRightOrientation: + new_image = FlipImage(image,exception); + break; + case BottomRightOrientation: + new_image = RotateImage(image,180.0,exception); + break; + case BottomLeftOrientation: + new_image = FlopImage(image,exception); + break; + case LeftTopOrientation: + new_image = TransverseImage(image,exception); + break; + case RightTopOrientation: + new_image = RotateImage(image,270.0,exception); + break; + case RightBottomOrientation: + new_image = TransposeImage(image,exception); + break; + case LeftBottomOrientation: + new_image = RotateImage(image,90.0,exception); + break; + } + + DestroyImageList(image); + return new_image; +} + static Image *ReadHEICImage(const ImageInfo *image_info, ExceptionInfo *exception) { @@ -165,6 +215,9 @@ static Image *ReadHEICImage(const ImageInfo *image_info, void *file_data; + const char + *option; + /* Open image file. */ @@ -306,6 +359,21 @@ static Image *ReadHEICImage(const ImageInfo *image_info, heif_image_release(heif_image); heif_image_handle_release(image_handle); heif_context_free(heif_context); + + /* + There is a discrepancy between EXIF data and the actual orientation of + image pixels. ReadImage processes "exif:Orientation" expecting pixels to be + oriented accordingly. However, in HEIF the pixels are NOT rotated. + + There are two solutions to this problem: either reset the EXIF Orientation tag + so it matches the orientation of pixels, or rotate the pixels to match EXIF data. + */ + option=GetImageOption(image_info,"heic:preserve-orientation"); + if (IsStringTrue(option) == MagickTrue) + image = CompensateOrientation(image, exception); + else + SetImageProperty(image, "exif:Orientation", "1", exception); + return(GetFirstImageInList(image)); } #endif -- 2.40.0