Skip to content

Instantly share code, notes, and snippets.



Last active Apr 14, 2021
What would you like to do?
PDF Zine generator with fpdf
from fpdf import FPDF
A script for generating A5 size pdf zines
with a text-file input, under development,
GPL3 Licence, Mara Karagianni, April 2021
# Variables
header_font = 'helvetica'
header_font_size = 14
text_font = 'helvetica'
text_font_size = 10
top_margin = 15
left_margin = 20
right_margin = 20
left_max_margin = 160
max_height = 166
left_x = 20
top_y = 30
cell_width = 120
cell_header_height = 16
cell_height = 8
# Image variables
img_x = 20
img_y = 80
img_len = 120
# file to get the text
filename = "./notes_sample"
class Zine(FPDF):
def add_new_signature(self, top_margin, left_margin, right_margin):
# create new page/signature
self.set_margins(top_margin, left_margin, right_margin)
self.set_xy(left_margin, top_margin)
def move_to_page_right(self, top_margin, left_max_margin, right_margin):
self.set_margins(top_margin, left_max_margin, right_margin)
self.set_xy(left_max_margin, top_margin)
def position_img(self, img_filename, img_x, img_y):
import subprocess
img_size =
["identify", "-format",
"%[fx:w/72] by %[fx:h/72] inches",
"./%s" % img_filename],
stdout=subprocess.PIPE, text=True)
img_height_inches = img_size.stdout.split(' ')[2]
img_width_inches = img_size.stdout.split(' ')[0]
img_height_mm = float(img_height_inches) * float(24.5)
img_width_mm = float(img_width_inches) * float(24.5)
previous_y = self.get_y()
self.image(img_filename, img_x, img_y, img_width_mm)
# use identify to get the image height and move current y
# to bottom of the image
self.set_xy(self.get_x(), previous_y+img_height_mm)
def create_pages(self, filename, max_height, left_margin,
left_max_margin, top_margin, right_margin,
cell_width, cell_height):
index = 0
text = open(filename).readlines()
for line in text:
if index > len(text)-1:
# check if we have an image
if "<img>" in line:
img_filename = line.split("<img>")[1]
self.position_img(img_filename, self.get_x(), self.get_y())
# Ommit the image line from writing it as text input
index += 1
# check current page height and if we are in the right side of page
if self.get_y() >= max_height and self.get_x() == left_max_margin:
self.add_new_signature(top_margin, left_margin, right_margin)
if self.get_y() >= max_height:
print("ADD NEW PAGE")
self.move_to_page_right(top_margin, left_max_margin, right_margin)
except AttributeError:
# first page
print("FIRST PAGE")
self.set_margins(top=top_margin, left=left_margin,
# for first page text should go bit lower than top margin to make
# space for the header
self.set_xy(left_margin, top_margin+9)
variable_x = self.get_x()
self.multi_cell(cell_width, cell_height, text[index], 0, align='L')
self.set_xy(variable_x, self.get_y())
index += 1
# set font for all text
zine = Zine(orientation="L", unit="mm", format="A4")
# TODO move to a header function the lines below
# Header
title = 'Python Mailman Migrations'
#zine.set_font(header_font, 'B', header_font_size)
#zine.cell(cell_width, cell_header_height, title, 0, ln=1, align='C')
# left_x, top_y, left_x+cell_width, top_y,
# dash_length=3, space_length=3)
zine.set_font(text_font, size=text_font_size)
zine.create_pages(filename, max_height, left_margin, left_max_margin,
top_margin, right_margin, cell_width, cell_height)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment