Incorrect exif orientation?

Started by Neal Krawetz, November 19, 2023, 11:30:01 AM

Previous topic - Next topic

Neal Krawetz

Exiftool 12.69 and lots of earlier ones.

I just noticed that the EXIF Orientation values seem wrong, at least when using iOS and Samsung devices.

The values should be (snipped from my C code):
                case 1: "Normal"; break;
                case 2: "Flipped Horizontally"; break;
                case 3: "Rotated 180 degrees"; break;
                case 4: "Rotated 180 degrees, Flipped Horizontally"; break;
                case 5: "Rotated 90 degrees, Flipped Horizontally"; break;
                case 6: "Rotated 270 degrees"; break;
                case 7: "Rotated 270 degrees, Flipped Horizontally"; break;
                case 8: "Rotated 90 degrees"; break;

But Exif.pm says:
%orientation = (
    1 => 'Horizontal (normal)',
    2 => 'Mirror horizontal',
    3 => 'Rotate 180',
    4 => 'Mirror vertical',
    5 => 'Mirror horizontal and rotate 270 CW',
    6 => 'Rotate 90 CW',
    7 => 'Mirror horizontal and rotate 90 CW',
    8 => 'Rotate 270 CW',
);

"6" should be "rotate 90 CCW" or "Rotate 270 CW".
"8" should be "rotate 270 CCW" or "Rotate 90 CW".
I think your strings for 5,6,7,8 should be 7,8,5,6.

StarGeek

Your C code is wrong. From the EXIF standard
Quote6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
So the top of the image is the left most column and the right side of the image is the top row.  To make the 0th column the top, you would rotate it 90° clockwise

Quote8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
Here it needs to be rotated 90° counter clockwise aka 270° clockwise

This JPEG Snoop page (by way of Archive.org) gives a visual representation of the orientation values.

But if the file type is MP4 based (HEIC, CR3, etc) then there is also the Rotation to take into account.  There's a previous post about this, I'll see if I can find it.

Edit: See Orientation tags in .heic photo, especially @GreyBeard's posts there.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

Neal Krawetz

I'm seeing lots of pictures like this:
https://fotoforensics.com/analysis.php?id=33d452ce99dddc754d143f0948f0c5e0ed6eb060.2371113&show=meta
iPhone photo.
Visually, it is clearly rotated 270' CW (or 90' CCW).
EXIF code is "6".  The EXIF documentation defines 6 as "Rotated 270 degrees". (Matches the visual content.)
However, exiftool says it is "Rotate 90 CW".

Or this:
https://fotoforensics.com/analysis.php?id=1f17afa3c5e1daaa584715222ca1ffd9f56c17bc.332189&show=meta
LGE LM-X320
Visually, it is clearly rotated 90' CW.
EXIF code is "8".  The EXIF documentation defines 8 at "Rotated 90 degrees". (Matches the visual content.)
But exiftool says "Rotate 270 CW".

FotoForensics shows the pre-rotation version of the picture, not the rendered post-rotation version.

(Off topic, rotated 270'/EXIF=6 is way more common than rotated 90'/EXIF=8. I guess most people rotate their phones the same way.)

Neal Krawetz

Ah, I think I see the difference.

You're interpreting the field as "The picture needs to be rotated x degrees for rendering."
While I'm seeing the field as "The picture is currently / was captured rotated x degrees."

It's the same thing.
Okay, this can be closed out as not-a-bug / no-change.

Phil Harvey

#4
Yes.  This image should be rotated 90 CW for proper viewing, and/or the camera was rotated 90 CW when the picture was taken.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

rhenley

#5
I've been confused by the same issue as the original post, since the Nikon Image SDK lists similar enum values as originally posted above:

///////////////////////////////////////////////////////////
//    eNkflOrientation
//
enum eNkflOrientation
{
    kNkfl_Orientation_CW0 = 1,        // Image's top left is visual top left
    kNkfl_Orientation_FlippedCW0 = 2,    // Image's top left is visual top right
    kNkfl_Orientation_CW180 = 3,    // Image's top left is visual bottom right
    kNkfl_Orientation_FlippedCW180 = 4,    // Image's top left is visual bottom left
    kNkfl_Orientation_FlippedCW270 = 5,    // Image's top left is visual left top
    kNkfl_Orientation_CW270 = 6,    // Image's top left is visual right top
    kNkfl_Orientation_FlippedCW90 = 7,    // Image's top left is visual right bottom
    kNkfl_Orientation_CW90 = 8        // Image's top left is visual left bottom
};

When I use Nikon's SDK, I see the value as an 8 unlike the 6 ExifTool reports for a similar type of rotation: Orientation: 8 = CW90

  | 9)  Orientation = 6
[IFD0] 274 Orientation: Rotate 90 CW
Orientation: Rotate 90 CW

I've been looking more closely at Nikon's SDK because I'm finding a number of cases where documented values are no longer supported in newer NEF files, the ISO tag value being an important one.

The Orientation value isn't the only apparent difference between the SDK's reported values, and ExifTool - for instance NEF Compression reports this with the SDK:

Image Quality: Lossless Compressed RAW (14-bit)
File Format Tag: 39 = NEF - Compressed, 1 = High Quality

vs,

When ExifTools reports a Compression value in a few places, but only one that is directly relevant, although it is a subvalue to another File format value in the SDK (39:1):

  FileType = NEF
  FileTypeExtension = NEF
  + [IFD0 directory with 28 entries]
  | 4)  Compression = 1
  | 20) SubIFD (SubDirectory) -->
  | + [SubIFD directory with 8 entries]
  | | 0)  SubfileType = 1
  | | 1)  Compression = 6
  | | 17) MakerNoteNikon (SubDirectory) -->
  | | | 54) NEFCompression = 3

NEF Compression                : Lossless

So no real bug here, just a bunch of translation/porting errors on Nikon's part instead:

///////////////////////////////////////////////////////////
// eNkflRawQuality
//
enum eNkflRawQuality
{
kNkfl_RawQuality_High = 0x0001,
kNkfl_RawQuality_Low = 0x0002,
kNkfl_RawQuality_LowResolution = 0x0003
};