V3.0.0 — Rotation, Annuler/Refaire, Delivretiser, Trim&Shift, Inverser
- Rotation de pages : clic droit sur vignette → Pivoter +90/-90/180 Aussi dans le menu Pages - Ctrl+Z / Ctrl+Y : annuler et refaire (pile de 20 etats) - Delivretiser : coupe les pages en 2 et remet dans l'ordre sequentiel (inverse de la creation de livret) - Trim & Shift : decaler le contenu des pages - Decalage X/Y different pages paires/impaires - Compensation de creep progressive pour livrets epais - Inverser l'ordre des pages (menu Pages) - Fix impression : ouvre le PDF dans le lecteur par defaut - Barre outils droite : ajout Delivretiser, Trim/Shift, Inverser Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
73
app/engine/unbooklet.py
Normal file
73
app/engine/unbooklet.py
Normal file
@@ -0,0 +1,73 @@
|
||||
"""Moteur Delivretiser — convertir un livret en pages sequentielles."""
|
||||
|
||||
from pypdf import PdfReader, PdfWriter, PageObject, Transformation
|
||||
from .pdf_utils import get_page_size
|
||||
import math
|
||||
|
||||
|
||||
def unbooklet(input_path, output_path):
|
||||
"""Delivretiser un PDF en format livret.
|
||||
|
||||
Chaque page du livret contient 2 pages cote a cote.
|
||||
On les coupe en 2 et on les remet dans l'ordre sequentiel.
|
||||
"""
|
||||
reader = PdfReader(input_path)
|
||||
num_sheets = len(reader.pages)
|
||||
total_pages = num_sheets * 2
|
||||
|
||||
# Extraire toutes les demi-pages
|
||||
half_pages = [] # (sheet_index, "left" ou "right")
|
||||
for i in range(num_sheets):
|
||||
half_pages.append((i, "left"))
|
||||
half_pages.append((i, "right"))
|
||||
|
||||
# Ordre du livret (piqure a cheval) :
|
||||
# Feuille 0 recto : page N, page 1
|
||||
# Feuille 0 verso : page 2, page N-1
|
||||
# Feuille 1 recto : page N-2, page 3
|
||||
# etc.
|
||||
# On reconstruit l'ordre
|
||||
page_map = {} # page_number (1-based) -> (sheet_index, side)
|
||||
n = total_pages
|
||||
for i in range(num_sheets):
|
||||
if i % 2 == 0:
|
||||
# Recto : gauche = N - i, droite = i + 1
|
||||
page_map[n - i] = (i, "left")
|
||||
page_map[i + 1] = (i, "right")
|
||||
else:
|
||||
# Verso : gauche = i + 1, droite = N - i
|
||||
page_map[i + 1] = (i, "left")
|
||||
page_map[n - i] = (i, "right")
|
||||
|
||||
writer = PdfWriter()
|
||||
|
||||
for page_num in range(1, total_pages + 1):
|
||||
if page_num not in page_map:
|
||||
continue
|
||||
sheet_idx, side = page_map[page_num]
|
||||
sheet = reader.pages[sheet_idx]
|
||||
sheet_w, sheet_h = get_page_size(sheet)
|
||||
half_w = sheet_w / 2
|
||||
|
||||
# Creer une nouvelle page avec la moitie
|
||||
new_page = PageObject.create_blank_page(width=half_w, height=sheet_h)
|
||||
|
||||
if side == "left":
|
||||
# Copier la moitie gauche
|
||||
overlay = PageObject.create_blank_page(width=half_w, height=sheet_h)
|
||||
overlay.merge_page(sheet)
|
||||
overlay.mediabox.upper_right = (half_w, sheet_h)
|
||||
new_page.merge_page(overlay)
|
||||
else:
|
||||
# Copier la moitie droite
|
||||
overlay = PageObject.create_blank_page(width=half_w, height=sheet_h)
|
||||
overlay.merge_page(sheet)
|
||||
overlay.add_transformation(Transformation().translate(-half_w, 0))
|
||||
overlay.mediabox.upper_right = (half_w, sheet_h)
|
||||
new_page.merge_page(overlay)
|
||||
|
||||
writer.add_page(new_page)
|
||||
|
||||
with open(output_path, "wb") as f:
|
||||
writer.write(f)
|
||||
return output_path
|
||||
Reference in New Issue
Block a user