JFIF is the small header that made JPEG a file format. The JPEG standard defines how to compress an image but not how to label the result, and JFIF, written at C-Cube Microsystems in the early 1990s, filled the gap: an APP0 segment directly after the start-of-image marker, holding a version, a pixel density and an optional thumbnail. Encoders built on libjpeg still write it, while many camera JPEGs go straight to EXIF.
The first bytes of a JPEG show it:
$ xxd -l 32 both.jpg
00000000: ffd8 ffe0 0010 4a46 4946 0001 0100 0001 ......JFIF......
00000010: 0001 0000 ffe1 0cee 4578 6966 0000 4949 ........Exif..IIffd8 is the start of image and ffe0 the APP0 marker, then a 16-byte length, the letters JFIF, a zero byte and 01 01 for version 1.01. At offset 0x14 the EXIF APP1 segment begins (ffe1, then Exif). Both specs want to come first; in practice JFIF does.
The fields
| ExifTool tag | Meaning |
|---|---|
| JFIFVersion | 1.01 or 1.02 |
| ResolutionUnit | 0 = none (aspect ratio only), 1 = inches, 2 = cm |
| XResolution, YResolution | Pixel density in that unit |
Version 1.01 is what libjpeg writes, so that is what Pillow and ImageMagick produce. Version 1.02 added the JFXX extension segment for thumbnails in other formats. A file saved by Pillow with no density set reads:
$ exiftool -G1 -s -n -JFIF:all pil.jpg
[JFIF] JFIFVersion : 1 1
[JFIF] ResolutionUnit : 0
[JFIF] XResolution : 1
[JFIF] YResolution : 1Unit 0 with 1:1 means square pixels and no DPI at all. Without -n, the version prints as 1.01.
Conflicts with EXIF
The density fields duplicate EXIF XResolution and YResolution, and readers differ on which wins when they disagree. The resolution entry shows Pillow reading 300 from JFIF while ImageMagick read 72 from EXIF on the same file. ExifTool can write the JFIF density fields, but not the version: -JFIF:JFIFVersion=1.02 returns "doesn't exist or isn't writable".
After stripping
exiftool -all= removes APP0 entirely, and a stripped file starts ffd8 ffdb, straight into the quantization tables. Pillow and ImageMagick still decoded it. Our metadata remover does the same full strip, covered in the metadata removal guide. To get a DPI value back, set it afterwards in the editor or with ExifTool, which puts it in EXIF IFD0 rather than a new JFIF segment.