Search code examples
exif

Exif: I can't calculate the orientation of the images


I have written a small and basic parser to determine the orientation of some jpeg images but it is not clear to me how to use the 0x112 tag, I do not find this information. Regarding ImageDescription, DateTime Value, I learned that it is enough to jump to the corresponding example address for date and time just refer to: tag 3201 which is at values 0200 (ascii) length 00000014 (20 characters) and address calculated from the beginning of APP1 000000C2 (194 decimal). The same reasoning made for orientation does not work: why?

Thanks

APP1 Length: 3710
APP1: Exif
byte order: MM
42: |00|2A|
offset: |00|00|00|08|
dir entry: 0 11
0F01|0200|00000006|00000092|
1001|0200|0000000E|00000098|
1201|0300|00000001|00010000|
1A01|0500|00000001|000000A6|
1B01|0500|00000001|000000AE|
2801|0300|00000001|00020000|
3101|0200|0000000B|000000B6|
3201|0200|00000014|000000C2|
1302|0300|00000001|00020000|
6987|0400|00000001|000000D6|
2588|0400|00000001|000003D6|


void MyExif(AnsiString filename)
{
    static unsigned char exif_data[65536L];

    FILE *fp;
    int c, length;

    fp=fopen(filename.c_str(),"rb");
    if(!fp) return;

    for (int i = 0; i < 500; i++) // I read 'n' data from the file to study Exif
    {
        c = (unsigned char) getc(fp);
        if(c == 0xFF) //FF D8
        {
            c = (unsigned char) getc(fp);

            if(c == 0xE1)  //FF E1
            {
                length = (((unsigned int) getc(fp)) << 8) + ((unsigned int) getc(fp));
                length -= 8;

                /* Read Exif head and check for "Exif" */
                for (int i = 0; i < 6; i++)
                exif_data[i] = (unsigned char) getc(fp);

                // check Exif head
                if(exif_data[0] == 'E' && exif_data[1] == 'x' &&
                        exif_data[2] == 'i' && exif_data[3] == 'f' &&
                        exif_data[4] == 0 && exif_data[5] == 0)
                {
                    Form1->Memo1->Lines->Add("APP1: Exif, Length: " + IntToStr(length));
                }
                else
                {
                    Form1->Memo1->Lines->Add("APP1: Not Exif");
                    if(fp) fclose(fp);
                    return;
                }

                // I read from byte order ....... onwards
                for(int i=0; i<length;i++)
                exif_data[i] = (unsigned char) getc(fp);

                // byte order II o MM
                AnsiString s;
                s.sprintf("byte order: %c%c",exif_data[0], exif_data[1]);
                Form1->Memo1->Lines->Add(s);

                // offset
                s.sprintf("offset: |%02X|%02X|%02X|%02X|",exif_data[4], exif_data[5],exif_data[6], exif_data[7]);
                Form1->Memo1->Lines->Add(s);


                // number of directory entry
                s.sprintf("dir entry: %d %d",exif_data[8],exif_data[9]);
                Form1->Memo1->Lines->Add(s);

                // the directory entry
                int numdataentry=exif_data[8]+exif_data[9];

                int tag[20], typ[20], cnt[20], ofs[20];
                int k=0; // indice dei data entry

                int byteorder = 0;
                if(exif_data[0] == 'M' && exif_data[1] == 'M') // big endian
                byteorder=1;
                if(exif_data[0] == 'I' && exif_data[1] == 'I') // little endian
                byteorder=0;

                // metto alcune info Exif negli array per usi vari
                for(int i=10; i < numdataentry*12; i+=12) // that's 12 bytes per directory entry
                {
                    if(byteorder) // if MM
                    {
                        tag[k]=exif_data[i] | exif_data[i+1] << 8;
                        typ[k]=exif_data[i+2] | exif_data[i+3] << 8;
                        cnt[k]=exif_data[i+4]<<24|exif_data[i+5]<<16|exif_data[i+6]<<8|exif_data[i+7];
                        ofs[k]=exif_data[i+8]<<24|exif_data[i+9]<<16|exif_data[i+10]<<8|exif_data[i+11];
                    }
                    else   // if II
                    {
                        tag[k]=exif_data[i] << 8 | exif_data[i+1];
                        typ[k]=exif_data[i+2] << 8 | exif_data[i+3];
                        cnt[k]=exif_data[i+4]|exif_data[i+5]<<8|exif_data[i+6]<<16|exif_data[i+7]<<24;
                        ofs[k]=exif_data[i+8]|exif_data[i+9]<<8|exif_data[i+10]<<16|exif_data[i+11]<<24;
                    }

                    k++;
                }

                int t, start, stop;

                for(t=0;t<numdataentry; t++)
                {
                    if(tag[t] == 0x1201)
                    {
                        // autorotation
                        if(ofs[t] == 0x80000) {ruota2(90.0);ruota2(90.0);ruota2(90.0);}
                        if(ofs[t] == 0x60000) ruota2(90.0);
                        if(ofs[t] == 0x30000) {ruota2(90.0); ruota2(90.0);}
                        if(ofs[t] == 0x03) {ruota2(90.0); ruota2(90.0);}

                        s="Rot: ";
                        s+=IntToHex(ofs[t],2);
                        Form1->Memo1->Lines->Add(IntToHex(tag[t],2)+ ")" + s);
                    }
                    if(tag[t] == 0x0F01)
                    {
                        s="Dev: ";
                        start=ofs[t], stop=ofs[t]+cnt[t]; //0x0F01
                        for(int i = start;i < stop ;i++)
                        s+=(char)exif_data[i];
                        Form1->Memo1->Lines->Add(IntToHex(tag[t],2)+ ")" + s);
                        //Form1->Image2->Canvas->TextOutW(10,135+k*15,s);
                    }
                    if(tag[t] == 0x1001)
                    {
                        s="Dev: ";
                        start=ofs[t], stop=ofs[t]+cnt[t]; //0x1001
                        for(int i = start;i < stop ;i++)
                        s+=(char)exif_data[i];
                        Form1->Memo1->Lines->Add(IntToHex(tag[t],2)+ ")" + s);
                        //Form1->Image2->Canvas->TextOutW(10,135+k*15,s);
                    }
                    if(tag[t] == 0x3201)
                    {
                        s="Data: ";
                        start=ofs[t], stop=ofs[t]+cnt[t]; //0x3201
                        for(int i = start;i < stop ;i++)
                        s+=(char)exif_data[i];
                        Form1->Memo1->Lines->Add(IntToHex(tag[t],2)+ ")" + s);
                        //Form1->Image2->Canvas->TextOutW(10,135+k*15,s);
                    }
                }
            }
        }
    }

    fclose(fp);
}

