""" Generator PSD - Podziekowanie dla gosci weselnych (buteleczka, Wzor 4). Otwiera szablon PSD, podmienia teksty w Smart Object (linkowane 8 kopii) z zachowaniem pozycji warstw, zapisuje jako nowy PSD w folderze _gotowe. Wymaga: uruchomiony Adobe Photoshop, pakiet photoshop-python-api. Uzycie: python buteleczki_slub_wzor4.py --imie_zenskie "Kasia" --imie_meskie "Mateusz" \ --data "04.07.2026" --klient "Kasia Nowak" python buteleczki_slub_wzor4.py --imie_zenskie "Kasia" --imie_meskie "Mateusz" \ --data "04.07.2026" --naglowek "Dziekujemy!" --klient "Kasia Nowak" """ import argparse import os import photoshop.api as ps # --- Sciezki --- PROJEKT_DIR = os.path.join( r"d:\pomysloweprezenty.pl\projekty\ślub - buteleczki", "Podziękowanie dla gości weselnych buteleczka z nadrukiem UV - Wzór 4", ) SZABLON_PATH = os.path.join(PROJEKT_DIR, "szablon 370x300.psd") GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe") # Szablon ma 8 linkowanych kopii Smart Object (Warstwa 2 + Warstwa 2 kopia..kopia 7). # Wystarczy edytowac jeden - zmiany propaguja sie na wszystkie. SMART_OBJECT_LAYER = "Warstwa 2 kopia" def open_smart_object(app): """Otwiera zawartosc aktywnej warstwy Smart Object do edycji.""" desc = ps.ActionDescriptor() ref = ps.ActionReference() ref.putEnumerated( app.stringIDToTypeID("layer"), app.stringIDToTypeID("ordinal"), app.stringIDToTypeID("targetEnum"), ) desc.putReference(app.stringIDToTypeID("null"), ref) app.executeAction(app.stringIDToTypeID("placedLayerEditContents"), desc) def change_text_preserve_position(layer, new_text): """Zmienia tekst warstwy z zachowaniem jej oryginalnej pozycji. Uwzglednia justowanie: - center: zachowuje srodek poziomy - right: zachowuje prawa krawedz - left (lub inne): zachowuje lewa krawedz W pionie zawsze zachowuje gora (pierwsza linia bazowa). """ bounds_before = [float(b) for b in layer.bounds] try: just_int = int(layer.textItem.justification) except Exception: just_int = 1 # Left layer.textItem.contents = new_text bounds_after = [float(b) for b in layer.bounds] # Photoshop Justification enum: 1=Left, 2=Center, 3=Right if just_int == 2: cx_before = (bounds_before[0] + bounds_before[2]) / 2 cx_after = (bounds_after[0] + bounds_after[2]) / 2 dx = cx_before - cx_after elif just_int == 3: dx = bounds_before[2] - bounds_after[2] else: dx = bounds_before[0] - bounds_after[0] dy = bounds_before[1] - bounds_after[1] if dx != 0 or dy != 0: layer.translate(dx, dy) def generate(imie_zenskie, imie_meskie, data, klient, naglowek=None): """Generuje PSD z podmienionymi danymi.""" os.makedirs(GOTOWE_DIR, exist_ok=True) output_path = os.path.join(GOTOWE_DIR, f"{klient}.psd") app = ps.Application() doc = app.open(SZABLON_PATH) print(f"Otwarto szablon: {doc.name}") # Znajdz Smart Object (dowolna kopia - sa linkowane) for layer in doc.layers: if layer.name == SMART_OBJECT_LAYER: app.activeDocument.activeLayer = layer break else: doc.close(ps.SaveOptions.DoNotSaveChanges) raise RuntimeError(f"Nie znaleziono warstwy '{SMART_OBJECT_LAYER}'") open_smart_object(app) so_doc = app.activeDocument # Nawiguj do grupy Tekst (zawiera wszystkie warstwy tekstowe) tekst_group = so_doc.layerSets["Tekst"] # Podmiana tekstow replacements = { "imie_zenskie": imie_zenskie, "imie_meskie": imie_meskie, "data": data, } if naglowek is not None: replacements["naglowek"] = naglowek for layer_name, new_text in replacements.items(): layer = tekst_group.artLayers[layer_name] old_text = layer.textItem.contents change_text_preserve_position(layer, new_text) print(f' {layer_name}: "{old_text}" -> "{new_text}"') # Zapisz Smart Object (propaguje sie na wszystkie 8 kopii) so_doc.save() so_doc.close() print("Smart Object zapisany") # Zapisz jako nowy PSD psd_opts = ps.PhotoshopSaveOptions() app.activeDocument.saveAs(output_path, psd_opts, True) print(f"Zapisano: {output_path}") # Zamknij oryginal bez zapisu app.activeDocument.close(ps.SaveOptions.DoNotSaveChanges) print("Gotowe!") return output_path def main(): parser = argparse.ArgumentParser( description="Generator PSD - buteleczki weselne Wzor 4" ) parser.add_argument("--imie_zenskie", required=True, help="Imie zenskie (np. Kasia)") parser.add_argument("--imie_meskie", required=True, help="Imie meskie (np. Mateusz)") parser.add_argument("--data", required=True, help="Data uroczystosci (np. 04.07.2026)") parser.add_argument("--klient", required=True, help="Imie i nazwisko klienta (nazwa pliku wyjsciowego)") parser.add_argument("--naglowek", default=None, help="Tekst naglowka (domyslnie: oryginalny z szablonu)") args = parser.parse_args() generate( imie_zenskie=args.imie_zenskie, imie_meskie=args.imie_meskie, data=args.data, klient=args.klient, naglowek=args.naglowek, ) if __name__ == "__main__": main()