V3.3.0 — Edition contenu, actions CLI, menu contextuel enrichi

- Edition de contenu PDF (Annotations > Editer le contenu) :
  - Onglet Texte : liste le texte detecte, masquer des lignes
  - Onglet Images : liste les images, remplacer ou masquer
- Actions en ligne de commande (--action booklet_a4|booklet_a3|nup_2x2|unbooklet)
- Menu contextuel Windows enrichi :
  - Ouvrir, Livret A4, Livret A3, 2x2 par feuille, Delivretiser
- Bouton Editer dans la barre d'outils droite

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jules
2026-03-21 16:33:43 +01:00
parent 202a4fc536
commit 2fcc92dbd9
7 changed files with 324 additions and 7 deletions

View File

@@ -0,0 +1,90 @@
"""Extraction de texte et images depuis un PDF."""
from pypdf import PdfReader
from .pdf_utils import get_page_size
def extract_text_from_page(input_path, page_index):
"""Extraire le texte d'une page avec positions approximatives."""
reader = PdfReader(input_path)
if page_index >= len(reader.pages):
return []
page = reader.pages[page_index]
text = page.extract_text() or ""
lines = text.split("\n")
w, h = get_page_size(page)
# Positions approximatives (pypdf ne donne pas les coords exactes)
results = []
line_height = h / max(len(lines), 1)
for i, line in enumerate(lines):
if line.strip():
results.append({
"text": line.strip(),
"y_approx": h - (i + 1) * line_height,
"line_index": i,
})
return results
def extract_images_from_page(input_path, page_index):
"""Extraire les images d'une page."""
reader = PdfReader(input_path)
if page_index >= len(reader.pages):
return []
page = reader.pages[page_index]
images = []
if "/XObject" in page["/Resources"]:
xobjects = page["/Resources"]["/XObject"].get_object()
for obj_name in xobjects:
obj = xobjects[obj_name].get_object()
if obj["/Subtype"] == "/Image":
width = obj["/Width"]
height = obj["/Height"]
images.append({
"name": obj_name,
"width": width,
"height": height,
})
return images
def replace_image_in_page(input_path, output_path, page_index, image_name, new_image_path):
"""Remplacer une image dans une page (overlay avec masquage)."""
from pypdf import PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
import io
reader = PdfReader(input_path)
writer = PdfWriter()
for i, page in enumerate(reader.pages):
if i == page_index and new_image_path:
w, h = get_page_size(page)
# On ne peut pas vraiment remplacer l'image dans le flux PDF
# On ajoute la nouvelle image par-dessus (avec un masque blanc si besoin)
packet = io.BytesIO()
c = canvas.Canvas(packet, pagesize=(w, h))
try:
img = ImageReader(new_image_path)
img_w, img_h = img.getSize()
# Centrer l'image
scale = min(w / img_w, h / img_h) * 0.8
draw_w = img_w * scale
draw_h = img_h * scale
x = (w - draw_w) / 2
y = (h - draw_h) / 2
c.drawImage(new_image_path, x, y, width=draw_w, height=draw_h,
preserveAspectRatio=True, mask='auto')
except Exception:
pass
c.showPage()
c.save()
packet.seek(0)
overlay = PdfReader(packet)
page.merge_page(overlay.pages[0])
writer.add_page(page)
with open(output_path, "wb") as f:
writer.write(f)
return output_path