[PYTHON] Create a PDF file with a random page size

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.

Things to prepare

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

  1. Create a one-page PDF file with ReportLab
  2. Read 1 with PyPDF2.PdfFileReader
  3. PyPDF2.Paste 2 into the PDF created by PdfFileWriter

Take the procedure. It's a little annoying.

code

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)

Where I was careful

About Canvas in Report Lab

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.

About Canvas object methods

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.

About 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)

To get the values for all existing page sizes

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)))

References

Recommended Posts

Create a PDF file with a random page size
Create a 1MByte random number file
Create a file uploader with Django
Create a large text file with shellscript
Create a VM with a YAML file (KVM)
Create a GUI executable file created with tkinter
A4 size with python-pptx
Create a page that loads infinitely with python
Create a new page in confluence with Python
Create a Photoshop format file (.psd) with python
Create a cylinder with open3d + STL file output
Create a Todo app with Django ③ Create a task list page
Create a random number with an arbitrary probability density
[Python] Create a Tkinter program distribution file with cx_Freeze
Create a 2d CAD file ".dxf" with python [ezdxf]
Create a homepage with django
Create a dummy data file
Create a heatmap with pyqtgraph
Create a directory with python
Create xlsx file with XlsxWriter
Create a PythonBox that outputs with Random after PEPPER Input
How to put a hyperlink to "file: // hogehoge" with sphinx-> pdf
[Python] Create a file & folder path specification screen with tkinter
Probably the easiest way to create a pdf with Python3
Build a deb file with Docker
Create a virtual environment with Python!
Create an Excel file with Python3
Create a binary file in Python
Create a poisson stepper with numpy.random
Create a random string in Python
How to create a config file
Create a temporary file with django as a zip file and return it
Web App Development Practice: Create a Shift Creation Page with Django! (Shift creation page)
[Python] Read a csv file with a large data size using a generator
Create and return a CP932 CSV file for Excel with Chalice
Create a compatibility judgment program with the random module of python.
Create a Python function decorator with Class
Creating a simple PowerPoint file with Python
Build a blockchain with Python ① Create a class
Create a dummy image with Python + PIL.
[Python] Create a virtual environment with Anaconda
Let's create a free group with Python
Web App Development Practice: Create a Shift Creation Page with Django! (Introduction)
Quickly create an excel file with Python #python
Create a GUI app with Python's Tkinter
Test & Debug Tips: Create a file of the specified size in Python
Create a star system with Blender 2.80 script
Create a virtual environment with Python_Mac version
Create a simple web app with flask
Create Excel file with Python + similarity matrix
Create a word frequency counter with Python 3.4
Create a deb file from a python package
[GPS] Create a kml file in Python
Create a Connecting Nearest Neighbor with NetworkX
Script to create a Mac dictionary file
Create a web service with Docker + Flask
Create Page / Todo Block with Notion API
Check the file size with du -sh *
Read a character data file with numpy
Create a private repository with AWS CodeArtifact
Create a car meter with raspberry pi