Open the same JPEG in Windows Explorer, Photoshop and a web-based checker and you might get 72, 300 and 96. This isn't a bug in any one of them. JPEG has two places to store resolution and nothing forces them to agree.
- JFIF (APP0): a units byte (0 = aspect ratio only, 1 = dots per inch, 2 = dots per cm) followed by Xdensity and Ydensity as 16-bit integers.
- EXIF (APP1): XResolution and YResolution as RATIONAL values, ResolutionUnit as 2 (inch) or 3 (cm).
Some programs read JFIF first, some read EXIF first, and some ignore both and show the screen's DPI. MS Paint is the classic example of the last one.
How it goes wrong in practice: an editor updates EXIF when you save for print but leaves JFIF at 72. Or a phone writes EXIF 72 and no JFIF at all, and a library adds a JFIF header with a 1:1 aspect ratio (units = 0), which some readers treat as "unknown, assume 72".
If you are writing code that sets DPI, the safe approach is:
- Write the same value to both JFIF and EXIF if they exist.
- Don't decode and re-encode the scan data. Copy it byte for byte, so image quality and other metadata stay as they are.
- Read the output back and check both fields before you hand the file over.
That is how FixDPI's browser DPI converter works, and its DPI checker shows the values a particular file is carrying.
Top comments (1)
That JFIF and EXIF mismatch causes plenty of scaling surprises when embedding JPEGs into PDFs.
A PDF Image XObject stores only pixel dimensions in
/Widthand/Heightwithout reading APP0 or APP1 directly during rendering. The PDF writer has to read one of those tags up front to calculate thecmtransformation matrix in 72-point user space. If Photoshop updates EXIF to 300 DPI while JFIF stays at 72, one PDF generator drops a 600 px graphic on the page at 2 inches wide, while another trusts JFIF and scales it to 8.33 inches across the page.Writing matching values into both headers without re-encoding the entropy-coded scan data avoids that layout drift and skips generation loss at the same time.