Skip to content

Instantly share code, notes, and snippets.

@mara004
Last active January 10, 2024 18:30
Show Gist options
  • Save mara004/f2ec2a3227624aff5270a0c676877960 to your computer and use it in GitHub Desktop.
Save mara004/f2ec2a3227624aff5270a0c676877960 to your computer and use it in GitHub Desktop.
JPEG to PDF N-up with pypdfium2
# SPDX-FileCopyrightText: 2023 mara004
# SPDX-License-Identifier: CC-BY-4.0 OR Apache-2.0 OR BSD-3-Clause
import math
import argparse
import itertools
import pypdfium2 as pdfium
from pathlib import Path
parser = argparse.ArgumentParser()
parser.add_argument("files", nargs="+", type=Path)
parser.add_argument("--output", "-o", type=Path)
args = parser.parse_args()
ROWS, COLS = 2, 2
PAGE_W, PAGE_H = 595, 842
ROTATION = 90
H_ALIGNS = ["right", "left"] # left, mid, right
V_ALIGNS = ["mid"] * ROWS # bottom, mid, top
def main():
n_tiles = ROWS*COLS
box_w, box_h = PAGE_W/COLS, PAGE_H/ROWS
n_pages = math.ceil( len(args.files) / n_tiles )
new_pdf = pdfium.PdfDocument.new()
for i in range(n_pages):
page = new_pdf.new_page(PAGE_W, PAGE_H)
for r, c in itertools.product(range(ROWS), range(COLS)):
file_idx = i*n_tiles + r*COLS + c
if not file_idx < len(args.files):
break
img = pdfium.PdfImage.new(new_pdf)
img.load_jpeg(args.files[file_idx])
page.insert_obj(img)
px_w, px_h = img.get_size()
tile_w, tile_h = box_w, box_h
if ROTATION in (90, 270):
tile_w, tile_h = tile_h, tile_w
scale = min(tile_w/px_w, tile_h/px_h)
scaled_w, scaled_h = px_w*scale, px_h*scale
w_diff, h_diff = tile_w-scaled_w, tile_h-scaled_h
tile_w, tile_h = scaled_w, scaled_h
m = pdfium.PdfMatrix()
m = m.scale(tile_w, tile_h)
if ROTATION != 0:
# TODO pypdfium2: consider adding abstraction for rotating an object around a point on itself - translating back and forth is slightly annoying
m = m.translate(-tile_w/2, -tile_h/2)
m = m.rotate(ROTATION)
if ROTATION in (90, 270):
tile_w, tile_h = tile_h, tile_w
w_diff, h_diff = h_diff, w_diff
m = m.translate(tile_w/2, tile_h/2)
pos_y = PAGE_H - box_h*(r+1)
pos_x = box_w * c
pos_x += dict(left=0, mid=w_diff/2, right=w_diff)[ H_ALIGNS[c] ]
pos_y += dict(bottom=0, mid=h_diff/2, top=h_diff)[ V_ALIGNS[r] ]
m = m.translate(pos_x, pos_y)
img.set_matrix(m)
page.gen_content()
new_pdf.save(args.output)
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment