notebookvb
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
"""
|
||||
Konverze JPG/PNG → PDF se správnou orientací stránky (A4).
|
||||
|
||||
Řeší:
|
||||
- EXIF orientaci (fotky z telefonu/skeneru bývají otočené)
|
||||
- Správné umístění na A4 stránce (na výšku nebo na šířku dle obsahu)
|
||||
- Zachování kvality
|
||||
|
||||
Použití:
|
||||
python jpg_to_pdf.py soubor.jpg
|
||||
python jpg_to_pdf.py soubor.jpg vystup.pdf
|
||||
"""
|
||||
|
||||
import io
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageOps
|
||||
|
||||
# A4 rozměry v mm
|
||||
A4_W_MM = 210
|
||||
A4_H_MM = 297
|
||||
MARGIN_MM = 0 # bez okraje, tisk si řeší Acrobat (Fit to Print)
|
||||
|
||||
|
||||
def fix_orientation(img: Image.Image) -> Image.Image:
|
||||
"""Opraví rotaci podle EXIF dat (tag 274)."""
|
||||
return ImageOps.exif_transpose(img)
|
||||
|
||||
|
||||
def image_to_pdf(src: Path, dst: Path, dpi: int = 150, quality: int = 80, rotate_ccw: int = 0):
|
||||
img = Image.open(src)
|
||||
print(f" Originál: {img.size[0]}×{img.size[1]} px, mode={img.mode}, format={img.format}")
|
||||
|
||||
# 1. Oprav EXIF orientaci
|
||||
img = fix_orientation(img)
|
||||
print(f" Po EXIF korekci: {img.size[0]}×{img.size[1]} px")
|
||||
|
||||
# 2. Rotace dle parametru (od Claude nebo ručně)
|
||||
if rotate_ccw and rotate_ccw != 0:
|
||||
img = img.rotate(rotate_ccw, expand=True)
|
||||
print(f" Po rotaci {rotate_ccw}° CCW: {img.size[0]}×{img.size[1]} px")
|
||||
|
||||
# 2. Převeď na RGB (PDF nepodporuje RGBA/P)
|
||||
if img.mode in ("RGBA", "P", "LA"):
|
||||
img = img.convert("RGB")
|
||||
|
||||
# 3. Urči orientaci stránky podle poměru stran obrázku
|
||||
img_w, img_h = img.size
|
||||
if img_w > img_h:
|
||||
# Obrázek na šířku → stránka na šířku (A4 landscape)
|
||||
page_w_mm, page_h_mm = A4_H_MM, A4_W_MM
|
||||
print(f" Orientace stránky: na šířku (landscape)")
|
||||
else:
|
||||
# Obrázek na výšku → stránka na výšku (A4 portrait)
|
||||
page_w_mm, page_h_mm = A4_W_MM, A4_H_MM
|
||||
print(f" Orientace stránky: na výšku (portrait)")
|
||||
|
||||
# 4. Vypočti cílovou velikost s okrajem (mm → px při daném DPI)
|
||||
mm_to_px = dpi / 25.4
|
||||
max_w_px = int((page_w_mm - 2 * MARGIN_MM) * mm_to_px)
|
||||
max_h_px = int((page_h_mm - 2 * MARGIN_MM) * mm_to_px)
|
||||
|
||||
# 5. Škáluj obrázek na stránku (zachovej poměr stran)
|
||||
img.thumbnail((max_w_px, max_h_px), Image.LANCZOS)
|
||||
print(f" Výsledná velikost obrázku: {img.size[0]}×{img.size[1]} px")
|
||||
|
||||
# 6. Vlož obrázek na bílé A4 plátno
|
||||
page_w_px = int(page_w_mm * mm_to_px)
|
||||
page_h_px = int(page_h_mm * mm_to_px)
|
||||
canvas = Image.new("RGB", (page_w_px, page_h_px), "white")
|
||||
|
||||
offset_x = (page_w_px - img.size[0]) // 2
|
||||
offset_y = (page_h_px - img.size[1]) // 2
|
||||
canvas.paste(img, (offset_x, offset_y))
|
||||
|
||||
# 7. Ulož jako PDF
|
||||
canvas.save(dst, "PDF", resolution=dpi, quality=quality)
|
||||
print(f" ✓ Uloženo: {dst.name} ({dst.stat().st_size // 1024} KB)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if sys.platform == "win32":
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace")
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Použití: python jpg_to_pdf.py soubor.jpg [vystup.pdf] [rotace_ccw]")
|
||||
print(" rotace_ccw: 0 / 90 / 180 / 270 (výchozí: 0)")
|
||||
sys.exit(1)
|
||||
|
||||
src = Path(sys.argv[1])
|
||||
if not src.exists():
|
||||
print(f"Soubor nenalezen: {src}")
|
||||
sys.exit(1)
|
||||
|
||||
dst = Path(sys.argv[2]) if len(sys.argv) > 2 else src.with_suffix(".pdf")
|
||||
rotate_ccw = int(sys.argv[3]) if len(sys.argv) > 3 else 0
|
||||
|
||||
print(f"Konvertuji: {src.name} → {dst.name}")
|
||||
image_to_pdf(src, dst, rotate_ccw=rotate_ccw)
|
||||
Reference in New Issue
Block a user