Extract an API to predict the DPI used by img2pdf

This commit is contained in:
mara004 2024-08-25 16:57:40 +02:00
parent 819b366bf5
commit 67f61d3fad

View file

@ -1295,6 +1295,47 @@ class pdfdoc(object):
raise ValueError("unknown engine: %s" % self.engine) raise ValueError("unknown engine: %s" % self.engine)
def pil_get_dpi(imgdata, imgformat, default_dpi):
ndpi = imgdata.info.get("dpi")
if ndpi is None:
# 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
if imgformat == ImageFormat.PNG and imgdata.info.get("aspect") is not None:
aspect = imgdata.info["aspect"]
# make sure not to go below the default dpi
if aspect[0] > aspect[1]:
ndpi = (default_dpi * aspect[0] / aspect[1], default_dpi)
else:
ndpi = (default_dpi, default_dpi * aspect[1] / aspect[0])
else:
ndpi = (default_dpi, default_dpi)
# In python3, the returned dpi value for some tiff images will
# not be an integer but a float. To make the behaviour of
# img2pdf the same between python2 and python3, we convert that
# float into an integer by rounding.
# Search online for the 72.009 dpi problem for more info.
ndpi = (int(round(ndpi[0])), int(round(ndpi[1])))
# Since commit 07a96209597c5e8dfe785c757d7051ce67a980fb or release 4.1.0
# Pillow retrieves the DPI from EXIF if it cannot find the DPI in the JPEG
# header. In that case it can happen that the horizontal and vertical DPI
# are set to zero.
if ndpi == (0, 0):
ndpi = (default_dpi, default_dpi)
# PIL defaults to a dpi of 1 if a TIFF image does not specify the dpi.
# In that case, we want to use a different default.
if ndpi == (1, 1) and imgformat == ImageFormat.TIFF:
ndpi = (
imgdata.tag_v2.get(TiffImagePlugin.X_RESOLUTION, default_dpi),
imgdata.tag_v2.get(TiffImagePlugin.Y_RESOLUTION, default_dpi),
)
return ndpi
def get_imgmetadata( def get_imgmetadata(
imgdata, imgformat, default_dpi, colorspace, rawdata=None, rotreq=None imgdata, imgformat, default_dpi, colorspace, rawdata=None, rotreq=None
): ):
@ -1310,28 +1351,11 @@ def get_imgmetadata(
ndpi = (hdpi, vdpi) ndpi = (hdpi, vdpi)
else: else:
imgwidthpx, imgheightpx = imgdata.size imgwidthpx, imgheightpx = imgdata.size
ndpi = pil_get_dpi(imgdata, imgformat, default_dpi)
ndpi = imgdata.info.get("dpi")
if ndpi is None:
# 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
if imgformat == ImageFormat.PNG and imgdata.info.get("aspect") is not None:
aspect = imgdata.info["aspect"]
# make sure not to go below the default dpi
if aspect[0] > aspect[1]:
ndpi = (default_dpi * aspect[0] / aspect[1], default_dpi)
else:
ndpi = (default_dpi, default_dpi * aspect[1] / aspect[0])
else:
ndpi = (default_dpi, default_dpi)
# In python3, the returned dpi value for some tiff images will
# not be an integer but a float. To make the behaviour of
# img2pdf the same between python2 and python3, we convert that
# float into an integer by rounding.
# Search online for the 72.009 dpi problem for more info.
ndpi = (int(round(ndpi[0])), int(round(ndpi[1])))
ics = imgdata.mode ics = imgdata.mode
logger.debug("input dpi = %d x %d", *ndpi)
# GIF and PNG files with transparency are supported # GIF and PNG files with transparency are supported
if imgformat in [ImageFormat.PNG, ImageFormat.GIF, ImageFormat.JPEG2000] and ( if imgformat in [ImageFormat.PNG, ImageFormat.GIF, ImageFormat.JPEG2000] and (
ics in ["RGBA", "LA"] or "transparency" in imgdata.info ics in ["RGBA", "LA"] or "transparency" in imgdata.info
@ -1353,23 +1377,6 @@ def get_imgmetadata(
elif ics in ["LA", "PA", "RGBA"] or "transparency" in imgdata.info: elif ics in ["LA", "PA", "RGBA"] or "transparency" in imgdata.info:
raise AlphaChannelError("This function must not be called on images with alpha") raise AlphaChannelError("This function must not be called on images with alpha")
# Since commit 07a96209597c5e8dfe785c757d7051ce67a980fb or release 4.1.0
# Pillow retrieves the DPI from EXIF if it cannot find the DPI in the JPEG
# header. In that case it can happen that the horizontal and vertical DPI
# are set to zero.
if ndpi == (0, 0):
ndpi = (default_dpi, default_dpi)
# PIL defaults to a dpi of 1 if a TIFF image does not specify the dpi.
# In that case, we want to use a different default.
if ndpi == (1, 1) and imgformat == ImageFormat.TIFF:
ndpi = (
imgdata.tag_v2.get(TiffImagePlugin.X_RESOLUTION, default_dpi),
imgdata.tag_v2.get(TiffImagePlugin.Y_RESOLUTION, default_dpi),
)
logger.debug("input dpi = %d x %d", *ndpi)
rotation = 0 rotation = 0
if rotreq in (None, Rotation.auto, Rotation.ifvalid): if rotreq in (None, Rotation.auto, Rotation.ifvalid):
if hasattr(imgdata, "_getexif") and imgdata._getexif() is not None: if hasattr(imgdata, "_getexif") and imgdata._getexif() is not None: