|
|
|
@ -62,7 +62,7 @@ try:
|
|
|
|
|
except ImportError:
|
|
|
|
|
have_pikepdf = False
|
|
|
|
|
|
|
|
|
|
__version__ = "0.4.4"
|
|
|
|
|
__version__ = "0.5.1"
|
|
|
|
|
default_dpi = 96.0
|
|
|
|
|
papersizes = {
|
|
|
|
|
"letter": "8.5inx11in",
|
|
|
|
@ -1311,7 +1311,19 @@ def get_imgmetadata(
|
|
|
|
|
else:
|
|
|
|
|
imgwidthpx, imgheightpx = imgdata.size
|
|
|
|
|
|
|
|
|
|
ndpi = imgdata.info.get("dpi", (default_dpi, 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
|
|
|
|
@ -1481,22 +1493,16 @@ def get_imgmetadata(
|
|
|
|
|
# SmartAlbums old version (found 2.2.6) exports JPG with only 1 compone
|
|
|
|
|
# with an RGB ICC profile which is useless.
|
|
|
|
|
# This produces an error in Adobe Acrobat, so we ignore it with a warning.
|
|
|
|
|
# Update: Found another case, the JPG is created by Adobe PhotoShop, so we
|
|
|
|
|
# don't check software anymore.
|
|
|
|
|
if iccp is not None and (
|
|
|
|
|
(color == Colorspace["L"] and imgformat == ImageFormat.JPEG)
|
|
|
|
|
):
|
|
|
|
|
exifsoft = None
|
|
|
|
|
if hasattr(imgdata, "_getexif") and imgdata._getexif() is not None:
|
|
|
|
|
for tag, value in imgdata._getexif().items():
|
|
|
|
|
if TAGS.get(tag, tag) == "Software":
|
|
|
|
|
exifsoft = value
|
|
|
|
|
with io.BytesIO(iccp) as f:
|
|
|
|
|
prf = ImageCms.ImageCmsProfile(f)
|
|
|
|
|
if (prf.profile.model and "sRGB" in prf.profile.model) and (
|
|
|
|
|
exifsoft and "SmartAlbums" in exifsoft
|
|
|
|
|
):
|
|
|
|
|
logger.warning(
|
|
|
|
|
"Ignoring RGB ICC profile in Grayscale JPG created by SmartAlbums"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if prf.profile.xcolor_space not in ("GRAY"):
|
|
|
|
|
logger.warning("Ignoring non-GRAY ICC profile in Grayscale JPG")
|
|
|
|
|
iccp = None
|
|
|
|
|
|
|
|
|
|
logger.debug("width x height = %dpx x %dpx", imgwidthpx, imgheightpx)
|
|
|
|
@ -3820,14 +3826,31 @@ def gui():
|
|
|
|
|
app.mainloop()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def file_is_icc(fname):
|
|
|
|
|
with open(fname, "rb") as f:
|
|
|
|
|
data = f.read(40)
|
|
|
|
|
if len(data) < 40:
|
|
|
|
|
return False
|
|
|
|
|
return data[36:] == b"acsp"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def validate_icc(fname):
|
|
|
|
|
if not file_is_icc(fname):
|
|
|
|
|
raise argparse.ArgumentTypeError('"%s" is not an ICC profile' % fname)
|
|
|
|
|
return fname
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_default_icc_profile():
|
|
|
|
|
for profile in [
|
|
|
|
|
"/usr/share/color/icc/sRGB.icc",
|
|
|
|
|
"/usr/share/color/icc/OpenICC/sRGB.icc",
|
|
|
|
|
"/usr/share/color/icc/colord/sRGB.icc",
|
|
|
|
|
]:
|
|
|
|
|
if os.path.exists(profile):
|
|
|
|
|
return profile
|
|
|
|
|
if not os.path.exists(profile):
|
|
|
|
|
continue
|
|
|
|
|
if not file_is_icc(profile):
|
|
|
|
|
continue
|
|
|
|
|
return profile
|
|
|
|
|
return "/usr/share/color/icc/sRGB.icc"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -4098,17 +4121,29 @@ RGB.""",
|
|
|
|
|
% Image.MAX_IMAGE_PIXELS,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
outargs.add_argument(
|
|
|
|
|
"--pdfa",
|
|
|
|
|
nargs="?",
|
|
|
|
|
const=get_default_icc_profile(),
|
|
|
|
|
default=None,
|
|
|
|
|
help="Output a PDF/A-1b compliant document. By default, this will "
|
|
|
|
|
"embed either /usr/share/color/icc/sRGB.icc, "
|
|
|
|
|
"/usr/share/color/icc/OpenICC/sRGB.icc or "
|
|
|
|
|
"/usr/share/color/icc/colord/sRGB.icc as the color profile, whichever "
|
|
|
|
|
"is found to exist first.",
|
|
|
|
|
)
|
|
|
|
|
if sys.platform == "win32":
|
|
|
|
|
# on Windows, there are no default paths to search for an ICC profile
|
|
|
|
|
# so make the argument required instead of optional
|
|
|
|
|
outargs.add_argument(
|
|
|
|
|
"--pdfa",
|
|
|
|
|
type=validate_icc,
|
|
|
|
|
help="Output a PDF/A-1b compliant document. The argument to this "
|
|
|
|
|
"option is the path to the ICC profile that will be embedded into "
|
|
|
|
|
"the resulting PDF.",
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
outargs.add_argument(
|
|
|
|
|
"--pdfa",
|
|
|
|
|
nargs="?",
|
|
|
|
|
const=get_default_icc_profile(),
|
|
|
|
|
default=None,
|
|
|
|
|
type=validate_icc,
|
|
|
|
|
help="Output a PDF/A-1b compliant document. By default, this will "
|
|
|
|
|
"embed either /usr/share/color/icc/sRGB.icc, "
|
|
|
|
|
"/usr/share/color/icc/OpenICC/sRGB.icc or "
|
|
|
|
|
"/usr/share/color/icc/colord/sRGB.icc as the color profile, whichever "
|
|
|
|
|
"is found to exist first.",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
sizeargs = parser.add_argument_group(
|
|
|
|
|
title="Image and page size and layout arguments",
|
|
|
|
|