mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-13 18:56:17 +03:00
Support saving PDF with different X and Y resolution.
Add a `dpi` parameter to the PDF save function, which accepts a tuple with X and Y dpi. This is useful for converting tiffg3 (fax) images to pdf, which have split dpi like (204,391), (204,196) or (204,98).
This commit is contained in:
parent
d48dca3dc4
commit
36bcc0a898
|
@ -80,6 +80,48 @@ def test_resolution(tmp_path):
|
||||||
assert size == (61.44, 61.44)
|
assert size == (61.44, 61.44)
|
||||||
|
|
||||||
|
|
||||||
|
def test_dpi(tmp_path):
|
||||||
|
im = hopper()
|
||||||
|
|
||||||
|
outfile = str(tmp_path / "temp.pdf")
|
||||||
|
im.save(outfile, dpi=(75, 150))
|
||||||
|
|
||||||
|
with open(outfile, "rb") as fp:
|
||||||
|
contents = fp.read()
|
||||||
|
|
||||||
|
size = tuple(
|
||||||
|
float(d)
|
||||||
|
for d in contents.split(b"stream\nq ")[1].split(b" 0 0 cm")[0].split(b" 0 0 ")
|
||||||
|
)
|
||||||
|
assert size == (122.88, 61.44)
|
||||||
|
|
||||||
|
size = tuple(
|
||||||
|
float(d) for d in contents.split(b"/MediaBox [ 0 0 ")[1].split(b"]")[0].split()
|
||||||
|
)
|
||||||
|
assert size == (122.88, 61.44)
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolution_and_dpi(tmp_path):
|
||||||
|
im = hopper()
|
||||||
|
|
||||||
|
outfile = str(tmp_path / "temp.pdf")
|
||||||
|
im.save(outfile, resolution=200, dpi=(75, 150))
|
||||||
|
|
||||||
|
with open(outfile, "rb") as fp:
|
||||||
|
contents = fp.read()
|
||||||
|
|
||||||
|
size = tuple(
|
||||||
|
float(d)
|
||||||
|
for d in contents.split(b"stream\nq ")[1].split(b" 0 0 cm")[0].split(b" 0 0 ")
|
||||||
|
)
|
||||||
|
assert size == (122.88, 61.44)
|
||||||
|
|
||||||
|
size = tuple(
|
||||||
|
float(d) for d in contents.split(b"/MediaBox [ 0 0 ")[1].split(b"]")[0].split()
|
||||||
|
)
|
||||||
|
assert size == (122.88, 61.44)
|
||||||
|
|
||||||
|
|
||||||
@mark_if_feature_version(
|
@mark_if_feature_version(
|
||||||
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
|
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1497,6 +1497,11 @@ The :py:meth:`~PIL.Image.Image.save` method can take the following keyword argum
|
||||||
image, will determine the physical dimensions of the page that will be
|
image, will determine the physical dimensions of the page that will be
|
||||||
saved in the PDF.
|
saved in the PDF.
|
||||||
|
|
||||||
|
**dpi**
|
||||||
|
A tuple of (x_resolution, y_resolution), with inches as the resolution
|
||||||
|
unit. If both the ``resolution`` parameter and the ``dpi`` parameter are
|
||||||
|
present, ``resolution`` will be ignored.
|
||||||
|
|
||||||
**title**
|
**title**
|
||||||
The document’s title. If not appending to an existing PDF file, this will
|
The document’s title. If not appending to an existing PDF file, this will
|
||||||
default to the filename.
|
default to the filename.
|
||||||
|
|
|
@ -53,7 +53,12 @@ def _save(im, fp, filename, save_all=False):
|
||||||
else:
|
else:
|
||||||
existing_pdf = PdfParser.PdfParser(f=fp, filename=filename, mode="w+b")
|
existing_pdf = PdfParser.PdfParser(f=fp, filename=filename, mode="w+b")
|
||||||
|
|
||||||
resolution = im.encoderinfo.get("resolution", 72.0)
|
x_resolution = y_resolution = im.encoderinfo.get("resolution", 72.0)
|
||||||
|
|
||||||
|
dpi = im.encoderinfo.get("dpi")
|
||||||
|
if dpi:
|
||||||
|
x_resolution = dpi[0]
|
||||||
|
y_resolution = dpi[1]
|
||||||
|
|
||||||
info = {
|
info = {
|
||||||
"title": None
|
"title": None
|
||||||
|
@ -214,8 +219,8 @@ def _save(im, fp, filename, save_all=False):
|
||||||
stream=stream,
|
stream=stream,
|
||||||
Type=PdfParser.PdfName("XObject"),
|
Type=PdfParser.PdfName("XObject"),
|
||||||
Subtype=PdfParser.PdfName("Image"),
|
Subtype=PdfParser.PdfName("Image"),
|
||||||
Width=width, # * 72.0 / resolution,
|
Width=width, # * 72.0 / x_resolution,
|
||||||
Height=height, # * 72.0 / resolution,
|
Height=height, # * 72.0 / y_resolution,
|
||||||
Filter=filter,
|
Filter=filter,
|
||||||
BitsPerComponent=bits,
|
BitsPerComponent=bits,
|
||||||
Decode=decode,
|
Decode=decode,
|
||||||
|
@ -235,8 +240,8 @@ def _save(im, fp, filename, save_all=False):
|
||||||
MediaBox=[
|
MediaBox=[
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
width * 72.0 / resolution,
|
width * 72.0 / x_resolution,
|
||||||
height * 72.0 / resolution,
|
height * 72.0 / y_resolution,
|
||||||
],
|
],
|
||||||
Contents=contents_refs[page_number],
|
Contents=contents_refs[page_number],
|
||||||
)
|
)
|
||||||
|
@ -245,8 +250,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 / resolution,
|
width * 72.0 / x_resolution,
|
||||||
height * 72.0 / resolution,
|
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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user