Compare commits
5 commits
81502f21af
...
85cbe1d128
Author | SHA1 | Date | |
---|---|---|---|
85cbe1d128 | |||
b25429a4c1 | |||
c703e9df06 | |||
79e9985f35 | |||
cb2644c34f |
2 changed files with 323 additions and 33 deletions
100
src/img2pdf.py
100
src/img2pdf.py
|
@ -1750,7 +1750,9 @@ def parse_miff(data):
|
|||
# fmt: on
|
||||
|
||||
|
||||
def read_images(rawdata, colorspace, first_frame_only=False, rot=None):
|
||||
def read_images(
|
||||
rawdata, colorspace, first_frame_only=False, rot=None, include_thumbnails=False
|
||||
):
|
||||
im = BytesIO(rawdata)
|
||||
im.seek(0)
|
||||
imgdata = None
|
||||
|
@ -1836,6 +1838,77 @@ def read_images(rawdata, colorspace, first_frame_only=False, rot=None):
|
|||
if imgformat == ImageFormat.MPO:
|
||||
result = []
|
||||
img_page_count = 0
|
||||
assert len(imgdata._MpoImageFile__mpoffsets) == len(imgdata.mpinfo[0xB002])
|
||||
num_frames = len(imgdata.mpinfo[0xB002])
|
||||
# An MPO file can be a main image together with one or more thumbnails
|
||||
# if that is the case, then we only include all frames if the
|
||||
# --include-thumbnails option is given. If it is not, such an MPO file
|
||||
# will be embedded as is, so including its thumbnails but showing up
|
||||
# as a single image page in the resulting PDF.
|
||||
num_main_frames = 0
|
||||
num_thumbnail_frames = 0
|
||||
for i, mpent in enumerate(imgdata.mpinfo[0xB002]):
|
||||
# check only the first frame for being the main image
|
||||
if (
|
||||
i == 0
|
||||
and mpent["Attribute"]["DependentParentImageFlag"]
|
||||
and not mpent["Attribute"]["DependentChildImageFlag"]
|
||||
and mpent["Attribute"]["RepresentativeImageFlag"]
|
||||
and mpent["Attribute"]["MPType"] == "Baseline MP Primary Image"
|
||||
):
|
||||
num_main_frames += 1
|
||||
elif (
|
||||
not mpent["Attribute"]["DependentParentImageFlag"]
|
||||
and mpent["Attribute"]["DependentChildImageFlag"]
|
||||
and not mpent["Attribute"]["RepresentativeImageFlag"]
|
||||
and mpent["Attribute"]["MPType"]
|
||||
in [
|
||||
"Large Thumbnail (VGA Equivalent)",
|
||||
"Large Thumbnail (Full HD Equivalent)",
|
||||
]
|
||||
):
|
||||
num_thumbnail_frames += 1
|
||||
logger.debug(f"number of frames: {num_frames}")
|
||||
logger.debug(f"number of main frames: {num_main_frames}")
|
||||
logger.debug(f"number of thumbnail frames: {num_thumbnail_frames}")
|
||||
# this MPO file is a main image plus zero or more thumbnails
|
||||
# embed as-is unless the --include-thumbnails option was given
|
||||
if num_frames == 1 or (
|
||||
not include_thumbnails
|
||||
and num_main_frames == 1
|
||||
and num_thumbnail_frames + 1 == num_frames
|
||||
):
|
||||
color, ndpi, imgwidthpx, imgheightpx, rotation, iccp = get_imgmetadata(
|
||||
imgdata, imgformat, default_dpi, colorspace, rawdata, rot
|
||||
)
|
||||
if color == Colorspace["1"]:
|
||||
raise JpegColorspaceError("jpeg can't be monochrome")
|
||||
if color == Colorspace["P"]:
|
||||
raise JpegColorspaceError("jpeg can't have a color palette")
|
||||
if color == Colorspace["RGBA"]:
|
||||
raise JpegColorspaceError("jpeg can't have an alpha channel")
|
||||
logger.debug("read_images() embeds an MPO verbatim")
|
||||
cleanup()
|
||||
return [
|
||||
(
|
||||
color,
|
||||
ndpi,
|
||||
ImageFormat.JPEG,
|
||||
rawdata,
|
||||
None,
|
||||
imgwidthpx,
|
||||
imgheightpx,
|
||||
[],
|
||||
False,
|
||||
8,
|
||||
rotation,
|
||||
iccp,
|
||||
)
|
||||
]
|
||||
# If the control flow reaches here, the MPO has more than a single
|
||||
# frame but was not detected to be a main image followed by multiple
|
||||
# thumbnails. We thus treat this MPO as we do other multi-frame images
|
||||
# and include all its frames as individual pages.
|
||||
for offset, mpent in zip(
|
||||
imgdata._MpoImageFile__mpoffsets, imgdata.mpinfo[0xB002]
|
||||
):
|
||||
|
@ -2509,6 +2582,7 @@ def convert(*images, **kwargs):
|
|||
artborder=None,
|
||||
pdfa=None,
|
||||
rotation=None,
|
||||
include_thumbnails=False,
|
||||
)
|
||||
for kwname, default in _default_kwargs.items():
|
||||
if kwname not in kwargs:
|
||||
|
@ -2601,6 +2675,7 @@ def convert(*images, **kwargs):
|
|||
kwargs["colorspace"],
|
||||
kwargs["first_frame_only"],
|
||||
kwargs["rotation"],
|
||||
kwargs["include_thumbnails"],
|
||||
):
|
||||
pagewidth, pageheight, imgwidthpdf, imgheightpdf = kwargs["layout_fun"](
|
||||
imgwidthpx, imgheightpx, ndpi
|
||||
|
@ -2976,7 +3051,7 @@ def valid_date(string):
|
|||
else:
|
||||
try:
|
||||
return parser.parse(string)
|
||||
except TypeError:
|
||||
except:
|
||||
pass
|
||||
# as a last resort, try the local date utility
|
||||
try:
|
||||
|
@ -2989,7 +3064,7 @@ def valid_date(string):
|
|||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
else:
|
||||
return datetime.utcfromtimestamp(int(utime))
|
||||
return datetime.fromtimestamp(int(utime))
|
||||
raise argparse.ArgumentTypeError("cannot parse date: %s" % string)
|
||||
|
||||
|
||||
|
@ -3691,7 +3766,7 @@ def gui():
|
|||
app.mainloop()
|
||||
|
||||
|
||||
def main(argv=sys.argv):
|
||||
def get_main_parser():
|
||||
rendered_papersizes = ""
|
||||
for k, v in sorted(papersizes.items()):
|
||||
rendered_papersizes += " %-8s %s\n" % (papernames[k], v)
|
||||
|
@ -3936,6 +4011,17 @@ RGB.""",
|
|||
"input image be converted into a page in the resulting PDF.",
|
||||
)
|
||||
|
||||
outargs.add_argument(
|
||||
"--include-thumbnails",
|
||||
action="store_true",
|
||||
help="Some multi-frame formats like MPO carry a main image and "
|
||||
"one or more scaled-down copies of the main image (thumbnails). "
|
||||
"In such a case, img2pdf will only include the main image and "
|
||||
"not create additional pages for each of the thumbnails. If this "
|
||||
"option is set, img2pdf will instead create one page per frame and "
|
||||
"thus store each thumbnail on its own page.",
|
||||
)
|
||||
|
||||
outargs.add_argument(
|
||||
"--pillow-limit-break",
|
||||
action="store_true",
|
||||
|
@ -4243,8 +4329,11 @@ and left/right, respectively. It is not possible to specify asymmetric borders.
|
|||
action="store_true",
|
||||
help="Instruct the PDF viewer to open the PDF in fullscreen mode",
|
||||
)
|
||||
return parser
|
||||
|
||||
args = parser.parse_args(argv[1:])
|
||||
|
||||
def main(argv=sys.argv):
|
||||
args = get_main_parser().parse_args(argv[1:])
|
||||
|
||||
if args.verbose:
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
@ -4333,6 +4422,7 @@ and left/right, respectively. It is not possible to specify asymmetric borders.
|
|||
artborder=args.art_border,
|
||||
pdfa=args.pdfa,
|
||||
rotation=args.rotation,
|
||||
include_thumbnails=args.include_thumbnails,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("error: " + str(e))
|
||||
|
|
|
@ -19,6 +19,8 @@ from packaging.version import parse as parse_version
|
|||
import warnings
|
||||
import json
|
||||
import pathlib
|
||||
import itertools
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
img2pdfprog = os.getenv("img2pdfprog", default="src/img2pdf.py")
|
||||
|
||||
|
@ -37,6 +39,14 @@ for glob in ICC_PROFILE_PATHS:
|
|||
ICC_PROFILE = path
|
||||
break
|
||||
|
||||
HAVE_FAKETIME = True
|
||||
try:
|
||||
ver = subprocess.check_output(["faketime", "--version"])
|
||||
if b"faketime: Version " not in ver:
|
||||
HAVE_FAKETIME = False
|
||||
except FileNotFoundError:
|
||||
HAVE_FAKETIME = False
|
||||
|
||||
HAVE_MUTOOL = True
|
||||
try:
|
||||
ver = subprocess.check_output(["mutool", "-v"], stderr=subprocess.STDOUT)
|
||||
|
@ -130,6 +140,25 @@ psnr_re = re.compile(rb"((?:inf|(?:0|[1-9][0-9]*)(?:\.[0-9]+)?))(?: \([0-9.]+\))
|
|||
###############################################################################
|
||||
|
||||
|
||||
# Interpret a datetime string in a given timezone and format it according to a
|
||||
# given format string in in UTC.
|
||||
# We avoid using the Python datetime module for this job because doing so would
|
||||
# just replicate the code we want to test for correctness.
|
||||
def tz2utcstrftime(string, fmt, timezone):
|
||||
return (
|
||||
subprocess.check_output(
|
||||
[
|
||||
"date",
|
||||
"--utc",
|
||||
f'--date=TZ="{timezone}" {string}',
|
||||
f"+{fmt}",
|
||||
]
|
||||
)
|
||||
.decode("utf8")
|
||||
.removesuffix("\n")
|
||||
)
|
||||
|
||||
|
||||
def find_closest_palette_color(color, palette):
|
||||
if color.ndim == 0:
|
||||
idx = (numpy.abs(palette - color)).argmin()
|
||||
|
@ -603,7 +632,7 @@ def alpha_value():
|
|||
alpha = numpy.zeros((60, 60, 4), dtype=numpy.dtype("int64"))
|
||||
|
||||
# draw three circles
|
||||
for (xpos, ypos, color) in [
|
||||
for xpos, ypos, color in [
|
||||
(12, 3, [0xFFFF, 0, 0, 0xFFFF]),
|
||||
(21, 21, [0, 0xFFFF, 0, 0xFFFF]),
|
||||
(3, 21, [0, 0, 0xFFFF, 0xFFFF]),
|
||||
|
@ -2331,7 +2360,10 @@ def tiff_float_img(tmp_path_factory, tmp_normal_png):
|
|||
assert identify[0]["image"].get("colorspace") == "sRGB", str(identify)
|
||||
assert identify[0]["image"].get("type") == "TrueColor", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 8, str(identify)
|
||||
|
@ -2392,7 +2424,10 @@ def tiff_cmyk8_img(tmp_path_factory, tmp_normal_png):
|
|||
assert identify[0]["image"].get("colorspace") == "CMYK", str(identify)
|
||||
assert identify[0]["image"].get("type") == "ColorSeparation", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 8, str(identify)
|
||||
|
@ -2451,7 +2486,10 @@ def tiff_cmyk16_img(tmp_path_factory, tmp_normal_png):
|
|||
assert identify[0]["image"].get("colorspace") == "CMYK", str(identify)
|
||||
assert identify[0]["image"].get("type") == "ColorSeparation", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 16, str(identify)
|
||||
|
@ -2500,7 +2538,10 @@ def tiff_rgb8_img(tmp_path_factory, tmp_normal_png):
|
|||
assert identify[0]["image"].get("colorspace") == "sRGB", str(identify)
|
||||
assert identify[0]["image"].get("type") == "TrueColor", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 8, str(identify)
|
||||
|
@ -2556,7 +2597,10 @@ def tiff_rgb12_img(tmp_path_factory, tmp_normal16_png):
|
|||
assert identify[0]["image"].get("colorspace") == "sRGB", str(identify)
|
||||
assert identify[0]["image"].get("type") == "TrueColor", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("baseDepth") == 12, str(identify)
|
||||
|
@ -2612,7 +2656,10 @@ def tiff_rgb14_img(tmp_path_factory, tmp_normal16_png):
|
|||
assert identify[0]["image"].get("colorspace") == "sRGB", str(identify)
|
||||
assert identify[0]["image"].get("type") == "TrueColor", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("baseDepth") == 14, str(identify)
|
||||
|
@ -2668,7 +2715,10 @@ def tiff_rgb16_img(tmp_path_factory, tmp_normal16_png):
|
|||
assert identify[0]["image"].get("colorspace") == "sRGB", str(identify)
|
||||
assert identify[0]["image"].get("type") == "TrueColor", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 16, str(identify)
|
||||
|
@ -2725,7 +2775,10 @@ def tiff_rgba8_img(tmp_path_factory, tmp_alpha_png):
|
|||
assert identify[0]["image"].get("colorspace") == "sRGB", str(identify)
|
||||
assert identify[0]["image"].get("type") == "TrueColorAlpha", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 8, str(identify)
|
||||
|
@ -2782,7 +2835,10 @@ def tiff_rgba16_img(tmp_path_factory, tmp_alpha_png):
|
|||
assert identify[0]["image"].get("colorspace") == "sRGB", str(identify)
|
||||
assert identify[0]["image"].get("type") == "TrueColorAlpha", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 16, str(identify)
|
||||
|
@ -2838,7 +2894,10 @@ def tiff_gray1_img(tmp_path_factory, tmp_gray1_png):
|
|||
assert identify[0]["image"].get("colorspace") == "Gray", str(identify)
|
||||
assert identify[0]["image"].get("type") == "Bilevel", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 1, str(identify)
|
||||
|
@ -2895,7 +2954,10 @@ def tiff_gray2_img(tmp_path_factory, tmp_gray2_png):
|
|||
assert identify[0]["image"].get("colorspace") == "Gray", str(identify)
|
||||
assert identify[0]["image"].get("type") == "Grayscale", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 2, str(identify)
|
||||
|
@ -2952,7 +3014,10 @@ def tiff_gray4_img(tmp_path_factory, tmp_gray4_png):
|
|||
assert identify[0]["image"].get("colorspace") == "Gray", str(identify)
|
||||
assert identify[0]["image"].get("type") == "Grayscale", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 4, str(identify)
|
||||
|
@ -3009,7 +3074,10 @@ def tiff_gray8_img(tmp_path_factory, tmp_gray8_png):
|
|||
assert identify[0]["image"].get("colorspace") == "Gray", str(identify)
|
||||
assert identify[0]["image"].get("type") == "Grayscale", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 8, str(identify)
|
||||
|
@ -3066,7 +3134,10 @@ def tiff_gray16_img(tmp_path_factory, tmp_gray16_png):
|
|||
assert identify[0]["image"].get("colorspace") == "Gray", str(identify)
|
||||
assert identify[0]["image"].get("type") == "Grayscale", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 16, str(identify)
|
||||
|
@ -3125,7 +3196,10 @@ def tiff_multipage_img(tmp_path_factory, tmp_normal_png, tmp_inverse_png):
|
|||
assert identify[0]["image"].get("colorspace") == "sRGB", str(identify)
|
||||
assert identify[0]["image"].get("type") == "TrueColor", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 8, str(identify)
|
||||
|
@ -3165,7 +3239,10 @@ def tiff_multipage_img(tmp_path_factory, tmp_normal_png, tmp_inverse_png):
|
|||
assert identify[0]["image"].get("colorspace") == "sRGB", str(identify)
|
||||
assert identify[0]["image"].get("type") == "TrueColor", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 8, str(identify)
|
||||
|
@ -3214,7 +3291,10 @@ def tiff_palette1_img(tmp_path_factory, tmp_palette1_png):
|
|||
assert identify[0]["image"].get("colorspace") == "sRGB", str(identify)
|
||||
assert identify[0]["image"].get("type") == "Palette", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 8, str(identify)
|
||||
|
@ -3264,7 +3344,10 @@ def tiff_palette2_img(tmp_path_factory, tmp_palette2_png):
|
|||
assert identify[0]["image"].get("colorspace") == "sRGB", str(identify)
|
||||
assert identify[0]["image"].get("type") == "Palette", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 8, str(identify)
|
||||
|
@ -3314,7 +3397,10 @@ def tiff_palette4_img(tmp_path_factory, tmp_palette4_png):
|
|||
assert identify[0]["image"].get("colorspace") == "sRGB", str(identify)
|
||||
assert identify[0]["image"].get("type") == "Palette", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 8, str(identify)
|
||||
|
@ -3364,7 +3450,10 @@ def tiff_palette8_img(tmp_path_factory, tmp_palette8_png):
|
|||
assert identify[0]["image"].get("colorspace") == "sRGB", str(identify)
|
||||
assert identify[0]["image"].get("type") == "Palette", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 8, str(identify)
|
||||
|
@ -3427,7 +3516,10 @@ def tiff_ccitt_lsb_m2l_white_img(tmp_path_factory, tmp_gray1_png):
|
|||
assert identify[0]["image"].get("colorspace") == "Gray", str(identify)
|
||||
assert identify[0]["image"].get("type") == "Bilevel", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 1, str(identify)
|
||||
|
@ -3677,7 +3769,10 @@ def tiff_ccitt_lsb_m2l_black_img(tmp_path_factory, tmp_gray1_png):
|
|||
assert identify[0]["image"].get("colorspace") == "Gray", str(identify)
|
||||
assert identify[0]["image"].get("type") == "Bilevel", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 1, str(identify)
|
||||
|
@ -3767,7 +3862,10 @@ def tiff_ccitt_nometa1_img(tmp_path_factory, tmp_gray1_png):
|
|||
assert identify[0]["image"].get("colorspace") == "Gray", str(identify)
|
||||
assert identify[0]["image"].get("type") == "Bilevel", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 1, str(identify)
|
||||
|
@ -3851,7 +3949,10 @@ def tiff_ccitt_nometa2_img(tmp_path_factory, tmp_gray1_png):
|
|||
assert identify[0]["image"].get("units") == "PixelsPerInch", str(identify)
|
||||
assert identify[0]["image"].get("type") == "Bilevel", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("colorspace") == "Gray", str(identify)
|
||||
|
@ -3920,7 +4021,10 @@ def miff_cmyk8_img(tmp_path_factory, tmp_normal_png):
|
|||
assert identify[0]["image"].get("colorspace") == "CMYK", str(identify)
|
||||
assert identify[0]["image"].get("type") == "ColorSeparation", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 8, str(identify)
|
||||
|
@ -3968,7 +4072,10 @@ def miff_cmyk16_img(tmp_path_factory, tmp_normal_png):
|
|||
assert identify[0]["image"].get("colorspace") == "CMYK", str(identify)
|
||||
assert identify[0]["image"].get("type") == "ColorSeparation", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 16, str(identify)
|
||||
|
@ -4007,7 +4114,10 @@ def miff_rgb8_img(tmp_path_factory, tmp_normal_png):
|
|||
assert identify[0]["image"].get("colorspace") == "sRGB", str(identify)
|
||||
assert identify[0]["image"].get("type") == "TrueColor", str(identify)
|
||||
endian = "endianess" if identify[0].get("version", "0") < "1.0" else "endianness"
|
||||
assert identify[0]["image"].get(endian) in ["Undefined", "LSB",], str(
|
||||
assert identify[0]["image"].get(endian) in [
|
||||
"Undefined",
|
||||
"LSB",
|
||||
], str(
|
||||
identify
|
||||
) # FIXME: should be LSB
|
||||
assert identify[0]["image"].get("depth") == 8, str(identify)
|
||||
|
@ -6832,6 +6942,96 @@ def general_input(request):
|
|||
return request.param
|
||||
|
||||
|
||||
@pytest.mark.skipif(not HAVE_FAKETIME, reason="requires faketime")
|
||||
@pytest.mark.parametrize(
|
||||
"engine,testdata,timezone,pdfa",
|
||||
itertools.product(
|
||||
["internal", "pikepdf"],
|
||||
["2021-02-05 17:49:00"],
|
||||
["Europe/Berlin", "GMT+12"],
|
||||
[True, False],
|
||||
),
|
||||
)
|
||||
def test_faketime(tmp_path_factory, jpg_img, engine, testdata, timezone, pdfa):
|
||||
expected = tz2utcstrftime(testdata, "D:%Y%m%d%H%M%SZ", timezone)
|
||||
out_pdf = tmp_path_factory.mktemp("faketime") / "out.pdf"
|
||||
subprocess.check_call(
|
||||
["env", f"TZ={timezone}", "faketime", "-f", testdata, img2pdfprog]
|
||||
+ (["--pdfa"] if pdfa else [])
|
||||
+ [
|
||||
"--producer=",
|
||||
"--engine=" + engine,
|
||||
"--output=" + str(out_pdf),
|
||||
str(jpg_img),
|
||||
]
|
||||
)
|
||||
with pikepdf.open(str(out_pdf)) as p:
|
||||
assert p.docinfo.CreationDate == expected
|
||||
assert p.docinfo.ModDate == expected
|
||||
if pdfa:
|
||||
assert p.Root.Metadata.Subtype == "/XML"
|
||||
assert p.Root.Metadata.Type == "/Metadata"
|
||||
expected = tz2utcstrftime(testdata, "%Y-%m-%dT%H:%M:%SZ", timezone)
|
||||
root = ET.fromstring(p.Root.Metadata.read_bytes())
|
||||
for k in ["ModifyDate", "CreateDate"]:
|
||||
assert (
|
||||
root.find(
|
||||
f".//xmp:{k}", {"xmp": "http://ns.adobe.com/xap/1.0/"}
|
||||
).text
|
||||
== expected
|
||||
)
|
||||
out_pdf.unlink()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"engine,testdata,timezone,pdfa",
|
||||
itertools.product(
|
||||
["internal", "pikepdf"],
|
||||
[
|
||||
"2021-02-05 17:49:00",
|
||||
"2021-02-05T17:49:00",
|
||||
"Fri, 05 Feb 2021 17:49:00 +0100",
|
||||
"last year 12:00",
|
||||
],
|
||||
["Europe/Berlin", "GMT+12"],
|
||||
[True, False],
|
||||
),
|
||||
)
|
||||
def test_date(tmp_path_factory, jpg_img, engine, testdata, timezone, pdfa):
|
||||
# we use the date utility to convert the timestamp from the local
|
||||
# timezone into UTC with the format used by PDF
|
||||
expected = tz2utcstrftime(testdata, "D:%Y%m%d%H%M%SZ", timezone)
|
||||
out_pdf = tmp_path_factory.mktemp("faketime") / "out.pdf"
|
||||
subprocess.check_call(
|
||||
["env", f"TZ={timezone}", img2pdfprog]
|
||||
+ (["--pdfa"] if pdfa else [])
|
||||
+ [
|
||||
f"--moddate={testdata}",
|
||||
f"--creationdate={testdata}",
|
||||
"--producer=",
|
||||
"--engine=" + engine,
|
||||
"--output=" + str(out_pdf),
|
||||
str(jpg_img),
|
||||
]
|
||||
)
|
||||
with pikepdf.open(str(out_pdf)) as p:
|
||||
assert p.docinfo.CreationDate == expected
|
||||
assert p.docinfo.ModDate == expected
|
||||
if pdfa:
|
||||
assert p.Root.Metadata.Subtype == "/XML"
|
||||
assert p.Root.Metadata.Type == "/Metadata"
|
||||
expected = tz2utcstrftime(testdata, "%Y-%m-%dT%H:%M:%SZ", timezone)
|
||||
root = ET.fromstring(p.Root.Metadata.read_bytes())
|
||||
for k in ["ModifyDate", "CreateDate"]:
|
||||
assert (
|
||||
root.find(
|
||||
f".//xmp:{k}", {"xmp": "http://ns.adobe.com/xap/1.0/"}
|
||||
).text
|
||||
== expected
|
||||
)
|
||||
out_pdf.unlink()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("engine", ["internal", "pikepdf"])
|
||||
def test_general(general_input, engine):
|
||||
inputf = os.path.join(os.path.dirname(__file__), "tests", "input", general_input)
|
||||
|
|
Loading…
Reference in a new issue