I needed a PDF file with different page sizes for my job (1st page is A4, 2nd page is B5, etc.).
At first glance, I didn't have a tool that could create a PDF file with a different size for each page, so I made it myself in Python.
The environment used is Windows 10 Home 1903 Ver.
PyPDF2 can create empty PDF pages. However, you cannot write any object such as text or image on the created page **.
ReportLab can create a PDF with characters and figures written directly from the program code. However, ** (as far as I can see) you cannot create PDFs with different page sizes for each page **.
So roughly
Take the procedure. It's a little annoying.
This time, I want to insert pages of all sizes from A0 to C10 (I know C for the first time), so get all the page sizes defined in reportlab.lib.pagesizes
. Saw.
testpdf_creator.py
import random
import os
from pathlib import Path
from tqdm import tqdm
from PyPDF2 import PdfFileReader, PdfFileWriter
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
import reportlab.lib.pagesizes
YU_GOTHIC = Path(filter(lambda n: (Path(n) / "Fonts" / "YuGothB.ttc").exists(), os.environ.get("PATH").split(";")).__next__()) / "Fonts" / "YuGothB.ttc"
def makepage(writer, size, name):
A4 = reportlab.lib.pagesizes.A4
#Create a PDF with text
c = canvas.Canvas("base.pdf", pagesize=A4)
pdfmetrics.registerFont(TTFont("YU", YU_GOTHIC))
c.setFont('YU', 20)
c.drawString(12, 12, f"This is {name} page.")
c.drawString(12, A4[1] - 50, f"This is {name} page.")
c.rect(0, 0, A4[0], A4[1])
c.showPage()
c.save()
# Create Page
with open("base.pdf", mode="rb") as f:
r = PdfFileReader(f)
p = writer.addBlankPage(size[0], size[1])
scale = [a / b for a, b in zip(size, A4)]
p.mergeTransformedPage(r.getPage(0), [scale[0], 0, 0 , scale[1], 0, 0] , True)
if __name__ == "__main__":
writer = PdfFileWriter()
sizes = list(filter(lambda n: type(eval(f'reportlab.lib.pagesizes.{n}')) == tuple, dir(reportlab.lib.pagesizes)))
s = random.sample(sizes, 10)
for n in tqdm(s):
makepage(writer, eval(f"reportlab.lib.pagesizes.{n}"), n)
with open("multisize.pdf", mode="wb") as f:
writer.write(f)
In ReportLab, you can create a PDF file by using the Canvas
class.
However, in the canvas that can be obtained here, ** the lower left is the origin (X: 0 Y: 0) **, so be careful when drawing the figure.
If you don't like that, add bottomup = False
to the constructor of the Canvas
class.
The Canvas
object methodrect ()
takes some arguments after the X, Y coordinates, height and width, as follows:
reportlab/pdfgen/canvas.py
def rect(self, x, y, width, height, stroke=1, fill=0):
"draws a rectangle with lower left corner at (x,y) and width and height as given."
However, the values such as storke
and fill
of this argument do not indicate the values such as line width and color, but are Boolean types of whether to paint or not **.
About this, there is the following description on the 44th line of reportlab / pdfgen / canvas.py
.
reportlab/pdfgen/canvas.py
PATH_OPS = {(0, 0, FILL_EVEN_ODD) : 'n', #no op
(0, 0, FILL_NON_ZERO) : 'n', #no op
(1, 0, FILL_EVEN_ODD) : 'S', #stroke only
(1, 0, FILL_NON_ZERO) : 'S', #stroke only
(0, 1, FILL_EVEN_ODD) : 'f*', #Fill only
(0, 1, FILL_NON_ZERO) : 'f', #Fill only
(1, 1, FILL_EVEN_ODD) : 'B*', #Stroke and Fill
(1, 1, FILL_NON_ZERO) : 'B', #Stroke and Fill
The rect
method refers to this variable called PATH_OPS
, and the two arguments stroke
and fill
seem to correspond to the two values in this array.
mergeScalePage
of PyPDF2.PageObject
To create a new page in PDF with PyPDF2.PdfFileWriter
, use thePdfFileWriter # addBlankPage ()
method.
If you want to paste another page object here, use PageObject # merge *** Page ()
.
At first glance, it seems that you can go around mergeScaledPage ()
just by changing the scale, but since scale
of this method accepts only one value, it cannot be used when the vertical and horizontal scales are different.
If the vertical and horizontal scales are different, you can use mergeTransformedPage ()
. That's because mergeScaledPage ()
just calls mergeTransformedPage ()
with the same vertical and horizontal magnifications.
If you want to set the vertical to 1.5x and the horizontal to 2x, you can do as follows.
page.mergeTransformedPage('PageObject you want to add', [2, 0, 0 , 1.5, 0, 0] , True)
reportlab / lib / pagesizes.py
contains tuples that define all page size values, so we get them with the dir
function.
However, this file also defines functions such as portlait
and landscape
that reverse the height and width of the page, so remove them with the filter
function.
list(filter(lambda n: type(eval(f'reportlab.lib.pagesizes.{n}')) == tuple, dir(reportlab.lib.pagesizes)))
Recommended Posts