Skip to content

Commit

Permalink
DOC: merge_transformed_page() (#1647)
Browse files Browse the repository at this point in the history
Several issues could have been avoided if the example in this PR existed before, e.g. #1630, #1426

Co-authored-by: Louis <[email protected]>
  • Loading branch information
paternal and Louis authored Feb 25, 2023
1 parent f98ff02 commit cc32b59
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 19 deletions.
39 changes: 20 additions & 19 deletions docs/user/add-watermark.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ Adding stamps or watermarks are two common ways to manipulate PDF files.
A stamp is adding something on top of the document, a watermark is in the
background of the document.

In both cases you might want to ensure that the mediabox/cropbox of the original
content stays the same.

## Stamp (Overlay)

Using the ``Transformation()`` class, one can translate, rotate, scale, etc. the stamp before merging it to the content page.

```python
from pathlib import Path
from typing import Union, Literal, List
Expand All @@ -22,8 +21,7 @@ def stamp(
pdf_result: Path,
page_indices: Union[Literal["ALL"], List[int]] = "ALL",
):
reader = PdfReader(stamp_pdf)
image_page = reader.pages[0]
stamp_page = PdfReader(stamp_pdf).pages[0]

writer = PdfWriter()

Expand All @@ -32,9 +30,10 @@ def stamp(
page_indices = list(range(0, len(reader.pages)))
for index in page_indices:
content_page = reader.pages[index]
mediabox = content_page.mediabox
content_page.merge_page(image_page)
content_page.mediabox = mediabox
content_page.merge_transformed_page(
stamp_page,
Transformation(),
)
writer.add_page(content_page)

with open(pdf_result, "wb") as fp:
Expand All @@ -45,11 +44,15 @@ def stamp(

## Watermark (Underlay)

To merge the watermark *under* the content, use the argument ``over=False`` of the method ``merge_transformed_page()``.

Once again, watermark size and position (and more) can be customized using the ``Transformation()`` class.

```python
from pathlib import Path
from typing import Union, Literal, List

from pypdf import PdfWriter, PdfReader
from pypdf import PdfWriter, PdfReader, Transformation


def watermark(
Expand All @@ -60,20 +63,18 @@ def watermark(
):
reader = PdfReader(content_pdf)
if page_indices == "ALL":
page_indices = list(range(0, len(reader.pages)))
page_indices = range(len(reader.pages))

writer = PdfWriter()
watermark_page = PdfReader(stamp_pdf).pages[0]
for index in page_indices:
content_page = reader.pages[index]
mediabox = content_page.mediabox

# You need to load it again, as the last time it was overwritten
reader_stamp = PdfReader(stamp_pdf)
image_page = reader_stamp.pages[0]

image_page.merge_page(content_page)
image_page.mediabox = mediabox
writer.add_page(image_page)
content_page.merge_transformed_page(
watermark_page,
Transformation(),
over=False,
)
writer.add_page(content_page)

with open(pdf_result, "wb") as fp:
writer.write(fp)
Expand Down
83 changes: 83 additions & 0 deletions docs/user/cropping-and-transforming.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,86 @@ In the mean time, you can add the following code to get the old behavior:
```python
pypdf._page.MERGE_CROP_BOX = "trimbox"
```

# Transforming several copies of the same page

We have designed the following business card (A8 format) to advertize our new startup.

![](nup-source.png)

We would like to copy this card sixteen times on an A4 page, to print it, cut it, and give it to all our friends. Having learned about the ``merge_page()`` method and the ``Transformation`` class, we run the following code. Notice that we had to tweak the media box of the source page to extend it, which is already a dirty hack (in this case).

```python
from pypdf import PdfReader, PdfWriter, Transformation, PaperSize

# Read source file
reader = PdfReader("nup-source.pdf")
sourcepage = reader.pages[0]

# Create a destination file, and add a blank page to it
writer = PdfWriter()
destpage = writer.add_blank_page(width=PaperSize.A4.height, height=PaperSize.A4.width)

# Extend source page mediabox
sourcepage.mediabox = destpage.mediabox

# Copy source page to destination page, several times
for x in range(4):
for y in range(4):
# Translate page
sourcepage.add_transformation(
Transformation().translate(
x * PaperSize.A8.height,
y * PaperSize.A8.width,
)
)
# Merge translated page
destpage.merge_page(sourcepage)

# Write file
with open("nup-dest1.pdf", "wb") as fp:
writer.write(fp)
```

And the result is… unexpected.

![](nup-dest1.png)

The problem is that, having run ``add.transformation()`` several times on the *same* source page, those transformations add up: for instance, the sixteen transformations are applied to the last copy of the source page, so most of the business cards are *outside* the destination page.

We need a way to merge a transformed page, *without* modifying the source page. Here comes ``merge_transformed_page()``. With this method:
- we no longer need the media box hack of our first try;
- transformations are only applied *once*.

```python
from pypdf import PdfReader, PdfWriter, Transformation, PaperSize

# Read source file
reader = PdfReader("nup-source.pdf")
sourcepage = reader.pages[0]

# Create a destination file, and add a blank page to it
writer = PdfWriter()
destpage = writer.add_blank_page(width=PaperSize.A4.height, height=PaperSize.A4.width)

# Copy source page to destination page, several times
for x in range(4):
for y in range(4):
destpage.merge_transformed_page(
sourcepage,
Transformation().translate(
x * sourcepage.mediabox.width,
y * sourcepage.mediabox.height,
),
)

# Write file
with open("nup-dest2.pdf", "wb") as fp:
writer.write(fp)
```

We get the expected result.

![](nup-dest2.png)

There is still some work to do, for instance to insert margins between and around cards, but this is left as an exercise for the reader…
Binary file added docs/user/nup-dest1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/user/nup-dest2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/user/nup-source.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit cc32b59

Please sign in to comment.