forked from josch/img2pdf
4685 lines
183 KiB
Python
4685 lines
183 KiB
Python
#!/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
|
|
|
|
|
|
###############################################################################
|
|
# 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("<H", len(chunk))
|
|
# the one's complement of the chunk length
|
|
# one's complement is all bits inverted which is the result of
|
|
# xor with 0xffff for a 16 bit unsigned integer
|
|
result += struct.pack("<H", len(chunk) ^ 0xFFFF)
|
|
result += chunk
|
|
# adler32 checksum of the uncompressed data as big endian 32 bit unsigned
|
|
# integer
|
|
result += struct.pack(">I", zlib.adler32(data))
|
|
return result
|
|
|
|
|
|
def write_png(data, path, bitdepth, colortype, palette=None):
|
|
with open(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 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_ghostscript(tmpdir, img, pdf, gsdevice="png16m", exact=True):
|
|
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),
|
|
]
|
|
)
|
|
if exact:
|
|
subprocess.check_call(
|
|
["compare", "-metric", "AE", str(img), str(tmpdir / "gs-1.") + ext, "null:"]
|
|
)
|
|
else:
|
|
psnr = subprocess.run(
|
|
[
|
|
"compare",
|
|
"-metric",
|
|
"PSNR",
|
|
str(img),
|
|
str(tmpdir / "gs-1.") + ext,
|
|
"null:",
|
|
],
|
|
check=False,
|
|
stderr=subprocess.PIPE,
|
|
).stderr
|
|
psnr = float(psnr.strip(b"0"))
|
|
assert psnr != 0 # or otherwise we would use the exact variant
|
|
assert psnr > 50
|
|
(tmpdir / ("gs-1." + ext)).unlink()
|
|
|
|
|
|
def compare_poppler(tmpdir, img, pdf, exact=True):
|
|
subprocess.check_call(
|
|
["pdftocairo", "-r", "96", "-png", str(pdf), str(tmpdir / "poppler")]
|
|
)
|
|
if exact:
|
|
subprocess.check_call(
|
|
[
|
|
"compare",
|
|
"-metric",
|
|
"AE",
|
|
str(img),
|
|
str(tmpdir / "poppler-1.png"),
|
|
"null:",
|
|
]
|
|
)
|
|
else:
|
|
psnr = subprocess.run(
|
|
[
|
|
"compare",
|
|
"-metric",
|
|
"PSNR",
|
|
str(img),
|
|
str(tmpdir / "poppler-1.png"),
|
|
"null:",
|
|
],
|
|
check=False,
|
|
stderr=subprocess.PIPE,
|
|
).stderr
|
|
psnr = float(psnr.strip(b"0"))
|
|
assert psnr != 0 # or otherwise we would use the exact variant
|
|
assert psnr > 50
|
|
(tmpdir / "poppler-1.png").unlink()
|
|
|
|
|
|
def compare_mupdf(tmpdir, img, pdf, exact=True, cmyk=False):
|
|
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)]
|
|
)
|
|
if exact:
|
|
if cmyk:
|
|
raise Exception("cmyk cannot be exact")
|
|
subprocess.check_call(["compare", "-metric", "AE", str(img), str(out), "null:"])
|
|
else:
|
|
psnr = subprocess.run(
|
|
["compare", "-metric", "PSNR", str(img), str(out), "null:"],
|
|
check=False,
|
|
stderr=subprocess.PIPE,
|
|
).stderr
|
|
psnr = float(psnr.strip(b"0"))
|
|
assert psnr != 0 # or otherwise we would use the exact variant
|
|
assert psnr > 50
|
|
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_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):
|
|
subprocess.check_call(["pdfimages", "-png", str(pdf), str(tmpdir / "images")])
|
|
if exact:
|
|
subprocess.check_call(
|
|
[
|
|
"compare",
|
|
"-metric",
|
|
"AE",
|
|
str(img),
|
|
str(tmpdir / "images-000.png"),
|
|
"null:",
|
|
]
|
|
)
|
|
else:
|
|
psnr = subprocess.run(
|
|
[
|
|
"compare",
|
|
"-metric",
|
|
"PSNR",
|
|
str(img),
|
|
str(tmpdir / "images-000.png"),
|
|
"null:",
|
|
],
|
|
check=False,
|
|
stderr=subprocess.PIPE,
|
|
).stderr
|
|
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
|
|
)
|
|
|
|
|
|
###############################################################################
|
|
# INPUT FIXTURES #
|
|
###############################################################################
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def alpha():
|
|
# 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],
|
|
],
|
|
numpy.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)
|
|
return alpha
|
|
|
|
|
|
@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()
|
|
== "cc611e80cde3b9b7adb7723801a4e5d4"
|
|
)
|
|
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()
|
|
== "ff4d9f18de39be879926be2e65990167"
|
|
)
|
|
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()
|
|
== "d51900476658a1c9dd26a7b27db8a21f"
|
|
)
|
|
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()
|
|
== "722223ba74be9cba1af4a549076b70d3"
|
|
)
|
|
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()
|
|
== "2320216faa5a10bf0f5f04ebce07f8e1"
|
|
)
|
|
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()
|
|
== "706175887af8ca1a33cfd93449f970df"
|
|
)
|
|
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()
|
|
== "35a47d6ae6de8c9d0b31aa0cda8648f3"
|
|
)
|
|
yield tmp_inverse_png
|
|
tmp_inverse_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()
|
|
== "6ad810399058a87d8145d8d9a7734da5"
|
|
)
|
|
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()
|
|
== "c8d2e1f116f31ecdeae050524efca7b6"
|
|
)
|
|
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()
|
|
== "18a3dfca369f976996ef93389ddfad61"
|
|
)
|
|
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()
|
|
== "d38646afa6fa0714be9badef25ff9392"
|
|
)
|
|
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()
|
|
== "e1c59e68a68fca3273b6dc164d526ed7"
|
|
)
|
|
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()
|
|
== "50bf09eb3571901f0bf642b9a733038c"
|
|
)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: JPEG \(Joint Photographic Experts Group JFIF format\)$",
|
|
r"^ Mime type: image/jpeg$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColor$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: JPEG$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: JPEG \(Joint Photographic Experts Group JFIF format\)$",
|
|
r"^ Mime type: image/jpeg$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Resolution: 96x96$",
|
|
r"^ Units: PixelsPerInch$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColor$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: JPEG$",
|
|
r"^ Orientation: RightTop$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: JPEG \(Joint Photographic Experts Group JFIF format\)$",
|
|
r"^ Mime type: image/jpeg$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: CMYK$",
|
|
r"^ Type: ColorSeparation$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: JPEG$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: JP2 \(JPEG-2000 File Format Syntax\)$",
|
|
r"^ Mime type: image/jp2$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColor$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: JPEG2000$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
yield in_img
|
|
in_img.unlink()
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def png_rgb8_img(tmp_normal_png):
|
|
in_img = tmp_normal_png
|
|
identify = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColor$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 8$",
|
|
r"^ png:IHDR.bit_depth: 8$",
|
|
r"^ png:IHDR.color-type-orig: 2$",
|
|
r"^ png:IHDR.color_type: 2 \(Truecolor\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
return in_img
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def png_rgb16_img(tmp_normal16_png):
|
|
in_img = tmp_normal16_png
|
|
identify = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColor$",
|
|
r"^ Depth: 16-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 16$",
|
|
r"^ png:IHDR.bit_depth: 16$",
|
|
r"^ png:IHDR.color-type-orig: 2$",
|
|
r"^ png:IHDR.color_type: 2 \(Truecolor\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColorAlpha$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 8$",
|
|
r"^ png:IHDR.bit_depth: 8$",
|
|
r"^ png:IHDR.color-type-orig: 6$",
|
|
r"^ png:IHDR.color_type: 6 \(RGBA\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
yield in_img
|
|
in_img.unlink()
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def png_rgba16_img(tmp_alpha_png):
|
|
in_img = tmp_alpha_png
|
|
identify = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColorAlpha$",
|
|
r"^ Depth: 16-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 16$",
|
|
r"^ png:IHDR.bit_depth: 16$",
|
|
r"^ png:IHDR.color-type-orig: 6$",
|
|
r"^ png:IHDR.color_type: 6 \(RGBA\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: GrayscaleAlpha$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 8$",
|
|
r"^ png:IHDR.bit_depth: 8$",
|
|
r"^ png:IHDR.color-type-orig: 4$",
|
|
r"^ png:IHDR.color_type: 4 \(GrayAlpha\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: GrayscaleAlpha$",
|
|
r"^ Depth: 16-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 16$",
|
|
r"^ png:IHDR.bit_depth: 16$",
|
|
r"^ png:IHDR.color-type-orig: 4$",
|
|
r"^ png:IHDR.color_type: 4 \(GrayAlpha\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColor$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 8$",
|
|
r"^ png:IHDR.bit_depth: 8$",
|
|
r"^ png:IHDR.color-type-orig: 2$",
|
|
r"^ png:IHDR.color_type: 2 \(Truecolor\)$",
|
|
r"^ png:IHDR.interlace_method: 1 \(Adam7 method\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
yield in_img
|
|
in_img.unlink()
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def png_gray1_img(tmp_path_factory, tmp_gray1_png):
|
|
identify = subprocess.check_output(["identify", "-verbose", tmp_gray1_png])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Bilevel$",
|
|
r"^ Depth: 8/1-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 1$",
|
|
r"^ png:IHDR.bit_depth: 1$",
|
|
r"^ png:IHDR.color-type-orig: 0$",
|
|
r"^ png:IHDR.color_type: 0 \(Grayscale\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
return tmp_gray1_png
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def png_gray2_img(tmp_path_factory, tmp_gray2_png):
|
|
identify = subprocess.check_output(["identify", "-verbose", tmp_gray2_png])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Grayscale$",
|
|
r"^ Depth: 8/2-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 2$",
|
|
r"^ png:IHDR.bit_depth: 2$",
|
|
r"^ png:IHDR.color-type-orig: 0$",
|
|
r"^ png:IHDR.color_type: 0 \(Grayscale\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
return tmp_gray2_png
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def png_gray4_img(tmp_path_factory, tmp_gray4_png):
|
|
identify = subprocess.check_output(["identify", "-verbose", tmp_gray4_png])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Grayscale$",
|
|
r"^ Depth: 8/4-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 4$",
|
|
r"^ png:IHDR.bit_depth: 4$",
|
|
r"^ png:IHDR.color-type-orig: 0$",
|
|
r"^ png:IHDR.color_type: 0 \(Grayscale\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
return tmp_gray4_png
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def png_gray8_img(tmp_path_factory, tmp_gray8_png):
|
|
identify = subprocess.check_output(["identify", "-verbose", tmp_gray8_png])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Grayscale$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 8$",
|
|
r"^ png:IHDR.bit_depth: 8$",
|
|
r"^ png:IHDR.color-type-orig: 0$",
|
|
r"^ png:IHDR.color_type: 0 \(Grayscale\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
return tmp_gray8_png
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def png_gray16_img(tmp_path_factory, tmp_gray16_png):
|
|
identify = subprocess.check_output(["identify", "-verbose", tmp_gray16_png])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Grayscale$",
|
|
r"^ Depth: 16-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 16$",
|
|
r"^ png:IHDR.bit_depth: 16$",
|
|
r"^ png:IHDR.color-type-orig: 0$",
|
|
r"^ png:IHDR.color_type: 0 \(Grayscale\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
return tmp_gray16_png
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def png_palette1_img(tmp_path_factory, tmp_palette1_png):
|
|
identify = subprocess.check_output(["identify", "-verbose", tmp_palette1_png])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: Palette$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 1$",
|
|
r"^ png:IHDR.bit_depth: 1$",
|
|
r"^ png:IHDR.color-type-orig: 3$",
|
|
r"^ png:IHDR.color_type: 3 \(Indexed\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
return tmp_palette1_png
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def png_palette2_img(tmp_path_factory, tmp_palette2_png):
|
|
identify = subprocess.check_output(["identify", "-verbose", tmp_palette2_png])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: Palette$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 2$",
|
|
r"^ png:IHDR.bit_depth: 2$",
|
|
r"^ png:IHDR.color-type-orig: 3$",
|
|
r"^ png:IHDR.color_type: 3 \(Indexed\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
return tmp_palette2_png
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def png_palette4_img(tmp_path_factory, tmp_palette4_png):
|
|
identify = subprocess.check_output(["identify", "-verbose", tmp_palette4_png])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: Palette$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 4$",
|
|
r"^ png:IHDR.bit_depth: 4$",
|
|
r"^ png:IHDR.color-type-orig: 3$",
|
|
r"^ png:IHDR.color_type: 3 \(Indexed\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
return tmp_palette4_png
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def png_palette8_img(tmp_path_factory, tmp_palette8_png):
|
|
identify = subprocess.check_output(["identify", "-verbose", tmp_palette8_png])
|
|
expected = [
|
|
r"^ Format: PNG \(Portable Network Graphics\)$",
|
|
r"^ Mime type: image/png$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: Palette$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ png:IHDR.bit-depth-orig: 8$",
|
|
r"^ png:IHDR.bit_depth: 8$",
|
|
r"^ png:IHDR.color-type-orig: 3$",
|
|
r"^ png:IHDR.color_type: 3 \(Indexed\)$",
|
|
r"^ png:IHDR.interlace_method: 0 \(Not interlaced\)$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: GIF \(CompuServe graphics interchange format\)$",
|
|
r"^ Mime type: image/gif$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: PaletteAlpha$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Colormap entries: 256$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: LZW$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: GIF \(CompuServe graphics interchange format\)$",
|
|
r"^ Mime type: image/gif$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: Palette$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Colormap entries: 2$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: LZW$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: GIF \(CompuServe graphics interchange format\)$",
|
|
r"^ Mime type: image/gif$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: Palette$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Colormap entries: 4$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: LZW$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: GIF \(CompuServe graphics interchange format\)$",
|
|
r"^ Mime type: image/gif$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: Palette$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Colormap entries: 16$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: LZW$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: GIF \(CompuServe graphics interchange format\)$",
|
|
r"^ Mime type: image/gif$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: Palette$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Colormap entries: 256$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: LZW$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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", tmp_normal_png, tmp_inverse_png, "-strip", str(in_img)]
|
|
)
|
|
identify = subprocess.check_output(["identify", "-verbose", str(in_img) + "[0]"])
|
|
expected = [
|
|
r"^ Format: GIF \(CompuServe graphics interchange format\)$",
|
|
r"^ Mime type: image/gif$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: Palette$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Colormap entries: 256$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: LZW$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
identify = subprocess.check_output(["identify", "-verbose", str(in_img) + "[1]"])
|
|
expected = [
|
|
r"^ Format: GIF \(CompuServe graphics interchange format\)$",
|
|
r"^ Mime type: image/gif$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: Palette$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Colormap entries: 256$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: LZW$",
|
|
r"^ Scene: 1$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColor$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 32/(8|16)-bit$", # imagemagick may produce a Depth: 32/8-bit or 32/16-bit image
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ quantum:format: floating-point$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: RGB$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: CMYK$",
|
|
r"^ Type: ColorSeparation$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: separated$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: CMYK$",
|
|
r"^ Type: ColorSeparation$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 16-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: separated$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColor$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: RGB$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColor$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 12(/16)?-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: RGB$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColor$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 14(/16)?-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: RGB$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColor$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 16-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: RGB$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColorAlpha$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unassociated$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: RGB$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColorAlpha$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 16-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unassociated$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: RGB$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Bilevel$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 1-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: min-is-black$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Grayscale$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 2-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: min-is-black$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Grayscale$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 4-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: min-is-black$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Grayscale$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: min-is-black$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Grayscale$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 16-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: min-is-black$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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", tmp_normal_png, tmp_inverse_png, "-strip", str(in_img)]
|
|
)
|
|
identify = subprocess.check_output(["identify", "-verbose", str(in_img) + "[0]"])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColor$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: RGB$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
identify = subprocess.check_output(["identify", "-verbose", str(in_img) + "[1]"])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: TrueColor$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: RGB$",
|
|
r"^ Scene: 1$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: Palette$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 1/8-bit$",
|
|
r"^ Colormap entries: 2$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: palette$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: Palette$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 2/8-bit$",
|
|
r"^ Colormap entries: 4$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: palette$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: Palette$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 4/8-bit$",
|
|
r"^ Colormap entries: 16$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: palette$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: sRGB$",
|
|
r"^ Type: Palette$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 8-bit$",
|
|
r"^ Colormap entries: 256$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Zip$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: palette$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Bilevel$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 1-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Group4$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: min-is-white$",
|
|
r"^ tiff:rows-per-strip: 60$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
tiffinfo = subprocess.check_output(["tiffinfo", 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)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Bilevel$",
|
|
r"^ Endiann?ess: MSB$",
|
|
r"^ Depth: 1-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Group4$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: msb$",
|
|
r"^ tiff:photometric: min-is-white$",
|
|
r"^ tiff:rows-per-strip: 60$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
tiffinfo = subprocess.check_output(["tiffinfo", 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)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Bilevel$",
|
|
r"^ Endiann?ess: MSB$",
|
|
r"^ Depth: 1-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Group4$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: msb$",
|
|
r"^ tiff:photometric: min-is-white$",
|
|
r"^ tiff:rows-per-strip: 60$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
tiffinfo = subprocess.check_output(["tiffinfo", 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)
|
|
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
|
|
# 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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Bilevel$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 1-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Group4$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: min-is-black$",
|
|
r"^ tiff:rows-per-strip: 60$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
tiffinfo = subprocess.check_output(["tiffinfo", 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)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Bilevel$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 1-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Group4$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: min-is-white$",
|
|
r"^ tiff:rows-per-strip: 60$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
tiffinfo = subprocess.check_output(["tiffinfo", 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)
|
|
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 = subprocess.check_output(["identify", "-verbose", in_img])
|
|
expected = [
|
|
r"^ Format: TIFF \(Tagged Image File Format\)$",
|
|
r"^ Mime type: image/tiff$",
|
|
r"^ Geometry: 60x60\+0\+0$",
|
|
r"^ Colorspace: Gray$",
|
|
r"^ Type: Bilevel$",
|
|
r"^ Endiann?ess: LSB$",
|
|
r"^ Depth: 1-bit$",
|
|
r"^ Page geometry: 60x60\+0\+0$",
|
|
r"^ Compression: Group4$",
|
|
r"^ tiff:alpha: unspecified$",
|
|
r"^ tiff:endian: lsb$",
|
|
r"^ tiff:photometric: min-is-white$",
|
|
]
|
|
for e in expected:
|
|
assert re.search(e, identify.decode("utf8"), re.MULTILINE)
|
|
unexpected = [" tiff:rows-per-strip: "]
|
|
for e in unexpected:
|
|
assert e not in identify.decode("utf8")
|
|
tiffinfo = subprocess.check_output(["tiffinfo", 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)
|
|
unexpected = [" Rows/Strip: "]
|
|
for e in unexpected:
|
|
assert e not in tiffinfo.decode("utf8")
|
|
yield in_img
|
|
in_img.unlink()
|
|
|
|
|
|
###############################################################################
|
|
# 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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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"])
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
gif_animation_img,
|
|
]
|
|
)
|
|
pdfinfo = subprocess.check_output(["pdfinfo", str(out_pdf)])
|
|
assert re.search("^Pages: +2$", pdfinfo.decode("utf8"), re.MULTILINE)
|
|
subprocess.check_call(["pdfseparate", 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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
tiff_multipage_img,
|
|
]
|
|
)
|
|
pdfinfo = subprocess.check_output(["pdfinfo", str(out_pdf)])
|
|
assert re.search("^Pages: +2$", pdfinfo.decode("utf8"), re.MULTILINE)
|
|
subprocess.check_call(["pdfseparate", 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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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 #
|
|
###############################################################################
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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_jpg(tmpdir, jpg_cmyk_img, jpg_cmyk_pdf)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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.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),
|
|
png_rgba8_img,
|
|
]
|
|
).returncode
|
|
)
|
|
out_pdf.unlink()
|
|
|
|
|
|
@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),
|
|
png_rgba16_img,
|
|
]
|
|
).returncode
|
|
)
|
|
out_pdf.unlink()
|
|
|
|
|
|
@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),
|
|
png_gray8a_img,
|
|
]
|
|
).returncode
|
|
)
|
|
out_pdf.unlink()
|
|
|
|
|
|
@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),
|
|
png_gray16a_img,
|
|
]
|
|
).returncode
|
|
)
|
|
out_pdf.unlink()
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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.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),
|
|
gif_transparent_img,
|
|
]
|
|
).returncode
|
|
)
|
|
out_pdf.unlink()
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
def test_gif_animation(tmp_path_factory, gif_animation_img, gif_animation_pdf):
|
|
tmpdir = tmp_path_factory.mktemp("gif_animation")
|
|
subprocess.check_call(
|
|
["pdfseparate", 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.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),
|
|
tiff_float_img,
|
|
]
|
|
).returncode
|
|
)
|
|
out_pdf.unlink()
|
|
|
|
|
|
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.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),
|
|
tiff_cmyk16_img,
|
|
]
|
|
).returncode
|
|
)
|
|
out_pdf.unlink()
|
|
|
|
|
|
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.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),
|
|
tiff_rgb12_img,
|
|
]
|
|
).returncode
|
|
)
|
|
out_pdf.unlink()
|
|
|
|
|
|
@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),
|
|
tiff_rgb14_img,
|
|
]
|
|
).returncode
|
|
)
|
|
out_pdf.unlink()
|
|
|
|
|
|
@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),
|
|
tiff_rgb16_img,
|
|
]
|
|
).returncode
|
|
)
|
|
out_pdf.unlink()
|
|
|
|
|
|
@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),
|
|
tiff_rgba8_img,
|
|
]
|
|
).returncode
|
|
)
|
|
out_pdf.unlink()
|
|
|
|
|
|
@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),
|
|
tiff_rgba16_img,
|
|
]
|
|
).returncode
|
|
)
|
|
out_pdf.unlink()
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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.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),
|
|
tiff_gray16_img,
|
|
]
|
|
).returncode
|
|
)
|
|
out_pdf.unlink()
|
|
|
|
|
|
def test_tiff_multipage(tmp_path_factory, tiff_multipage_img, tiff_multipage_pdf):
|
|
tmpdir = tmp_path_factory.mktemp("tiff_multipage")
|
|
subprocess.check_call(
|
|
["pdfseparate", 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()
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
)
|
|
|
|
|
|
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
|
|
)
|
|
|
|
|
|
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
|
|
)
|
|
|
|
|
|
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
|
|
)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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__), "src", "tests", "input")),
|
|
)
|
|
def general_input(request):
|
|
assert os.path.isfile(
|
|
os.path.join(os.path.dirname(__file__), "src", "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__), "src", "tests", "input", general_input
|
|
)
|
|
outputf = os.path.join(
|
|
os.path.dirname(__file__), "src", "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)
|
|
assert rec(x.Root) == rec(y.Root)
|
|
# the python-pil version 2.3.0-1ubuntu3 in Ubuntu does not have the
|
|
# close() method
|
|
try:
|
|
orig_img.close()
|
|
except AttributeError:
|
|
pass
|