Compare commits
No commits in common. "3da370d3bd4a04822bf0a7611a55ab7eb0beff48" and "30d705f0208ee72357f7fc47699e866de5aeea95" have entirely different histories.
3da370d3bd
...
30d705f020
7 changed files with 32 additions and 50 deletions
|
@ -82,10 +82,7 @@ Bugs
|
||||||
only nine different values from 1 to 9 are permitted, Anroid phones and
|
only nine different values from 1 to 9 are permitted, Anroid phones and
|
||||||
Canon DSLR cameras produce JPEG images with the invalid value of zero.
|
Canon DSLR cameras produce JPEG images with the invalid value of zero.
|
||||||
Either fix your input images with `exiftool` or similar software before
|
Either fix your input images with `exiftool` or similar software before
|
||||||
passing the JPEG to `img2pdf` or run `img2pdf` with `--rotation=ifvalid`
|
passing the JPEG to `img2pdf` or run `img2pdf` with `--rotation=ifvalid`.
|
||||||
(if you run img2pdf from the commandline) or by passing
|
|
||||||
`rotation=img2pdf.Rotation.ifvalid` as an argument to `convert()` when using
|
|
||||||
img2pdf as a library.
|
|
||||||
|
|
||||||
- img2pdf uses PIL (or Pillow) to obtain image meta data and to convert the
|
- img2pdf uses PIL (or Pillow) to obtain image meta data and to convert the
|
||||||
input if necessary. To prevent decompression bomb denial of service attacks,
|
input if necessary. To prevent decompression bomb denial of service attacks,
|
||||||
|
@ -194,10 +191,6 @@ The package can also be used as a library:
|
||||||
with open("name.pdf","wb") as f:
|
with open("name.pdf","wb") as f:
|
||||||
f.write(img2pdf.convert(glob.glob("/path/to/*.jpg")))
|
f.write(img2pdf.convert(glob.glob("/path/to/*.jpg")))
|
||||||
|
|
||||||
# ignore invalid rotation values in the input images
|
|
||||||
with open("name.pdf","wb") as f:
|
|
||||||
f.write(img2pdf.convert('test.jpg'), rotation=img2pdf.Rotation.ifvalid)
|
|
||||||
|
|
||||||
# writing to file descriptor
|
# writing to file descriptor
|
||||||
with open("name.pdf","wb") as f1, open("test.jpg") as f2:
|
with open("name.pdf","wb") as f1, open("test.jpg") as f2:
|
||||||
img2pdf.convert(f2, outputstream=f1)
|
img2pdf.convert(f2, outputstream=f1)
|
||||||
|
|
|
@ -16,13 +16,12 @@ environment:
|
||||||
- PYTHON: "C:\\Python37-x64"
|
- PYTHON: "C:\\Python37-x64"
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- "%PYTHON%\\python.exe -m pip install tox wheel pyinstaller Pillow"
|
- "%PYTHON%\\python.exe -m pip install tox wheel pyinstaller"
|
||||||
|
|
||||||
build: off
|
build: off
|
||||||
|
|
||||||
# don't run tests on windows because we don't have imagemagick
|
test_script:
|
||||||
#test_script:
|
- "%PYTHON%\\python.exe -m tox"
|
||||||
# - "%PYTHON%\\python.exe -m tox"
|
|
||||||
|
|
||||||
after_test:
|
after_test:
|
||||||
- "%PYTHON%\\python.exe setup.py bdist_wheel"
|
- "%PYTHON%\\python.exe setup.py bdist_wheel"
|
||||||
|
|
|
@ -1277,25 +1277,17 @@ def get_imgmetadata(
|
||||||
elif value in (2, 4, 5, 7):
|
elif value in (2, 4, 5, 7):
|
||||||
if rotreq == Rotation.ifvalid:
|
if rotreq == Rotation.ifvalid:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Unsupported flipped rotation mode (%d): use "
|
"Unsupported flipped rotation mode (%d)", value
|
||||||
"--rotation=ifvalid or "
|
|
||||||
"rotation=img2pdf.Rotation.ifvalid to ignore",
|
|
||||||
value,
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ExifOrientationError(
|
raise ExifOrientationError(
|
||||||
"Unsupported flipped rotation mode (%d): use "
|
"Unsupported flipped rotation mode (%d)" % value
|
||||||
"--rotation=ifvalid or "
|
|
||||||
"rotation=img2pdf.Rotation.ifvalid to ignore" % value
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if rotreq == Rotation.ifvalid:
|
if rotreq == Rotation.ifvalid:
|
||||||
logger.warning("Invalid rotation (%d)", value)
|
logger.warning("Invalid rotation (%d)", value)
|
||||||
else:
|
else:
|
||||||
raise ExifOrientationError(
|
raise ExifOrientationError("Invalid rotation (%d)" % value)
|
||||||
"Invalid rotation (%d): use --rotation=ifvalid "
|
|
||||||
"or rotation=img2pdf.Rotation.ifvalid to ignore" % value
|
|
||||||
)
|
|
||||||
elif rotreq in (Rotation.none, Rotation["0"]):
|
elif rotreq in (Rotation.none, Rotation["0"]):
|
||||||
rotation = 0
|
rotation = 0
|
||||||
elif rotreq == Rotation["90"]:
|
elif rotreq == Rotation["90"]:
|
||||||
|
|
|
@ -2190,37 +2190,15 @@ def gif_palette8_img(tmp_path_factory, tmp_palette8_png):
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def gif_animation_img(tmp_path_factory, tmp_normal_png, tmp_inverse_png):
|
def gif_animation_img(tmp_path_factory, tmp_normal_png, tmp_inverse_png):
|
||||||
in_img = tmp_path_factory.mktemp("gif_animation_img") / "in.gif"
|
in_img = tmp_path_factory.mktemp("gif_animation_img") / "in.gif"
|
||||||
pal_img = tmp_path_factory.mktemp("gif_animation_img") / "pal.gif"
|
|
||||||
tmp_img = tmp_path_factory.mktemp("gif_animation_img") / "tmp.gif"
|
|
||||||
subprocess.check_call(
|
subprocess.check_call(
|
||||||
CONVERT
|
CONVERT
|
||||||
+ [
|
+ [
|
||||||
str(tmp_normal_png),
|
str(tmp_normal_png),
|
||||||
str(tmp_inverse_png),
|
str(tmp_inverse_png),
|
||||||
str(tmp_img),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
# create palette image with all unique colors
|
|
||||||
subprocess.check_call(
|
|
||||||
CONVERT
|
|
||||||
+ [
|
|
||||||
str(tmp_img),
|
|
||||||
"-unique-colors",
|
|
||||||
str(pal_img),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
# make sure all frames have the same palette by using -remap
|
|
||||||
subprocess.check_call(
|
|
||||||
CONVERT
|
|
||||||
+ [
|
|
||||||
str(tmp_img),
|
|
||||||
"-strip",
|
"-strip",
|
||||||
"-remap", str(pal_img),
|
str(in_img),
|
||||||
str(in_img)
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
pal_img.unlink()
|
|
||||||
tmp_img.unlink()
|
|
||||||
identify = json.loads(
|
identify = json.loads(
|
||||||
subprocess.check_output(CONVERT + [str(in_img) + "[0]", "json:"])
|
subprocess.check_output(CONVERT + [str(in_img) + "[0]", "json:"])
|
||||||
)
|
)
|
||||||
|
@ -2250,7 +2228,6 @@ def gif_animation_img(tmp_path_factory, tmp_normal_png, tmp_inverse_png):
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}, str(identify)
|
}, str(identify)
|
||||||
assert identify[0]["image"].get("compression") == "LZW", str(identify)
|
assert identify[0]["image"].get("compression") == "LZW", str(identify)
|
||||||
colormap_frame0 = identify[0]["image"].get("colormap")
|
|
||||||
identify = json.loads(
|
identify = json.loads(
|
||||||
subprocess.check_output(CONVERT + [str(in_img) + "[1]", "json:"])
|
subprocess.check_output(CONVERT + [str(in_img) + "[1]", "json:"])
|
||||||
)
|
)
|
||||||
|
@ -2281,8 +2258,6 @@ def gif_animation_img(tmp_path_factory, tmp_normal_png, tmp_inverse_png):
|
||||||
}, str(identify)
|
}, str(identify)
|
||||||
assert identify[0]["image"].get("compression") == "LZW", str(identify)
|
assert identify[0]["image"].get("compression") == "LZW", str(identify)
|
||||||
assert identify[0]["image"].get("scene") == 1, str(identify)
|
assert identify[0]["image"].get("scene") == 1, str(identify)
|
||||||
colormap_frame1 = identify[0]["image"].get("colormap")
|
|
||||||
assert colormap_frame0 == colormap_frame1
|
|
||||||
yield in_img
|
yield in_img
|
||||||
in_img.unlink()
|
in_img.unlink()
|
||||||
|
|
||||||
|
@ -6737,6 +6712,29 @@ def test_general(general_input, engine):
|
||||||
y = pikepdf.open(out)
|
y = pikepdf.open(out)
|
||||||
pydictx = rec(x.Root)
|
pydictx = rec(x.Root)
|
||||||
pydicty = rec(y.Root)
|
pydicty = rec(y.Root)
|
||||||
|
if f.endswith(os.path.sep + "animation.gif"):
|
||||||
|
# starting with PIL 8.2.0 the palette is half the size when encoding
|
||||||
|
# our test GIF image as PNG
|
||||||
|
#
|
||||||
|
# to still compare successfully, we truncate the expected palette
|
||||||
|
import PIL
|
||||||
|
|
||||||
|
if PIL.__version__ >= "8.2.0":
|
||||||
|
assert len(pydictx["/Pages"]["/Kids"]) == 2
|
||||||
|
for p in pydictx["/Pages"]["/Kids"]:
|
||||||
|
assert p["/Resources"]["/XObject"]["/Im0"]["/ColorSpace"][2] == 127
|
||||||
|
assert len(pydicty["/Pages"]["/Kids"]) == 2
|
||||||
|
for p in pydicty["/Pages"]["/Kids"]:
|
||||||
|
cs = p["/Resources"]["/XObject"]["/Im0"]["/ColorSpace"]
|
||||||
|
cs[2] = decimal.Decimal("127")
|
||||||
|
cs[3] = cs[3][:384]
|
||||||
|
else:
|
||||||
|
assert (
|
||||||
|
pydictx["/Pages"]["/Kids"][0]["/Resources"]["/XObject"]["/Im0"][
|
||||||
|
"/ColorSpace"
|
||||||
|
][2]
|
||||||
|
== 255
|
||||||
|
)
|
||||||
assert pydictx == pydicty
|
assert pydictx == pydicty
|
||||||
# the python-pil version 2.3.0-1ubuntu3 in Ubuntu does not have the
|
# the python-pil version 2.3.0-1ubuntu3 in Ubuntu does not have the
|
||||||
# close() method
|
# close() method
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
2
tox.ini
2
tox.ini
|
@ -4,7 +4,7 @@
|
||||||
# and then run "tox" from this directory.
|
# and then run "tox" from this directory.
|
||||||
|
|
||||||
[tox]
|
[tox]
|
||||||
envlist = py37, py38, py39, py310
|
envlist = py35, py36, py37, py38, py39
|
||||||
skip_missing_interpreters = true
|
skip_missing_interpreters = true
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
|
|
Loading…
Reference in a new issue