mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-14 05:36:48 +03:00
Merge branch 'main' into iptc
This commit is contained in:
commit
dcfce9487e
|
@ -1,6 +1,6 @@
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 23.3.0
|
rev: 23.7.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
args: [--target-version=py38]
|
args: [--target-version=py38]
|
||||||
|
@ -23,13 +23,13 @@ repos:
|
||||||
- id: yesqa
|
- id: yesqa
|
||||||
|
|
||||||
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
||||||
rev: v1.5.1
|
rev: v1.5.3
|
||||||
hooks:
|
hooks:
|
||||||
- id: remove-tabs
|
- id: remove-tabs
|
||||||
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$)
|
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$)
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/flake8
|
- repo: https://github.com/PyCQA/flake8
|
||||||
rev: 6.0.0
|
rev: 6.1.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
|
@ -55,7 +55,7 @@ repos:
|
||||||
- id: sphinx-lint
|
- id: sphinx-lint
|
||||||
|
|
||||||
- repo: https://github.com/tox-dev/pyproject-fmt
|
- repo: https://github.com/tox-dev/pyproject-fmt
|
||||||
rev: 0.12.1
|
rev: 0.13.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyproject-fmt
|
- id: pyproject-fmt
|
||||||
|
|
||||||
|
|
15
CHANGES.rst
15
CHANGES.rst
|
@ -5,6 +5,21 @@ Changelog (Pillow)
|
||||||
10.1.0 (unreleased)
|
10.1.0 (unreleased)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
- Read WebP duration after opening #7311
|
||||||
|
[k128, radarhere]
|
||||||
|
|
||||||
|
- Allow "loop=None" when saving GIF images #7329
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Fixed transparency when saving P mode images to PDF #7323
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Added saving LA images as PDFs #7299
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Set SMaskInData to 1 for PDFs with alpha #7316, #7317
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
- Changed Image mode property to be read-only by default #7307
|
- Changed Image mode property to be read-only by default #7307
|
||||||
[radarhere]
|
[radarhere]
|
||||||
|
|
||||||
|
|
|
@ -875,6 +875,14 @@ def test_identical_frames_to_single_frame(duration, tmp_path):
|
||||||
assert reread.info["duration"] == 8500
|
assert reread.info["duration"] == 8500
|
||||||
|
|
||||||
|
|
||||||
|
def test_loop_none(tmp_path):
|
||||||
|
out = str(tmp_path / "temp.gif")
|
||||||
|
im = Image.new("L", (100, 100), "#000")
|
||||||
|
im.save(out, loop=None)
|
||||||
|
with Image.open(out) as reread:
|
||||||
|
assert "loop" not in reread.info
|
||||||
|
|
||||||
|
|
||||||
def test_number_of_loops(tmp_path):
|
def test_number_of_loops(tmp_path):
|
||||||
number_of_loops = 2
|
number_of_loops = 2
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,22 @@ def test_save_alpha(tmp_path, mode):
|
||||||
helper_save_as_pdf(tmp_path, mode)
|
helper_save_as_pdf(tmp_path, mode)
|
||||||
|
|
||||||
|
|
||||||
|
def test_p_alpha(tmp_path):
|
||||||
|
# Arrange
|
||||||
|
outfile = str(tmp_path / "temp.pdf")
|
||||||
|
with Image.open("Tests/images/pil123p.png") as im:
|
||||||
|
assert im.mode == "P"
|
||||||
|
assert isinstance(im.info["transparency"], bytes)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
im.save(outfile)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
with open(outfile, "rb") as fp:
|
||||||
|
contents = fp.read()
|
||||||
|
assert b"\n/SMask " in contents
|
||||||
|
|
||||||
|
|
||||||
def test_monochrome(tmp_path):
|
def test_monochrome(tmp_path):
|
||||||
# Arrange
|
# Arrange
|
||||||
mode = "1"
|
mode = "1"
|
||||||
|
|
|
@ -79,7 +79,7 @@ class TestFilePng:
|
||||||
|
|
||||||
def test_sanity(self, tmp_path):
|
def test_sanity(self, tmp_path):
|
||||||
# internal version number
|
# internal version number
|
||||||
assert re.search(r"\d+\.\d+\.\d+(\.\d+)?$", features.version_codec("zlib"))
|
assert re.search(r"\d+(\.\d+){1,3}$", features.version_codec("zlib"))
|
||||||
|
|
||||||
test_file = str(tmp_path / "temp.png")
|
test_file = str(tmp_path / "temp.png")
|
||||||
|
|
||||||
|
|
|
@ -233,5 +233,4 @@ class TestFileWebp:
|
||||||
im.save(out_webp, save_all=True)
|
im.save(out_webp, save_all=True)
|
||||||
|
|
||||||
with Image.open(out_webp) as reloaded:
|
with Image.open(out_webp) as reloaded:
|
||||||
reloaded.load()
|
|
||||||
assert reloaded.info["duration"] == 1000
|
assert reloaded.info["duration"] == 1000
|
||||||
|
|
|
@ -661,15 +661,15 @@ class TestImage:
|
||||||
blank_p.palette = None
|
blank_p.palette = None
|
||||||
blank_pa.palette = None
|
blank_pa.palette = None
|
||||||
|
|
||||||
def _make_new(base_image, im, palette_result=None):
|
def _make_new(base_image, image, palette_result=None):
|
||||||
new_im = base_image._new(im)
|
new_image = base_image._new(image.im)
|
||||||
assert new_im.mode == im.mode
|
assert new_image.mode == image.mode
|
||||||
assert new_im.size == im.size
|
assert new_image.size == image.size
|
||||||
assert new_im.info == base_image.info
|
assert new_image.info == base_image.info
|
||||||
if palette_result is not None:
|
if palette_result is not None:
|
||||||
assert new_im.palette.tobytes() == palette_result.tobytes()
|
assert new_image.palette.tobytes() == palette_result.tobytes()
|
||||||
else:
|
else:
|
||||||
assert new_im.palette is None
|
assert new_image.palette is None
|
||||||
|
|
||||||
_make_new(im, im_p, ImagePalette.ImagePalette(list(range(256)) * 3))
|
_make_new(im, im_p, ImagePalette.ImagePalette(list(range(256)) * 3))
|
||||||
_make_new(im_p, im, None)
|
_make_new(im_p, im, None)
|
||||||
|
|
|
@ -253,7 +253,7 @@ their :py:attr:`~PIL.Image.Image.info` values.
|
||||||
|
|
||||||
**loop**
|
**loop**
|
||||||
Integer number of times the GIF should loop. 0 means that it will loop
|
Integer number of times the GIF should loop. 0 means that it will loop
|
||||||
forever. By default, the image will not loop.
|
forever. If omitted or ``None``, the image will not loop.
|
||||||
|
|
||||||
**comment**
|
**comment**
|
||||||
A comment about the image.
|
A comment about the image.
|
||||||
|
|
|
@ -83,10 +83,9 @@ Install Pillow with :command:`pip`::
|
||||||
.. tab:: Windows
|
.. tab:: Windows
|
||||||
|
|
||||||
We provide Pillow binaries for Windows compiled for the matrix of
|
We provide Pillow binaries for Windows compiled for the matrix of
|
||||||
supported Pythons in both 32 and 64-bit versions in the wheel format.
|
supported Pythons in 64-bit versions in the wheel format. These binaries include
|
||||||
These binaries include support for all optional libraries except
|
support for all optional libraries except libimagequant and libxcb. Raqm support
|
||||||
libimagequant and libxcb. Raqm support requires
|
requires FriBiDi to be installed separately::
|
||||||
FriBiDi to be installed separately::
|
|
||||||
|
|
||||||
python3 -m pip install --upgrade pip
|
python3 -m pip install --upgrade pip
|
||||||
python3 -m pip install --upgrade Pillow
|
python3 -m pip install --upgrade Pillow
|
||||||
|
|
|
@ -206,4 +206,4 @@ Support reading signed 8-bit TIFF images
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
TIFF images with signed integer data, 8 bits per sample and a photometric
|
TIFF images with signed integer data, 8 bits per sample and a photometric
|
||||||
interpretaton of BlackIsZero can now be read.
|
interpretation of BlackIsZero can now be read.
|
||||||
|
|
|
@ -912,7 +912,7 @@ def _get_global_header(im, info):
|
||||||
info
|
info
|
||||||
and (
|
and (
|
||||||
"transparency" in info
|
"transparency" in info
|
||||||
or "loop" in info
|
or info.get("loop") is not None
|
||||||
or info.get("duration")
|
or info.get("duration")
|
||||||
or info.get("comment")
|
or info.get("comment")
|
||||||
)
|
)
|
||||||
|
@ -937,7 +937,7 @@ def _get_global_header(im, info):
|
||||||
# Global Color Table
|
# Global Color Table
|
||||||
_get_header_palette(palette_bytes),
|
_get_header_palette(palette_bytes),
|
||||||
]
|
]
|
||||||
if "loop" in info:
|
if info.get("loop") is not None:
|
||||||
header.append(
|
header.append(
|
||||||
b"!"
|
b"!"
|
||||||
+ o8(255) # extension intro
|
+ o8(255) # extension intro
|
||||||
|
|
|
@ -247,7 +247,7 @@ def eval(expression, _dict={}, **kw):
|
||||||
|
|
||||||
def scan(code):
|
def scan(code):
|
||||||
for const in code.co_consts:
|
for const in code.co_consts:
|
||||||
if type(const) == type(compiled_code):
|
if type(const) is type(compiled_code):
|
||||||
scan(const)
|
scan(const)
|
||||||
|
|
||||||
for name in code.co_names:
|
for name in code.co_names:
|
||||||
|
|
|
@ -46,6 +46,132 @@ def _save_all(im, fp, filename):
|
||||||
# (Internal) Image save plugin for the PDF format.
|
# (Internal) Image save plugin for the PDF format.
|
||||||
|
|
||||||
|
|
||||||
|
def _write_image(im, filename, existing_pdf, image_refs):
|
||||||
|
# FIXME: Should replace ASCIIHexDecode with RunLengthDecode
|
||||||
|
# (packbits) or LZWDecode (tiff/lzw compression). Note that
|
||||||
|
# PDF 1.2 also supports Flatedecode (zip compression).
|
||||||
|
|
||||||
|
params = None
|
||||||
|
decode = None
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get image characteristics
|
||||||
|
|
||||||
|
width, height = im.size
|
||||||
|
|
||||||
|
dict_obj = {"BitsPerComponent": 8}
|
||||||
|
if im.mode == "1":
|
||||||
|
if features.check("libtiff"):
|
||||||
|
filter = "CCITTFaxDecode"
|
||||||
|
dict_obj["BitsPerComponent"] = 1
|
||||||
|
params = PdfParser.PdfArray(
|
||||||
|
[
|
||||||
|
PdfParser.PdfDict(
|
||||||
|
{
|
||||||
|
"K": -1,
|
||||||
|
"BlackIs1": True,
|
||||||
|
"Columns": width,
|
||||||
|
"Rows": height,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
filter = "DCTDecode"
|
||||||
|
dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceGray")
|
||||||
|
procset = "ImageB" # grayscale
|
||||||
|
elif im.mode == "L":
|
||||||
|
filter = "DCTDecode"
|
||||||
|
# params = f"<< /Predictor 15 /Columns {width-2} >>"
|
||||||
|
dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceGray")
|
||||||
|
procset = "ImageB" # grayscale
|
||||||
|
elif im.mode == "LA":
|
||||||
|
filter = "JPXDecode"
|
||||||
|
# params = f"<< /Predictor 15 /Columns {width-2} >>"
|
||||||
|
procset = "ImageB" # grayscale
|
||||||
|
dict_obj["SMaskInData"] = 1
|
||||||
|
elif im.mode == "P":
|
||||||
|
filter = "ASCIIHexDecode"
|
||||||
|
palette = im.getpalette()
|
||||||
|
dict_obj["ColorSpace"] = [
|
||||||
|
PdfParser.PdfName("Indexed"),
|
||||||
|
PdfParser.PdfName("DeviceRGB"),
|
||||||
|
255,
|
||||||
|
PdfParser.PdfBinary(palette),
|
||||||
|
]
|
||||||
|
procset = "ImageI" # indexed color
|
||||||
|
|
||||||
|
if "transparency" in im.info:
|
||||||
|
smask = im.convert("LA").getchannel("A")
|
||||||
|
smask.encoderinfo = {}
|
||||||
|
|
||||||
|
image_ref = _write_image(smask, filename, existing_pdf, image_refs)[0]
|
||||||
|
dict_obj["SMask"] = image_ref
|
||||||
|
elif im.mode == "RGB":
|
||||||
|
filter = "DCTDecode"
|
||||||
|
dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceRGB")
|
||||||
|
procset = "ImageC" # color images
|
||||||
|
elif im.mode == "RGBA":
|
||||||
|
filter = "JPXDecode"
|
||||||
|
procset = "ImageC" # color images
|
||||||
|
dict_obj["SMaskInData"] = 1
|
||||||
|
elif im.mode == "CMYK":
|
||||||
|
filter = "DCTDecode"
|
||||||
|
dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceCMYK")
|
||||||
|
procset = "ImageC" # color images
|
||||||
|
decode = [1, 0, 1, 0, 1, 0, 1, 0]
|
||||||
|
else:
|
||||||
|
msg = f"cannot save mode {im.mode}"
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
#
|
||||||
|
# image
|
||||||
|
|
||||||
|
op = io.BytesIO()
|
||||||
|
|
||||||
|
if filter == "ASCIIHexDecode":
|
||||||
|
ImageFile._save(im, op, [("hex", (0, 0) + im.size, 0, im.mode)])
|
||||||
|
elif filter == "CCITTFaxDecode":
|
||||||
|
im.save(
|
||||||
|
op,
|
||||||
|
"TIFF",
|
||||||
|
compression="group4",
|
||||||
|
# use a single strip
|
||||||
|
strip_size=math.ceil(width / 8) * height,
|
||||||
|
)
|
||||||
|
elif filter == "DCTDecode":
|
||||||
|
Image.SAVE["JPEG"](im, op, filename)
|
||||||
|
elif filter == "JPXDecode":
|
||||||
|
del dict_obj["BitsPerComponent"]
|
||||||
|
Image.SAVE["JPEG2000"](im, op, filename)
|
||||||
|
else:
|
||||||
|
msg = f"unsupported PDF filter ({filter})"
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
stream = op.getvalue()
|
||||||
|
if filter == "CCITTFaxDecode":
|
||||||
|
stream = stream[8:]
|
||||||
|
filter = PdfParser.PdfArray([PdfParser.PdfName(filter)])
|
||||||
|
else:
|
||||||
|
filter = PdfParser.PdfName(filter)
|
||||||
|
|
||||||
|
image_ref = image_refs.pop(0)
|
||||||
|
existing_pdf.write_obj(
|
||||||
|
image_ref,
|
||||||
|
stream=stream,
|
||||||
|
Type=PdfParser.PdfName("XObject"),
|
||||||
|
Subtype=PdfParser.PdfName("Image"),
|
||||||
|
Width=width, # * 72.0 / x_resolution,
|
||||||
|
Height=height, # * 72.0 / y_resolution,
|
||||||
|
Filter=filter,
|
||||||
|
Decode=decode,
|
||||||
|
DecodeParms=params,
|
||||||
|
**dict_obj,
|
||||||
|
)
|
||||||
|
|
||||||
|
return image_ref, procset
|
||||||
|
|
||||||
|
|
||||||
def _save(im, fp, filename, save_all=False):
|
def _save(im, fp, filename, save_all=False):
|
||||||
is_appending = im.encoderinfo.get("append", False)
|
is_appending = im.encoderinfo.get("append", False)
|
||||||
if is_appending:
|
if is_appending:
|
||||||
|
@ -109,6 +235,9 @@ def _save(im, fp, filename, save_all=False):
|
||||||
number_of_pages += im_number_of_pages
|
number_of_pages += im_number_of_pages
|
||||||
for i in range(im_number_of_pages):
|
for i in range(im_number_of_pages):
|
||||||
image_refs.append(existing_pdf.next_object_id(0))
|
image_refs.append(existing_pdf.next_object_id(0))
|
||||||
|
if im.mode == "P" and "transparency" in im.info:
|
||||||
|
image_refs.append(existing_pdf.next_object_id(0))
|
||||||
|
|
||||||
page_refs.append(existing_pdf.next_object_id(0))
|
page_refs.append(existing_pdf.next_object_id(0))
|
||||||
contents_refs.append(existing_pdf.next_object_id(0))
|
contents_refs.append(existing_pdf.next_object_id(0))
|
||||||
existing_pdf.pages.append(page_refs[-1])
|
existing_pdf.pages.append(page_refs[-1])
|
||||||
|
@ -121,123 +250,7 @@ def _save(im, fp, filename, save_all=False):
|
||||||
for im_sequence in ims:
|
for im_sequence in ims:
|
||||||
im_pages = ImageSequence.Iterator(im_sequence) if save_all else [im_sequence]
|
im_pages = ImageSequence.Iterator(im_sequence) if save_all else [im_sequence]
|
||||||
for im in im_pages:
|
for im in im_pages:
|
||||||
# FIXME: Should replace ASCIIHexDecode with RunLengthDecode
|
image_ref, procset = _write_image(im, filename, existing_pdf, image_refs)
|
||||||
# (packbits) or LZWDecode (tiff/lzw compression). Note that
|
|
||||||
# PDF 1.2 also supports Flatedecode (zip compression).
|
|
||||||
|
|
||||||
params = None
|
|
||||||
decode = None
|
|
||||||
|
|
||||||
#
|
|
||||||
# Get image characteristics
|
|
||||||
|
|
||||||
width, height = im.size
|
|
||||||
|
|
||||||
dict_obj = {"BitsPerComponent": 8}
|
|
||||||
if im.mode == "1":
|
|
||||||
if features.check("libtiff"):
|
|
||||||
filter = "CCITTFaxDecode"
|
|
||||||
dict_obj["BitsPerComponent"] = 1
|
|
||||||
params = PdfParser.PdfArray(
|
|
||||||
[
|
|
||||||
PdfParser.PdfDict(
|
|
||||||
{
|
|
||||||
"K": -1,
|
|
||||||
"BlackIs1": True,
|
|
||||||
"Columns": width,
|
|
||||||
"Rows": height,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
filter = "DCTDecode"
|
|
||||||
dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceGray")
|
|
||||||
procset = "ImageB" # grayscale
|
|
||||||
elif im.mode == "L":
|
|
||||||
filter = "DCTDecode"
|
|
||||||
# params = f"<< /Predictor 15 /Columns {width-2} >>"
|
|
||||||
dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceGray")
|
|
||||||
procset = "ImageB" # grayscale
|
|
||||||
elif im.mode == "LA":
|
|
||||||
filter = "JPXDecode"
|
|
||||||
# params = f"<< /Predictor 15 /Columns {width-2} >>"
|
|
||||||
procset = "ImageB" # grayscale
|
|
||||||
dict_obj["SMaskInData"] = 1
|
|
||||||
elif im.mode == "P":
|
|
||||||
filter = "ASCIIHexDecode"
|
|
||||||
palette = im.getpalette()
|
|
||||||
dict_obj["ColorSpace"] = [
|
|
||||||
PdfParser.PdfName("Indexed"),
|
|
||||||
PdfParser.PdfName("DeviceRGB"),
|
|
||||||
255,
|
|
||||||
PdfParser.PdfBinary(palette),
|
|
||||||
]
|
|
||||||
procset = "ImageI" # indexed color
|
|
||||||
elif im.mode == "RGB":
|
|
||||||
filter = "DCTDecode"
|
|
||||||
dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceRGB")
|
|
||||||
procset = "ImageC" # color images
|
|
||||||
elif im.mode == "RGBA":
|
|
||||||
filter = "JPXDecode"
|
|
||||||
procset = "ImageC" # color images
|
|
||||||
dict_obj["SMaskInData"] = 1
|
|
||||||
elif im.mode == "CMYK":
|
|
||||||
filter = "DCTDecode"
|
|
||||||
dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceCMYK")
|
|
||||||
procset = "ImageC" # color images
|
|
||||||
decode = [1, 0, 1, 0, 1, 0, 1, 0]
|
|
||||||
else:
|
|
||||||
msg = f"cannot save mode {im.mode}"
|
|
||||||
raise ValueError(msg)
|
|
||||||
|
|
||||||
#
|
|
||||||
# image
|
|
||||||
|
|
||||||
op = io.BytesIO()
|
|
||||||
|
|
||||||
if filter == "ASCIIHexDecode":
|
|
||||||
ImageFile._save(im, op, [("hex", (0, 0) + im.size, 0, im.mode)])
|
|
||||||
elif filter == "CCITTFaxDecode":
|
|
||||||
im.save(
|
|
||||||
op,
|
|
||||||
"TIFF",
|
|
||||||
compression="group4",
|
|
||||||
# use a single strip
|
|
||||||
strip_size=math.ceil(im.width / 8) * im.height,
|
|
||||||
)
|
|
||||||
elif filter == "DCTDecode":
|
|
||||||
Image.SAVE["JPEG"](im, op, filename)
|
|
||||||
elif filter == "JPXDecode":
|
|
||||||
del dict_obj["BitsPerComponent"]
|
|
||||||
Image.SAVE["JPEG2000"](im, op, filename)
|
|
||||||
elif filter == "FlateDecode":
|
|
||||||
ImageFile._save(im, op, [("zip", (0, 0) + im.size, 0, im.mode)])
|
|
||||||
elif filter == "RunLengthDecode":
|
|
||||||
ImageFile._save(im, op, [("packbits", (0, 0) + im.size, 0, im.mode)])
|
|
||||||
else:
|
|
||||||
msg = f"unsupported PDF filter ({filter})"
|
|
||||||
raise ValueError(msg)
|
|
||||||
|
|
||||||
stream = op.getvalue()
|
|
||||||
if filter == "CCITTFaxDecode":
|
|
||||||
stream = stream[8:]
|
|
||||||
filter = PdfParser.PdfArray([PdfParser.PdfName(filter)])
|
|
||||||
else:
|
|
||||||
filter = PdfParser.PdfName(filter)
|
|
||||||
|
|
||||||
existing_pdf.write_obj(
|
|
||||||
image_refs[page_number],
|
|
||||||
stream=stream,
|
|
||||||
Type=PdfParser.PdfName("XObject"),
|
|
||||||
Subtype=PdfParser.PdfName("Image"),
|
|
||||||
Width=width, # * 72.0 / x_resolution,
|
|
||||||
Height=height, # * 72.0 / y_resolution,
|
|
||||||
Filter=filter,
|
|
||||||
Decode=decode,
|
|
||||||
DecodeParms=params,
|
|
||||||
**dict_obj,
|
|
||||||
)
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# page
|
# page
|
||||||
|
@ -246,13 +259,13 @@ def _save(im, fp, filename, save_all=False):
|
||||||
page_refs[page_number],
|
page_refs[page_number],
|
||||||
Resources=PdfParser.PdfDict(
|
Resources=PdfParser.PdfDict(
|
||||||
ProcSet=[PdfParser.PdfName("PDF"), PdfParser.PdfName(procset)],
|
ProcSet=[PdfParser.PdfName("PDF"), PdfParser.PdfName(procset)],
|
||||||
XObject=PdfParser.PdfDict(image=image_refs[page_number]),
|
XObject=PdfParser.PdfDict(image=image_ref),
|
||||||
),
|
),
|
||||||
MediaBox=[
|
MediaBox=[
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
width * 72.0 / x_resolution,
|
im.width * 72.0 / x_resolution,
|
||||||
height * 72.0 / y_resolution,
|
im.height * 72.0 / y_resolution,
|
||||||
],
|
],
|
||||||
Contents=contents_refs[page_number],
|
Contents=contents_refs[page_number],
|
||||||
)
|
)
|
||||||
|
@ -261,8 +274,8 @@ def _save(im, fp, filename, save_all=False):
|
||||||
# page contents
|
# page contents
|
||||||
|
|
||||||
page_contents = b"q %f 0 0 %f 0 0 cm /image Do Q\n" % (
|
page_contents = b"q %f 0 0 %f 0 0 cm /image Do Q\n" % (
|
||||||
width * 72.0 / x_resolution,
|
im.width * 72.0 / x_resolution,
|
||||||
height * 72.0 / y_resolution,
|
im.height * 72.0 / y_resolution,
|
||||||
)
|
)
|
||||||
|
|
||||||
existing_pdf.write_obj(contents_refs[page_number], stream=page_contents)
|
existing_pdf.write_obj(contents_refs[page_number], stream=page_contents)
|
||||||
|
|
|
@ -74,6 +74,9 @@ class WebPImageFile(ImageFile.ImageFile):
|
||||||
self.info["background"] = (bg_r, bg_g, bg_b, bg_a)
|
self.info["background"] = (bg_r, bg_g, bg_b, bg_a)
|
||||||
self.n_frames = frame_count
|
self.n_frames = frame_count
|
||||||
self.is_animated = self.n_frames > 1
|
self.is_animated = self.n_frames > 1
|
||||||
|
ret = self._decoder.get_next()
|
||||||
|
if ret is not None:
|
||||||
|
self.info["duration"] = ret[1]
|
||||||
self._mode = "RGB" if mode == "RGBX" else mode
|
self._mode = "RGB" if mode == "RGBX" else mode
|
||||||
self.rawmode = mode
|
self.rawmode = mode
|
||||||
self.tile = []
|
self.tile = []
|
||||||
|
@ -90,7 +93,7 @@ class WebPImageFile(ImageFile.ImageFile):
|
||||||
self.info["xmp"] = xmp
|
self.info["xmp"] = xmp
|
||||||
|
|
||||||
# Initialize seek state
|
# Initialize seek state
|
||||||
self._reset(reset=False)
|
self._reset()
|
||||||
|
|
||||||
def _getexif(self):
|
def _getexif(self):
|
||||||
if "exif" not in self.info:
|
if "exif" not in self.info:
|
||||||
|
@ -113,9 +116,8 @@ class WebPImageFile(ImageFile.ImageFile):
|
||||||
# Set logical frame to requested position
|
# Set logical frame to requested position
|
||||||
self.__logical_frame = frame
|
self.__logical_frame = frame
|
||||||
|
|
||||||
def _reset(self, reset=True):
|
def _reset(self):
|
||||||
if reset:
|
self._decoder.reset()
|
||||||
self._decoder.reset()
|
|
||||||
self.__physical_frame = 0
|
self.__physical_frame = 0
|
||||||
self.__loaded = -1
|
self.__loaded = -1
|
||||||
self.__timestamp = 0
|
self.__timestamp = 0
|
||||||
|
|
|
@ -130,9 +130,9 @@ deps = {
|
||||||
"bins": ["cjpeg.exe", "djpeg.exe"],
|
"bins": ["cjpeg.exe", "djpeg.exe"],
|
||||||
},
|
},
|
||||||
"zlib": {
|
"zlib": {
|
||||||
"url": "https://zlib.net/zlib1213.zip",
|
"url": "https://zlib.net/zlib13.zip",
|
||||||
"filename": "zlib1213.zip",
|
"filename": "zlib13.zip",
|
||||||
"dir": "zlib-1.2.13",
|
"dir": "zlib-1.3",
|
||||||
"license": "README",
|
"license": "README",
|
||||||
"license_pattern": "Copyright notice:\n\n(.+)$",
|
"license_pattern": "Copyright notice:\n\n(.+)$",
|
||||||
"build": [
|
"build": [
|
||||||
|
@ -335,9 +335,9 @@ deps = {
|
||||||
"libs": [r"imagequant.lib"],
|
"libs": [r"imagequant.lib"],
|
||||||
},
|
},
|
||||||
"harfbuzz": {
|
"harfbuzz": {
|
||||||
"url": "https://github.com/harfbuzz/harfbuzz/archive/8.0.0.zip",
|
"url": "https://github.com/harfbuzz/harfbuzz/archive/8.1.1.zip",
|
||||||
"filename": "harfbuzz-8.0.0.zip",
|
"filename": "harfbuzz-8.1.1.zip",
|
||||||
"dir": "harfbuzz-8.0.0",
|
"dir": "harfbuzz-8.1.1",
|
||||||
"license": "COPYING",
|
"license": "COPYING",
|
||||||
"build": [
|
"build": [
|
||||||
*cmds_cmake(
|
*cmds_cmake(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user