Skip to content

Commit

Permalink
Merge pull request #6961 from jvanderneutstulen/add-save-pdf-dpi-tuple
Browse files Browse the repository at this point in the history
Support saving PDF with different X and Y resolution
  • Loading branch information
radarhere committed Feb 24, 2023
2 parents 29adca3 + 3c3d888 commit 4777379
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 7 deletions.
28 changes: 28 additions & 0 deletions Tests/test_file_pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,34 @@ def test_resolution(tmp_path):
assert size == (61.44, 61.44)


@pytest.mark.parametrize(
"params",
(
{"dpi": (75, 150)},
{"dpi": (75, 150), "resolution": 200},
),
)
def test_dpi(params, tmp_path):
im = hopper()

outfile = str(tmp_path / "temp.pdf")
im.save(outfile, **params)

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(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
)
Expand Down
5 changes: 5 additions & 0 deletions docs/handbook/image-file-formats.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
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**
The document’s title. If not appending to an existing PDF file, this will
default to the filename.
Expand Down
19 changes: 12 additions & 7 deletions src/PIL/PdfImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ def _save(im, fp, filename, save_all=False):
else:
existing_pdf = PdfParser.PdfParser(f=fp, filename=filename, mode="w+b")

resolution = im.encoderinfo.get("resolution", 72.0)
dpi = im.encoderinfo.get("dpi")
if dpi:
x_resolution = dpi[0]
y_resolution = dpi[1]
else:
x_resolution = y_resolution = im.encoderinfo.get("resolution", 72.0)

info = {
"title": None
Expand Down Expand Up @@ -214,8 +219,8 @@ def _save(im, fp, filename, save_all=False):
stream=stream,
Type=PdfParser.PdfName("XObject"),
Subtype=PdfParser.PdfName("Image"),
Width=width, # * 72.0 / resolution,
Height=height, # * 72.0 / resolution,
Width=width, # * 72.0 / x_resolution,
Height=height, # * 72.0 / y_resolution,
Filter=filter,
BitsPerComponent=bits,
Decode=decode,
Expand All @@ -235,8 +240,8 @@ def _save(im, fp, filename, save_all=False):
MediaBox=[
0,
0,
width * 72.0 / resolution,
height * 72.0 / resolution,
width * 72.0 / x_resolution,
height * 72.0 / y_resolution,
],
Contents=contents_refs[page_number],
)
Expand All @@ -245,8 +250,8 @@ def _save(im, fp, filename, save_all=False):
# page contents

page_contents = b"q %f 0 0 %f 0 0 cm /image Do Q\n" % (
width * 72.0 / resolution,
height * 72.0 / resolution,
width * 72.0 / x_resolution,
height * 72.0 / y_resolution,
)

existing_pdf.write_obj(contents_refs[page_number], stream=page_contents)
Expand Down

0 comments on commit 4777379

Please sign in to comment.