]> granicus.if.org Git - imagemagick/commitdiff
Align pixel orientation with exif:Orientation in HEIC decoder (#1233)
authorSergii Rudchenko <rudchenkos@gmail.com>
Mon, 3 Sep 2018 18:33:15 +0000 (20:33 +0200)
committerDirk Lemstra <dirk@git.imagemagick.org>
Mon, 3 Sep 2018 18:33:15 +0000 (20:33 +0200)
* 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

index 419ca9845c56382fd9846a4cf7bd902ff17a6f75..83e2a3a806d18eb91d3e574d96bbe8215867903b 100644 (file)
@@ -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