Compare commits

...

7 commits

7 changed files with 51 additions and 33 deletions

View file

@ -82,7 +82,10 @@ Bugs
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.
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
input if necessary. To prevent decompression bomb denial of service attacks,
@ -191,6 +194,10 @@ The package can also be used as a library:
with open("name.pdf","wb") as f:
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
with open("name.pdf","wb") as f1, open("test.jpg") as f2:
img2pdf.convert(f2, outputstream=f1)

View file

@ -16,12 +16,13 @@ environment:
- PYTHON: "C:\\Python37-x64"
install:
- "%PYTHON%\\python.exe -m pip install tox wheel pyinstaller"
- "%PYTHON%\\python.exe -m pip install tox wheel pyinstaller Pillow"
build: off
test_script:
- "%PYTHON%\\python.exe -m tox"
# don't run tests on windows because we don't have imagemagick
#test_script:
# - "%PYTHON%\\python.exe -m tox"
after_test:
- "%PYTHON%\\python.exe setup.py bdist_wheel"

View file

@ -1277,17 +1277,25 @@ def get_imgmetadata(
elif value in (2, 4, 5, 7):
if rotreq == Rotation.ifvalid:
logger.warning(
"Unsupported flipped rotation mode (%d)", value
"Unsupported flipped rotation mode (%d): use "
"--rotation=ifvalid or "
"rotation=img2pdf.Rotation.ifvalid to ignore",
value,
)
else:
raise ExifOrientationError(
"Unsupported flipped rotation mode (%d)" % value
"Unsupported flipped rotation mode (%d): use "
"--rotation=ifvalid or "
"rotation=img2pdf.Rotation.ifvalid to ignore" % value
)
else:
if rotreq == Rotation.ifvalid:
logger.warning("Invalid rotation (%d)", value)
else:
raise ExifOrientationError("Invalid rotation (%d)" % value)
raise ExifOrientationError(
"Invalid rotation (%d): use --rotation=ifvalid "
"or rotation=img2pdf.Rotation.ifvalid to ignore" % value
)
elif rotreq in (Rotation.none, Rotation["0"]):
rotation = 0
elif rotreq == Rotation["90"]:

View file

@ -2190,15 +2190,37 @@ def gif_palette8_img(tmp_path_factory, tmp_palette8_png):
@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"
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(
CONVERT
+ [
str(tmp_normal_png),
str(tmp_inverse_png),
"-strip",
str(in_img),
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",
"-remap", str(pal_img),
str(in_img)
]
)
pal_img.unlink()
tmp_img.unlink()
identify = json.loads(
subprocess.check_output(CONVERT + [str(in_img) + "[0]", "json:"])
)
@ -2228,6 +2250,7 @@ def gif_animation_img(tmp_path_factory, tmp_normal_png, tmp_inverse_png):
"y": 0,
}, str(identify)
assert identify[0]["image"].get("compression") == "LZW", str(identify)
colormap_frame0 = identify[0]["image"].get("colormap")
identify = json.loads(
subprocess.check_output(CONVERT + [str(in_img) + "[1]", "json:"])
)
@ -2258,6 +2281,8 @@ def gif_animation_img(tmp_path_factory, tmp_normal_png, tmp_inverse_png):
}, str(identify)
assert identify[0]["image"].get("compression") == "LZW", 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
in_img.unlink()
@ -6712,29 +6737,6 @@ def test_general(general_input, engine):
y = pikepdf.open(out)
pydictx = rec(x.Root)
pydicty = rec(y.Root)
if f.endswith(os.path.sep + "animation.gif"):
# starting with PIL 8.2.0 the palette is half the size when encoding
# our test GIF image as PNG
#
# to still compare successfully, we truncate the expected palette
import PIL
if PIL.__version__ >= "8.2.0":
assert len(pydictx["/Pages"]["/Kids"]) == 2
for p in pydictx["/Pages"]["/Kids"]:
assert p["/Resources"]["/XObject"]["/Im0"]["/ColorSpace"][2] == 127
assert len(pydicty["/Pages"]["/Kids"]) == 2
for p in pydicty["/Pages"]["/Kids"]:
cs = p["/Resources"]["/XObject"]["/Im0"]["/ColorSpace"]
cs[2] = decimal.Decimal("127")
cs[3] = cs[3][:384]
else:
assert (
pydictx["/Pages"]["/Kids"][0]["/Resources"]["/XObject"]["/Im0"][
"/ColorSpace"
][2]
== 255
)
assert pydictx == pydicty
# the python-pil version 2.3.0-1ubuntu3 in Ubuntu does not have the
# close() method

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

View file

@ -4,7 +4,7 @@
# and then run "tox" from this directory.
[tox]
envlist = py35, py36, py37, py38, py39
envlist = py37, py38, py39, py310
skip_missing_interpreters = true
[testenv]