use resolution (DPI) from EXIF first, if not found or invalid, then use info from Pillow image

This commit is contained in:
Leo 2023-11-30 13:16:50 +08:00
parent 819b366bf5
commit 98493e6a9a

View file

@ -22,7 +22,7 @@ import sys
import os import os
import zlib import zlib
import argparse import argparse
from PIL import Image, TiffImagePlugin, GifImagePlugin, ImageCms from PIL import Image, TiffImagePlugin, GifImagePlugin, ImageCms, ExifTags
if hasattr(GifImagePlugin, "LoadingStrategy"): if hasattr(GifImagePlugin, "LoadingStrategy"):
# Pillow 9.0.0 started emitting all frames but the first as RGB instead of # Pillow 9.0.0 started emitting all frames but the first as RGB instead of
@ -1298,6 +1298,7 @@ class pdfdoc(object):
def get_imgmetadata( def get_imgmetadata(
imgdata, imgformat, default_dpi, colorspace, rawdata=None, rotreq=None imgdata, imgformat, default_dpi, colorspace, rawdata=None, rotreq=None
): ):
if imgformat == ImageFormat.JPEG2000 and rawdata is not None and imgdata is None: if imgformat == ImageFormat.JPEG2000 and rawdata is not None and imgdata is None:
# this codepath gets called if the PIL installation is not able to # this codepath gets called if the PIL installation is not able to
# handle JPEG2000 files # handle JPEG2000 files
@ -1311,7 +1312,25 @@ def get_imgmetadata(
else: else:
imgwidthpx, imgheightpx = imgdata.size imgwidthpx, imgheightpx = imgdata.size
ndpi = None
# For JPEG images with both EXIF tags and JFIF tags, Pillow seems reading image resolution from JFIF.
# However, "Preview" on Mac and "Photos" on Windows read the resolution from EXIF.
# We try to read the value from EXIF first
exif = imgdata.getexif()
if exif:
exif_res_unit = exif.get(ExifTags.Base.ResolutionUnit)
exif_x_res = exif.get(ExifTags.Base.XResolution)
exif_y_res = exif.get(ExifTags.Base.YResolution)
if exif_x_res and exif_y_res:
if (exif_res_unit == 3): # cm
ndpi = (exif_x_res * 2.54, exif_y_res * 2.54)
else:
ndpi = (exif_x_res, exif_y_res)
# if no DPI from EXIF, get it from `info`
if ndpi is None:
ndpi = imgdata.info.get("dpi") ndpi = imgdata.info.get("dpi")
if ndpi is None: if ndpi is None:
# the PNG plugin of PIL adds the undocumented "aspect" field instead of # the PNG plugin of PIL adds the undocumented "aspect" field instead of
# the "dpi" field if the PNG pHYs chunk unit is not set to meters # the "dpi" field if the PNG pHYs chunk unit is not set to meters