Image Properties |
Remove Properties and Personal Information |
Apply Property Error An error occurred when writing the property 'Altitude' to the file 'IMG_0734.JPG'. |
Not all personal properties were cleared Windows was unable to remove properties from the selected files. Before sharing these files, you should review them for unwanted personal information. |
HDR symbol |
Apple Store Zurich MD5: ddbe1f1ea166c7793328db78896f18dd SHA1: ba2e522cdd8ffa1644cb4f09e38a8bee68359956 |
Ok, to start, I opened this jpg file in a hex editor. To find the Exif area, you first have to understand the jpg image format. Every jpg image starts with the "marker" ff d8. Then there follow blocks of data. Each block begins with a two-byte marker and a two-byte length. So for our file we have the following blocks (simplified):
000000: ff d8 ; marker SOI, Start Of Image
000002: ff e1 ; marker APP1, Application-specific
000004: 3f fe ; length of this block (next block at 004002)
000006: 45 78 69 66 00 00 4d... ; content of this block
004002: ff db ; marker DQT, Define Quantization Table(s)
004004: 00 84 ; length of this block (next block at 004088)
004006: 00 01 01 01 01 01 01... ; content of this block
004088: ff c0 ; marker SOF0, Start Of Frame (Baseline DCT)
00408a: 00 11 ; length of this block (next block at 00409b)
00408c: 08 09 90 0c c0 03 01... ; content of this block
00409b: ff c4 ; marker DHT, Huffman table
00409d: 01 a2 ; length of this block (next block at 00423f)
00409f: 00 00 01 05 01 01 01... ; content of this block
00423f: ff da ; marker SOS, Start Of Scan
004241: 00 0c 03 01 00 02 11... ; 12 bytes general data, then the image data
377f39: ff d9 ; marker EOI, End Of Image
One thing that is difficult here is that the image data (in the 'ff da' tag) cannot be read easily manually, so there is no easy way to find the next block, so if there is a block after that one, we would probably miss it. If you want to know more details and want to investigate deeper, there are some links at the end of this post. But actually this is not important for now, as we only need to look at the APP1 block, which contains the Exif data. We will examine this APP1 block now.
In this APP1 block, this starts with an Exif marker to indicate the Exif information.
0000: 45 78 69 66 00 ; "Exif\0"
0005: 00 ; padding
0006:
After this 6-byte introduction the structure of the rest of the Exif-block is similar to a TIFF version 6 file. I will start showing the addresses now starting with zero again, because all further pointers are starting here as well. If you want to calculate this back to the offset in the entire file, you have to add 6 for the Exif introduction and 6 more bytes for the jpg start (SOI+APP1 markers and length). So just add 0xC or 12d to the offset to get the real position within the file.
Ok, after the Exif introduction above, the TIFF header starts, now as mentioned, starting with offset 0 here.
0000: 4d 4d ; big-endian (Motorola)
0002: 00 2a ; 42d magic number
0004: 00 00 00 08 ; Offset to first IFD (just following)First we have an identification that all the following values are stored in big-endian (Motorola-style), meaning you can read the bytes just from left to right. I like this a lot more than little-endian, where you have to read from right to left (even worse if you store nibbles in bytes in words and such stuff; get almost impossible to read manually). So this identification says that the rest of the Exif block has to be read in big-endian style. Please note that there is no alignment, so a SHORT value (two bytes) can start either at an even or at an odd address.
What the rest of this Exif information contains, is actually just a list of IFDs (IFD stands for TIFF image file directory). The first IFD (IFD 0) usually just follows the TIFF header, so that's why the above offset is set to 00000008, meaning we can read it at the next address.
How is an IFD constructed? First we have a length (number of entries in the directory), then the entries themself (each 0xc/12d bytes long), then a LONG value with a pointer to the next IFD (zero if no other follows) and then usually the data that is referenced by the entries.
Each entry looks like this:
- two bytes tag identification
- two bytes data type
- four bytes number of values (not bytes!)
- four bytes pointer to the data, or, if the data fits into four bytes, the data itself
- 1=BYTE
- 2=ASCII (bytes, no unicode)
- 3=SHORT
- 4=LONG
- 5=RATIONAL (2 LONGs, first is numerator, then denominator)
- 7=UNDEFINED
- 9=SIGNED LONG
- 0xa=SIGNED RATIONAL
0008: 00 0b ; 11d fields follow, each 0xc/12d bytes size
000a: 01 0f 00 02 00 00 00 06 00 00 00 92 ; 010f Make 06 ASC:92->
0016: 01 10 00 02 00 00 00 0a 00 00 00 98 ; 0110 Model 0a ASC:98->
0022: 01 12 00 03 00 00 00 01 00 01 00 00 ; 0112 Orientation 01 SRT:0001
002e: 01 1a 00 05 00 00 00 01 00 00 00 a2 ; 011a XResolution 01 RAT:a2->
003a: 01 1b 00 05 00 00 00 01 00 00 00 aa ; 011b YResolution 01 RAT:aa->
0046: 01 28 00 03 00 00 00 01 00 02 00 00 ; 0128 ResolutionUnit 01 SRT:0002
0052: 01 31 00 02 00 00 00 06 00 00 00 b2 ; 0131 Software 06 ASC:b2->
005e: 01 32 00 02 00 00 00 14 00 00 00 b8 ; 0132 DateTime 14 ASC:b8->
006a: 02 13 00 03 00 00 00 01 00 01 00 00 ; 0213 YCbCrPositioning 01 SRT:0001
0076: 87 69 00 04 00 00 00 01 00 00 00 cc ; 8769 ExifIFD 01 LNG:000000cc
0082: 88 25 00 04 00 00 00 01 00 00 02 4a ; 8825 GPS IFD 01 LNG:0000024a
008e: 00 00 03 14 ; pointer to next IFD (314->)
0092: 41 70 70 6c 65 00 ; "Apple\0"
0098: 69 50 68 6f 6e 65 20 34 53 00 ; "iPhone 4S\0"
00a2: 00 00 00 48 00 00 00 01 ; 72d/1=72d
00aa: 00 00 00 48 00 00 00 01 ; 72d/1=72d
00b2: 35 2e 31 2e 31 00 ; "5.1.1\0"
00b8: 32 30 31 32 3a 31 30 3a 30 34 ; "2012:10:04 13:39:02\0"
00c2: 20 31 33 3a 33 39 3a 30 32 00
So this IFD 0 gives us these properties:
- Make: Apple
- Model: iPhone 4S
- Orientation: 1 (normal, the image doesn't need to be turned, it's horizontal already)
- XResolution: 72d
- YResolution: 72d
- ResolutionUnit: 2 (Inch)
- Software: 5.1.1 (iOS software version I used)
- DateTime: 2012:10:04 13:39:02
- YCbCrPositioning: 1 (centered)
First is the Exif Sub-IFD:
00cc: 00 18 ; 11d fields follow, each 12d bytes size, same as above
00ce: 82 9a 00 05 00 00 00 01 00 00 01 f2 ; 829a ExposureTime | 5=RATNL | 01 | 1f2->
00da: 82 9d 00 05 00 00 00 01 00 00 01 fa ; 829d FNumber | 5=RATNL | 01 | 1fa->
00e6: 88 22 00 03 00 00 00 01 00 02 00 00 ; 8822 ExposureProgram | 3=SHORT | 01 | 0002 normal prog
00f2: 88 27 00 03 00 00 00 01 00 50 00 00 ; 8827 ISOSpeedRatings | 3=SHORT | 01 | 0050 80d, ISO 80
00fe: 90 00 00 07 00 00 00 04 30 32 32 31 ; 9000 ExifVersion | 7=UNDEF | 04 | "0221" V2.21
010a: 90 03 00 02 00 00 00 14 00 00 02 02 ; 9003 DateTimeOriginal | 2=ASCII | 14 | 202->
0116: 90 04 00 02 00 00 00 14 00 00 02 16 ; 9004 DateTimeDigitized | 2=ASCII | 14 | 216->
0122: 91 01 00 07 00 00 00 04 01 02 03 00 ; 9101 ComponentsConfiguration | 7=UNDEF | 04 | 1230 -> Y,Cb,Cr
012e: 92 01 00 0a 00 00 00 01 00 00 02 2a ; 9201 ShutterSpeedValue | a=S-RAT | 01 | 22a->
013a: 92 02 00 05 00 00 00 01 00 00 02 32 ; 9202 ApertureValue | 5=RATNL | 01 | 232->
0146: 92 03 00 0a 00 00 00 01 00 00 02 3a ; 9203 BrightnessValue | a=S-RAT | 01 | 23a->
0152: 92 07 00 03 00 00 00 01 00 05 00 00 ; 9207 MeteringMode | 3=SHORT | 01 | 0005 (Pattern)
015e: 92 09 00 03 00 00 00 01 00 00 00 00 ; 9209 Flash | 3=SHORT | 01 | 0000 (not fired)
016a: 92 0a 00 05 00 00 00 01 00 00 02 42 ; 920a FocalLength | 5=RATNL | 01 | 242->
0176: a0 00 00 07 00 00 00 04 30 31 30 30 ; a000 FlashpixVersion | 7=UNDEF | 04 | "0100" V1.0
0182: a0 01 00 03 00 00 00 01 00 01 00 00 ; a001 ColorSpace | 3=SHORT | 01 | 0001 (sRGB)
018e: a0 02 00 04 00 00 00 01 00 00 0c c0 ; a002 PixelXDimension | 4=LONG | 01 | 00000cc0 (3264d)
019a: a0 03 00 04 00 00 00 01 00 00 09 90 ; a003 PixelYDimension | 4=LONG | 01 | 00000990 (2448d)
01a6: a2 17 00 03 00 00 00 01 00 02 00 00 ; a217 SensingMethod | 3=SHORT | 01 | 0002 colarea sens
01b2: a4 01 00 03 00 00 00 01 00 03 00 00 ; a401 CustomRendered | 3=SHORT | 01 | 0003 0=Norm,1=Cst
01be: a4 02 00 03 00 00 00 01 00 00 00 00 ; a402 ExposureMode | 3=SHORT | 01 | 0000 auto exp
01ca: a4 03 00 03 00 00 00 01 00 00 00 00 ; a403 WhiteBalance | 3=SHORT | 01 | 0000 autowhitebal
01d6: a4 05 00 03 00 00 00 01 00 23 00 00 ; a405 FocalLengthIn35mmFilm | 3=SHORT | 01 | 0023 35d
01e2: a4 06 00 03 00 00 00 01 00 00 00 00 ; a406 SceneCaptureType | 3=SHORT | 01 | 0000 Standard
01ee: 00 00 00 00 ; offset to next IFD (none)
01f2: 00 00 00 01 00 00 00 78 ; Exposure time in seconds: 1/120d
01fa: 00 00 00 0c 00 00 00 05 ; F Number: 12d/5d=2.4d
0202: 32 30 31 32 3a 31 30 3a 30 34 ; "2012:10:04 13:39:02\0"
020c: 20 31 33 3a 33 39 3a 30 32 00
0216: 32 30 31 32 3a 31 30 3a 30 34 ; "2012:10:04 13:39:02\0"
0220: 20 31 33 3a 33 39 3a 30 32 00
022a: 00 00 15 bf 00 00 03 26 ; Shutter speed, APEX setting 15bf/326=5567d/806d=6->(1/2^x)->1/64d
0232: 00 00 12 ed 00 00 07 7e ; lens aperture, APEX unit 12ed/77e=4845d/1918d=2->(sqrt(2)^x)->2
023a: 00 00 22 7e 00 00 06 1b ; value of brightness: 227e/61b=8830d/1563d=~5.6d EV
0242: 00 00 00 6b 00 00 00 19 ; actual focal length of the lens in mm: 6b/19=107d/25d=4.28d
This is the GPS Sub-IFD:
024a: 00 09 ; 9 fields follow, each 12d bytes size, same as above
024c: 00 01 00 02 00 00 00 02 4e 00 00 00 ; 0001 GPSLatitudeRef | 2=ASCII | 02 | "N\0" (north latitude)
0258: 00 02 00 05 00 00 00 03 00 00 02 bc ; 0002 GPSLatitude | 5=RATNL | 03 | 2bc->
0264: 00 03 00 02 00 00 00 02 45 00 00 00 ; 0003 GPSLongitudeRef | 2=ASCII | 02 | "E\0" (east longitude)
0270: 00 04 00 05 00 00 00 03 00 00 02 d4 ; 0004 GPSLongitude | 5=RATNL | 03 | 2d4->
027c: 00 05 00 01 00 00 00 01 00 00 00 00 ; 0005 GPSAltitudeRef | 1=BYTE | 01 | 0 (above sea level)
0288: 00 06 00 05 00 00 00 01 00 00 02 ec ; 0006 GPSAltitude | 5=RATNL | 01 | 2ec->
0294: 00 07 00 05 00 00 00 03 00 00 02 f4 ; 0007 GPSTimeStamp | 5=RATNL | 03 | 2f4->
02a0: 00 10 00 02 00 00 00 02 54 00 00 00 ; 0010 GPSImgDirectionRef | 2=ASCII | 02 | "T\0" (True North dir)
02ac: 00 11 00 05 00 00 00 01 00 00 03 0c ; 0011 GPSImgDirection | 5=RATNL | 01 | 30c->
02b8: 00 00 00 00 ; offset to next IFD (none)
02bc: 00 00 00 2f 00 00 00 01 ; latitude: 47d/1, 2248d/100d, 0/1 -> 47° 22.48'
02c4: 00 00 08 c8 00 00 00 64
02cc: 00 00 00 00 00 00 00 01
02d4: 00 00 00 08 00 00 00 01 ; longitude: 8/1, 3233d/100d, 0/1 -> 8° 32.33'
02dc: 00 00 0c a1 00 00 00 64
02e4: 00 00 00 00 00 00 00 01
02ec: 00 00 01 b6 00 00 00 01 ; Altitude in meters: 1b6/1=438d/1
02f4: 00 00 00 0b 00 00 00 01 ; timestamp: 11d/1,39/1,206/100 -> "11:39:2.06 GMT"
02fc: 00 00 00 27 00 00 00 01
0304: 00 00 00 ce 00 00 00 64
030c: 00 00 b1 76 00 00 00 97 ; direction of image: b176/97=45430/151=~300.86°
And this is IFD 1:
0314: 00 06 ; 6 fields follow, each 12d bytes size, same as above
0316: 01 03 00 03 00 00 00 01 00 06 00 00 ; 0103 Compression | 01 SRT:0006 (JPEG old-style)
0322: 01 1a 00 05 00 00 00 01 00 00 03 62 ; 011a XResolution | 01 RAT:362->
032e: 01 1b 00 05 00 00 00 01 00 00 03 6a ; 011b YResolution | 01 RAT:36a->
0346: 02 01 00 04 00 00 00 01 00 00 03 72 ; 0201 JPEGInterchangeFormat | 01 LNG:372->
0352: 02 02 00 04 00 00 00 01 00 00 30 ed ; 0202 JPEGInterchangeFormatLength | 01 LNG:000030ed
035e: 00 00 00 00 ; offset to next IFD (none)
0362: 00 00 00 48 00 00 00 01 ; number of pixels per resolution unit in image width direction: 48/1=72d
036a: 00 00 00 48 00 00 00 01 ; number of pixels per resolution unit in image length direction: 48/1=72d
Here starts the thumbnail image, also part of this IFD 1:
0372: ff d8 ff db 00 43 00 02 ; JPEG image (thumbnail 160x120)
...
3457: 8c f4 a2 8a 82 d1 ff d9 ; end of JPEG image thumbnail, JPEG length is 000030ed
345f:
00346b: 00 00 00 00 00 00 00 00 ; null bytes at address (file offset now) 0372+000030ed+C=00346b
...
003ffa: 00 00 00 00 00 00 00 00 ; number of null bytes:
; APP1_size-length_size-Exif_start-Exif_content_size=3ffe-2-6-345f=b97,
; also 004002-00346b=b97 (2967d)
004002: ff db ; marker DQT, Define Quantization Table(s)
004004: 00 84 ; length of this block (next block at 004004+0084=004088)
004006: 00 01 01 01 01 01 01... ; content of this block
So where is the HDR marker (this is an HDR image)?
The HDR marker is the a401 CustomRendered=3 tag in the Exif IFD. In non-HDR photos, this tag is completely missing. In non-HDR photos there are two other tags, both in the Exif Sub-IFD instead:
- 9214 SubjectArea, four SHORTs, X-Y-W-H for the area you clicked to be the subject, located between tags 920a and a000
- a40a Sharpness, one SHORT, value 0 (=Normal), located at the end
Ok, nothing special so far. But the bugs? Did you spot anything that could've caused Windows to react in such a way? Well, yes, there are many things that are bad here:
- In IFD 1 the counter says there are 6 fields, but there are actually only 5.
- In the Exif IFD, a405 FocalLengthIn35mmFilm has a value of 35. I assume this is wrong and not accidentally just exactly 35. Probably they don't care and just wanted to fill out this field with "something". The focal length is 4.28mm, but calculated into 35mm film?
- old-style thumbnail: The usage of the tags 0201 and 0202 has been disallowed since 17-Mar-1995, because there are problems and incompatibilities. See TIFF TechNote 2 in the links for details.
- After the thumbnail image there are a lot of zeroes. While not disallowed, this is still a waste of space in the file.
- The Exif IFD tag a401 CustomRenderer, used as the HDR marker, allows only the values 0 (Normal) and 1 (Custom). The value of 3 (HDR) is not defined in the standard. The standard says that custom tags can be obtained and I don't see the reason why Apple is not using any newly requested standard tag for that.
- In the GPS IFD the mandatory version tag is missing.
- The GPS IFD has a GPSTimeStamp tag, but not a GPSDateStamp.
Finally I found out that having the GPS IFD in general is causing this. It is not iOS related. I found several images with geolocation information on the Internet (from four different Nikon cameras: Coolpix P6000, D90, D300, D200) and the problem existed there as well. So Windows cannot remove GPS location properties. I think geolocation data is the most personal identifying information that a photo can have, so if Windows cannot remove that, then this feature is totally broken. I tried only with Windows 7, 64-bit, Ultimate, english. Maybe it's fixed with Windows 8. And from the above iOS image problems, maybe some are fixed with the release of iOS6, but I didn't test yet.
Here some links for more information about the file structure that were helpful for me if you want to dig into this yourself:
- Wikipedia EN: JPEG A general introduction to JPEG and the basic block markers
- xbdev.net: jpeg_file_layout Some more information about the JPEG file structure
- opennet.ru: jpeg.txt A thorough description of the JPEG format including image decoding
- media.mit.edu: exif Description of Exif file format
- exif.org: specifications Official EXIF format specification (see EXIF 2.2 PDF there)
- awaresystems.be: tifftags/baseline A nice description of each TIFF tag, see also Extension Tags, Private Tags, etc. in the menu
- awaresystems.be: tag jpeginterchangeformat Short description of JPEGInterchangeFormat and why it shouldn't be used
- remotesensing.org: TIFFTechNote2 TIFF Technical Note #2
- adobe.com: TIFF6 TIFF specification Revision 6.0
- picasaweb.google.com Photo of Zurich Apple Store