#!/usr/bin/env python3 import sys import numpy import scipy.signal import zlib import struct import subprocess import pytest import re import pikepdf import hashlib import img2pdf import os from io import BytesIO from PIL import Image import decimal from packaging.version import parse as parse_version import warnings import json import pathlib HAVE_MUTOOL = True try: ver = subprocess.check_output(["mutool", "-v"], stderr=subprocess.STDOUT) m = re.fullmatch(r"mutool version ([0-9.]+)\n", ver.decode("utf8")) if m is None: HAVE_MUTOOL = False else: if parse_version(m.group(1)) < parse_version("1.10.0"): HAVE_MUTOOL = False except FileNotFoundError: HAVE_MUTOOL = False if not HAVE_MUTOOL: warnings.warn("mutool >= 1.10.0 not available, skipping checks...") HAVE_PDFIMAGES_CMYK = True try: ver = subprocess.check_output(["pdfimages", "-v"], stderr=subprocess.STDOUT) m = re.fullmatch(r"pdfimages version ([0-9.]+)", ver.split(b"\n")[0].decode("utf8")) if m is None: HAVE_PDFIMAGES_CMYK = False else: if parse_version(m.group(1)) < parse_version("0.42.0"): HAVE_PDFIMAGES_CMYK = False except FileNotFoundError: HAVE_PDFIMAGES_CMYK = False if not HAVE_PDFIMAGES_CMYK: warnings.warn("pdfimages >= 0.42.0 not available, skipping CMYK checks...") HAVE_IMAGEMAGICK_MODERN = True try: ver = subprocess.check_output(["convert", "-version"], stderr=subprocess.STDOUT) m = re.fullmatch( r"Version: ImageMagick ([0-9.]+-[0-9]+) .*", ver.split(b"\n")[0].decode("utf8") ) if m is None: HAVE_IMAGEMAGICK_MODERN = False else: if parse_version(m.group(1)) < parse_version("6.9.10-12"): HAVE_IMAGEMAGICK_MODERN = False except FileNotFoundError: HAVE_IMAGEMAGICK_MODERN = False except subprocess.CalledProcessError: HAVE_IMAGEMAGICK_MODERN = False if not HAVE_IMAGEMAGICK_MODERN: warnings.warn("imagemagick >= 6.9.10-12 not available, skipping certain checks...") HAVE_JP2 = True try: ver = subprocess.check_output( ["identify", "-list", "format"], stderr=subprocess.STDOUT ) found = False for line in ver.split(b"\n"): if re.match(rb"\s+JP2\* JP2\s+rw-\s+JPEG-2000 File Format Syntax", line): found = True break if not found: HAVE_JP2 = False except FileNotFoundError: HAVE_JP2 = False except subprocess.CalledProcessError: HAVE_JP2 = False if not HAVE_JP2: warnings.warn("imagemagick has no jpeg 2000 support, skipping certain checks...") ############################################################################### # HELPER FUNCTIONS # ############################################################################### def find_closest_palette_color(color, palette): if color.ndim == 0: idx = (numpy.abs(palette - color)).argmin() else: # naive distance function by computing the euclidean distance in RGB space idx = ((palette - color) ** 2).sum(axis=-1).argmin() return palette[idx] def floyd_steinberg(img, palette): result = numpy.array(img, copy=True) for y in range(result.shape[0]): for x in range(result.shape[1]): oldpixel = result[y, x] newpixel = find_closest_palette_color(oldpixel, palette) quant_error = oldpixel - newpixel result[y, x] = newpixel if x + 1 < result.shape[1]: result[y, x + 1] += quant_error * 7 / 16 if y + 1 < result.shape[0]: result[y + 1, x - 1] += quant_error * 3 / 16 result[y + 1, x] += quant_error * 5 / 16 if x + 1 < result.shape[1] and y + 1 < result.shape[0]: result[y + 1, x + 1] += quant_error * 1 / 16 return result def convolve_rgba(img, kernel): return numpy.stack( ( scipy.signal.convolve2d(img[:, :, 0], kernel, "same"), scipy.signal.convolve2d(img[:, :, 1], kernel, "same"), scipy.signal.convolve2d(img[:, :, 2], kernel, "same"), scipy.signal.convolve2d(img[:, :, 3], kernel, "same"), ), axis=-1, ) def rgb2gray(img): result = numpy.zeros((60, 60), dtype=numpy.dtype("int64")) count = 0 for y in range(img.shape[0]): for x in range(img.shape[1]): clin = sum(img[y, x] * [0.2126, 0.7152, 0.0722]) / 0xFFFF if clin <= 0.0031308: csrgb = 12.92 * clin else: csrgb = 1.055 * clin ** (1 / 2.4) - 0.055 result[y, x] = csrgb * 0xFFFF count += 1 # if count == 24: # raise Exception(result[y, x]) return result def palettize(img, pal): result = numpy.zeros((img.shape[0], img.shape[1]), dtype=numpy.dtype("int64")) for y in range(img.shape[0]): for x in range(img.shape[1]): for i, col in enumerate(pal): if numpy.array_equal(img[y, x], col): result[y, x] = i break else: raise Exception() return result # we cannot use zlib.compress() because different compressors may compress the # same data differently, for example by using different optimizations on # different architectures: # https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/thread/R7GD4L5Z6HELCDAL2RDESWR2F3ZXHWVX/ # # to make the compressed representation of the uncompressed data bit-by-bit # identical on all platforms we make use of the compression method 0, that is, # no compression at all :) def compress(data): # two-byte zlib header (rfc1950) # common header for lowest compression level # bits 0-3: Compression info, base-2 logarithm of the LZ77 window size, # minus eight -- 7 indicates a 32K window size # bits 4-7: Compression method -- 8 is deflate # bits 8-9: Compression level -- 0 is fastest # bit 10: preset dictionary -- 0 is none # bits 11-15: check bits so that the 16-bit unsigned integer stored in MSB # order is a multiple of 31 result = b"\x78\x01" # content is stored in deflate format (rfc1951) # maximum chunk size is the largest 16 bit unsigned integer chunksize = 0xFFFF for i in range(0, len(data), chunksize): # bits 0-4 are unused # bits 5-6 indicate compression method -- 0 is no compression # bit 7 indicates the last chunk if i * chunksize < len(data) - chunksize: result += b"\x00" else: # last chunck result += b"\x01" chunk = data[i : i + chunksize] # the chunk length as little endian 16 bit unsigned integer result += struct.pack("I", zlib.adler32(data)) return result def write_png(data, path, bitdepth, colortype, palette=None, iccp=None): with open(str(path), "wb") as f: f.write(b"\x89PNG\r\n\x1A\n") # PNG image type Colour type Allowed bit depths # Greyscale 0 1, 2, 4, 8, 16 # Truecolour 2 8, 16 # Indexed-colour 3 1, 2, 4, 8 # Greyscale with alpha 4 8, 16 # Truecolour with alpha 6 8, 16 block = b"IHDR" + struct.pack( ">IIBBBBB", data.shape[1], # width data.shape[0], # height bitdepth, # bitdepth colortype, # colortype 0, # compression 0, # filtertype 0, # interlaced ) f.write( struct.pack(">I", len(block) - 4) + block + struct.pack(">I", zlib.crc32(block)) ) if iccp is not None: with open(iccp, "rb") as infh: iccdata = infh.read() block = b"iCCP" block += b"icc\0" # arbitrary profile name block += b"\0" # compression method (deflate) block += zlib.compress(iccdata) f.write( struct.pack(">I", len(block) - 4) + block + struct.pack(">I", zlib.crc32(block)) ) if palette is not None: block = b"PLTE" for col in palette: block += struct.pack(">BBB", col[0], col[1], col[2]) f.write( struct.pack(">I", len(block) - 4) + block + struct.pack(">I", zlib.crc32(block)) ) raw = b"" for y in range(data.shape[0]): raw += b"\0" if bitdepth == 16: raw += data[y].astype(">u2").tobytes() elif bitdepth == 8: raw += data[y].astype(">u1").tobytes() elif bitdepth in [4, 2, 1]: valsperbyte = 8 // bitdepth for x in range(0, data.shape[1], valsperbyte): val = 0 for j in range(valsperbyte): if x + j >= data.shape[1]: break val |= (data[y, x + j].astype(">u2") & (2 ** bitdepth - 1)) << ( (valsperbyte - j - 1) * bitdepth ) raw += struct.pack(">B", val) else: raise Exception() compressed = compress(raw) block = b"IDAT" + compressed f.write( struct.pack(">I", len(compressed)) + block + struct.pack(">I", zlib.crc32(block)) ) block = b"IEND" f.write(struct.pack(">I", 0) + block + struct.pack(">I", zlib.crc32(block))) def compare(im1, im2, exact, icc, cmyk): if exact: if cmyk: raise Exception("cmyk cannot be exact") elif icc: raise Exception("icc cannot be exact") else: subprocess.check_call( [ "compare", "-metric", "AE", im1, im2, "null:", ] ) else: iccargs = [] if icc: profile = "/usr/share/color/icc/sRGB.icc" if not os.path.isfile(profile): warnings.warn(profile + " not present, skipping checks...") return iccargs = ["-profile", profile] psnr = subprocess.run( ["compare"] + iccargs + [ "-metric", "PSNR", im1, im2, "null:", ], check=False, stderr=subprocess.PIPE, ).stderr assert psnr != b"0" psnr = float(psnr.strip(b"0")) assert psnr != 0 # or otherwise we would use the exact variant assert psnr > 50 def compare_ghostscript(tmpdir, img, pdf, gsdevice="png16m", exact=True, icc=False): if gsdevice in ["png16m", "pnggray"]: ext = "png" elif gsdevice in ["tiff24nc", "tiff32nc", "tiff48nc"]: ext = "tiff" else: raise Exception("unknown gsdevice: " + gsdevice) subprocess.check_call( [ "gs", "-dQUIET", "-dNOPAUSE", "-dBATCH", "-sDEVICE=" + gsdevice, "-r96", "-sOutputFile=" + str(tmpdir / "gs-") + "%00d." + ext, str(pdf), ] ) compare(str(img), str(tmpdir / "gs-1.") + ext, exact, icc, False) (tmpdir / ("gs-1." + ext)).unlink() def compare_poppler(tmpdir, img, pdf, exact=True, icc=False): subprocess.check_call( ["pdftocairo", "-r", "96", "-png", str(pdf), str(tmpdir / "poppler")] ) compare(str(img), str(tmpdir / "poppler-1.png"), exact, icc, False) (tmpdir / "poppler-1.png").unlink() def compare_mupdf(tmpdir, img, pdf, exact=True, cmyk=False): if not HAVE_MUTOOL: return if cmyk: out = tmpdir / "mupdf.pam" subprocess.check_call( ["mutool", "draw", "-r", "96", "-c", "cmyk", "-o", str(out), str(pdf)] ) else: out = tmpdir / "mupdf.png" subprocess.check_call( ["mutool", "draw", "-r", "96", "-png", "-o", str(out), str(pdf)] ) compare(str(img), str(out), exact, False, cmyk) out.unlink() def compare_pdfimages_jpg(tmpdir, img, pdf): subprocess.check_call(["pdfimages", "-j", str(pdf), str(tmpdir / "images")]) assert img.read_bytes() == (tmpdir / "images-000.jpg").read_bytes() (tmpdir / "images-000.jpg").unlink() def compare_pdfimages_cmyk(tmpdir, img, pdf): if not HAVE_PDFIMAGES_CMYK: return subprocess.check_call(["pdfimages", "-j", str(pdf), str(tmpdir / "images")]) assert img.read_bytes() == (tmpdir / "images-000.jpg").read_bytes() (tmpdir / "images-000.jpg").unlink() def compare_pdfimages_jp2(tmpdir, img, pdf): subprocess.check_call(["pdfimages", "-jp2", str(pdf), str(tmpdir / "images")]) assert img.read_bytes() == (tmpdir / "images-000.jp2").read_bytes() (tmpdir / "images-000.jp2").unlink() def compare_pdfimages_tiff(tmpdir, img, pdf): subprocess.check_call(["pdfimages", "-tiff", str(pdf), str(tmpdir / "images")]) subprocess.check_call( ["compare", "-metric", "AE", str(img), str(tmpdir / "images-000.tif"), "null:"] ) (tmpdir / "images-000.tif").unlink() def compare_pdfimages_png(tmpdir, img, pdf, exact=True, icc=False): subprocess.check_call(["pdfimages", "-png", str(pdf), str(tmpdir / "images")]) if exact: if icc: raise Exception("not exact with icc") subprocess.check_call( [ "compare", "-metric", "AE", str(img), str(tmpdir / "images-000.png"), "null:", ] ) else: if icc: profile = "/usr/share/color/icc/ghostscript/srgb.icc" if not os.path.isfile(profile): warnings.warn(profile + " not present, skipping checks...") return psnr = subprocess.run( [ "compare", "-metric", "PSNR", "(", "-profile", profile, "-depth", "8", str(img), ")", str(tmpdir / "images-000.png"), "null:", ], check=False, stderr=subprocess.PIPE, ).stderr else: psnr = subprocess.run( [ "compare", "-metric", "PSNR", str(img), str(tmpdir / "images-000.png"), "null:", ], check=False, stderr=subprocess.PIPE, ).stderr assert psnr != b"0" psnr = float(psnr.strip(b"0")) assert psnr != 0 # or otherwise we would use the exact variant assert psnr > 50 (tmpdir / "images-000.png").unlink() def tiff_header_for_ccitt(width, height, img_size, ccitt_group=4): # Quick and dirty TIFF header builder from # https://stackoverflow.com/questions/2641770 tiff_header_struct = "<" + "2s" + "h" + "l" + "h" + "hhll" * 8 + "h" return struct.pack( # fmt: off tiff_header_struct, b'II', # Byte order indication: Little indian 42, # Version number (always 42) 8, # Offset to first IFD 8, # Number of tags in IFD 256, 4, 1, width, # ImageWidth, LONG, 1, width 257, 4, 1, height, # ImageLength, LONG, 1, lenght 258, 3, 1, 1, # BitsPerSample, SHORT, 1, 1 259, 3, 1, ccitt_group, # Compression, SHORT, 1, 4 = CCITT Group 4 262, 3, 1, 1, # Threshholding, SHORT, 1, 0 = WhiteIsZero 273, 4, 1, struct.calcsize( tiff_header_struct), # StripOffsets, LONG, 1, len of header 278, 4, 1, height, # RowsPerStrip, LONG, 1, lenght 279, 4, 1, img_size, # StripByteCounts, LONG, 1, size of image 0 # last IFD # fmt: on ) pixel_R = [ [1, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 1], [1, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 1], [1, 0, 0, 1], ] pixel_G = [ [0, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 0], [1, 0, 1, 1], [1, 0, 0, 1], [1, 0, 0, 1], [0, 1, 1, 0], ] pixel_B = [ [1, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 1], [1, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 1], [1, 1, 1, 0], ] def alpha_value(): # gaussian kernel with sigma=3 kernel = numpy.array( [ [0.011362, 0.014962, 0.017649, 0.018648, 0.017649, 0.014962, 0.011362], [0.014962, 0.019703, 0.02324, 0.024556, 0.02324, 0.019703, 0.014962], [0.017649, 0.02324, 0.027413, 0.028964, 0.027413, 0.02324, 0.017649], [0.018648, 0.024556, 0.028964, 0.030603, 0.028964, 0.024556, 0.018648], [0.017649, 0.02324, 0.027413, 0.028964, 0.027413, 0.02324, 0.017649], [0.014962, 0.019703, 0.02324, 0.024556, 0.02324, 0.019703, 0.014962], [0.011362, 0.014962, 0.017649, 0.018648, 0.017649, 0.014962, 0.011362], ], float, ) # constructs a 2D array of a circle with a width of 36 circle = list() offsets_36 = [14, 11, 9, 7, 6, 5, 4, 3, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0] for offs in offsets_36 + offsets_36[::-1]: circle.append([0] * offs + [1] * (len(offsets_36) - offs) * 2 + [0] * offs) alpha = numpy.zeros((60, 60, 4), dtype=numpy.dtype("int64")) # draw three circles for (xpos, ypos, color) in [ (12, 3, [0xFFFF, 0, 0, 0xFFFF]), (21, 21, [0, 0xFFFF, 0, 0xFFFF]), (3, 21, [0, 0, 0xFFFF, 0xFFFF]), ]: for x, row in enumerate(circle): for y, pos in enumerate(row): if pos: alpha[y + ypos, x + xpos] += color alpha = numpy.clip(alpha, 0, 0xFFFF) alpha = convolve_rgba(alpha, kernel) # draw letters for y, row in enumerate(pixel_R): for x, pos in enumerate(row): if pos: alpha[13 + y, 28 + x] = [0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF] for y, row in enumerate(pixel_G): for x, pos in enumerate(row): if pos: alpha[39 + y, 40 + x] = [0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF] for y, row in enumerate(pixel_B): for x, pos in enumerate(row): if pos: alpha[39 + y, 15 + x] = [0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF] return alpha def icc_profile(): PCS = (0.96420288, 1.0, 0.82490540) # D50 illuminant constants # approximate X,Y,Z values for white, red, green and blue white = (0.95, 1.0, 1.09) red = (0.44, 0.22, 0.014) green = (0.39, 0.72, 0.1) blue = (0.14, 0.06, 0.71) getxyz = lambda v: (round(65536 * v[0]), round(65536 * v[1]), round(65536 * v[2])) header = ( # header +4 * b"\0" # cmmsignatures + 4 * b"\0" # version + b"mntr" # device class + b"RGB " # color space + b"XYZ " # PCS + 12 * b"\0" # datetime + b"\x61\x63\x73\x70" # static signature + 4 * b"\0" # platform + 4 * b"\0" # flags + 4 * b"\0" # device manufacturer + 4 * b"\0" # device model + 8 * b"\0" # device attributes + 4 * b"\0" # rendering intents + struct.pack(">III", *getxyz(PCS)) + 4 * b"\0" # creator + 16 * b"\0" # identifier + 28 * b"\0" # reserved ) def pad4(s): if len(s) % 4 == 0: return s else: return s + b"\x00" * (4 - len(s) % 4) tagdata = [ b"desc\x00\x00\x00\x00" + struct.pack(">I", 5) + b"fake" + 79 * b"\x00", b"XYZ \x00\x00\x00\x00" + struct.pack(">III", *getxyz(white)), # by mixing up red, green and blue, we create a test profile b"XYZ \x00\x00\x00\x00" + struct.pack(">III", *getxyz(blue)), # red b"XYZ \x00\x00\x00\x00" + struct.pack(">III", *getxyz(red)), # green b"XYZ \x00\x00\x00\x00" + struct.pack(">III", *getxyz(green)), # blue # by only supplying two values, we create the most trivial "curve", # where the remaining values will be linearly interpolated between them b"curv\x00\x00\x00\x00" + struct.pack(">IHH", 2, 0, 65535), b"text\x00\x00\x00\x00" + b"no copyright, use freely" + 1 * b"\x00", ] table = [ (b"desc", 0), (b"wtpt", 1), (b"rXYZ", 2), (b"gXYZ", 3), (b"bXYZ", 4), # we use the same curve for all three channels, so the same offset is referenced (b"rTRC", 5), (b"gTRC", 5), (b"bTRC", 5), (b"cprt", 6), ] offset = ( lambda n: 4 # total size + len(header) # header length + 4 # number table entries + len(table) * 12 # table length + sum([len(pad4(s)) for s in tagdata[:n]]) ) table = struct.pack(">I", len(table)) + b"".join( [t + struct.pack(">II", offset(o), len(tagdata[o])) for t, o in table] ) data = b"".join([pad4(s) for s in tagdata]) data = ( struct.pack(">I", 4 + len(header) + len(table) + len(data)) + header + table + data ) return data ############################################################################### # INPUT FIXTURES # ############################################################################### @pytest.fixture(scope="session") def alpha(): return alpha_value() @pytest.fixture(scope="session") def tmp_alpha_png(tmp_path_factory, alpha): tmp_alpha_png = tmp_path_factory.mktemp("alpha_png") / "alpha.png" write_png(alpha, str(tmp_alpha_png), 16, 6) assert ( hashlib.md5(tmp_alpha_png.read_bytes()).hexdigest() == "600bb4cffb039a022cec6ed55537deba" ) yield tmp_alpha_png tmp_alpha_png.unlink() @pytest.fixture(scope="session") def tmp_gray1_png(tmp_path_factory, alpha): normal16 = alpha[:, :, 0:3] gray16 = rgb2gray(normal16) tmp_gray1_png = tmp_path_factory.mktemp("gray1_png") / "gray1.png" write_png( floyd_steinberg(gray16, numpy.arange(2) / 0x1 * 0xFFFF) / 0xFFFF * 0x1, str(tmp_gray1_png), 1, 0, ) assert ( hashlib.md5(tmp_gray1_png.read_bytes()).hexdigest() == "dd2c528152d34324747355b73495a115" ) yield tmp_gray1_png tmp_gray1_png.unlink() @pytest.fixture(scope="session") def tmp_gray2_png(tmp_path_factory, alpha): normal16 = alpha[:, :, 0:3] gray16 = rgb2gray(normal16) tmp_gray2_png = tmp_path_factory.mktemp("gray2_png") / "gray2.png" write_png( floyd_steinberg(gray16, numpy.arange(4) / 0x3 * 0xFFFF) / 0xFFFF * 0x3, str(tmp_gray2_png), 2, 0, ) assert ( hashlib.md5(tmp_gray2_png.read_bytes()).hexdigest() == "68e614f4e6a85053d47098dad0ca3976" ) yield tmp_gray2_png tmp_gray2_png.unlink() @pytest.fixture(scope="session") def tmp_gray4_png(tmp_path_factory, alpha): normal16 = alpha[:, :, 0:3] gray16 = rgb2gray(normal16) tmp_gray4_png = tmp_path_factory.mktemp("gray4_png") / "gray4.png" write_png( floyd_steinberg(gray16, numpy.arange(16) / 0xF * 0xFFFF) / 0xFFFF * 0xF, str(tmp_gray4_png), 4, 0, ) assert ( hashlib.md5(tmp_gray4_png.read_bytes()).hexdigest() == "ff04a6fea88133eb77bbb748692ae0fd" ) yield tmp_gray4_png tmp_gray4_png.unlink() @pytest.fixture(scope="session") def tmp_gray8_png(tmp_path_factory, alpha): normal16 = alpha[:, :, 0:3] gray16 = rgb2gray(normal16) tmp_gray8_png = tmp_path_factory.mktemp("gray8_png") / "gray8.png" write_png(gray16 / 0xFFFF * 0xFF, tmp_gray8_png, 8, 0) assert ( hashlib.md5(tmp_gray8_png.read_bytes()).hexdigest() == "90b4ed9123f295dda7fde499744dede7" ) yield tmp_gray8_png tmp_gray8_png.unlink() @pytest.fixture(scope="session") def tmp_gray16_png(tmp_path_factory, alpha): normal16 = alpha[:, :, 0:3] gray16 = rgb2gray(normal16) tmp_gray16_png = tmp_path_factory.mktemp("gray16_png") / "gray16.png" write_png(gray16, str(tmp_gray16_png), 16, 0) assert ( hashlib.md5(tmp_gray16_png.read_bytes()).hexdigest() == "f76153d2e72fada11d934c32c8168a57" ) yield tmp_gray16_png tmp_gray16_png.unlink() @pytest.fixture(scope="session") def tmp_inverse_png(tmp_path_factory, alpha): normal16 = alpha[:, :, 0:3] tmp_inverse_png = tmp_path_factory.mktemp("inverse_png") / "inverse.png" write_png(0xFF - normal16 / 0xFFFF * 0xFF, str(tmp_inverse_png), 8, 2) assert ( hashlib.md5(tmp_inverse_png.read_bytes()).hexdigest() == "0a7d57dc09c4d8fd1ad3511b116c7dfa" ) yield tmp_inverse_png tmp_inverse_png.unlink() @pytest.fixture(scope="session") def tmp_icc_profile(tmp_path_factory): tmp_icc_profile = tmp_path_factory.mktemp("icc_profile") / "fake.icc" tmp_icc_profile.write_bytes(icc_profile()) yield tmp_icc_profile tmp_icc_profile.unlink() @pytest.fixture(scope="session") def tmp_icc_png(tmp_path_factory, alpha, tmp_icc_profile): normal16 = alpha[:, :, 0:3] tmp_icc_png = tmp_path_factory.mktemp("icc_png") / "icc.png" write_png( normal16 / 0xFFFF * 0xFF, str(tmp_icc_png), 8, 2, iccp=str(tmp_icc_profile), ) assert ( hashlib.md5(tmp_icc_png.read_bytes()).hexdigest() == "bf25f673c1617f5f9353b2a043747655" ) yield tmp_icc_png tmp_icc_png.unlink() @pytest.fixture(scope="session") def tmp_normal16_png(tmp_path_factory, alpha): normal16 = alpha[:, :, 0:3] tmp_normal16_png = tmp_path_factory.mktemp("normal16_png") / "normal16.png" write_png(normal16, str(tmp_normal16_png), 16, 2) assert ( hashlib.md5(tmp_normal16_png.read_bytes()).hexdigest() == "820dd30a2566775fc64c110e8ac65c7e" ) yield tmp_normal16_png tmp_normal16_png.unlink() @pytest.fixture(scope="session") def tmp_normal_png(tmp_path_factory, alpha): normal16 = alpha[:, :, 0:3] tmp_normal_png = tmp_path_factory.mktemp("normal_png") / "normal.png" write_png(normal16 / 0xFFFF * 0xFF, str(tmp_normal_png), 8, 2) assert ( hashlib.md5(tmp_normal_png.read_bytes()).hexdigest() == "bc30c705f455991cd04be1c298063002" ) yield tmp_normal_png tmp_normal_png.unlink() @pytest.fixture(scope="session") def tmp_palette1_png(tmp_path_factory, alpha): normal16 = alpha[:, :, 0:3] tmp_palette1_png = tmp_path_factory.mktemp("palette1_png") / "palette1.png" # don't choose black and white or otherwise imagemagick will classify the # image as bilevel with 8/1-bit depth instead of palette with 8-bit color # don't choose gray colors or otherwise imagemagick will classify the # image as grayscale pal1 = numpy.array( [[0x01, 0x02, 0x03], [0xFE, 0xFD, 0xFC]], dtype=numpy.dtype("int64") ) write_png( palettize( floyd_steinberg(normal16, pal1 * 0xFFFF / 0xFF) / 0xFFFF * 0xFF, pal1 ), str(tmp_palette1_png), 1, 3, pal1, ) assert ( hashlib.md5(tmp_palette1_png.read_bytes()).hexdigest() == "3d065f731540e928fb730b3233e4e8a7" ) yield tmp_palette1_png tmp_palette1_png.unlink() @pytest.fixture(scope="session") def tmp_palette2_png(tmp_path_factory, alpha): normal16 = alpha[:, :, 0:3] tmp_palette2_png = tmp_path_factory.mktemp("palette2_png") / "palette2.png" # choose values slightly off red, lime and blue because otherwise # imagemagick will classify the image as Depth: 8/1-bit pal2 = numpy.array( [[0, 0, 0], [0xFE, 0, 0], [0, 0xFE, 0], [0, 0, 0xFE]], dtype=numpy.dtype("int64"), ) write_png( palettize( floyd_steinberg(normal16, pal2 * 0xFFFF / 0xFF) / 0xFFFF * 0xFF, pal2 ), str(tmp_palette2_png), 2, 3, pal2, ) assert ( hashlib.md5(tmp_palette2_png.read_bytes()).hexdigest() == "0b0d4412c28da26163a622d218ee02ca" ) yield tmp_palette2_png tmp_palette2_png.unlink() @pytest.fixture(scope="session") def tmp_palette4_png(tmp_path_factory, alpha): normal16 = alpha[:, :, 0:3] tmp_palette4_png = tmp_path_factory.mktemp("palette4_png") / "palette4.png" # windows 16 color palette pal4 = numpy.array( [ [0x00, 0x00, 0x00], [0x80, 0x00, 0x00], [0x00, 0x80, 0x00], [0x80, 0x80, 0x00], [0x00, 0x00, 0x80], [0x80, 0x00, 0x80], [0x00, 0x80, 0x80], [0xC0, 0xC0, 0xC0], [0x80, 0x80, 0x80], [0xFF, 0x00, 0x00], [0x00, 0xFF, 0x00], [0xFF, 0x00, 0x00], [0x00, 0xFF, 0x00], [0xFF, 0x00, 0xFF], [0x00, 0xFF, 0x00], [0xFF, 0xFF, 0xFF], ], dtype=numpy.dtype("int64"), ) write_png( palettize( floyd_steinberg(normal16, pal4 * 0xFFFF / 0xFF) / 0xFFFF * 0xFF, pal4 ), str(tmp_palette4_png), 4, 3, pal4, ) assert ( hashlib.md5(tmp_palette4_png.read_bytes()).hexdigest() == "163f6d7964b80eefa0dc6a48cb7315dd" ) yield tmp_palette4_png tmp_palette4_png.unlink() @pytest.fixture(scope="session") def tmp_palette8_png(tmp_path_factory, alpha): normal16 = alpha[:, :, 0:3] tmp_palette8_png = tmp_path_factory.mktemp("palette8_png") / "palette8.png" # create a 256 color palette by first writing 16 shades of gray # and then writing an array of RGB colors with 6, 8 and 5 levels # for red, green and blue, respectively pal8 = numpy.zeros((256, 3), dtype=numpy.dtype("int64")) i = 0 for gray in range(15, 255, 15): pal8[i] = [gray, gray, gray] i += 1 for red in 0, 0x33, 0x66, 0x99, 0xCC, 0xFF: for green in 0, 0x24, 0x49, 0x6D, 0x92, 0xB6, 0xDB, 0xFF: for blue in 0, 0x40, 0x80, 0xBF, 0xFF: pal8[i] = [red, green, blue] i += 1 assert i == 256 write_png( palettize( floyd_steinberg(normal16, pal8 * 0xFFFF / 0xFF) / 0xFFFF * 0xFF, pal8 ), str(tmp_palette8_png), 8, 3, pal8, ) assert ( hashlib.md5(tmp_palette8_png.read_bytes()).hexdigest() == "8847bb734eba0e2d85e3f97fc2849dd4" ) yield tmp_palette8_png tmp_palette8_png.unlink() @pytest.fixture(scope="session") def jpg_img(tmp_path_factory, tmp_normal_png): in_img = tmp_path_factory.mktemp("jpg") / "in.jpg" 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") == "JPEG", str(identify) assert identify[0]["image"].get("mimeType") == "image/jpeg", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert "resolution" not in identify[0]["image"] assert identify[0]["image"].get("units") == "Undefined", 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) == "Undefined", str(identify) assert identify[0]["image"].get("colorspace") == "sRGB", 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") == "JPEG", str(identify) assert identify[0]["image"].get("orientation") == "Undefined", str(identify) assert ( identify[0]["image"].get("properties", {}).get("jpeg:colorspace") == "2" ), str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def jpg_rot_img(tmp_path_factory, tmp_normal_png): in_img = tmp_path_factory.mktemp("jpg_rot") / "in.jpg" subprocess.check_call(["convert", str(tmp_normal_png), str(in_img)]) subprocess.check_call( ["exiftool", "-overwrite_original", "-all=", str(in_img), "-n"] ) subprocess.check_call( [ "exiftool", "-overwrite_original", "-Orientation=6", "-XResolution=96", "-YResolution=96", "-n", 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") == "JPEG", str(identify) assert identify[0]["image"].get("mimeType") == "image/jpeg", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("resolution") == {"x": 96, "y": 96} assert identify[0]["image"].get("units") == "PixelsPerInch", 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) assert identify[0]["image"].get("compression") == "JPEG", str(identify) assert identify[0]["image"].get("orientation") == "RightTop", str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def jpg_cmyk_img(tmp_path_factory, tmp_normal_png): in_img = tmp_path_factory.mktemp("jpg_cmyk") / "in.jpg" 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") == "JPEG", str(identify) assert identify[0]["image"].get("mimeType") == "image/jpeg", str(identify) 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) assert identify[0]["image"].get("compression") == "JPEG", str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def jpg_2000_img(tmp_path_factory, tmp_normal_png): in_img = tmp_path_factory.mktemp("jpg_2000") / "in.jp2" 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") == "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") == "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) 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:"])) 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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", 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") == "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) assert identify[0]["image"].get("compression") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "8" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "8" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "2" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "2 (Truecolor)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) return in_img @pytest.fixture(scope="session") def png_rgb16_img(tmp_normal16_png): in_img = tmp_normal16_png 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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", 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") == "TrueColor", 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") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "16" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "16" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "2" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "2 (Truecolor)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) return in_img @pytest.fixture(scope="session") def png_rgba8_img(tmp_path_factory, tmp_alpha_png): in_img = tmp_path_factory.mktemp("png_rgba8") / "in.png" subprocess.check_call( ["convert", str(tmp_alpha_png), "-depth", "8", "-strip", 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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", 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") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "8" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "8" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "6" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "6 (RGBA)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def png_rgba16_img(tmp_alpha_png): in_img = tmp_alpha_png 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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", 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") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "16" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "16" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "6" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "6 (RGBA)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) return in_img @pytest.fixture(scope="session") def png_gray8a_img(tmp_path_factory, tmp_alpha_png): in_img = tmp_path_factory.mktemp("png_gray8a") / "in.png" subprocess.check_call( [ "convert", str(tmp_alpha_png), "-colorspace", "Gray", "-dither", "FloydSteinberg", "-colors", "256", "-depth", "8", "-strip", 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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("colorspace") == "Gray", str(identify) assert identify[0]["image"].get("type") == "GrayscaleAlpha", 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") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "8" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "8" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "4" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "4 (GrayAlpha)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def png_gray16a_img(tmp_path_factory, tmp_alpha_png): in_img = tmp_path_factory.mktemp("png_gray16a") / "in.png" subprocess.check_call( [ "convert", str(tmp_alpha_png), "-colorspace", "Gray", "-depth", "16", "-strip", 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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("colorspace") == "Gray", str(identify) assert identify[0]["image"].get("type") == "GrayscaleAlpha", 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") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "16" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "16" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "4" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "4 (GrayAlpha)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def png_interlaced_img(tmp_path_factory, tmp_normal_png): in_img = tmp_path_factory.mktemp("png_interlaced") / "in.png" subprocess.check_call( ["convert", str(tmp_normal_png), "-interlace", "PNG", "-strip", 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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", 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") == "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) assert identify[0]["image"].get("compression") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "8" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "8" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "2" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "2 (Truecolor)" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.interlace_method") == "1 (Adam7 method)" ), str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def png_gray1_img(tmp_path_factory, tmp_gray1_png): identify = json.loads( subprocess.check_output(["convert", str(tmp_gray1_png), "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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "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("depth") == 1, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "1" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "1" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "0" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "0 (Grayscale)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) return tmp_gray1_png @pytest.fixture(scope="session") def png_gray2_img(tmp_path_factory, tmp_gray2_png): identify = json.loads( subprocess.check_output(["convert", str(tmp_gray2_png), "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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("colorspace") == "Gray", str(identify) assert identify[0]["image"].get("type") == "Grayscale", str(identify) assert identify[0]["image"].get("depth") == 2, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "2" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "2" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "0" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "0 (Grayscale)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) return tmp_gray2_png @pytest.fixture(scope="session") def png_gray4_img(tmp_path_factory, tmp_gray4_png): identify = json.loads( subprocess.check_output(["convert", str(tmp_gray4_png), "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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("colorspace") == "Gray", str(identify) assert identify[0]["image"].get("type") == "Grayscale", str(identify) assert identify[0]["image"].get("depth") == 4, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "4" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "4" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "0" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "0 (Grayscale)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) return tmp_gray4_png @pytest.fixture(scope="session") def png_gray8_img(tmp_path_factory, tmp_gray8_png): identify = json.loads( subprocess.check_output(["convert", str(tmp_gray8_png), "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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("colorspace") == "Gray", str(identify) assert identify[0]["image"].get("type") == "Grayscale", 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") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "8" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "8" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "0" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "0 (Grayscale)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) return tmp_gray8_png @pytest.fixture(scope="session") def png_gray16_img(tmp_path_factory, tmp_gray16_png): identify = json.loads( subprocess.check_output(["convert", str(tmp_gray16_png), "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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("colorspace") == "Gray", str(identify) assert identify[0]["image"].get("type") == "Grayscale", 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") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "16" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "16" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "0" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "0 (Grayscale)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) return tmp_gray16_png @pytest.fixture(scope="session") def png_palette1_img(tmp_path_factory, tmp_palette1_png): identify = json.loads( subprocess.check_output(["convert", str(tmp_palette1_png), "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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", 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") == "Palette", 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") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "1" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "1" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "3" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "3 (Indexed)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) return tmp_palette1_png @pytest.fixture(scope="session") def png_palette2_img(tmp_path_factory, tmp_palette2_png): identify = json.loads( subprocess.check_output(["convert", str(tmp_palette2_png), "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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", 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") == "Palette", 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") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "2" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "2" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "3" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "3 (Indexed)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) return tmp_palette2_png @pytest.fixture(scope="session") def png_palette4_img(tmp_path_factory, tmp_palette4_png): identify = json.loads( subprocess.check_output(["convert", str(tmp_palette4_png), "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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", 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") == "Palette", 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") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "4" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "4" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "3" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "3 (Indexed)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) return tmp_palette4_png @pytest.fixture(scope="session") def png_palette8_img(tmp_path_factory, tmp_palette8_png): identify = json.loads( subprocess.check_output(["convert", str(tmp_palette8_png), "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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", 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") == "Palette", 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") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "8" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "8" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "3" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "3 (Indexed)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) return tmp_palette8_png @pytest.fixture(scope="session") def gif_transparent_img(tmp_path_factory, tmp_alpha_png): in_img = tmp_path_factory.mktemp("gif_transparent_img") / "in.gif" 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") == "GIF", str(identify) assert identify[0]["image"].get("mimeType") == "image/gif", 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") == "PaletteAlpha", str(identify) assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("colormapEntries") == 256, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "LZW", str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def gif_palette1_img(tmp_path_factory, tmp_palette1_png): in_img = tmp_path_factory.mktemp("gif_palette1_img") / "in.gif" subprocess.check_call(["convert", str(tmp_palette1_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") == "GIF", str(identify) assert identify[0]["image"].get("mimeType") == "image/gif", 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") == "Palette", str(identify) assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("colormapEntries") == 2, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "LZW", str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def gif_palette2_img(tmp_path_factory, tmp_palette2_png): in_img = tmp_path_factory.mktemp("gif_palette2_img") / "in.gif" subprocess.check_call(["convert", str(tmp_palette2_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") == "GIF", str(identify) assert identify[0]["image"].get("mimeType") == "image/gif", 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") == "Palette", str(identify) assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("colormapEntries") == 4, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "LZW", str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def gif_palette4_img(tmp_path_factory, tmp_palette4_png): in_img = tmp_path_factory.mktemp("gif_palette4_img") / "in.gif" subprocess.check_call(["convert", str(tmp_palette4_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") == "GIF", str(identify) assert identify[0]["image"].get("mimeType") == "image/gif", 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") == "Palette", str(identify) assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("colormapEntries") == 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") == "LZW", str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def gif_palette8_img(tmp_path_factory, tmp_palette8_png): in_img = tmp_path_factory.mktemp("gif_palette8_img") / "in.gif" subprocess.check_call(["convert", str(tmp_palette8_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") == "GIF", str(identify) assert identify[0]["image"].get("mimeType") == "image/gif", 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") == "Palette", str(identify) assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("colormapEntries") == 256, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "LZW", str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def gif_animation_img(tmp_path_factory, tmp_normal_png, tmp_inverse_png): in_img = tmp_path_factory.mktemp("gif_animation_img") / "in.gif" subprocess.check_call( ["convert", str(tmp_normal_png), str(tmp_inverse_png), "-strip", str(in_img)] ) identify = json.loads( subprocess.check_output(["convert", str(in_img) + "[0]", "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") == "GIF", str(identify) assert identify[0]["image"].get("mimeType") == "image/gif", 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") == "Palette", str(identify) assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("colormapEntries") == 256, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "LZW", str(identify) identify = json.loads( subprocess.check_output(["convert", str(in_img) + "[1]", "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") == "GIF", str(identify) assert identify[0]["image"].get("mimeType") == "image/gif", 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") == "Palette", str(identify) assert identify[0]["image"].get("depth") == 8, str(identify) assert identify[0]["image"].get("colormapEntries") == 256, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "LZW", str(identify) assert identify[0]["image"].get("scene") == 1, str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_float_img(tmp_path_factory, tmp_normal_png): in_img = tmp_path_factory.mktemp("tiff_float_img") / "in.tiff" subprocess.check_call( [ "convert", str(tmp_normal_png), "-depth", "32", "-define", "quantum:format=floating-point", 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", 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") == "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") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("quantum:format") == "floating-point" ), str(identify) 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) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_cmyk8_img(tmp_path_factory, tmp_normal_png): in_img = tmp_path_factory.mktemp("tiff_cmyk8") / "in.tiff" 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", str(identify) 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) 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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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" ), str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_cmyk16_img(tmp_path_factory, tmp_normal_png): in_img = tmp_path_factory.mktemp("tiff_cmyk16") / "in.tiff" 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", str(identify) 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) 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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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" ), str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_rgb8_img(tmp_path_factory, tmp_normal_png): in_img = tmp_path_factory.mktemp("tiff_rgb8") / "in.tiff" 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", 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") == "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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_rgb12_img(tmp_path_factory, tmp_normal16_png): in_img = tmp_path_factory.mktemp("tiff_rgb8") / "in.tiff" subprocess.check_call( ["convert", str(tmp_normal16_png), "-depth", "12", 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", 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") == "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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_rgb14_img(tmp_path_factory, tmp_normal16_png): in_img = tmp_path_factory.mktemp("tiff_rgb8") / "in.tiff" subprocess.check_call( ["convert", str(tmp_normal16_png), "-depth", "14", 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", 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") == "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") == 14, str(identify) else: 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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_rgb16_img(tmp_path_factory, tmp_normal16_png): in_img = tmp_path_factory.mktemp("tiff_rgb8") / "in.tiff" subprocess.check_call( ["convert", str(tmp_normal16_png), "-depth", "16", 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", 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") == "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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_rgba8_img(tmp_path_factory, tmp_alpha_png): in_img = tmp_path_factory.mktemp("tiff_rgba8") / "in.tiff" subprocess.check_call( ["convert", str(tmp_alpha_png), "-depth", "8", "-strip", 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", 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) 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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_rgba16_img(tmp_path_factory, tmp_alpha_png): in_img = tmp_path_factory.mktemp("tiff_rgba16") / "in.tiff" subprocess.check_call( ["convert", str(tmp_alpha_png), "-depth", "16", "-strip", 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", 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) 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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_gray1_img(tmp_path_factory, tmp_gray1_png): in_img = tmp_path_factory.mktemp("tiff_gray1") / "in.tiff" subprocess.check_call(["convert", str(tmp_gray1_png), "-depth", "1", 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, 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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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" ), str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_gray2_img(tmp_path_factory, tmp_gray2_png): in_img = tmp_path_factory.mktemp("tiff_gray2") / "in.tiff" subprocess.check_call(["convert", str(tmp_gray2_png), "-depth", "2", 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, 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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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" ), str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_gray4_img(tmp_path_factory, tmp_gray4_png): in_img = tmp_path_factory.mktemp("tiff_gray4") / "in.tiff" subprocess.check_call(["convert", str(tmp_gray4_png), "-depth", "4", 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, 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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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" ), str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_gray8_img(tmp_path_factory, tmp_gray8_png): in_img = tmp_path_factory.mktemp("tiff_gray8") / "in.tiff" subprocess.check_call(["convert", str(tmp_gray8_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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, 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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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" ), str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_gray16_img(tmp_path_factory, tmp_gray16_png): in_img = tmp_path_factory.mktemp("tiff_gray16") / "in.tiff" subprocess.check_call(["convert", str(tmp_gray16_png), "-depth", "16", 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, 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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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" ), str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_multipage_img(tmp_path_factory, tmp_normal_png, tmp_inverse_png): in_img = tmp_path_factory.mktemp("tiff_multipage_img") / "in.tiff" subprocess.check_call( ["convert", str(tmp_normal_png), str(tmp_inverse_png), "-strip", str(in_img)] ) identify = json.loads( subprocess.check_output(["convert", str(in_img) + "[0]", "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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", 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") == "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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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) identify = json.loads( subprocess.check_output(["convert", str(in_img) + "[1]", "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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", 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") == "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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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) assert identify[0]["image"].get("scene") == 1, str(identify) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_palette1_img(tmp_path_factory, tmp_palette1_png): in_img = tmp_path_factory.mktemp("tiff_palette1_img") / "in.tiff" subprocess.check_call(["convert", str(tmp_palette1_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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", 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") == "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) assert identify[0]["image"].get("pageGeometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_palette2_img(tmp_path_factory, tmp_palette2_png): in_img = tmp_path_factory.mktemp("tiff_palette2_img") / "in.tiff" subprocess.check_call(["convert", str(tmp_palette2_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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", 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") == "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) assert identify[0]["image"].get("pageGeometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_palette4_img(tmp_path_factory, tmp_palette4_png): in_img = tmp_path_factory.mktemp("tiff_palette4_img") / "in.tiff" subprocess.check_call(["convert", str(tmp_palette4_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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", 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") == "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) assert identify[0]["image"].get("pageGeometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_palette8_img(tmp_path_factory, tmp_palette8_png): in_img = tmp_path_factory.mktemp("tiff_palette8_img") / "in.tiff" subprocess.check_call(["convert", str(tmp_palette8_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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", 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") == "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") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Zip", str(identify) 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) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_ccitt_lsb_m2l_white_img(tmp_path_factory, tmp_gray1_png): in_img = tmp_path_factory.mktemp("tiff_ccitt_lsb_m2l_white_img") / "in.tiff" subprocess.check_call( [ "convert", str(tmp_gray1_png), "-compress", "group4", "-define", "tiff:endian=lsb", "-define", "tiff:fill-order=msb", "-define", "quantum:polarity=min-is-white", 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, 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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Group4", str(identify) 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-white" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("tiff:rows-per-strip") == "60" ), str(identify) tiffinfo = subprocess.check_output(["tiffinfo", str(in_img)]) expected = [ r"^ Image Width: 60 Image Length: 60", r"^ Bits/Sample: 1", r"^ Compression Scheme: CCITT Group 4", r"^ Photometric Interpretation: min-is-white", r"^ FillOrder: msb-to-lsb", r"^ Samples/Pixel: 1", r"^ Rows/Strip: 60", ] for e in expected: assert re.search(e, tiffinfo.decode("utf8"), re.MULTILINE), identify.decode( "utf8" ) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_ccitt_msb_m2l_white_img(tmp_path_factory, tmp_gray1_png): in_img = tmp_path_factory.mktemp("tiff_ccitt_msb_m2l_white_img") / "in.tiff" subprocess.check_call( [ "convert", str(tmp_gray1_png), "-compress", "group4", "-define", "tiff:endian=msb", "-define", "tiff:fill-order=msb", "-define", "quantum:polarity=min-is-white", 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, 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", "MSB", ] # FIXME: should be MSB assert identify[0]["image"].get("depth") == 1, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Group4", str(identify) assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "msb", str( identify ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "min-is-white" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("tiff:rows-per-strip") == "60" ), str(identify) tiffinfo = subprocess.check_output(["tiffinfo", str(in_img)]) expected = [ r"^ Image Width: 60 Image Length: 60", r"^ Bits/Sample: 1", r"^ Compression Scheme: CCITT Group 4", r"^ Photometric Interpretation: min-is-white", r"^ FillOrder: msb-to-lsb", r"^ Samples/Pixel: 1", r"^ Rows/Strip: 60", ] for e in expected: assert re.search(e, tiffinfo.decode("utf8"), re.MULTILINE), identify.decode( "utf8" ) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_ccitt_msb_l2m_white_img(tmp_path_factory, tmp_gray1_png): in_img = tmp_path_factory.mktemp("tiff_ccitt_msb_l2m_white_img") / "in.tiff" subprocess.check_call( [ "convert", str(tmp_gray1_png), "-compress", "group4", "-define", "tiff:endian=msb", "-define", "tiff:fill-order=lsb", "-define", "quantum:polarity=min-is-white", 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, 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", "MSB", ] # FIXME: should be MSB assert identify[0]["image"].get("depth") == 1, str(identify) assert identify[0]["image"].get("pageGeometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Group4", str(identify) assert ( identify[0]["image"].get("properties", {}).get("tiff:alpha") == "unspecified" ), str(identify) assert identify[0]["image"].get("properties", {}).get("tiff:endian") == "msb", str( identify ) assert ( identify[0]["image"].get("properties", {}).get("tiff:photometric") == "min-is-white" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("tiff:rows-per-strip") == "60" ), str(identify) tiffinfo = subprocess.check_output(["tiffinfo", str(in_img)]) expected = [ r"^ Image Width: 60 Image Length: 60", r"^ Bits/Sample: 1", r"^ Compression Scheme: CCITT Group 4", r"^ Photometric Interpretation: min-is-white", r"^ FillOrder: lsb-to-msb", r"^ Samples/Pixel: 1", r"^ Rows/Strip: 60", ] for e in expected: assert re.search(e, tiffinfo.decode("utf8"), re.MULTILINE), identify.decode( "utf8" ) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_ccitt_lsb_m2l_black_img(tmp_path_factory, tmp_gray1_png): in_img = tmp_path_factory.mktemp("tiff_ccitt_lsb_m2l_black_img") / "in.tiff" # "-define quantum:polarity=min-is-black" requires ImageMagick with: # https://github.com/ImageMagick/ImageMagick/commit/00730551f0a34328685c59d0dde87dd9e366103a # or at least 7.0.8-11 from Aug 29, 2018 # or at least 6.9.10-12 from Sep 7, 2018 (for the ImageMagick6 branch) # also see: https://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=34605 subprocess.check_call( [ "convert", str(tmp_gray1_png), "-compress", "group4", "-define", "tiff:endian=lsb", "-define", "tiff:fill-order=msb", "-define", "quantum:polarity=min-is-black", 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, 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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Group4", str(identify) 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" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("tiff:rows-per-strip") == "60" ), str(identify) tiffinfo = subprocess.check_output(["tiffinfo", str(in_img)]) expected = [ r"^ Image Width: 60 Image Length: 60", r"^ Bits/Sample: 1", r"^ Compression Scheme: CCITT Group 4", r"^ Photometric Interpretation: min-is-black", r"^ FillOrder: msb-to-lsb", r"^ Samples/Pixel: 1", r"^ Rows/Strip: 60", ] for e in expected: assert re.search(e, tiffinfo.decode("utf8"), re.MULTILINE), identify.decode( "utf8" ) yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_ccitt_nometa1_img(tmp_path_factory, tmp_gray1_png): in_img = tmp_path_factory.mktemp("tiff_ccitt_nometa1_img") / "in.tiff" subprocess.check_call( [ "convert", str(tmp_gray1_png), "-compress", "group4", "-define", "tiff:endian=lsb", "-define", "tiff:fill-order=msb", "-define", "quantum:polarity=min-is-white", str(in_img), ] ) subprocess.check_call( ["tiffset", "-u", "258", str(in_img)] ) # remove BitsPerSample (258) subprocess.check_call( ["tiffset", "-u", "266", str(in_img)] ) # remove FillOrder (266) subprocess.check_call( ["tiffset", "-u", "277", str(in_img)] ) # remove SamplesPerPixel (277) 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, 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, "height": 60, "x": 0, "y": 0, }, str(identify) assert identify[0]["image"].get("compression") == "Group4", str(identify) 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-white" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("tiff:rows-per-strip") == "60" ), str(identify) tiffinfo = subprocess.check_output(["tiffinfo", str(in_img)]) expected = [ r"^ Image Width: 60 Image Length: 60", r"^ Compression Scheme: CCITT Group 4", r"^ Photometric Interpretation: min-is-white", r"^ Rows/Strip: 60", ] for e in expected: assert re.search(e, tiffinfo.decode("utf8"), re.MULTILINE), identify.decode( "utf8" ) unexpected = [" Bits/Sample: ", " FillOrder: ", " Samples/Pixel: "] for e in unexpected: assert e not in tiffinfo.decode("utf8") yield in_img in_img.unlink() @pytest.fixture(scope="session") def tiff_ccitt_nometa2_img(tmp_path_factory, tmp_gray1_png): in_img = tmp_path_factory.mktemp("tiff_ccitt_nometa2_img") / "in.tiff" subprocess.check_call( [ "convert", str(tmp_gray1_png), "-compress", "group4", "-define", "tiff:endian=lsb", "-define", "tiff:fill-order=msb", "-define", "quantum:polarity=min-is-white", str(in_img), ] ) subprocess.check_call( ["tiffset", "-u", "278", str(in_img)] ) # remove RowsPerStrip (278) 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") == "TIFF", str(identify) assert identify[0]["image"].get("mimeType") == "image/tiff", str(identify) assert identify[0]["image"].get("geometry") == { "width": 60, "height": 60, "x": 0, "y": 0, }, str(identify) 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("colorspace") == "Gray", str(identify) assert identify[0]["image"].get("depth") == 1, str(identify) assert identify[0]["image"].get("compression") == "Group4", str(identify) 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-white" ), str(identify) assert "tiff:rows-per-strip" not in identify[0]["image"]["properties"] tiffinfo = subprocess.check_output(["tiffinfo", str(in_img)]) expected = [ r"^ Image Width: 60 Image Length: 60", r"^ Bits/Sample: 1", r"^ Compression Scheme: CCITT Group 4", r"^ Photometric Interpretation: min-is-white", r"^ FillOrder: msb-to-lsb", r"^ Samples/Pixel: 1", ] for e in expected: assert re.search(e, tiffinfo.decode("utf8"), re.MULTILINE), identify.decode( "utf8" ) unexpected = [" Rows/Strip: "] for e in unexpected: assert e not in tiffinfo.decode("utf8") 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:"])) 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") == "PNG", str(identify) assert identify[0]["image"].get("mimeType") == "image/png", 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") == "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) assert identify[0]["image"].get("compression") == "Zip", str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit-depth-orig") == "8" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.bit_depth") == "8" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color-type-orig") == "2" ), str(identify) assert ( identify[0]["image"].get("properties", {}).get("png:IHDR.color_type") == "2 (Truecolor)" ), str(identify) assert ( identify[0]["image"]["properties"]["png:IHDR.interlace_method"] == "0 (Not interlaced)" ), str(identify) return in_img ############################################################################### # OUTPUT FIXTURES # ############################################################################### @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def jpg_pdf(tmp_path_factory, jpg_img, request): out_pdf = tmp_path_factory.mktemp("jpg_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(jpg_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.Filter == "/DCTDecode" 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", "pdfrw"]) def jpg_rot_pdf(tmp_path_factory, jpg_rot_img, request): out_pdf = tmp_path_factory.mktemp("jpg_rot_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(jpg_rot_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.Filter == "/DCTDecode" assert p.pages[0].Resources.XObject.Im0.Height == 60 assert p.pages[0].Resources.XObject.Im0.Width == 60 assert p.pages[0].Rotate == 90 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def jpg_cmyk_pdf(tmp_path_factory, jpg_cmyk_img, request): out_pdf = tmp_path_factory.mktemp("jpg_cmyk_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(jpg_cmyk_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.Decode == pikepdf.Array( [1, 0, 1, 0, 1, 0, 1, 0] ) assert p.pages[0].Resources.XObject.Im0.Filter == "/DCTDecode" 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", "pdfrw"]) def jpg_2000_pdf(tmp_path_factory, jpg_2000_img, request): out_pdf = tmp_path_factory.mktemp("jpg_2000_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), jpg_2000_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.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", "pdfrw"]) 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( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(png_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() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def png_rgb16_pdf(tmp_path_factory, png_rgb16_img, request): out_pdf = tmp_path_factory.mktemp("png_rgb16_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(png_rgb16_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 == "/DeviceRGB" assert p.pages[0].Resources.XObject.Im0.DecodeParms.BitsPerComponent == 16 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() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def png_interlaced_pdf(tmp_path_factory, png_interlaced_img, request): out_pdf = tmp_path_factory.mktemp("png_interlaced_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(png_interlaced_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() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def png_gray1_pdf(tmp_path_factory, tmp_gray1_png, request): out_pdf = tmp_path_factory.mktemp("png_gray1_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tmp_gray1_png), ] ) 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 == 1 assert p.pages[0].Resources.XObject.Im0.ColorSpace == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms.BitsPerComponent == 1 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def png_gray2_pdf(tmp_path_factory, tmp_gray2_png, request): out_pdf = tmp_path_factory.mktemp("png_gray2_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tmp_gray2_png), ] ) 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 == 2 assert p.pages[0].Resources.XObject.Im0.ColorSpace == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms.BitsPerComponent == 2 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def png_gray4_pdf(tmp_path_factory, tmp_gray4_png, request): out_pdf = tmp_path_factory.mktemp("png_gray4_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tmp_gray4_png), ] ) 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 == 4 assert p.pages[0].Resources.XObject.Im0.ColorSpace == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms.BitsPerComponent == 4 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def png_gray8_pdf(tmp_path_factory, tmp_gray8_png, request): out_pdf = tmp_path_factory.mktemp("png_gray8_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tmp_gray8_png), ] ) 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 == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms.BitsPerComponent == 8 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def png_gray16_pdf(tmp_path_factory, tmp_gray16_png, request): out_pdf = tmp_path_factory.mktemp("png_gray16_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tmp_gray16_png), ] ) 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 == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms.BitsPerComponent == 16 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf"]) def png_palette1_pdf(tmp_path_factory, tmp_palette1_png, request): out_pdf = tmp_path_factory.mktemp("png_palette1_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tmp_palette1_png), ] ) 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 == 1 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 == 1 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf"]) def png_palette2_pdf(tmp_path_factory, tmp_palette2_png, request): out_pdf = tmp_path_factory.mktemp("png_palette2_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tmp_palette2_png), ] ) 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 == 2 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 == 2 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf"]) def png_palette4_pdf(tmp_path_factory, tmp_palette4_png, request): out_pdf = tmp_path_factory.mktemp("png_palette4_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tmp_palette4_png), ] ) 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 == 4 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 == 4 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf"]) def png_palette8_pdf(tmp_path_factory, tmp_palette8_png, request): out_pdf = tmp_path_factory.mktemp("png_palette8_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tmp_palette8_png), ] ) 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[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 == 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def png_icc_pdf(tmp_path_factory, tmp_icc_png, tmp_icc_profile, request): out_pdf = tmp_path_factory.mktemp("png_icc_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tmp_icc_png), ] ) 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[0] == "/ICCBased" assert p.pages[0].Resources.XObject.Im0.ColorSpace[1].N == 3 assert p.pages[0].Resources.XObject.Im0.ColorSpace[1].Alternate == "/DeviceRGB" assert ( p.pages[0].Resources.XObject.Im0.ColorSpace[1].read_bytes() == tmp_icc_profile.read_bytes() ) 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() @pytest.fixture(scope="session", params=["internal", "pikepdf"]) def gif_palette1_pdf(tmp_path_factory, gif_palette1_img, request): out_pdf = tmp_path_factory.mktemp("gif_palette1_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(gif_palette1_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 == 1 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 == 1 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf"]) def gif_palette2_pdf(tmp_path_factory, gif_palette2_img, request): out_pdf = tmp_path_factory.mktemp("gif_palette2_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(gif_palette2_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 == 2 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 == 2 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf"]) def gif_palette4_pdf(tmp_path_factory, gif_palette4_img, request): out_pdf = tmp_path_factory.mktemp("gif_palette4_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(gif_palette4_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 == 4 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 == 4 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf"]) def gif_palette8_pdf(tmp_path_factory, gif_palette8_img, request): out_pdf = tmp_path_factory.mktemp("gif_palette8_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(gif_palette8_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[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 == 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf"]) def gif_animation_pdf(tmp_path_factory, gif_animation_img, request): tmpdir = tmp_path_factory.mktemp("gif_animation_pdf") out_pdf = tmpdir / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(gif_animation_img), ] ) pdfinfo = subprocess.check_output(["pdfinfo", str(out_pdf)]) assert re.search( "^Pages: +2$", pdfinfo.decode("utf8"), re.MULTILINE ), identify.decode("utf8") subprocess.check_call(["pdfseparate", str(out_pdf), str(tmpdir / "page-%d.pdf")]) for page in [1, 2]: gif_animation_pdf_nr = tmpdir / ("page-%d.pdf" % page) with pikepdf.open(gif_animation_pdf_nr) 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[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 == 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 gif_animation_pdf_nr.unlink() yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def tiff_cmyk8_pdf(tmp_path_factory, tiff_cmyk8_img, request): out_pdf = tmp_path_factory.mktemp("tiff_cmyk8_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_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", "pdfrw"]) def tiff_rgb8_pdf(tmp_path_factory, tiff_rgb8_img, request): out_pdf = tmp_path_factory.mktemp("tiff_rgb8_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_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() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def tiff_gray1_pdf(tmp_path_factory, tiff_gray1_img, request): out_pdf = tmp_path_factory.mktemp("tiff_gray1_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_gray1_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 == 1 assert p.pages[0].Resources.XObject.Im0.ColorSpace == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].BlackIs1 == True assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].Columns == 60 assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].K == -1 assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].Rows == 60 assert p.pages[0].Resources.XObject.Im0.Filter[0] == "/CCITTFaxDecode" 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", "pdfrw"]) def tiff_gray2_pdf(tmp_path_factory, tiff_gray2_img, request): out_pdf = tmp_path_factory.mktemp("tiff_gray2_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_gray2_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 == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms.BitsPerComponent == 8 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def tiff_gray4_pdf(tmp_path_factory, tiff_gray4_img, request): out_pdf = tmp_path_factory.mktemp("tiff_gray4_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_gray4_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 == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms.BitsPerComponent == 8 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def tiff_gray8_pdf(tmp_path_factory, tiff_gray8_img, request): out_pdf = tmp_path_factory.mktemp("tiff_gray8_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_gray8_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 == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms.BitsPerComponent == 8 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def tiff_multipage_pdf(tmp_path_factory, tiff_multipage_img, request): tmpdir = tmp_path_factory.mktemp("tiff_multipage_pdf") out_pdf = tmpdir / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_multipage_img), ] ) pdfinfo = subprocess.check_output(["pdfinfo", str(out_pdf)]) assert re.search( "^Pages: +2$", pdfinfo.decode("utf8"), re.MULTILINE ), identify.decode("utf8") subprocess.check_call(["pdfseparate", str(out_pdf), str(tmpdir / "page-%d.pdf")]) for page in [1, 2]: tiff_multipage_pdf_nr = tmpdir / ("page-%d.pdf" % page) with pikepdf.open(tiff_multipage_pdf_nr) 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 tiff_multipage_pdf_nr.unlink() yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf"]) def tiff_palette1_pdf(tmp_path_factory, tiff_palette1_img, request): out_pdf = tmp_path_factory.mktemp("tiff_palette1_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_palette1_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 == 1 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 == 1 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf"]) def tiff_palette2_pdf(tmp_path_factory, tiff_palette2_img, request): out_pdf = tmp_path_factory.mktemp("tiff_palette2_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_palette2_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 == 2 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 == 2 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf"]) def tiff_palette4_pdf(tmp_path_factory, tiff_palette4_img, request): out_pdf = tmp_path_factory.mktemp("tiff_palette4_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_palette4_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 == 4 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 == 4 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf"]) def tiff_palette8_pdf(tmp_path_factory, tiff_palette8_img, request): out_pdf = tmp_path_factory.mktemp("tiff_palette8_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_palette8_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[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 == 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 assert p.pages[0].Resources.XObject.Im0.Width == 60 yield out_pdf out_pdf.unlink() @pytest.fixture(scope="session", params=["internal", "pikepdf", "pdfrw"]) def tiff_ccitt_lsb_m2l_white_pdf( tmp_path_factory, tiff_ccitt_lsb_m2l_white_img, request ): out_pdf = tmp_path_factory.mktemp("tiff_ccitt_lsb_m2l_white_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_ccitt_lsb_m2l_white_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 == 1 assert p.pages[0].Resources.XObject.Im0.ColorSpace == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].BlackIs1 == False assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].Columns == 60 assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].K == -1 assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].Rows == 60 assert p.pages[0].Resources.XObject.Im0.Filter[0] == "/CCITTFaxDecode" 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", "pdfrw"]) def tiff_ccitt_msb_m2l_white_pdf( tmp_path_factory, tiff_ccitt_msb_m2l_white_img, request ): out_pdf = tmp_path_factory.mktemp("tiff_ccitt_msb_m2l_white_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_ccitt_msb_m2l_white_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 == 1 assert p.pages[0].Resources.XObject.Im0.ColorSpace == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].BlackIs1 == False assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].Columns == 60 assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].K == -1 assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].Rows == 60 assert p.pages[0].Resources.XObject.Im0.Filter[0] == "/CCITTFaxDecode" 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", "pdfrw"]) def tiff_ccitt_msb_l2m_white_pdf( tmp_path_factory, tiff_ccitt_msb_l2m_white_img, request ): out_pdf = tmp_path_factory.mktemp("tiff_ccitt_msb_l2m_white_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_ccitt_msb_l2m_white_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 == 1 assert p.pages[0].Resources.XObject.Im0.ColorSpace == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].BlackIs1 == False assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].Columns == 60 assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].K == -1 assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].Rows == 60 assert p.pages[0].Resources.XObject.Im0.Filter[0] == "/CCITTFaxDecode" 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", "pdfrw"]) def tiff_ccitt_lsb_m2l_black_pdf( tmp_path_factory, tiff_ccitt_lsb_m2l_black_img, request ): out_pdf = tmp_path_factory.mktemp("tiff_ccitt_lsb_m2l_black_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_ccitt_lsb_m2l_black_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 == 1 assert p.pages[0].Resources.XObject.Im0.ColorSpace == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].BlackIs1 == True assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].Columns == 60 assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].K == -1 assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].Rows == 60 assert p.pages[0].Resources.XObject.Im0.Filter[0] == "/CCITTFaxDecode" 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", "pdfrw"]) def tiff_ccitt_nometa1_pdf(tmp_path_factory, tiff_ccitt_nometa1_img, request): out_pdf = tmp_path_factory.mktemp("tiff_ccitt_nometa1_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_ccitt_nometa1_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 == 1 assert p.pages[0].Resources.XObject.Im0.ColorSpace == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].BlackIs1 == False assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].Columns == 60 assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].K == -1 assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].Rows == 60 assert p.pages[0].Resources.XObject.Im0.Filter[0] == "/CCITTFaxDecode" 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", "pdfrw"]) def tiff_ccitt_nometa2_pdf(tmp_path_factory, tiff_ccitt_nometa2_img, request): out_pdf = tmp_path_factory.mktemp("tiff_ccitt_nometa2_pdf") / "out.pdf" subprocess.check_call( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + request.param, "--output=" + str(out_pdf), str(tiff_ccitt_nometa2_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 == 1 assert p.pages[0].Resources.XObject.Im0.ColorSpace == "/DeviceGray" assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].BlackIs1 == False assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].Columns == 60 assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].K == -1 assert p.pages[0].Resources.XObject.Im0.DecodeParms[0].Rows == 60 assert p.pages[0].Resources.XObject.Im0.Filter[0] == "/CCITTFaxDecode" 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 # ############################################################################### @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_jpg(tmp_path_factory, jpg_img, jpg_pdf): tmpdir = tmp_path_factory.mktemp("jpg") pnm = tmpdir / "jpg.pnm" # We have to use jpegtopnm with the original JPG before being able to compare # it with imagemagick because imagemagick will decode the JPG slightly # differently than ghostscript, poppler and mupdf do it. # We have to use jpegtopnm and cannot use djpeg because the latter produces # slightly different results as well when called like this: # djpeg -dct int -pnm "$tempdir/normal.jpg" > "$tempdir/normal.pnm" # An alternative way to compare the JPG would be to require a different DCT # method when decoding by setting -define jpeg:dct-method=ifast in the # compare command. pnm.write_bytes(subprocess.check_output(["jpegtopnm", "-dct", "int", str(jpg_img)])) compare_ghostscript(tmpdir, pnm, jpg_pdf) compare_poppler(tmpdir, pnm, jpg_pdf) compare_mupdf(tmpdir, pnm, jpg_pdf) pnm.unlink() compare_pdfimages_jpg(tmpdir, jpg_img, jpg_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_jpg_rot(tmp_path_factory, jpg_rot_img, jpg_rot_pdf): tmpdir = tmp_path_factory.mktemp("jpg_rot") # We have to use jpegtopnm with the original JPG before being able to compare # it with imagemagick because imagemagick will decode the JPG slightly # differently than ghostscript, poppler and mupdf do it. # We have to use jpegtopnm and cannot use djpeg because the latter produces # slightly different results as well when called like this: # djpeg -dct int -pnm "$tempdir/normal.jpg" > "$tempdir/normal.pnm" # An alternative way to compare the JPG would be to require a different DCT # method when decoding by setting -define jpeg:dct-method=ifast in the # compare command. jpg_rot_pnm = tmpdir / "jpg_rot.pnm" jpg_rot_pnm.write_bytes( subprocess.check_output(["jpegtopnm", "-dct", "int", str(jpg_rot_img)]) ) jpg_rot_png = tmpdir / "jpg_rot.png" subprocess.check_call( ["convert", "-rotate", "90", str(jpg_rot_pnm), str(jpg_rot_png)] ) jpg_rot_pnm.unlink() compare_ghostscript(tmpdir, jpg_rot_png, jpg_rot_pdf) compare_poppler(tmpdir, jpg_rot_png, jpg_rot_pdf) compare_mupdf(tmpdir, jpg_rot_png, jpg_rot_pdf) jpg_rot_png.unlink() compare_pdfimages_jpg(tmpdir, jpg_rot_img, jpg_rot_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) 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 ) # not testing with poppler as it cannot write CMYK images compare_mupdf(tmpdir, jpg_cmyk_img, jpg_cmyk_pdf, exact=False, cmyk=True) compare_pdfimages_cmyk(tmpdir, jpg_cmyk_img, jpg_cmyk_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) @pytest.mark.skipif( not HAVE_JP2, reason="requires imagemagick with support for jpeg2000" ) def test_jpg_2000(tmp_path_factory, jpg_2000_img, jpg_2000_pdf): tmpdir = tmp_path_factory.mktemp("jpg_2000") compare_ghostscript(tmpdir, jpg_2000_img, jpg_2000_pdf) compare_poppler(tmpdir, jpg_2000_img, jpg_2000_pdf) compare_mupdf(tmpdir, jpg_2000_img, jpg_2000_pdf) compare_pdfimages_jp2(tmpdir, jpg_2000_img, jpg_2000_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "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) compare_poppler(tmpdir, png_rgb8_img, png_rgb8_pdf) compare_mupdf(tmpdir, png_rgb8_img, png_rgb8_pdf) compare_pdfimages_png(tmpdir, png_rgb8_img, png_rgb8_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_png_rgb16(tmp_path_factory, png_rgb16_img, png_rgb16_pdf): tmpdir = tmp_path_factory.mktemp("png_rgb16") compare_ghostscript(tmpdir, png_rgb16_img, png_rgb16_pdf, gsdevice="tiff48nc") # poppler outputs 8-bit RGB so the comparison will not be exact compare_poppler(tmpdir, png_rgb16_img, png_rgb16_pdf, exact=False) # pdfimages is unable to write 16 bit output @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) @pytest.mark.parametrize("engine", ["internal", "pikepdf", "pdfrw"]) def test_png_rgba8(tmp_path_factory, png_rgba8_img, engine): out_pdf = tmp_path_factory.mktemp("png_rgba8") / "out.pdf" assert ( 0 != subprocess.run( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + engine, "--output=" + str(out_pdf), str(png_rgba8_img), ] ).returncode ) out_pdf.unlink() @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) @pytest.mark.parametrize("engine", ["internal", "pikepdf", "pdfrw"]) def test_png_rgba16(tmp_path_factory, png_rgba16_img, engine): out_pdf = tmp_path_factory.mktemp("png_rgba16") / "out.pdf" assert ( 0 != subprocess.run( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + engine, "--output=" + str(out_pdf), str(png_rgba16_img), ] ).returncode ) out_pdf.unlink() @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) @pytest.mark.parametrize("engine", ["internal", "pikepdf", "pdfrw"]) def test_png_gray8a(tmp_path_factory, png_gray8a_img, engine): out_pdf = tmp_path_factory.mktemp("png_gray8a") / "out.pdf" assert ( 0 != subprocess.run( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + engine, "--output=" + str(out_pdf), str(png_gray8a_img), ] ).returncode ) out_pdf.unlink() @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) @pytest.mark.parametrize("engine", ["internal", "pikepdf", "pdfrw"]) def test_png_gray16a(tmp_path_factory, png_gray16a_img, engine): out_pdf = tmp_path_factory.mktemp("png_gray16a") / "out.pdf" assert ( 0 != subprocess.run( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + engine, "--output=" + str(out_pdf), str(png_gray16a_img), ] ).returncode ) out_pdf.unlink() @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_png_interlaced(tmp_path_factory, png_interlaced_img, png_interlaced_pdf): tmpdir = tmp_path_factory.mktemp("png_interlaced") compare_ghostscript(tmpdir, png_interlaced_img, png_interlaced_pdf) compare_poppler(tmpdir, png_interlaced_img, png_interlaced_pdf) compare_mupdf(tmpdir, png_interlaced_img, png_interlaced_pdf) compare_pdfimages_png(tmpdir, png_interlaced_img, png_interlaced_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_png_gray1(tmp_path_factory, png_gray1_img, png_gray1_pdf): tmpdir = tmp_path_factory.mktemp("png_gray1") compare_ghostscript(tmpdir, png_gray1_img, png_gray1_pdf, gsdevice="pnggray") compare_poppler(tmpdir, png_gray1_img, png_gray1_pdf) compare_mupdf(tmpdir, png_gray1_img, png_gray1_pdf) compare_pdfimages_png(tmpdir, png_gray1_img, png_gray1_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_png_gray2(tmp_path_factory, png_gray2_img, png_gray2_pdf): tmpdir = tmp_path_factory.mktemp("png_gray2") compare_ghostscript(tmpdir, png_gray2_img, png_gray2_pdf, gsdevice="pnggray") compare_poppler(tmpdir, png_gray2_img, png_gray2_pdf) compare_mupdf(tmpdir, png_gray2_img, png_gray2_pdf) compare_pdfimages_png(tmpdir, png_gray2_img, png_gray2_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_png_gray4(tmp_path_factory, png_gray4_img, png_gray4_pdf): tmpdir = tmp_path_factory.mktemp("png_gray4") compare_ghostscript(tmpdir, png_gray4_img, png_gray4_pdf, gsdevice="pnggray") compare_poppler(tmpdir, png_gray4_img, png_gray4_pdf) compare_mupdf(tmpdir, png_gray4_img, png_gray4_pdf) compare_pdfimages_png(tmpdir, png_gray4_img, png_gray4_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_png_gray8(tmp_path_factory, png_gray8_img, png_gray8_pdf): tmpdir = tmp_path_factory.mktemp("png_gray8") compare_ghostscript(tmpdir, png_gray8_img, png_gray8_pdf, gsdevice="pnggray") compare_poppler(tmpdir, png_gray8_img, png_gray8_pdf) compare_mupdf(tmpdir, png_gray8_img, png_gray8_pdf) compare_pdfimages_png(tmpdir, png_gray8_img, png_gray8_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_png_gray16(tmp_path_factory, png_gray16_img, png_gray16_pdf): tmpdir = tmp_path_factory.mktemp("png_gray16") # ghostscript outputs 8-bit grayscale, so the comparison will not be exact compare_ghostscript( tmpdir, png_gray16_img, png_gray16_pdf, gsdevice="pnggray", exact=False ) # poppler outputs 8-bit grayscale so the comparison will not be exact compare_poppler(tmpdir, png_gray16_img, png_gray16_pdf, exact=False) # pdfimages outputs 8-bit grayscale so the comparison will not be exact compare_pdfimages_png(tmpdir, png_gray16_img, png_gray16_pdf, exact=False) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_png_palette1(tmp_path_factory, png_palette1_img, png_palette1_pdf): tmpdir = tmp_path_factory.mktemp("png_palette1") compare_ghostscript(tmpdir, png_palette1_img, png_palette1_pdf) compare_poppler(tmpdir, png_palette1_img, png_palette1_pdf) compare_mupdf(tmpdir, png_palette1_img, png_palette1_pdf) # pdfimages cannot export palette based images @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_png_palette2(tmp_path_factory, png_palette2_img, png_palette2_pdf): tmpdir = tmp_path_factory.mktemp("png_palette2") compare_ghostscript(tmpdir, png_palette2_img, png_palette2_pdf) compare_poppler(tmpdir, png_palette2_img, png_palette2_pdf) compare_mupdf(tmpdir, png_palette2_img, png_palette2_pdf) # pdfimages cannot export palette based images @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_png_palette4(tmp_path_factory, png_palette4_img, png_palette4_pdf): tmpdir = tmp_path_factory.mktemp("png_palette4") compare_ghostscript(tmpdir, png_palette4_img, png_palette4_pdf) compare_poppler(tmpdir, png_palette4_img, png_palette4_pdf) compare_mupdf(tmpdir, png_palette4_img, png_palette4_pdf) # pdfimages cannot export palette based images @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_png_palette8(tmp_path_factory, png_palette8_img, png_palette8_pdf): tmpdir = tmp_path_factory.mktemp("png_palette8") compare_ghostscript(tmpdir, png_palette8_img, png_palette8_pdf) compare_poppler(tmpdir, png_palette8_img, png_palette8_pdf) compare_mupdf(tmpdir, png_palette8_img, png_palette8_pdf) # pdfimages cannot export palette based images @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_png_icc(tmp_path_factory, png_icc_img, png_icc_pdf): tmpdir = tmp_path_factory.mktemp("png_icc") compare_ghostscript(tmpdir, png_icc_img, png_icc_pdf, exact=False, icc=True) compare_poppler(tmpdir, png_icc_img, png_icc_pdf, exact=False, icc=True) # mupdf ignores the ICC profile in Debian (needs patched thirdparty liblcms2-art) compare_pdfimages_png(tmpdir, png_icc_img, png_icc_pdf, exact=False, icc=True) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) @pytest.mark.parametrize("engine", ["internal", "pikepdf", "pdfrw"]) def test_gif_transparent(tmp_path_factory, gif_transparent_img, engine): out_pdf = tmp_path_factory.mktemp("gif_transparent") / "out.pdf" assert ( 0 != subprocess.run( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + engine, "--output=" + str(out_pdf), str(gif_transparent_img), ] ).returncode ) out_pdf.unlink() @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_gif_palette1(tmp_path_factory, gif_palette1_img, gif_palette1_pdf): tmpdir = tmp_path_factory.mktemp("gif_palette1") compare_ghostscript(tmpdir, gif_palette1_img, gif_palette1_pdf) compare_poppler(tmpdir, gif_palette1_img, gif_palette1_pdf) compare_mupdf(tmpdir, gif_palette1_img, gif_palette1_pdf) # pdfimages cannot export palette based images @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_gif_palette2(tmp_path_factory, gif_palette2_img, gif_palette2_pdf): tmpdir = tmp_path_factory.mktemp("gif_palette2") compare_ghostscript(tmpdir, gif_palette2_img, gif_palette2_pdf) compare_poppler(tmpdir, gif_palette2_img, gif_palette2_pdf) compare_mupdf(tmpdir, gif_palette2_img, gif_palette2_pdf) # pdfimages cannot export palette based images @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_gif_palette4(tmp_path_factory, gif_palette4_img, gif_palette4_pdf): tmpdir = tmp_path_factory.mktemp("gif_palette4") compare_ghostscript(tmpdir, gif_palette4_img, gif_palette4_pdf) compare_poppler(tmpdir, gif_palette4_img, gif_palette4_pdf) compare_mupdf(tmpdir, gif_palette4_img, gif_palette4_pdf) # pdfimages cannot export palette based images @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_gif_palette8(tmp_path_factory, gif_palette8_img, gif_palette8_pdf): tmpdir = tmp_path_factory.mktemp("gif_palette8") compare_ghostscript(tmpdir, gif_palette8_img, gif_palette8_pdf) compare_poppler(tmpdir, gif_palette8_img, gif_palette8_pdf) compare_mupdf(tmpdir, gif_palette8_img, gif_palette8_pdf) # pdfimages cannot export palette based images @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_gif_animation(tmp_path_factory, gif_animation_img, gif_animation_pdf): tmpdir = tmp_path_factory.mktemp("gif_animation") subprocess.check_call( ["pdfseparate", str(gif_animation_pdf), str(tmpdir / "page-%d.pdf")] ) for page in [1, 2]: gif_animation_pdf_nr = tmpdir / ("page-%d.pdf" % page) compare_ghostscript( tmpdir, str(gif_animation_img) + "[%d]" % (page - 1), gif_animation_pdf_nr ) compare_poppler( tmpdir, str(gif_animation_img) + "[%d]" % (page - 1), gif_animation_pdf_nr ) compare_mupdf( tmpdir, str(gif_animation_img) + "[%d]" % (page - 1), gif_animation_pdf_nr ) # pdfimages cannot export palette based images gif_animation_pdf_nr.unlink() @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) @pytest.mark.parametrize("engine", ["internal", "pikepdf", "pdfrw"]) def test_tiff_float(tmp_path_factory, tiff_float_img, engine): out_pdf = tmp_path_factory.mktemp("tiff_float") / "out.pdf" assert ( 0 != subprocess.run( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + engine, "--output=" + str(out_pdf), str(tiff_float_img), ] ).returncode ) out_pdf.unlink() @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) 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 ) # not testing with poppler as it cannot write CMYK images compare_mupdf(tmpdir, tiff_cmyk8_img, tiff_cmyk8_pdf, exact=False, cmyk=True) compare_pdfimages_tiff(tmpdir, tiff_cmyk8_img, tiff_cmyk8_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) @pytest.mark.parametrize("engine", ["internal", "pikepdf", "pdfrw"]) def test_tiff_cmyk16(tmp_path_factory, tiff_cmyk16_img, engine): out_pdf = tmp_path_factory.mktemp("tiff_cmyk16") / "out.pdf" # PIL is unable to read 16 bit CMYK images assert ( 0 != subprocess.run( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + engine, "--output=" + str(out_pdf), str(tiff_cmyk16_img), ] ).returncode ) out_pdf.unlink() @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_rgb8(tmp_path_factory, tiff_rgb8_img, tiff_rgb8_pdf): tmpdir = tmp_path_factory.mktemp("tiff_rgb8") compare_ghostscript(tmpdir, tiff_rgb8_img, tiff_rgb8_pdf, gsdevice="tiff24nc") compare_poppler(tmpdir, tiff_rgb8_img, tiff_rgb8_pdf) compare_mupdf(tmpdir, tiff_rgb8_img, tiff_rgb8_pdf) compare_pdfimages_tiff(tmpdir, tiff_rgb8_img, tiff_rgb8_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) @pytest.mark.parametrize("engine", ["internal", "pikepdf", "pdfrw"]) def test_tiff_rgb12(tmp_path_factory, tiff_rgb12_img, engine): out_pdf = tmp_path_factory.mktemp("tiff_rgb12") / "out.pdf" # PIL is unable to preserve more than 8 bits per sample assert ( 0 != subprocess.run( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + engine, "--output=" + str(out_pdf), str(tiff_rgb12_img), ] ).returncode ) out_pdf.unlink() @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) @pytest.mark.parametrize("engine", ["internal", "pikepdf", "pdfrw"]) def test_tiff_rgb14(tmp_path_factory, tiff_rgb14_img, engine): out_pdf = tmp_path_factory.mktemp("tiff_rgb14") / "out.pdf" # PIL is unable to preserve more than 8 bits per sample assert ( 0 != subprocess.run( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + engine, "--output=" + str(out_pdf), str(tiff_rgb14_img), ] ).returncode ) out_pdf.unlink() @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) @pytest.mark.parametrize("engine", ["internal", "pikepdf", "pdfrw"]) def test_tiff_rgb16(tmp_path_factory, tiff_rgb16_img, engine): out_pdf = tmp_path_factory.mktemp("tiff_rgb16") / "out.pdf" # PIL is unable to preserve more than 8 bits per sample assert ( 0 != subprocess.run( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + engine, "--output=" + str(out_pdf), str(tiff_rgb16_img), ] ).returncode ) out_pdf.unlink() @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) @pytest.mark.parametrize("engine", ["internal", "pikepdf", "pdfrw"]) def test_tiff_rgba8(tmp_path_factory, tiff_rgba8_img, engine): out_pdf = tmp_path_factory.mktemp("tiff_rgba8") / "out.pdf" assert ( 0 != subprocess.run( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + engine, "--output=" + str(out_pdf), str(tiff_rgba8_img), ] ).returncode ) out_pdf.unlink() @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) @pytest.mark.parametrize("engine", ["internal", "pikepdf", "pdfrw"]) def test_tiff_rgba16(tmp_path_factory, tiff_rgba16_img, engine): out_pdf = tmp_path_factory.mktemp("tiff_rgba16") / "out.pdf" assert ( 0 != subprocess.run( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + engine, "--output=" + str(out_pdf), str(tiff_rgba16_img), ] ).returncode ) out_pdf.unlink() @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_gray1(tmp_path_factory, tiff_gray1_img, tiff_gray1_pdf): tmpdir = tmp_path_factory.mktemp("tiff_gray1") compare_ghostscript(tmpdir, tiff_gray1_img, tiff_gray1_pdf, gsdevice="pnggray") compare_poppler(tmpdir, tiff_gray1_img, tiff_gray1_pdf) compare_mupdf(tmpdir, tiff_gray1_img, tiff_gray1_pdf) compare_pdfimages_tiff(tmpdir, tiff_gray1_img, tiff_gray1_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_gray2(tmp_path_factory, tiff_gray2_img, tiff_gray2_pdf): tmpdir = tmp_path_factory.mktemp("tiff_gray2") compare_ghostscript(tmpdir, tiff_gray2_img, tiff_gray2_pdf, gsdevice="pnggray") compare_poppler(tmpdir, tiff_gray2_img, tiff_gray2_pdf) compare_mupdf(tmpdir, tiff_gray2_img, tiff_gray2_pdf) compare_pdfimages_tiff(tmpdir, tiff_gray2_img, tiff_gray2_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_gray4(tmp_path_factory, tiff_gray4_img, tiff_gray4_pdf): tmpdir = tmp_path_factory.mktemp("tiff_gray4") compare_ghostscript(tmpdir, tiff_gray4_img, tiff_gray4_pdf, gsdevice="pnggray") compare_poppler(tmpdir, tiff_gray4_img, tiff_gray4_pdf) compare_mupdf(tmpdir, tiff_gray4_img, tiff_gray4_pdf) compare_pdfimages_tiff(tmpdir, tiff_gray4_img, tiff_gray4_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_gray8(tmp_path_factory, tiff_gray8_img, tiff_gray8_pdf): tmpdir = tmp_path_factory.mktemp("tiff_gray8") compare_ghostscript(tmpdir, tiff_gray8_img, tiff_gray8_pdf, gsdevice="pnggray") compare_poppler(tmpdir, tiff_gray8_img, tiff_gray8_pdf) compare_mupdf(tmpdir, tiff_gray8_img, tiff_gray8_pdf) compare_pdfimages_tiff(tmpdir, tiff_gray8_img, tiff_gray8_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) @pytest.mark.parametrize("engine", ["internal", "pikepdf", "pdfrw"]) def test_tiff_gray16(tmp_path_factory, tiff_gray16_img, engine): out_pdf = tmp_path_factory.mktemp("tiff_gray16") / "out.pdf" assert ( 0 != subprocess.run( [ "src/img2pdf.py", "--producer=", "--nodate", "--engine=" + engine, "--output=" + str(out_pdf), str(tiff_gray16_img), ] ).returncode ) out_pdf.unlink() @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_multipage(tmp_path_factory, tiff_multipage_img, tiff_multipage_pdf): tmpdir = tmp_path_factory.mktemp("tiff_multipage") subprocess.check_call( ["pdfseparate", str(tiff_multipage_pdf), str(tmpdir / "page-%d.pdf")] ) for page in [1, 2]: tiff_multipage_pdf_nr = tmpdir / ("page-%d.pdf" % page) compare_ghostscript( tmpdir, str(tiff_multipage_img) + "[%d]" % (page - 1), tiff_multipage_pdf_nr ) compare_poppler( tmpdir, str(tiff_multipage_img) + "[%d]" % (page - 1), tiff_multipage_pdf_nr ) compare_mupdf( tmpdir, str(tiff_multipage_img) + "[%d]" % (page - 1), tiff_multipage_pdf_nr ) compare_pdfimages_tiff( tmpdir, str(tiff_multipage_img) + "[%d]" % (page - 1), tiff_multipage_pdf_nr ) tiff_multipage_pdf_nr.unlink() @pytest.mark.skipif( not HAVE_IMAGEMAGICK_MODERN, reason="requires imagemagick with support for keeping the palette depth", ) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_palette1(tmp_path_factory, tiff_palette1_img, tiff_palette1_pdf): tmpdir = tmp_path_factory.mktemp("tiff_palette1") compare_ghostscript(tmpdir, tiff_palette1_img, tiff_palette1_pdf) compare_poppler(tmpdir, tiff_palette1_img, tiff_palette1_pdf) compare_mupdf(tmpdir, tiff_palette1_img, tiff_palette1_pdf) # pdfimages cannot export palette based images @pytest.mark.skipif( not HAVE_IMAGEMAGICK_MODERN, reason="requires imagemagick with support for keeping the palette depth", ) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_palette2(tmp_path_factory, tiff_palette2_img, tiff_palette2_pdf): tmpdir = tmp_path_factory.mktemp("tiff_palette2") compare_ghostscript(tmpdir, tiff_palette2_img, tiff_palette2_pdf) compare_poppler(tmpdir, tiff_palette2_img, tiff_palette2_pdf) compare_mupdf(tmpdir, tiff_palette2_img, tiff_palette2_pdf) # pdfimages cannot export palette based images @pytest.mark.skipif( not HAVE_IMAGEMAGICK_MODERN, reason="requires imagemagick with support for keeping the palette depth", ) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_palette4(tmp_path_factory, tiff_palette4_img, tiff_palette4_pdf): tmpdir = tmp_path_factory.mktemp("tiff_palette4") compare_ghostscript(tmpdir, tiff_palette4_img, tiff_palette4_pdf) compare_poppler(tmpdir, tiff_palette4_img, tiff_palette4_pdf) compare_mupdf(tmpdir, tiff_palette4_img, tiff_palette4_pdf) # pdfimages cannot export palette based images @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_palette8(tmp_path_factory, tiff_palette8_img, tiff_palette8_pdf): tmpdir = tmp_path_factory.mktemp("tiff_palette8") compare_ghostscript(tmpdir, tiff_palette8_img, tiff_palette8_pdf) compare_poppler(tmpdir, tiff_palette8_img, tiff_palette8_pdf) compare_mupdf(tmpdir, tiff_palette8_img, tiff_palette8_pdf) # pdfimages cannot export palette based images @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_ccitt_lsb_m2l_white( tmp_path_factory, tiff_ccitt_lsb_m2l_white_img, tiff_ccitt_lsb_m2l_white_pdf ): tmpdir = tmp_path_factory.mktemp("tiff_ccitt_lsb_m2l_white") compare_ghostscript( tmpdir, tiff_ccitt_lsb_m2l_white_img, tiff_ccitt_lsb_m2l_white_pdf, gsdevice="pnggray", ) compare_poppler(tmpdir, tiff_ccitt_lsb_m2l_white_img, tiff_ccitt_lsb_m2l_white_pdf) compare_mupdf(tmpdir, tiff_ccitt_lsb_m2l_white_img, tiff_ccitt_lsb_m2l_white_pdf) compare_pdfimages_tiff( tmpdir, tiff_ccitt_lsb_m2l_white_img, tiff_ccitt_lsb_m2l_white_pdf ) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_ccitt_msb_m2l_white( tmp_path_factory, tiff_ccitt_msb_m2l_white_img, tiff_ccitt_msb_m2l_white_pdf ): tmpdir = tmp_path_factory.mktemp("tiff_ccitt_msb_m2l_white") compare_ghostscript( tmpdir, tiff_ccitt_msb_m2l_white_img, tiff_ccitt_msb_m2l_white_pdf, gsdevice="pnggray", ) compare_poppler(tmpdir, tiff_ccitt_msb_m2l_white_img, tiff_ccitt_msb_m2l_white_pdf) compare_mupdf(tmpdir, tiff_ccitt_msb_m2l_white_img, tiff_ccitt_msb_m2l_white_pdf) compare_pdfimages_tiff( tmpdir, tiff_ccitt_msb_m2l_white_img, tiff_ccitt_msb_m2l_white_pdf ) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_ccitt_msb_l2m_white( tmp_path_factory, tiff_ccitt_msb_l2m_white_img, tiff_ccitt_msb_l2m_white_pdf ): tmpdir = tmp_path_factory.mktemp("tiff_ccitt_msb_l2m_white") compare_ghostscript( tmpdir, tiff_ccitt_msb_l2m_white_img, tiff_ccitt_msb_l2m_white_pdf, gsdevice="pnggray", ) compare_poppler(tmpdir, tiff_ccitt_msb_l2m_white_img, tiff_ccitt_msb_l2m_white_pdf) compare_mupdf(tmpdir, tiff_ccitt_msb_l2m_white_img, tiff_ccitt_msb_l2m_white_pdf) compare_pdfimages_tiff( tmpdir, tiff_ccitt_msb_l2m_white_img, tiff_ccitt_msb_l2m_white_pdf ) @pytest.mark.skipif( not HAVE_IMAGEMAGICK_MODERN, reason="requires imagemagick with support for min-is-black", ) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_ccitt_lsb_m2l_black( tmp_path_factory, tiff_ccitt_lsb_m2l_black_img, tiff_ccitt_lsb_m2l_black_pdf ): tmpdir = tmp_path_factory.mktemp("tiff_ccitt_lsb_m2l_black") compare_ghostscript( tmpdir, tiff_ccitt_lsb_m2l_black_img, tiff_ccitt_lsb_m2l_black_pdf, gsdevice="pnggray", ) compare_poppler(tmpdir, tiff_ccitt_lsb_m2l_black_img, tiff_ccitt_lsb_m2l_black_pdf) compare_mupdf(tmpdir, tiff_ccitt_lsb_m2l_black_img, tiff_ccitt_lsb_m2l_black_pdf) compare_pdfimages_tiff( tmpdir, tiff_ccitt_lsb_m2l_black_img, tiff_ccitt_lsb_m2l_black_pdf ) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_ccitt_nometa1( tmp_path_factory, tiff_ccitt_nometa1_img, tiff_ccitt_nometa1_pdf ): tmpdir = tmp_path_factory.mktemp("tiff_ccitt_nometa1") compare_ghostscript( tmpdir, tiff_ccitt_nometa1_img, tiff_ccitt_nometa1_pdf, gsdevice="pnggray" ) compare_poppler(tmpdir, tiff_ccitt_nometa1_img, tiff_ccitt_nometa1_pdf) compare_mupdf(tmpdir, tiff_ccitt_nometa1_img, tiff_ccitt_nometa1_pdf) compare_pdfimages_tiff(tmpdir, tiff_ccitt_nometa1_img, tiff_ccitt_nometa1_pdf) @pytest.mark.skipif( sys.platform in ["darwin", "win32"], reason="test utilities not available on Windows and MacOS", ) def test_tiff_ccitt_nometa2( tmp_path_factory, tiff_ccitt_nometa2_img, tiff_ccitt_nometa2_pdf ): tmpdir = tmp_path_factory.mktemp("tiff_ccitt_nometa2") compare_ghostscript( tmpdir, tiff_ccitt_nometa2_img, tiff_ccitt_nometa2_pdf, gsdevice="pnggray" ) compare_poppler(tmpdir, tiff_ccitt_nometa2_img, tiff_ccitt_nometa2_pdf) compare_mupdf(tmpdir, tiff_ccitt_nometa2_img, tiff_ccitt_nometa2_pdf) compare_pdfimages_tiff(tmpdir, tiff_ccitt_nometa2_img, tiff_ccitt_nometa2_pdf) # we define some variables so that the table below can be narrower psl = (972, 504) # --pagesize landscape psp = (504, 972) # --pagesize portrait isl = (756, 324) # --imgsize landscape isp = (324, 756) # --imgsize portrait border = (162, 270) # --border poster = (97200, 50400) # shortcuts for fit modes f_into = img2pdf.FitMode.into f_fill = img2pdf.FitMode.fill f_exact = img2pdf.FitMode.exact f_shrink = img2pdf.FitMode.shrink f_enlarge = img2pdf.FitMode.enlarge @pytest.mark.parametrize( "layout_test_cases", [ # fmt: off # psp=972x504, psl=504x972, isl=756x324, isp=324x756, border=162:270 # --pagesize --border -a pagepdf imgpdf # --imgsize --fit (None, None, None, f_into, 0, (648, 216), (648, 216), # 000 (864, 432), (864, 432)), (None, None, None, f_into, 1, (648, 216), (648, 216), # 001 (864, 432), (864, 432)), (None, None, None, f_fill, 0, (648, 216), (648, 216), # 002 (864, 432), (864, 432)), (None, None, None, f_fill, 1, (648, 216), (648, 216), # 003 (864, 432), (864, 432)), (None, None, None, f_exact, 0, (648, 216), (648, 216), # 004 (864, 432), (864, 432)), (None, None, None, f_exact, 1, (648, 216), (648, 216), # 005 (864, 432), (864, 432)), (None, None, None, f_shrink, 0, (648, 216), (648, 216), # 006 (864, 432), (864, 432)), (None, None, None, f_shrink, 1, (648, 216), (648, 216), # 007 (864, 432), (864, 432)), (None, None, None, f_enlarge, 0, (648, 216), (648, 216), # 008 (864, 432), (864, 432)), (None, None, None, f_enlarge, 1, (648, 216), (648, 216), # 009 (864, 432), (864, 432)), (None, None, border, f_into, 0, (1188, 540), (648, 216), # 010 (1404, 756), (864, 432)), (None, None, border, f_into, 1, (1188, 540), (648, 216), # 011 (1404, 756), (864, 432)), (None, None, border, f_fill, 0, (1188, 540), (648, 216), # 012 (1404, 756), (864, 432)), (None, None, border, f_fill, 1, (1188, 540), (648, 216), # 013 (1404, 756), (864, 432)), (None, None, border, f_exact, 0, (1188, 540), (648, 216), # 014 (1404, 756), (864, 432)), (None, None, border, f_exact, 1, (1188, 540), (648, 216), # 015 (1404, 756), (864, 432)), (None, None, border, f_shrink, 0, (1188, 540), (648, 216), # 016 (1404, 756), (864, 432)), (None, None, border, f_shrink, 1, (1188, 540), (648, 216), # 017 (1404, 756), (864, 432)), (None, None, border, f_enlarge, 0, (1188, 540), (648, 216), # 018 (1404, 756), (864, 432)), (None, None, border, f_enlarge, 1, (1188, 540), (648, 216), # 019 (1404, 756), (864, 432)), (None, isp, None, f_into, 0, (324, 108), (324, 108), # 020 (324, 162), (324, 162)), (None, isp, None, f_into, 1, (324, 108), (324, 108), # 021 (324, 162), (324, 162)), (None, isp, None, f_fill, 0, (2268, 756), (2268, 756), # 022 (1512, 756), (1512, 756)), (None, isp, None, f_fill, 1, (2268, 756), (2268, 756), # 023 (1512, 756), (1512, 756)), (None, isp, None, f_exact, 0, (324, 756), (324, 756), # 024 (324, 756), (324, 756)), (None, isp, None, f_exact, 1, (324, 756), (324, 756), # 025 (324, 756), (324, 756)), (None, isp, None, f_shrink, 0, (324, 108), (324, 108), # 026 (324, 162), (324, 162)), (None, isp, None, f_shrink, 1, (324, 108), (324, 108), # 027 (324, 162), (324, 162)), (None, isp, None, f_enlarge, 0, (648, 216), (648, 216), # 028 (864, 432), (864, 432)), (None, isp, None, f_enlarge, 1, (648, 216), (648, 216), # 029 (864, 432), (864, 432)), (None, isp, border, f_into, 0, (864, 432), (324, 108), # 030 (864, 486), (324, 162)), (None, isp, border, f_into, 1, (864, 432), (324, 108), # 031 (864, 486), (324, 162)), (None, isp, border, f_fill, 0, (2808, 1080), (2268, 756), # 032 (2052, 1080), (1512, 756)), (None, isp, border, f_fill, 1, (2808, 1080), (2268, 756), # 033 (2052, 1080), (1512, 756)), (None, isp, border, f_exact, 0, (864, 1080), (324, 756), # 034 (864, 1080), (324, 756)), (None, isp, border, f_exact, 1, (864, 1080), (324, 756), # 035 (864, 1080), (324, 756)), (None, isp, border, f_shrink, 0, (864, 432), (324, 108), # 036 (864, 486), (324, 162)), (None, isp, border, f_shrink, 1, (864, 432), (324, 108), # 037 (864, 486), (324, 162)), (None, isp, border, f_enlarge, 0, (1188, 540), (648, 216), # 038 (1404, 756), (864, 432)), (None, isp, border, f_enlarge, 1, (1188, 540), (648, 216), # 039 (1404, 756), (864, 432)), (None, isl, None, f_into, 0, (756, 252), (756, 252), # 040 (648, 324), (648, 324)), (None, isl, None, f_into, 1, (756, 252), (756, 252), # 041 (648, 324), (648, 324)), (None, isl, None, f_fill, 0, (972, 324), (972, 324), # 042 (756, 378), (756, 378)), (None, isl, None, f_fill, 1, (972, 324), (972, 324), # 043 (756, 378), (756, 378)), (None, isl, None, f_exact, 0, (756, 324), (756, 324), # 044 (756, 324), (756, 324)), (None, isl, None, f_exact, 1, (756, 324), (756, 324), # 045 (756, 324), (756, 324)), (None, isl, None, f_shrink, 0, (648, 216), (648, 216), # 046 (648, 324), (648, 324)), (None, isl, None, f_shrink, 1, (648, 216), (648, 216), # 047 (648, 324), (648, 324)), (None, isl, None, f_enlarge, 0, (756, 252), (756, 252), # 048 (864, 432), (864, 432)), (None, isl, None, f_enlarge, 1, (756, 252), (756, 252), # 049 (864, 432), (864, 432)), # psp=972x504, psp=504x972, isl=756x324, isp=324x756, border=162:270 # --pagesize --border -a pagepdf imgpdf # --imgsize --fit imgpx (None, isl, border, f_into, 0, (1296, 576), (756, 252), # 050 (1188, 648), (648, 324)), (None, isl, border, f_into, 1, (1296, 576), (756, 252), # 051 (1188, 648), (648, 324)), (None, isl, border, f_fill, 0, (1512, 648), (972, 324), # 052 (1296, 702), (756, 378)), (None, isl, border, f_fill, 1, (1512, 648), (972, 324), # 053 (1296, 702), (756, 378)), (None, isl, border, f_exact, 0, (1296, 648), (756, 324), # 054 (1296, 648), (756, 324)), (None, isl, border, f_exact, 1, (1296, 648), (756, 324), # 055 (1296, 648), (756, 324)), (None, isl, border, f_shrink, 0, (1188, 540), (648, 216), # 056 (1188, 648), (648, 324)), (None, isl, border, f_shrink, 1, (1188, 540), (648, 216), # 057 (1188, 648), (648, 324)), (None, isl, border, f_enlarge, 0, (1296, 576), (756, 252), # 058 (1404, 756), (864, 432)), (None, isl, border, f_enlarge, 1, (1296, 576), (756, 252), # 059 (1404, 756), (864, 432)), (psp, None, None, f_into, 0, (504, 972), (504, 168), # 060 (504, 972), (504, 252)), (psp, None, None, f_into, 1, (972, 504), (972, 324), # 061 (972, 504), (972, 486)), (psp, None, None, f_fill, 0, (504, 972), (2916, 972), # 062 (504, 972), (1944, 972)), (psp, None, None, f_fill, 1, (972, 504), (1512, 504), # 063 (972, 504), (1008, 504)), (psp, None, None, f_exact, 0, (504, 972), (504, 972), # 064 (504, 972), (504, 972)), (psp, None, None, f_exact, 1, (972, 504), (972, 504), # 065 (972, 504), (972, 504)), (psp, None, None, f_shrink, 0, (504, 972), (504, 168), # 066 (504, 972), (504, 252)), (psp, None, None, f_shrink, 1, (972, 504), (648, 216), # 067 (972, 504), (864, 432)), (psp, None, None, f_enlarge, 0, (504, 972), (648, 216), # 068 (504, 972), (864, 432)), (psp, None, None, f_enlarge, 1, (972, 504), (972, 324), # 069 (972, 504), (972, 486)), (psp, None, border, f_into, 0, None, None, None, None), # 070 (psp, None, border, f_into, 1, None, None, None, None), # 071 (psp, None, border, f_fill, 0, (504, 972), (1944, 648), # 072 (504, 972), (1296, 648)), (psp, None, border, f_fill, 1, (972, 504), (648, 216), # 073 (972, 504), (648, 324)), (psp, None, border, f_exact, 0, None, None, None, None), # 074 (psp, None, border, f_exact, 1, None, None, None, None), # 075 (psp, None, border, f_shrink, 0, None, None, None, None), # 076 (psp, None, border, f_shrink, 1, None, None, None, None), # 077 (psp, None, border, f_enlarge, 0, (504, 972), (648, 216), # 078 (504, 972), (864, 432)), (psp, None, border, f_enlarge, 1, (972, 504), (648, 216), # 079 (972, 504), (864, 432)), (psp, isp, None, f_into, 0, (504, 972), (324, 108), # 080 (504, 972), (324, 162)), (psp, isp, None, f_into, 1, (972, 504), (324, 108), # 081 (972, 504), (324, 162)), (psp, isp, None, f_fill, 0, (504, 972), (2268, 756), # 082 (504, 972), (1512, 756)), (psp, isp, None, f_fill, 1, (972, 504), (2268, 756), # 083 (972, 504), (1512, 756)), (psp, isp, None, f_exact, 0, (504, 972), (324, 756), # 084 (504, 972), (324, 756)), (psp, isp, None, f_exact, 1, (972, 504), (324, 756), # 085 (972, 504), (324, 756)), (psp, isp, None, f_shrink, 0, (504, 972), (324, 108), # 086 (504, 972), (324, 162)), (psp, isp, None, f_shrink, 1, (972, 504), (324, 108), # 087 (972, 504), (324, 162)), (psp, isp, None, f_enlarge, 0, (504, 972), (648, 216), # 088 (504, 972), (864, 432)), (psp, isp, None, f_enlarge, 1, (972, 504), (648, 216), # 089 (972, 504), (864, 432)), (psp, isp, border, f_into, 0, (504, 972), (324, 108), # 090 (504, 972), (324, 162)), (psp, isp, border, f_into, 1, (972, 504), (324, 108), # 091 (972, 504), (324, 162)), (psp, isp, border, f_fill, 0, (504, 972), (2268, 756), # 092 (504, 972), (1512, 756)), (psp, isp, border, f_fill, 1, (972, 504), (2268, 756), # 093 (972, 504), (1512, 756)), (psp, isp, border, f_exact, 0, (504, 972), (324, 756), # 094 (504, 972), (324, 756)), (psp, isp, border, f_exact, 1, (972, 504), (324, 756), # 095 (972, 504), (324, 756)), (psp, isp, border, f_shrink, 0, (504, 972), (324, 108), # 096 (504, 972), (324, 162)), (psp, isp, border, f_shrink, 1, (972, 504), (324, 108), # 097 (972, 504), (324, 162)), (psp, isp, border, f_enlarge, 0, (504, 972), (648, 216), # 098 (504, 972), (864, 432)), (psp, isp, border, f_enlarge, 1, (972, 504), (648, 216), # 099 (972, 504), (864, 432)), # psp=972x504, psp=504x972, isl=756x324, isp=324x756, border=162:270 # --pagesize --border -a pagepdf imgpdf # --imgsize --fit imgpx (psp, isl, None, f_into, 0, (504, 972), (756, 252), # 100 (504, 972), (648, 324)), (psp, isl, None, f_into, 1, (972, 504), (756, 252), # 101 (972, 504), (648, 324)), (psp, isl, None, f_fill, 0, (504, 972), (972, 324), # 102 (504, 972), (756, 378)), (psp, isl, None, f_fill, 1, (972, 504), (972, 324), # 103 (972, 504), (756, 378)), (psp, isl, None, f_exact, 0, (504, 972), (756, 324), # 104 (504, 972), (756, 324)), (psp, isl, None, f_exact, 1, (972, 504), (756, 324), # 105 (972, 504), (756, 324)), (psp, isl, None, f_shrink, 0, (504, 972), (648, 216), # 106 (504, 972), (648, 324)), (psp, isl, None, f_shrink, 1, (972, 504), (648, 216), # 107 (972, 504), (648, 324)), (psp, isl, None, f_enlarge, 0, (504, 972), (756, 252), # 108 (504, 972), (864, 432)), (psp, isl, None, f_enlarge, 1, (972, 504), (756, 252), # 109 (972, 504), (864, 432)), (psp, isl, border, f_into, 0, (504, 972), (756, 252), # 110 (504, 972), (648, 324)), (psp, isl, border, f_into, 1, (972, 504), (756, 252), # 111 (972, 504), (648, 324)), (psp, isl, border, f_fill, 0, (504, 972), (972, 324), # 112 (504, 972), (756, 378)), (psp, isl, border, f_fill, 1, (972, 504), (972, 324), # 113 (972, 504), (756, 378)), (psp, isl, border, f_exact, 0, (504, 972), (756, 324), # 114 (504, 972), (756, 324)), (psp, isl, border, f_exact, 1, (972, 504), (756, 324), # 115 (972, 504), (756, 324)), (psp, isl, border, f_shrink, 0, (504, 972), (648, 216), # 116 (504, 972), (648, 324)), (psp, isl, border, f_shrink, 1, (972, 504), (648, 216), # 117 (972, 504), (648, 324)), (psp, isl, border, f_enlarge, 0, (504, 972), (756, 252), # 118 (504, 972), (864, 432)), (psp, isl, border, f_enlarge, 1, (972, 504), (756, 252), # 119 (972, 504), (864, 432)), (psl, None, None, f_into, 0, (972, 504), (972, 324), # 120 (972, 504), (972, 486)), (psl, None, None, f_into, 1, (972, 504), (972, 324), # 121 (972, 504), (972, 486)), (psl, None, None, f_fill, 0, (972, 504), (1512, 504), # 122 (972, 504), (1008, 504)), (psl, None, None, f_fill, 1, (972, 504), (1512, 504), # 123 (972, 504), (1008, 504)), (psl, None, None, f_exact, 0, (972, 504), (972, 504), # 124 (972, 504), (972, 504)), (psl, None, None, f_exact, 1, (972, 504), (972, 504), # 125 (972, 504), (972, 504)), (psl, None, None, f_shrink, 0, (972, 504), (648, 216), # 126 (972, 504), (864, 432)), (psl, None, None, f_shrink, 1, (972, 504), (648, 216), # 127 (972, 504), (864, 432)), (psl, None, None, f_enlarge, 0, (972, 504), (972, 324), # 128 (972, 504), (972, 486)), (psl, None, None, f_enlarge, 1, (972, 504), (972, 324), # 129 (972, 504), (972, 486)), (psl, None, border, f_into, 0, (972, 504), (432, 144), # 130 (972, 504), (360, 180)), (psl, None, border, f_into, 1, (972, 504), (432, 144), # 131 (972, 504), (360, 180)), (psl, None, border, f_fill, 0, (972, 504), (540, 180), # 132 (972, 504), (432, 216)), (psl, None, border, f_fill, 1, (972, 504), (540, 180), # 133 (972, 504), (432, 216)), (psl, None, border, f_exact, 0, (972, 504), (432, 180), # 134 (972, 504), (432, 180)), (psl, None, border, f_exact, 1, (972, 504), (432, 180), # 135 (972, 504), (432, 180)), (psl, None, border, f_shrink, 0, (972, 504), (432, 144), # 136 (972, 504), (360, 180)), (psl, None, border, f_shrink, 1, (972, 504), (432, 144), # 137 (972, 504), (360, 180)), (psl, None, border, f_enlarge, 0, (972, 504), (648, 216), # 138 (972, 504), (864, 432)), (psl, None, border, f_enlarge, 1, (972, 504), (648, 216), # 139 (972, 504), (864, 432)), (psl, isp, None, f_into, 0, (972, 504), (324, 108), # 140 (972, 504), (324, 162)), (psl, isp, None, f_into, 1, (972, 504), (324, 108), # 141 (972, 504), (324, 162)), (psl, isp, None, f_fill, 0, (972, 504), (2268, 756), # 142 (972, 504), (1512, 756)), (psl, isp, None, f_fill, 1, (972, 504), (2268, 756), # 143 (972, 504), (1512, 756)), (psl, isp, None, f_exact, 0, (972, 504), (324, 756), # 144 (972, 504), (324, 756)), (psl, isp, None, f_exact, 1, (972, 504), (324, 756), # 145 (972, 504), (324, 756)), (psl, isp, None, f_shrink, 0, (972, 504), (324, 108), # 146 (972, 504), (324, 162)), (psl, isp, None, f_shrink, 1, (972, 504), (324, 108), # 147 (972, 504), (324, 162)), (psl, isp, None, f_enlarge, 0, (972, 504), (648, 216), # 148 (972, 504), (864, 432)), (psl, isp, None, f_enlarge, 1, (972, 504), (648, 216), # 149 (972, 504), (864, 432)), # psp=972x504, psl=504x972, isl=756x324, isp=324x756, border=162:270 # --pagesize --border -a pagepdf imgpdf # --imgsize --fit imgpx (psl, isp, border, f_into, 0, (972, 504), (324, 108), # 150 (972, 504), (324, 162)), (psl, isp, border, f_into, 1, (972, 504), (324, 108), # 151 (972, 504), (324, 162)), (psl, isp, border, f_fill, 0, (972, 504), (2268, 756), # 152 (972, 504), (1512, 756)), (psl, isp, border, f_fill, 1, (972, 504), (2268, 756), # 153 (972, 504), (1512, 756)), (psl, isp, border, f_exact, 0, (972, 504), (324, 756), # 154 (972, 504), (324, 756)), (psl, isp, border, f_exact, 1, (972, 504), (324, 756), # 155 (972, 504), (324, 756)), (psl, isp, border, f_shrink, 0, (972, 504), (324, 108), # 156 (972, 504), (324, 162)), (psl, isp, border, f_shrink, 1, (972, 504), (324, 108), # 157 (972, 504), (324, 162)), (psl, isp, border, f_enlarge, 0, (972, 504), (648, 216), # 158 (972, 504), (864, 432)), (psl, isp, border, f_enlarge, 1, (972, 504), (648, 216), # 159 (972, 504), (864, 432)), (psl, isl, None, f_into, 0, (972, 504), (756, 252), # 160 (972, 504), (648, 324)), (psl, isl, None, f_into, 1, (972, 504), (756, 252), # 161 (972, 504), (648, 324)), (psl, isl, None, f_fill, 0, (972, 504), (972, 324), # 162 (972, 504), (756, 378)), (psl, isl, None, f_fill, 1, (972, 504), (972, 324), # 163 (972, 504), (756, 378)), (psl, isl, None, f_exact, 0, (972, 504), (756, 324), # 164 (972, 504), (756, 324)), (psl, isl, None, f_exact, 1, (972, 504), (756, 324), # 165 (972, 504), (756, 324)), (psl, isl, None, f_shrink, 0, (972, 504), (648, 216), # 166 (972, 504), (648, 324)), (psl, isl, None, f_shrink, 1, (972, 504), (648, 216), # 167 (972, 504), (648, 324)), (psl, isl, None, f_enlarge, 0, (972, 504), (756, 252), # 168 (972, 504), (864, 432)), (psl, isl, None, f_enlarge, 1, (972, 504), (756, 252), # 169 (972, 504), (864, 432)), (psl, isl, border, f_into, 0, (972, 504), (756, 252), # 170 (972, 504), (648, 324)), (psl, isl, border, f_into, 1, (972, 504), (756, 252), # 171 (972, 504), (648, 324)), (psl, isl, border, f_fill, 0, (972, 504), (972, 324), # 172 (972, 504), (756, 378)), (psl, isl, border, f_fill, 1, (972, 504), (972, 324), # 173 (972, 504), (756, 378)), (psl, isl, border, f_exact, 0, (972, 504), (756, 324), # 174 (972, 504), (756, 324)), (psl, isl, border, f_exact, 1, (972, 504), (756, 324), # 175 (972, 504), (756, 324)), (psl, isl, border, f_shrink, 0, (972, 504), (648, 216), # 176 (972, 504), (648, 324)), (psl, isl, border, f_shrink, 1, (972, 504), (648, 216), # 177 (972, 504), (648, 324)), (psl, isl, border, f_enlarge, 0, (972, 504), (756, 252), # 178 (972, 504), (864, 432)), (psl, isl, border, f_enlarge, 1, (972, 504), (756, 252), # 179 (972, 504), (864, 432)), (poster, None, None, f_fill, 0, (97200, 50400), (151200, 50400), (97200, 50400), (100800, 50400)), ] # fmt: on ) def test_layout(layout_test_cases): # there is no need to have test cases with the same images with inverted # orientation (landscape/portrait) because --pagesize and --imgsize are # already inverted im1 = (864, 288) # imgpx #1 => 648x216 im2 = (1152, 576) # imgpx #2 => 864x432 psopt, isopt, border, fit, ao, pspdf1, ispdf1, pspdf2, ispdf2 = layout_test_cases if isopt is not None: isopt = ((img2pdf.ImgSize.abs, isopt[0]), (img2pdf.ImgSize.abs, isopt[1])) layout_fun = img2pdf.get_layout_fun(psopt, isopt, border, fit, ao) try: pwpdf, phpdf, iwpdf, ihpdf = layout_fun( im1[0], im1[1], (img2pdf.default_dpi, img2pdf.default_dpi) ) assert (pwpdf, phpdf) == pspdf1 assert (iwpdf, ihpdf) == ispdf1 except img2pdf.NegativeDimensionError: assert pspdf1 is None assert ispdf1 is None try: pwpdf, phpdf, iwpdf, ihpdf = layout_fun( im2[0], im2[1], (img2pdf.default_dpi, img2pdf.default_dpi) ) assert (pwpdf, phpdf) == pspdf2 assert (iwpdf, ihpdf) == ispdf2 except img2pdf.NegativeDimensionError: assert pspdf2 is None assert ispdf2 is None @pytest.fixture( scope="session", params=os.listdir(os.path.join(os.path.dirname(__file__), "tests", "input")), ) def general_input(request): assert os.path.isfile( os.path.join(os.path.dirname(__file__), "tests", "input", request.param) ) return request.param @pytest.mark.parametrize("engine", ["internal", "pikepdf", "pdfrw"]) def test_general(general_input, engine): inputf = os.path.join(os.path.dirname(__file__), "tests", "input", general_input) outputf = os.path.join( os.path.dirname(__file__), "tests", "output", general_input + ".pdf" ) assert os.path.isfile(outputf) f = inputf out = outputf engine = getattr(img2pdf.Engine, engine) # we do not test animation.gif with pdfrw because it doesn't support # saving hexadecimal palette data if f.endswith(os.path.sep + "animation.gif") and engine == img2pdf.Engine.pdfrw: return with open(f, "rb") as inf: orig_imgdata = inf.read() output = img2pdf.convert(orig_imgdata, nodate=True, engine=engine) x = pikepdf.open(BytesIO(output)) assert x.Root.Pages.Count in (1, 2) if len(x.Root.Pages.Kids) == "1": assert x.Size == "7" assert len(x.Root.Pages.Kids) == 1 elif len(x.Root.Pages.Kids) == "2": assert x.Size == "10" assert len(x.Root.Pages.Kids) == 2 assert sorted(x.Root.keys()) == ["/Pages", "/Type"] assert x.Root.Type == "/Catalog" assert sorted(x.Root.Pages.keys()) == ["/Count", "/Kids", "/Type"] assert x.Root.Pages.Type == "/Pages" orig_img = Image.open(f) for pagenum in range(len(x.Root.Pages.Kids)): # retrieve the original image frame that this page was # generated from orig_img.seek(pagenum) cur_page = x.Root.Pages.Kids[pagenum] ndpi = orig_img.info.get("dpi", (96.0, 96.0)) # 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]))) imgwidthpx, imgheightpx = orig_img.size pagewidth = 72.0 * imgwidthpx / ndpi[0] pageheight = 72.0 * imgheightpx / ndpi[1] def format_float(f): if int(f) == f: return int(f) else: return decimal.Decimal("%.4f" % f) assert sorted(cur_page.keys()) == [ "/Contents", "/MediaBox", "/Parent", "/Resources", "/Type", ] assert cur_page.MediaBox == pikepdf.Array( [0, 0, format_float(pagewidth), format_float(pageheight)] ) assert cur_page.Parent == x.Root.Pages assert cur_page.Type == "/Page" assert cur_page.Resources.keys() == {"/XObject"} assert cur_page.Resources.XObject.keys() == {"/Im0"} if engine != img2pdf.Engine.pikepdf: assert cur_page.Contents.Length == len(cur_page.Contents.read_bytes()) assert ( cur_page.Contents.read_bytes() == b"q\n%.4f 0 0 %.4f 0.0000 0.0000 cm\n/Im0 Do\nQ" % ( pagewidth, pageheight, ) ) imgprops = cur_page.Resources.XObject.Im0 # test if the filter is valid: assert imgprops.Filter in [ "/DCTDecode", "/JPXDecode", "/FlateDecode", pikepdf.Array([pikepdf.Name.CCITTFaxDecode]), ] # test if the image has correct size assert imgprops.Width == orig_img.size[0] assert imgprops.Height == orig_img.size[1] # if the input file is a jpeg then it should've been copied # verbatim into the PDF if imgprops.Filter in ["/DCTDecode", "/JPXDecode"]: assert cur_page.Resources.XObject.Im0.read_raw_bytes() == orig_imgdata elif imgprops.Filter == pikepdf.Array([pikepdf.Name.CCITTFaxDecode]): tiff_header = tiff_header_for_ccitt( int(imgprops.Width), int(imgprops.Height), int(imgprops.Length), 4 ) imgio = BytesIO() imgio.write(tiff_header) imgio.write(cur_page.Resources.XObject.Im0.read_raw_bytes()) imgio.seek(0) im = Image.open(imgio) assert im.tobytes() == orig_img.tobytes() try: im.close() except AttributeError: pass elif imgprops.Filter == "/FlateDecode": # otherwise, the data is flate encoded and has to be equal # to the pixel data of the input image imgdata = zlib.decompress(cur_page.Resources.XObject.Im0.read_raw_bytes()) if hasattr(imgprops, "DecodeParms"): if orig_img.format == "PNG": pngidat, palette = img2pdf.parse_png(orig_imgdata) elif ( orig_img.format == "TIFF" and orig_img.info["compression"] == "group4" ): offset, length = img2pdf.ccitt_payload_location_from_pil(orig_img) pngidat = orig_imgdata[offset : offset + length] else: pngbuffer = BytesIO() orig_img.save(pngbuffer, format="png") pngidat, palette = img2pdf.parse_png(pngbuffer.getvalue()) assert zlib.decompress(pngidat) == imgdata else: colorspace = imgprops.ColorSpace if colorspace == "/DeviceGray": colorspace = "L" elif colorspace == "/DeviceRGB": colorspace = "RGB" elif colorspace == "/DeviceCMYK": colorspace = "CMYK" else: raise Exception("invalid colorspace") im = Image.frombytes( colorspace, (int(imgprops.Width), int(imgprops.Height)), imgdata ) if orig_img.mode == "1": assert im.tobytes() == orig_img.convert("L").tobytes() elif orig_img.mode not in ("RGB", "L", "CMYK", "CMYK;I"): assert im.tobytes() == orig_img.convert("RGB").tobytes() # the python-pil version 2.3.0-1ubuntu3 in Ubuntu does # not have the close() method try: im.close() except AttributeError: pass else: raise Exception("unknown filter") def rec(obj): if isinstance(obj, pikepdf.Dictionary): return {k: rec(v) for k, v in obj.items() if k != "/Parent"} elif isinstance(obj, pikepdf.Array): return [rec(v) for v in obj] elif isinstance(obj, pikepdf.Stream): ret = rec(obj.stream_dict) stream = obj.read_raw_bytes() assert len(stream) == ret["/Length"] del ret["/Length"] if ret.get("/Filter") == "/FlateDecode": stream = obj.read_bytes() del ret["/Filter"] ret["stream"] = stream return ret elif isinstance(obj, pikepdf.Name) or isinstance(obj, pikepdf.String): return str(obj) elif isinstance(obj, decimal.Decimal) or isinstance(obj, str): return obj elif isinstance(obj, int): return decimal.Decimal(obj) raise Exception("unhandled: %s" % (type(obj))) y = pikepdf.open(out) pydictx = rec(x.Root) pydicty = rec(y.Root) if f.endswith(os.path.sep + "animation.gif"): # starting with PIL 8.2.0 the palette is half the size when encoding # our test GIF image as PNG # # to still compare successfully, we truncate the expected palette import PIL if PIL.__version__ >= "8.2.0": assert len(pydictx["/Pages"]["/Kids"]) == 2 for p in pydictx["/Pages"]["/Kids"]: assert p["/Resources"]["/XObject"]["/Im0"]["/ColorSpace"][2] == 127 assert len(pydicty["/Pages"]["/Kids"]) == 2 for p in pydicty["/Pages"]["/Kids"]: cs = p["/Resources"]["/XObject"]["/Im0"]["/ColorSpace"] cs[2] = decimal.Decimal("127") cs[3] = cs[3][:384] else: assert ( pydictx["/Pages"]["/Kids"][0]["/Resources"]["/XObject"]["/Im0"][ "/ColorSpace" ][2] == 255 ) assert pydictx == pydicty # the python-pil version 2.3.0-1ubuntu3 in Ubuntu does not have the # close() method try: orig_img.close() except AttributeError: pass def main(): normal16 = alpha_value()[:, :, 0:3] pathlib.Path("test.icc").write_bytes(icc_profile()) write_png( normal16 / 0xFFFF * 0xFF, "icc.png", 8, 2, iccp="test.icc", ) write_png( normal16 / 0xFFFF * 0xFF, "normal.png", 8, 2, ) if __name__ == "__main__": main()