Solution

  • As you didn't share your code, it is hard to say what is wrong. Here's a way to work it out though:

    # Make a simple 1x1 black starting image with ImageMagick
    magick xc:black start.jpg
    
    # Make a copy with orientation=3 in "3.jpg"
    exiftool -orientation#=3 start.jpg -o 3.jpg
    
    # Analyse
    exiftool -v -v -v 3.jpg
    

      ExifToolVersion = 12.00
      FileName = 3.jpg
      Directory = .
      FileSize = 260
      FileModifyDate = 1632816155
      FileAccessDate = 1632816155
      FileInodeChangeDate = 1632816155
      FilePermissions = 33188
      FileType = JPEG
      FileTypeExtension = JPG
      MIMEType = image/jpeg
    JPEG APP0 (14 bytes):
        0006: 4a 46 49 46 00 01 01 00 00 01 00 01 00 00       [JFIF..........]
      + [BinaryData directory, 9 bytes]
      | JFIFVersion = 1 1
      | - Tag 0x0000 (2 bytes, int8u[2]):
      |     000b: 01 01                                           [..]
      | ResolutionUnit = 0
      | - Tag 0x0002 (1 bytes, int8u[1]):
      |     000d: 00                                              [.]
      | XResolution = 1
      | - Tag 0x0003 (2 bytes, int16u[1]):
      |     000e: 00 01                                           [..]
      | YResolution = 1
      | - Tag 0x0005 (2 bytes, int16u[1]):
      |     0010: 00 01                                           [..]
      | ThumbnailWidth = 0
      | - Tag 0x0007 (1 bytes, int8u[1]):
      |     0012: 00                                              [.]
      | ThumbnailHeight = 0
      | - Tag 0x0008 (1 bytes, int8u[1]):
      |     0013: 00                                              [.]
    JPEG APP1 (96 bytes):
        0018: 45 78 69 66 00 00 4d 4d 00 2a 00 00 00 08 00 05 [Exif..MM.*......]
        0028: 01 12 00 03 00 00 00 01 00 03 00 00 01 1a 00 05 [................]
        0038: 00 00 00 01 00 00 00 4a 01 1b 00 05 00 00 00 01 [.......J........]
        0048: 00 00 00 52 01 28 00 03 00 00 00 01 00 01 00 00 [...R.(..........]
        0058: 02 13 00 03 00 00 00 01 00 01 00 00 00 00 00 00 [................]
        0068: 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 01 [................]
      ExifByteOrder = MM
      + [IFD0 directory with 5 entries]
      | 0)  Orientation = 3
      |     - Tag 0x0112 (2 bytes, int16u[1]):
      |         0030: 00 03                                           [..]
      | 1)  XResolution = 1 (1/1)
      |     - Tag 0x011a (8 bytes, rational64u[1]):
      |         0068: 00 00 00 01 00 00 00 01                         [........]
      | 2)  YResolution = 1 (1/1)
      |     - Tag 0x011b (8 bytes, rational64u[1]):
      |         0070: 00 00 00 01 00 00 00 01                         [........]
      | 3)  ResolutionUnit = 1
      |     - Tag 0x0128 (2 bytes, int16u[1]):
      |         0054: 00 01                                           [..]
      | 4)  YCbCrPositioning = 1
      |     - Tag 0x0213 (2 bytes, int16u[1]):
      |         0060: 00 01                                           [..]
    JPEG DQT (65 bytes):
        007c: 00 03 02 02 02 02 02 03 02 02 02 03 03 03 03 04 [................]
        008c: 06 04 04 04 04 04 08 06 06 05 06 09 08 0a 0a 09 [................]
        009c: 08 09 09 0a 0c 0f 0c 0a 0b 0e 0b 09 09 0d 11 0d [................]
        00ac: 0e 0f 10 10 11 10 0a 0c 12 13 12 10 13 0f 10 10 [................]
        00bc: 10                                              [.]
    JPEG SOF0 (9 bytes):
        00c1: 08 00 01 00 01 01 01 11 00                      [.........]
      ImageWidth = 1
      ImageHeight = 1
      EncodingProcess = 0
      BitsPerSample = 8
      ColorComponents = 1
    JPEG DHT (18 bytes):
        00ce: 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
        00de: 00 09                                           [..]
    JPEG DHT (18 bytes):
        00e4: 10 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
        00f4: 00 00                                           [..]
    JPEG SOS
    JPEG EOI
    

    # Dump
    xxd 3.jpg
    

    00000000: ffd8 ffe0 0010 4a46 4946 0001 0100 0001  ......JFIF......
    00000010: 0001 0000 ffe1 0062 4578 6966 0000 4d4d  .......bExif..MM
    00000020: 002a 0000 0008 0005 0112 0003 0000 0001  .*..............
    00000030: 0003 0000 011a 0005 0000 0001 0000 004a  ...............J
    00000040: 011b 0005 0000 0001 0000 0052 0128 0003  ...........R.(..
    00000050: 0000 0001 0001 0000 0213 0003 0000 0001  ................
    00000060: 0001 0000 0000 0000 0000 0001 0000 0001  ................
    00000070: 0000 0001 0000 0001 ffdb 0043 0003 0202  ...........C....
    00000080: 0202 0203 0202 0203 0303 0304 0604 0404  ................
    00000090: 0404 0806 0605 0609 080a 0a09 0809 090a  ................
    000000a0: 0c0f 0c0a 0b0e 0b09 090d 110d 0e0f 1010  ................
    000000b0: 1110 0a0c 1213 1210 130f 1010 10ff c000  ................
    000000c0: 0b08 0001 0001 0101 1100 ffc4 0014 0001  ................
    000000d0: 0000 0000 0000 0000 0000 0000 0000 0009  ................
    000000e0: ffc4 0014 1001 0000 0000 0000 0000 0000  ................
    000000f0: 0000 0000 0000 ffda 0008 0101 0000 3f00  ..............?.
    00000100: 2a9f ffd9                                *...
    

    # Make a copy with orientation=5 in "5.jpg"
    exiftool -orientation#=5 start.jpg -o 5.jpg
    
    # Analyse
    exiftool -v -v -v 5.jpg
    

      ExifToolVersion = 12.00
      FileName = 5.jpg
      Directory = .
      FileSize = 260
      FileModifyDate = 1632816155
      FileAccessDate = 1632816155
      FileInodeChangeDate = 1632816155
      FilePermissions = 33188
      FileType = JPEG
      FileTypeExtension = JPG
      MIMEType = image/jpeg
    JPEG APP0 (14 bytes):
        0006: 4a 46 49 46 00 01 01 00 00 01 00 01 00 00       [JFIF..........]
      + [BinaryData directory, 9 bytes]
      | JFIFVersion = 1 1
      | - Tag 0x0000 (2 bytes, int8u[2]):
      |     000b: 01 01                                           [..]
      | ResolutionUnit = 0
      | - Tag 0x0002 (1 bytes, int8u[1]):
      |     000d: 00                                              [.]
      | XResolution = 1
      | - Tag 0x0003 (2 bytes, int16u[1]):
      |     000e: 00 01                                           [..]
      | YResolution = 1
      | - Tag 0x0005 (2 bytes, int16u[1]):
      |     0010: 00 01                                           [..]
      | ThumbnailWidth = 0
      | - Tag 0x0007 (1 bytes, int8u[1]):
      |     0012: 00                                              [.]
      | ThumbnailHeight = 0
      | - Tag 0x0008 (1 bytes, int8u[1]):
      |     0013: 00                                              [.]
    JPEG APP1 (96 bytes):
        0018: 45 78 69 66 00 00 4d 4d 00 2a 00 00 00 08 00 05 [Exif..MM.*......]
        0028: 01 12 00 03 00 00 00 01 00 05 00 00 01 1a 00 05 [................]
        0038: 00 00 00 01 00 00 00 4a 01 1b 00 05 00 00 00 01 [.......J........]
        0048: 00 00 00 52 01 28 00 03 00 00 00 01 00 01 00 00 [...R.(..........]
        0058: 02 13 00 03 00 00 00 01 00 01 00 00 00 00 00 00 [................]
        0068: 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 01 [................]
      ExifByteOrder = MM
      + [IFD0 directory with 5 entries]
      | 0)  Orientation = 5
      |     - Tag 0x0112 (2 bytes, int16u[1]):
      |         0030: 00 05                                           [..]
      | 1)  XResolution = 1 (1/1)
      |     - Tag 0x011a (8 bytes, rational64u[1]):
      |         0068: 00 00 00 01 00 00 00 01                         [........]
      | 2)  YResolution = 1 (1/1)
      |     - Tag 0x011b (8 bytes, rational64u[1]):
      |         0070: 00 00 00 01 00 00 00 01                         [........]
      | 3)  ResolutionUnit = 1
      |     - Tag 0x0128 (2 bytes, int16u[1]):
      |         0054: 00 01                                           [..]
      | 4)  YCbCrPositioning = 1
      |     - Tag 0x0213 (2 bytes, int16u[1]):
      |         0060: 00 01                                           [..]
    JPEG DQT (65 bytes):
        007c: 00 03 02 02 02 02 02 03 02 02 02 03 03 03 03 04 [................]
        008c: 06 04 04 04 04 04 08 06 06 05 06 09 08 0a 0a 09 [................]
        009c: 08 09 09 0a 0c 0f 0c 0a 0b 0e 0b 09 09 0d 11 0d [................]
        00ac: 0e 0f 10 10 11 10 0a 0c 12 13 12 10 13 0f 10 10 [................]
        00bc: 10                                              [.]
    JPEG SOF0 (9 bytes):
        00c1: 08 00 01 00 01 01 01 11 00                      [.........]
      ImageWidth = 1
      ImageHeight = 1
      EncodingProcess = 0
      BitsPerSample = 8
      ColorComponents = 1
    JPEG DHT (18 bytes):
        00ce: 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
        00de: 00 09                                           [..]
    JPEG DHT (18 bytes):
        00e4: 10 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
        00f4: 00 00                                           [..]
    JPEG SOS
    JPEG EOI
    

    # Dump
    xxd 5.jpg
    
    00000000: ffd8 ffe0 0010 4a46 4946 0001 0100 0001  ......JFIF......
    00000010: 0001 0000 ffe1 0062 4578 6966 0000 4d4d  .......bExif..MM
    00000020: 002a 0000 0008 0005 0112 0003 0000 0001  .*..............
    00000030: 0005 0000 011a 0005 0000 0001 0000 004a  ...............J
    00000040: 011b 0005 0000 0001 0000 0052 0128 0003  ...........R.(..
    00000050: 0000 0001 0001 0000 0213 0003 0000 0001  ................
    00000060: 0001 0000 0000 0000 0000 0001 0000 0001  ................
    00000070: 0000 0001 0000 0001 ffdb 0043 0003 0202  ...........C....
    00000080: 0202 0203 0202 0203 0303 0304 0604 0404  ................
    00000090: 0404 0806 0605 0609 080a 0a09 0809 090a  ................
    000000a0: 0c0f 0c0a 0b0e 0b09 090d 110d 0e0f 1010  ................
    000000b0: 1110 0a0c 1213 1210 130f 1010 10ff c000  ................
    000000c0: 0b08 0001 0001 0101 1100 ffc4 0014 0001  ................
    000000d0: 0000 0000 0000 0000 0000 0000 0000 0009  ................
    000000e0: ffc4 0014 1001 0000 0000 0000 0000 0000  ................
    000000f0: 0000 0000 0000 ffda 0008 0101 0000 3f00  ..............?.
    00000100: 2a9f ffd9                                *...
    

    Difference the two:

    enter image description here