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);
}
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: