diff options
Diffstat (limited to 'src/img2pdf_test.py')
-rwxr-xr-x | src/img2pdf_test.py | 743 |
1 files changed, 570 insertions, 173 deletions
diff --git a/src/img2pdf_test.py b/src/img2pdf_test.py index 80dd8e0..4882092 100755 --- a/src/img2pdf_test.py +++ b/src/img2pdf_test.py @@ -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) @@ -113,11 +123,36 @@ except subprocess.CalledProcessError: if not HAVE_JP2: warnings.warn("imagemagick has no jpeg 2000 support, skipping certain checks...") +# the result of compare -metric PSNR is either just a floating point value or a +# floating point value following by the same value multiplied by 0.01, +# surrounded in parenthesis since ImagemMagick 7.1.0-48: +# https://github.com/ImageMagick/ImageMagick/commit/751829cd4c911d7a42953a47c1f73068d9e7da2f +psnr_re = re.compile(rb"((?:inf|(?:0|[1-9][0-9]*)(?:\.[0-9]+)?))(?: \([0-9.]+\))?") + ############################################################################### # HELPER FUNCTIONS # ############################################################################### +# 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() @@ -291,7 +326,7 @@ def write_png(data, path, bitdepth, colortype, palette=None, iccp=None): for j in range(valsperbyte): if x + j >= data.shape[1]: break - val |= (data[y, x + j].astype(">u2") & (2 ** bitdepth - 1)) << ( + val |= (data[y, x + j].astype(">u2") & (2**bitdepth - 1)) << ( (valsperbyte - j - 1) * bitdepth ) raw += struct.pack(">B", val) @@ -310,9 +345,7 @@ def write_png(data, path, bitdepth, colortype, palette=None, iccp=None): def compare(im1, im2, exact, icc, cmyk): if exact: - if cmyk: - raise Exception("cmyk cannot be exact") - elif icc: + if icc: raise Exception("icc cannot be exact") else: subprocess.check_call( @@ -320,6 +353,8 @@ def compare(im1, im2, exact, icc, cmyk): + [ "-metric", "AE", + "-alpha", + "off", im1, im2, "null:", @@ -345,7 +380,10 @@ def compare(im1, im2, exact, icc, cmyk): stderr=subprocess.PIPE, ).stderr assert psnr != b"0" - psnr = float(psnr.strip(b"0")) + assert psnr != b"0 (0)" + assert psnr_re.fullmatch(psnr) is not None, psnr + psnr = psnr_re.fullmatch(psnr).group(1) + psnr = float(psnr) assert psnr != 0 # or otherwise we would use the exact variant assert psnr > 50 @@ -501,7 +539,9 @@ def compare_pdfimages_png(tmpdir, img, pdf, exact=True, icc=False): stderr=subprocess.PIPE, ).stderr assert psnr != b"0" - psnr = float(psnr.strip(b"0")) + assert psnr != b"0 (0)" + psnr = psnr_re.fullmatch(psnr).group(1) + psnr = float(psnr) assert psnr != 0 # or otherwise we would use the exact variant assert psnr > 50 (tmpdir / "images-000.png").unlink() @@ -586,7 +626,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]), @@ -1171,6 +1211,74 @@ def jpg_2000_img(tmp_path_factory, tmp_normal_png): @pytest.fixture(scope="session") +def jpg_2000_rgba8_img(tmp_path_factory, tmp_alpha_png): + in_img = tmp_path_factory.mktemp("jpg_2000_rgba8") / "in.jp2" + subprocess.check_call(CONVERT + [str(tmp_alpha_png), "-depth", "8", str(in_img)]) + identify = json.loads(subprocess.check_output(CONVERT + [str(in_img), "json:"])) + assert len(identify) == 1 + # somewhere between imagemagick 6.9.7.4 and 6.9.9.34, the json output was + # put into an array, here we cater for the older version containing just + # the bare dictionary + if "image" in identify: + identify = [identify] + assert "image" in identify[0] + assert identify[0]["image"].get("format") == "JP2", str(identify) + assert identify[0]["image"].get("mimeType") == "image/jp2", str(identify) + assert identify[0]["image"].get("geometry") == { + "width": 60, + "height": 60, + "x": 0, + "y": 0, + }, str(identify) + assert identify[0]["image"].get("colorspace") == "sRGB", str(identify) + assert identify[0]["image"].get("type") == "TrueColorAlpha", str(identify) + assert identify[0]["image"].get("depth") == 8, str(identify) + assert identify[0]["image"].get("pageGeometry") == { + "width": 60, + "height": 60, + "x": 0, + "y": 0, + }, str(identify) + assert identify[0]["image"].get("compression") == "JPEG2000", str(identify) + yield in_img + in_img.unlink() + + +@pytest.fixture(scope="session") +def jpg_2000_rgba16_img(tmp_path_factory, tmp_alpha_png): + in_img = tmp_path_factory.mktemp("jpg_2000_rgba16") / "in.jp2" + subprocess.check_call(CONVERT + [str(tmp_alpha_png), str(in_img)]) + identify = json.loads(subprocess.check_output(CONVERT + [str(in_img), "json:"])) + assert len(identify) == 1 + # somewhere between imagemagick 6.9.7.4 and 6.9.9.34, the json output was + # put into an array, here we cater for the older version containing just + # the bare dictionary + if "image" in identify: + identify = [identify] + assert "image" in identify[0] + assert identify[0]["image"].get("format") == "JP2", str(identify) + assert identify[0]["image"].get("mimeType") == "image/jp2", str(identify) + assert identify[0]["image"].get("geometry") == { + "width": 60, + "height": 60, + "x": 0, + "y": 0, + }, str(identify) + assert identify[0]["image"].get("colorspace") == "sRGB", str(identify) + assert identify[0]["image"].get("type") == "TrueColorAlpha", str(identify) + assert identify[0]["image"].get("depth") == 16, str(identify) + assert identify[0]["image"].get("pageGeometry") == { + "width": 60, + "height": 60, + "x": 0, + "y": 0, + }, str(identify) + assert identify[0]["image"].get("compression") == "JPEG2000", str(identify) + yield in_img + in_img.unlink() + + +@pytest.fixture(scope="session") def png_rgb8_img(tmp_normal_png): in_img = tmp_normal_png identify = json.loads(subprocess.check_output(CONVERT + [str(in_img), "json:"])) @@ -1582,7 +1690,7 @@ def png_gray1_img(tmp_path_factory, tmp_gray1_png): "y": 0, }, str(identify) assert identify[0]["image"].get("colorspace") == "Gray", str(identify) - assert identify[0]["image"].get("type") == "Bilevel", str(identify) + assert identify[0]["image"].get("type") in ["Bilevel", "Grayscale"], str(identify) assert identify[0]["image"].get("depth") == 1, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -2313,10 +2421,6 @@ def tiff_float_img(tmp_path_factory, tmp_normal_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("baseDepth") == 32, str(identify) assert identify[0]["image"].get("pageGeometry") == { @@ -2332,9 +2436,6 @@ def tiff_float_img(tmp_path_factory, tmp_normal_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "RGB" ), str(identify) @@ -2374,10 +2475,6 @@ def tiff_cmyk8_img(tmp_path_factory, tmp_normal_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -2388,9 +2485,6 @@ def tiff_cmyk8_img(tmp_path_factory, tmp_normal_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "separated" @@ -2433,10 +2527,6 @@ def tiff_cmyk16_img(tmp_path_factory, tmp_normal_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 16, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -2447,9 +2537,6 @@ def tiff_cmyk16_img(tmp_path_factory, tmp_normal_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "separated" @@ -2482,10 +2569,6 @@ def tiff_rgb8_img(tmp_path_factory, tmp_normal_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -2496,9 +2579,6 @@ def tiff_rgb8_img(tmp_path_factory, tmp_normal_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "RGB" ), str(identify) @@ -2538,14 +2618,6 @@ def tiff_rgb12_img(tmp_path_factory, tmp_normal16_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB - if identify[0].get("version", "0") < "1.0": - assert identify[0]["image"].get("depth") == 12, str(identify) - else: - assert identify[0]["image"].get("depth") == 16, str(identify) assert identify[0]["image"].get("baseDepth") == 12, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -2556,9 +2628,6 @@ def tiff_rgb12_img(tmp_path_factory, tmp_normal16_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "RGB" ), str(identify) @@ -2598,11 +2667,6 @@ def tiff_rgb14_img(tmp_path_factory, tmp_normal16_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB - assert identify[0]["image"].get("depth") == 16, str(identify) assert identify[0]["image"].get("baseDepth") == 14, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -2613,9 +2677,6 @@ def tiff_rgb14_img(tmp_path_factory, tmp_normal16_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "RGB" ), str(identify) @@ -2655,10 +2716,6 @@ def tiff_rgb16_img(tmp_path_factory, tmp_normal16_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 16, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -2669,9 +2726,6 @@ def tiff_rgb16_img(tmp_path_factory, tmp_normal16_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "RGB" ), str(identify) @@ -2712,10 +2766,6 @@ def tiff_rgba8_img(tmp_path_factory, tmp_alpha_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -2726,9 +2776,6 @@ def tiff_rgba8_img(tmp_path_factory, tmp_alpha_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unassociated" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "RGB" ), str(identify) @@ -2769,10 +2816,6 @@ def tiff_rgba16_img(tmp_path_factory, tmp_alpha_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 16, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -2783,9 +2826,6 @@ def tiff_rgba16_img(tmp_path_factory, tmp_alpha_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unassociated" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "RGB" ), str(identify) @@ -2825,10 +2865,6 @@ def tiff_gray1_img(tmp_path_factory, tmp_gray1_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 1, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -2839,9 +2875,6 @@ def tiff_gray1_img(tmp_path_factory, tmp_gray1_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "min-is-black" @@ -2882,10 +2915,6 @@ def tiff_gray2_img(tmp_path_factory, tmp_gray2_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 2, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -2896,9 +2925,6 @@ def tiff_gray2_img(tmp_path_factory, tmp_gray2_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "min-is-black" @@ -2939,10 +2965,6 @@ def tiff_gray4_img(tmp_path_factory, tmp_gray4_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 4, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -2953,9 +2975,6 @@ def tiff_gray4_img(tmp_path_factory, tmp_gray4_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "min-is-black" @@ -2996,10 +3015,6 @@ def tiff_gray8_img(tmp_path_factory, tmp_gray8_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -3010,9 +3025,6 @@ def tiff_gray8_img(tmp_path_factory, tmp_gray8_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "min-is-black" @@ -3053,10 +3065,6 @@ def tiff_gray16_img(tmp_path_factory, tmp_gray16_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 16, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -3067,9 +3075,6 @@ def tiff_gray16_img(tmp_path_factory, tmp_gray16_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "min-is-black" @@ -3112,10 +3117,6 @@ def tiff_multipage_img(tmp_path_factory, tmp_normal_png, tmp_inverse_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -3126,9 +3127,6 @@ def tiff_multipage_img(tmp_path_factory, tmp_normal_png, tmp_inverse_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "RGB" ), str(identify) @@ -3152,10 +3150,6 @@ def tiff_multipage_img(tmp_path_factory, tmp_normal_png, tmp_inverse_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -3166,9 +3160,6 @@ def tiff_multipage_img(tmp_path_factory, tmp_normal_png, tmp_inverse_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "RGB" ), str(identify) @@ -3201,10 +3192,6 @@ def tiff_palette1_img(tmp_path_factory, tmp_palette1_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("baseDepth") == 1, str(identify) assert identify[0]["image"].get("colormapEntries") == 2, str(identify) @@ -3217,9 +3204,6 @@ def tiff_palette1_img(tmp_path_factory, tmp_palette1_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "palette" ), str(identify) @@ -3251,10 +3235,6 @@ def tiff_palette2_img(tmp_path_factory, tmp_palette2_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("baseDepth") == 2, str(identify) assert identify[0]["image"].get("colormapEntries") == 4, str(identify) @@ -3267,9 +3247,6 @@ def tiff_palette2_img(tmp_path_factory, tmp_palette2_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "palette" ), str(identify) @@ -3301,10 +3278,6 @@ def tiff_palette4_img(tmp_path_factory, tmp_palette4_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("baseDepth") == 4, str(identify) assert identify[0]["image"].get("colormapEntries") == 16, str(identify) @@ -3317,9 +3290,6 @@ def tiff_palette4_img(tmp_path_factory, tmp_palette4_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "palette" ), str(identify) @@ -3351,10 +3321,6 @@ def tiff_palette8_img(tmp_path_factory, tmp_palette8_png): }, str(identify) 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( - identify - ) # FIXME: should be LSB assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("colormapEntries") == 256, str(identify) assert identify[0]["image"].get("pageGeometry") == { @@ -3366,9 +3332,6 @@ def tiff_palette8_img(tmp_path_factory, tmp_palette8_png): assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) - assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "lsb", str( - identify - ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "palette" ), str(identify) @@ -3415,9 +3378,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( - identify - ) # FIXME: should be LSB + assert identify[0]["image"].get(endian) in [ + "Undefined", + "LSB", + ], str(identify) assert identify[0]["image"].get("depth") == 1, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -3665,9 +3629,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( - identify - ) # FIXME: should be LSB + assert identify[0]["image"].get(endian) in [ + "Undefined", + "LSB", + ], str(identify) assert identify[0]["image"].get("depth") == 1, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -3755,9 +3720,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( - identify - ) # FIXME: should be LSB + assert identify[0]["image"].get(endian) in [ + "Undefined", + "LSB", + ], str(identify) assert identify[0]["image"].get("depth") == 1, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, @@ -3839,9 +3805,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( - identify - ) # FIXME: should be LSB + assert identify[0]["image"].get(endian) in [ + "Undefined", + "LSB", + ], str(identify) assert identify[0]["image"].get("colorspace") == "Gray", str(identify) assert identify[0]["image"].get("depth") == 1, str(identify) assert identify[0]["image"].get("compression") == "Group4", str(identify) @@ -3877,6 +3844,127 @@ def tiff_ccitt_nometa2_img(tmp_path_factory, tmp_gray1_png): @pytest.fixture(scope="session") +def miff_cmyk8_img(tmp_path_factory, tmp_normal_png): + in_img = tmp_path_factory.mktemp("miff_cmyk8") / "in.miff" + subprocess.check_call( + CONVERT + + [ + str(tmp_normal_png), + "-colorspace", + "cmyk", + str(in_img), + ] + ) + identify = json.loads(subprocess.check_output(CONVERT + [str(in_img), "json:"])) + assert len(identify) == 1 + # somewhere between imagemagick 6.9.7.4 and 6.9.9.34, the json output was + # put into an array, here we cater for the older version containing just + # the bare dictionary + if "image" in identify: + identify = [identify] + assert "image" in identify[0] + assert identify[0]["image"].get("format") == "MIFF", str(identify) + assert identify[0]["image"].get("class") == "DirectClass" + assert identify[0]["image"].get("type") == "ColorSeparation" + assert identify[0]["image"].get("geometry") == { + "width": 60, + "height": 60, + "x": 0, + "y": 0, + }, str(identify) + assert identify[0]["image"].get("colorspace") == "CMYK", str(identify) + assert identify[0]["image"].get("type") == "ColorSeparation", str(identify) + assert identify[0]["image"].get("depth") == 8, str(identify) + assert identify[0]["image"].get("pageGeometry") == { + "width": 60, + "height": 60, + "x": 0, + "y": 0, + }, str(identify) + yield in_img + in_img.unlink() + + +@pytest.fixture(scope="session") +def miff_cmyk16_img(tmp_path_factory, tmp_normal_png): + in_img = tmp_path_factory.mktemp("miff_cmyk16") / "in.miff" + subprocess.check_call( + CONVERT + + [ + str(tmp_normal_png), + "-depth", + "16", + "-colorspace", + "cmyk", + str(in_img), + ] + ) + identify = json.loads(subprocess.check_output(CONVERT + [str(in_img), "json:"])) + assert len(identify) == 1 + # somewhere between imagemagick 6.9.7.4 and 6.9.9.34, the json output was + # put into an array, here we cater for the older version containing just + # the bare dictionary + if "image" in identify: + identify = [identify] + assert "image" in identify[0] + assert identify[0]["image"].get("format") == "MIFF", str(identify) + assert identify[0]["image"].get("class") == "DirectClass" + assert identify[0]["image"].get("type") == "ColorSeparation" + assert identify[0]["image"].get("geometry") == { + "width": 60, + "height": 60, + "x": 0, + "y": 0, + }, str(identify) + assert identify[0]["image"].get("colorspace") == "CMYK", str(identify) + assert identify[0]["image"].get("type") == "ColorSeparation", str(identify) + assert identify[0]["image"].get("depth") == 16, str(identify) + assert identify[0]["image"].get("baseDepth") == 16, str(identify) + assert identify[0]["image"].get("pageGeometry") == { + "width": 60, + "height": 60, + "x": 0, + "y": 0, + }, str(identify) + yield in_img + in_img.unlink() + + +@pytest.fixture(scope="session") +def miff_rgb8_img(tmp_path_factory, tmp_normal_png): + in_img = tmp_path_factory.mktemp("miff_rgb8") / "in.miff" + subprocess.check_call(CONVERT + [str(tmp_normal_png), str(in_img)]) + identify = json.loads(subprocess.check_output(CONVERT + [str(in_img), "json:"])) + assert len(identify) == 1 + # somewhere between imagemagick 6.9.7.4 and 6.9.9.34, the json output was + # put into an array, here we cater for the older version containing just + # the bare dictionary + if "image" in identify: + identify = [identify] + assert "image" in identify[0] + assert identify[0]["image"].get("format") == "MIFF", str(identify) + assert identify[0]["image"].get("class") == "DirectClass" + assert identify[0]["image"].get("type") == "TrueColor" + assert identify[0]["image"].get("geometry") == { + "width": 60, + "height": 60, + "x": 0, + "y": 0, + }, str(identify) + assert identify[0]["image"].get("colorspace") == "sRGB", str(identify) + assert identify[0]["image"].get("type") == "TrueColor", str(identify) + assert identify[0]["image"].get("depth") == 8, str(identify) + assert identify[0]["image"].get("pageGeometry") == { + "width": 60, + "height": 60, + "x": 0, + "y": 0, + }, str(identify) + yield in_img + in_img.unlink() + + +@pytest.fixture(scope="session") def png_icc_img(tmp_icc_png): in_img = tmp_icc_png identify = json.loads(subprocess.check_output(CONVERT + [str(in_img), "json:"])) @@ -4043,6 +4131,60 @@ def jpg_2000_pdf(tmp_path_factory, jpg_2000_img, request): @pytest.fixture(scope="session", params=["internal", "pikepdf"]) +def jpg_2000_rgba8_pdf(tmp_path_factory, jpg_2000_rgba8_img, request): + out_pdf = tmp_path_factory.mktemp("jpg_2000_rgba8_pdf") / "out.pdf" + subprocess.check_call( + [ + img2pdfprog, + "--producer=", + "--nodate", + "--engine=" + request.param, + "--output=" + str(out_pdf), + jpg_2000_rgba8_img, + ] + ) + with pikepdf.open(str(out_pdf)) as p: + assert ( + p.pages[0].Contents.read_bytes() + == b"q\n45.0000 0 0 45.0000 0.0000 0.0000 cm\n/Im0 Do\nQ" + ) + assert p.pages[0].Resources.XObject.Im0.BitsPerComponent == 8 + assert not hasattr(p.pages[0].Resources.XObject.Im0, "ColorSpace") + assert p.pages[0].Resources.XObject.Im0.Filter == "/JPXDecode" + assert p.pages[0].Resources.XObject.Im0.Height == 60 + assert p.pages[0].Resources.XObject.Im0.Width == 60 + yield out_pdf + out_pdf.unlink() + + +@pytest.fixture(scope="session", params=["internal", "pikepdf"]) +def jpg_2000_rgba16_pdf(tmp_path_factory, jpg_2000_rgba16_img, request): + out_pdf = tmp_path_factory.mktemp("jpg_2000_rgba16_pdf") / "out.pdf" + subprocess.check_call( + [ + img2pdfprog, + "--producer=", + "--nodate", + "--engine=" + request.param, + "--output=" + str(out_pdf), + jpg_2000_rgba16_img, + ] + ) + with pikepdf.open(str(out_pdf)) as p: + assert ( + p.pages[0].Contents.read_bytes() + == b"q\n45.0000 0 0 45.0000 0.0000 0.0000 cm\n/Im0 Do\nQ" + ) + assert p.pages[0].Resources.XObject.Im0.BitsPerComponent == 16 + assert not hasattr(p.pages[0].Resources.XObject.Im0, "ColorSpace") + assert p.pages[0].Resources.XObject.Im0.Filter == "/JPXDecode" + assert p.pages[0].Resources.XObject.Im0.Height == 60 + assert p.pages[0].Resources.XObject.Im0.Width == 60 + yield out_pdf + out_pdf.unlink() + + +@pytest.fixture(scope="session", params=["internal", "pikepdf"]) def png_rgb8_pdf(tmp_path_factory, png_rgb8_img, request): out_pdf = tmp_path_factory.mktemp("png_rgb8_pdf") / "out.pdf" subprocess.check_call( @@ -4131,9 +4273,10 @@ def gif_transparent_pdf(tmp_path_factory, gif_transparent_img, request): == b"q\n45.0000 0 0 45.0000 0.0000 0.0000 cm\n/Im0 Do\nQ" ) assert p.pages[0].Resources.XObject.Im0.BitsPerComponent == 8 - assert p.pages[0].Resources.XObject.Im0.ColorSpace == "/DeviceRGB" + assert p.pages[0].Resources.XObject.Im0.ColorSpace[0] == "/Indexed" + assert p.pages[0].Resources.XObject.Im0.ColorSpace[1] == "/DeviceRGB" assert p.pages[0].Resources.XObject.Im0.DecodeParms.BitsPerComponent == 8 - assert p.pages[0].Resources.XObject.Im0.DecodeParms.Colors == 3 + assert p.pages[0].Resources.XObject.Im0.DecodeParms.Colors == 1 assert p.pages[0].Resources.XObject.Im0.DecodeParms.Predictor == 15 assert p.pages[0].Resources.XObject.Im0.Filter == "/FlateDecode" assert p.pages[0].Resources.XObject.Im0.Height == 60 @@ -5261,6 +5404,90 @@ def tiff_ccitt_nometa2_pdf(tmp_path_factory, tiff_ccitt_nometa2_img, request): out_pdf.unlink() +@pytest.fixture(scope="session", params=["internal", "pikepdf"]) +def miff_cmyk8_pdf(tmp_path_factory, miff_cmyk8_img, request): + out_pdf = tmp_path_factory.mktemp("miff_cmyk8_pdf") / "out.pdf" + subprocess.check_call( + [ + img2pdfprog, + "--producer=", + "--nodate", + "--engine=" + request.param, + "--output=" + str(out_pdf), + str(miff_cmyk8_img), + ] + ) + with pikepdf.open(str(out_pdf)) as p: + assert ( + p.pages[0].Contents.read_bytes() + == b"q\n45.0000 0 0 45.0000 0.0000 0.0000 cm\n/Im0 Do\nQ" + ) + assert p.pages[0].Resources.XObject.Im0.BitsPerComponent == 8 + assert p.pages[0].Resources.XObject.Im0.ColorSpace == "/DeviceCMYK" + assert p.pages[0].Resources.XObject.Im0.Filter == "/FlateDecode" + assert p.pages[0].Resources.XObject.Im0.Height == 60 + assert p.pages[0].Resources.XObject.Im0.Width == 60 + yield out_pdf + out_pdf.unlink() + + +@pytest.fixture(scope="session", params=["internal", "pikepdf"]) +def miff_cmyk16_pdf(tmp_path_factory, miff_cmyk16_img, request): + out_pdf = tmp_path_factory.mktemp("miff_cmyk16_pdf") / "out.pdf" + subprocess.check_call( + [ + img2pdfprog, + "--producer=", + "--nodate", + "--engine=" + request.param, + "--output=" + str(out_pdf), + str(miff_cmyk16_img), + ] + ) + with pikepdf.open(str(out_pdf)) as p: + assert ( + p.pages[0].Contents.read_bytes() + == b"q\n45.0000 0 0 45.0000 0.0000 0.0000 cm\n/Im0 Do\nQ" + ) + assert p.pages[0].Resources.XObject.Im0.BitsPerComponent == 16 + assert p.pages[0].Resources.XObject.Im0.ColorSpace == "/DeviceCMYK" + assert p.pages[0].Resources.XObject.Im0.Filter == "/FlateDecode" + assert p.pages[0].Resources.XObject.Im0.Height == 60 + assert p.pages[0].Resources.XObject.Im0.Width == 60 + yield out_pdf + out_pdf.unlink() + + +@pytest.fixture(scope="session", params=["internal", "pikepdf"]) +def miff_rgb8_pdf(tmp_path_factory, miff_rgb8_img, request): + out_pdf = tmp_path_factory.mktemp("miff_rgb8_pdf") / "out.pdf" + subprocess.check_call( + [ + img2pdfprog, + "--producer=", + "--nodate", + "--engine=" + request.param, + "--output=" + str(out_pdf), + str(miff_rgb8_img), + ] + ) + with pikepdf.open(str(out_pdf)) as p: + assert ( + p.pages[0].Contents.read_bytes() + == b"q\n45.0000 0 0 45.0000 0.0000 0.0000 cm\n/Im0 Do\nQ" + ) + assert p.pages[0].Resources.XObject.Im0.BitsPerComponent == 8 + assert p.pages[0].Resources.XObject.Im0.ColorSpace == "/DeviceRGB" + assert p.pages[0].Resources.XObject.Im0.DecodeParms.BitsPerComponent == 8 + assert p.pages[0].Resources.XObject.Im0.DecodeParms.Colors == 3 + assert p.pages[0].Resources.XObject.Im0.DecodeParms.Predictor == 15 + assert p.pages[0].Resources.XObject.Im0.Filter == "/FlateDecode" + assert p.pages[0].Resources.XObject.Im0.Height == 60 + assert p.pages[0].Resources.XObject.Im0.Width == 60 + yield out_pdf + out_pdf.unlink() + + ############################################################################### # TEST CASES # ############################################################################### @@ -5327,11 +5554,9 @@ def test_jpg_rot(tmp_path_factory, jpg_rot_img, jpg_rot_pdf): ) def test_jpg_cmyk(tmp_path_factory, jpg_cmyk_img, jpg_cmyk_pdf): tmpdir = tmp_path_factory.mktemp("jpg_cmyk") - compare_ghostscript( - tmpdir, jpg_cmyk_img, jpg_cmyk_pdf, gsdevice="tiff32nc", exact=False - ) + compare_ghostscript(tmpdir, jpg_cmyk_img, jpg_cmyk_pdf, gsdevice="tiff32nc") # not testing with poppler as it cannot write CMYK images - compare_mupdf(tmpdir, jpg_cmyk_img, jpg_cmyk_pdf, exact=False, cmyk=True) + compare_mupdf(tmpdir, jpg_cmyk_img, jpg_cmyk_pdf, cmyk=True) compare_pdfimages_cmyk(tmpdir, jpg_cmyk_img, jpg_cmyk_pdf) @@ -5354,6 +5579,45 @@ def test_jpg_2000(tmp_path_factory, jpg_2000_img, jpg_2000_pdf): sys.platform in ["win32"], reason="test utilities not available on Windows and MacOS", ) +@pytest.mark.skipif( + not HAVE_JP2, reason="requires imagemagick with support for jpeg2000" +) +@pytest.mark.skipif( + True, reason="https://github.com/ImageMagick/ImageMagick6/issues/285" +) +def test_jpg_2000_rgba8(tmp_path_factory, jpg_2000_rgba8_img, jpg_2000_rgba8_pdf): + tmpdir = tmp_path_factory.mktemp("jpg_2000_rgba8") + compare_ghostscript(tmpdir, jpg_2000_rgba8_img, jpg_2000_rgba8_pdf) + compare_poppler(tmpdir, jpg_2000_rgba8_img, jpg_2000_rgba8_pdf) + # compare_mupdf(tmpdir, jpg_2000_rgba8_img, jpg_2000_rgba8_pdf) + compare_pdfimages_jp2(tmpdir, jpg_2000_rgba8_img, jpg_2000_rgba8_pdf) + + +@pytest.mark.skipif( + sys.platform in ["win32"], + reason="test utilities not available on Windows and MacOS", +) +@pytest.mark.skipif( + not HAVE_JP2, reason="requires imagemagick with support for jpeg2000" +) +@pytest.mark.skipif( + True, reason="https://github.com/ImageMagick/ImageMagick6/issues/285" +) +def test_jpg_2000_rgba16(tmp_path_factory, jpg_2000_rgba16_img, jpg_2000_rgba16_pdf): + tmpdir = tmp_path_factory.mktemp("jpg_2000_rgba16") + compare_ghostscript( + tmpdir, jpg_2000_rgba16_img, jpg_2000_rgba16_pdf, gsdevice="tiff48nc" + ) + # poppler outputs 8-bit RGB so the comparison will not be exact + # compare_poppler(tmpdir, jpg_2000_rgba16_img, jpg_2000_rgba16_pdf, exact=False) + # compare_mupdf(tmpdir, jpg_2000_rgba16_img, jpg_2000_rgba16_pdf) + compare_pdfimages_jp2(tmpdir, jpg_2000_rgba16_img, jpg_2000_rgba16_pdf) + + +@pytest.mark.skipif( + sys.platform in ["win32"], + reason="test utilities not available on Windows and MacOS", +) def test_png_rgb8(tmp_path_factory, png_rgb8_img, png_rgb8_pdf): tmpdir = tmp_path_factory.mktemp("png_rgb8") compare_ghostscript(tmpdir, png_rgb8_img, png_rgb8_pdf) @@ -5685,10 +5949,13 @@ def test_tiff_float(tmp_path_factory, tiff_float_img, engine): def test_tiff_cmyk8(tmp_path_factory, tiff_cmyk8_img, tiff_cmyk8_pdf): tmpdir = tmp_path_factory.mktemp("tiff_cmyk8") compare_ghostscript( - tmpdir, tiff_cmyk8_img, tiff_cmyk8_pdf, gsdevice="tiff32nc", exact=False + tmpdir, + tiff_cmyk8_img, + tiff_cmyk8_pdf, + gsdevice="tiff32nc", ) # not testing with poppler as it cannot write CMYK images - compare_mupdf(tmpdir, tiff_cmyk8_img, tiff_cmyk8_pdf, exact=False, cmyk=True) + compare_mupdf(tmpdir, tiff_cmyk8_img, tiff_cmyk8_pdf, cmyk=True) compare_pdfimages_tiff(tmpdir, tiff_cmyk8_img, tiff_cmyk8_pdf) @@ -6123,6 +6390,46 @@ def test_tiff_ccitt_nometa2( compare_pdfimages_tiff(tmpdir, tiff_ccitt_nometa2_img, tiff_ccitt_nometa2_pdf) +@pytest.mark.skipif( + sys.platform in ["win32"], + reason="test utilities not available on Windows and MacOS", +) +def test_miff_cmyk8(tmp_path_factory, miff_cmyk8_img, tiff_cmyk8_img, miff_cmyk8_pdf): + tmpdir = tmp_path_factory.mktemp("miff_cmyk8") + compare_ghostscript(tmpdir, tiff_cmyk8_img, miff_cmyk8_pdf, gsdevice="tiff32nc") + # not testing with poppler as it cannot write CMYK images + compare_mupdf(tmpdir, tiff_cmyk8_img, miff_cmyk8_pdf, cmyk=True) + compare_pdfimages_tiff(tmpdir, tiff_cmyk8_img, miff_cmyk8_pdf) + + +@pytest.mark.skipif( + sys.platform in ["win32"], + reason="test utilities not available on Windows and MacOS", +) +def test_miff_cmyk16( + tmp_path_factory, miff_cmyk16_img, tiff_cmyk16_img, miff_cmyk16_pdf +): + tmpdir = tmp_path_factory.mktemp("miff_cmyk16") + compare_ghostscript( + tmpdir, tiff_cmyk16_img, miff_cmyk16_pdf, gsdevice="tiff32nc", exact=False + ) + # not testing with poppler as it cannot write CMYK images + compare_mupdf(tmpdir, tiff_cmyk16_img, miff_cmyk16_pdf, exact=False, cmyk=True) + # compare_pdfimages_tiff(tmpdir, tiff_cmyk16_img, miff_cmyk16_pdf) + + +@pytest.mark.skipif( + sys.platform in ["win32"], + reason="test utilities not available on Windows and MacOS", +) +def test_miff_rgb8(tmp_path_factory, miff_rgb8_img, tiff_rgb8_img, miff_rgb8_pdf): + tmpdir = tmp_path_factory.mktemp("miff_rgb8") + compare_ghostscript(tmpdir, tiff_rgb8_img, miff_rgb8_pdf, gsdevice="tiff24nc") + compare_poppler(tmpdir, tiff_rgb8_img, miff_rgb8_pdf) + compare_mupdf(tmpdir, tiff_rgb8_img, miff_rgb8_pdf) + compare_pdfimages_tiff(tmpdir, tiff_rgb8_img, miff_rgb8_pdf) + + # we define some variables so that the table below can be narrower psl = (972, 504) # --pagesize landscape psp = (504, 972) # --pagesize portrait @@ -6554,6 +6861,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) |