From bbc5852fa5750d7a7aa8def8f718c2d85647315d Mon Sep 17 00:00:00 2001 From: Piotr Tabor Date: Thu, 11 Jun 2026 21:27:27 +0200 Subject: [PATCH] feat: optional logo, paper size dropdown, and skip popup --- src/epub/create_epub.py | 8 ++-- src/formats/songbook_p.tex | 2 +- .../songbook_edit/songbook_edit.html | 6 ++- .../templates/songbook_edit/songbook_edit.js | 20 +++------ src/latex/songbook2tex.py | 10 ++++- src/lib/img2cover/img2cover.py | 45 ++++++++++--------- src/lib/songbook.py | 10 +++-- 7 files changed, 53 insertions(+), 48 deletions(-) diff --git a/src/epub/create_epub.py b/src/epub/create_epub.py index 58d2d546..8663fed1 100644 --- a/src/epub/create_epub.py +++ b/src/epub/create_epub.py @@ -273,7 +273,8 @@ def create_template_epub(songbook, target_path): os.path.join(path_images, "cover.png"), songbook.subtitle(), actual_date()) - shutil.copyfile(songbook.imageWebPath(), os.path.join(path_images, "logo." + songbook.imageWebExt())) + if songbook.imageWebPath(): + shutil.copyfile(songbook.imageWebPath(), os.path.join(path_images, "logo." + songbook.imageWebExt())) resolveTemplate(songbook, os.path.join(template_dir, "songs.xhtml"), os.path.join(path_oebps, "songs.xhtml")) @@ -325,8 +326,9 @@ def package_epub(songbook, target_dir, target_file="spiewnik.epub"): myzip.write(src_path, arcname=os.path.join("OEBPS", "CSS", css_file)) myzip.write(os.path.join(target_dir_epub, "OEBPS", "images", "cover.png"), arcname=os.path.join("OEBPS", "images", "cover.png")) - myzip.write(os.path.join(target_dir_epub, "OEBPS", "images", "logo."+songbook.imageWebExt()), - arcname=os.path.join("OEBPS", "images", "logo."+songbook.imageWebExt())) + if songbook.imageWebPath(): + myzip.write(os.path.join(target_dir_epub, "OEBPS", "images", "logo."+songbook.imageWebExt()), + arcname=os.path.join("OEBPS", "images", "logo."+songbook.imageWebExt())) def main(): diff --git a/src/formats/songbook_p.tex b/src/formats/songbook_p.tex index 59edb1ab..58dcbab7 100644 --- a/src/formats/songbook_p.tex +++ b/src/formats/songbook_p.tex @@ -85,7 +85,7 @@ \large \vspace{\stretch{7}} -\includegraphics[height=5 cm]{:imagePdfPath:} +:imagePdfPath: \vspace{\stretch{7}} :publisher: diff --git a/src/html/templates/songbook_edit/songbook_edit.html b/src/html/templates/songbook_edit/songbook_edit.html index 6801d26a..07e960f4 100644 --- a/src/html/templates/songbook_edit/songbook_edit.html +++ b/src/html/templates/songbook_edit/songbook_edit.html @@ -106,8 +106,12 @@

Wybrane piosenki

Nie wybrano jeszcze żadnych piosenek
-
+
+
diff --git a/src/html/templates/songbook_edit/songbook_edit.js b/src/html/templates/songbook_edit/songbook_edit.js index 2634e404..09f2d972 100644 --- a/src/html/templates/songbook_edit/songbook_edit.js +++ b/src/html/templates/songbook_edit/songbook_edit.js @@ -632,10 +632,14 @@ async function renderPDF() { const urlParams = new URLSearchParams(window.location.search); const branch = urlParams.get('branch') || 'main'; + // Get paper size + const paperSizeSelect = document.getElementById('paperSize'); + const paperSize = paperSizeSelect ? paperSizeSelect.value : 'a4'; + const payload = { yaml_content: yaml, branch: branch, - papersize: "a4" + papersize: paperSize }; const btn = document.getElementById('btnRenderPdf'); @@ -656,17 +660,6 @@ async function renderPDF() { } if (pdfDownloadLink) pdfDownloadLink.style.display = 'none'; - // Open blank window immediately to satisfy popup blocker - let pdfWindow = null; - try { - pdfWindow = window.open('about:blank', '_blank'); - if (pdfWindow) { - pdfWindow.document.write(`
Trwa generowanie śpiewnika PDF... Proszę czekać (szacowany czas: około ${estimatedSeconds} sekund).
`); - } - } catch (e) { - console.warn("Could not open new window automatically", e); - } - renderPdfCloudRun( payload, "/api/render/songbook_yaml", @@ -683,7 +676,6 @@ async function renderPDF() { pdfDownloadLink.href = url; pdfDownloadLink.style.display = 'block'; } - if (pdfWindow) pdfWindow.location.href = url; }, (err, errUrl) => { alert(err); @@ -692,8 +684,6 @@ async function renderPDF() { btn.textContent = originalBtnText; } if (pdfStatusText) pdfStatusText.textContent = err; - if (pdfWindow && errUrl) pdfWindow.location.href = errUrl; - else if (pdfWindow) pdfWindow.close(); } ); } diff --git a/src/latex/songbook2tex.py b/src/latex/songbook2tex.py index 101ff780..862b5e1e 100644 --- a/src/latex/songbook2tex.py +++ b/src/latex/songbook2tex.py @@ -48,8 +48,14 @@ def create_ready_tex(songbook, papersize): .replace(":subtitle:", str2tex(songbook.subtitle())) .replace(":place:", str2tex(songbook.place() + ", ") if songbook.place() else "") .replace(":url:", str2tex(songbook.url())) - .replace(":publisher:", str2tex(songbook.publisher())) - .replace(":imagePdfPath:", songbook.imagePdfPath())) + .replace(":publisher:", str2tex(songbook.publisher()))) + + if songbook.imagePdfPath(): + image_tex = f"\\includegraphics[height=5 cm]{{{songbook.imagePdfPath()}}}" + else: + image_tex = "" + + content = content.replace(":imagePdfPath:", image_tex) content += "".join([s2t.song2tex(file) for _, file in list_title_file]) diff --git a/src/lib/img2cover/img2cover.py b/src/lib/img2cover/img2cover.py index 99cfaa44..c03b002a 100644 --- a/src/lib/img2cover/img2cover.py +++ b/src/lib/img2cover/img2cover.py @@ -109,28 +109,29 @@ def draw_smart_text(position, text, base_font_path, initial_size, max_width, max # 5. Load, resize, and position the logo try: - if not os.path.exists(logo_path): - raise FileNotFoundError(f"The logo file was not found at '{logo_path}'") - - if logo_path.lower().endswith('.svg'): - png_data = cairosvg.svg2png(url=logo_path) - logo_img = Image.open(io.BytesIO(png_data)) - elif logo_path.lower().endswith(('.png', '.jpg', '.jpeg')): - logo_img = Image.open(logo_path) - else: - raise ValueError(f"Unsupported logo format: {os.path.basename(logo_path)}. Please use PNG, JPG, or SVG.") - - logo_area_y_start = last_y - logo_area_height = height_px - logo_area_y_start - (margin * 2) - logo_max_width = width_px * 0.7 - - logo_img.thumbnail((logo_max_width, logo_area_height), Image.Resampling.LANCZOS) - - logo_x = (width_px - logo_img.width) / 2 - logo_y = logo_area_y_start + (logo_area_height - logo_img.height) / 2 - - cover.paste(logo_img, (int(logo_x), int(logo_y)), logo_img.convert('RGBA')) - last_y = logo_y + logo_img.height + if logo_path: + if not os.path.exists(logo_path): + raise FileNotFoundError(f"The logo file was not found at '{logo_path}'") + + if logo_path.lower().endswith('.svg'): + png_data = cairosvg.svg2png(url=logo_path) + logo_img = Image.open(io.BytesIO(png_data)) + elif logo_path.lower().endswith(('.png', '.jpg', '.jpeg')): + logo_img = Image.open(logo_path) + else: + raise ValueError(f"Unsupported logo format: {os.path.basename(logo_path)}. Please use PNG, JPG, or SVG.") + + logo_area_y_start = last_y + logo_area_height = height_px - logo_area_y_start - (margin * 2) + logo_max_width = width_px * 0.7 + + logo_img.thumbnail((logo_max_width, logo_area_height), Image.Resampling.LANCZOS) + + logo_x = (width_px - logo_img.width) / 2 + logo_y = logo_area_y_start + (logo_area_height - logo_img.height) / 2 + + cover.paste(logo_img, (int(logo_x), int(logo_y)), logo_img.convert('RGBA')) + last_y = logo_y + logo_img.height except Exception as e: # Re-raise exceptions to be handled by the caller diff --git a/src/lib/songbook.py b/src/lib/songbook.py index 91685738..c230c98c 100644 --- a/src/lib/songbook.py +++ b/src/lib/songbook.py @@ -78,28 +78,30 @@ def hidden(self): return self.spec["hidden"] if "hidden" in self.spec else False def imagePdfPath(self): - return resolvePath(self.spec["image"]["pdf"] if "image" in self.spec and "pdf" in self.spec["image"] else "songbooks/wdw21/znak21.pdf", start=self.basedir) + if "image" in self.spec and "pdf" in self.spec["image"]: + return resolvePath(self.spec["image"]["pdf"], start=self.basedir) + return None def imageWebPath(self): if "image" in self.spec: if "png" in self.spec["image"]: return resolvePath(self.spec["image"]["png"], start=self.basedir) if "svg" in self.spec["image"]: return resolvePath(self.spec["image"]["svg"], start=self.basedir) if "jpg" in self.spec["image"]: return resolvePath(self.spec["image"]["jpg"], start=self.basedir) - return resolvePath("songbooks/wdw21/znak21.jpg", start=self.basedir) + return None def imageWebExt(self): if "image" in self.spec: if "png" in self.spec["image"]: return "png" if "svg" in self.spec["image"]: return "svg" if "jpg" in self.spec["image"]: return "jpg" - return "image/jpeg" + return None def imageWebMime(self): if "image" in self.spec: if "png" in self.spec["image"]: return "image/png" if "svg" in self.spec["image"]: return "image/svg+xml" if "jpg" in self.spec["image"]: return "image/jpeg" - return "image/jpeg" + return None def load_songbook_spec_from_yaml(filename, title=None, songFiles=None): with open(filename) as stream: