This commit is contained in:
2026-04-12 21:43:39 +02:00
parent 63bd1e73f2
commit f72a5019e9
27 changed files with 1791 additions and 266 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -0,0 +1,99 @@
"""
Wspólny rdzeń dla generatorów PSD pudełek komunijnych (chłopiec/dziewczynka).
Makieta A3 zawiera 4 grupy warstw (GL/GP/DL/DP) — 1 PSD = 1 zamówienie,
te same dane lecą do górnej i dolnej części makiety. Brak Smart Objectów,
teksty są bezpośrednio w grupach. Po normalizacji nazw (rename w PSD) wszystkie
warianty mają identyczną strukturę: od_kogo / naglowek / zyczenia / imie / data / tytul.
"""
import argparse
import os
import photoshop.api as ps
ZYCZENIA_GROUPS = [
("GL", "dane"),
("DL", None),
]
IMIE_GROUPS = [
("GP", "dane"),
("DP", None),
]
def set_text(layer, new_text):
"""Zmienia tekst warstwy zachowując środek bounding boxa.
Photoshop API po zmianie textItem.contents resetuje pozycję warstwy do
punktu kotwiczenia, co dla tekstu wycentrowanego psuje layout. Liczymy
środek bounds przed/po i kompensujemy translacją."""
b = [float(x) for x in layer.bounds]
cx_before = (b[0] + b[2]) / 2
cy_before = (b[1] + b[3]) / 2
layer.textItem.contents = new_text
b2 = [float(x) for x in layer.bounds]
cx_after = (b2[0] + b2[2]) / 2
cy_after = (b2[1] + b2[3]) / 2
dx = cx_before - cx_after
dy = cy_before - cy_after
if dx or dy:
layer.translate(dx, dy)
def get_container(doc, set_name, inner_name):
container = doc.layerSets[set_name]
if inner_name:
container = container.layerSets[inner_name]
return container
def apply_replacements(container, replacements):
for layer_name, new_text in replacements.items():
if new_text is None:
continue
layer = container.artLayers[layer_name]
old_text = layer.textItem.contents
set_text(layer, new_text)
print(f' {layer_name}: "{old_text}" -> "{new_text}"')
def generate(szablon_path, gotowe_dir, imie, data, od_kogo, klient,
zyczenia=None, naglowek=None, tytul=None):
"""Generuje PSD z podmienionymi danymi (1 PSD = 1 zamówienie)."""
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}")
zyczenia_map = {"od_kogo": od_kogo, "naglowek": naglowek, "zyczenia": zyczenia}
imie_map = {"imie": imie, "data": data, "tytul": tytul}
for set_name, inner in ZYCZENIA_GROUPS:
print(f" [{set_name}] życzenia:")
apply_replacements(get_container(doc, set_name, inner), zyczenia_map)
for set_name, inner in IMIE_GROUPS:
print(f" [{set_name}] imię/data:")
apply_replacements(get_container(doc, set_name, inner), imie_map)
psd_opts = ps.PhotoshopSaveOptions()
doc.saveAs(output_path, psd_opts, True)
print(f"Zapisano: {output_path}")
doc.close(ps.SaveOptions.DoNotSaveChanges)
print("Gotowe!")
return output_path
def build_arg_parser(description):
parser = argparse.ArgumentParser(description=description)
parser.add_argument("--klient", required=True, help="Nazwa pliku wyjściowego")
parser.add_argument("--imie", required=True, help="Imię dziecka")
parser.add_argument("--data", required=True, help="Data uroczystości (np. 10.05.2026)")
parser.add_argument("--od-kogo", dest="od_kogo", required=True, help="Od kogo (np. Rodzice Chrzestni)")
parser.add_argument("--zyczenia", default=None, help="Treść życzeń (opcjonalnie, domyślnie z szablonu)")
parser.add_argument("--naglowek", default=None, help="Nagłówek życzeń (opcjonalnie, domyślnie z szablonu)")
parser.add_argument("--tytul", default=None, help="Tytuł (opcjonalnie, domyślnie z szablonu)")
return parser

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 MiB

View File

@@ -0,0 +1,179 @@
"""
Generator PSD — Akrylowa statuetka podziekowanie dla Rodzicow ze zdjeciem (Wzor 1).
Plaska struktura PSD: w "Warstwa 1" znajduja sie:
- warstwy tekstowe: naglowek, imiona, data, zyczenia
- 4 Smart Objecty ze zdjeciami: zdjecie_01, zdjecie_02, zdjecie_03, zdjecie_04
Podmiana zdjec:
- jesli --zdjecieN wskazuje na istniejacy plik graficzny → zostaje wstawione,
przeskalowane "cover" do oryginalnych boundsow placeholdera i wycentrowane
- jesli zdjecie nie zostalo podane lub plik nie istnieje → wstawiamy
zielony prostokat (#00FF00) jako sygnal, ze klient nie przeslal foto
Wymaga: uruchomiony Adobe Photoshop, photoshop-python-api, Pillow.
"""
import argparse
import os
import photoshop.api as ps
PROJEKT_DIR = os.path.join(
r"d:\pomysloweprezenty.pl\projekty\ślub - podziękowania",
"Akrylowa statuetka podziękowanie dla rodziców ze zdjęciem - Wzór 1",
)
SZABLON_PATH = os.path.join(PROJEKT_DIR, "Akrylowa statuetka podziękowanie dla rodziców ze zdjęciem - Wzór 1.psd")
GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe")
ASSETS_DIR = os.path.join(os.path.dirname(__file__), "_assets")
GREEN_PLACEHOLDER_PATH = os.path.join(ASSETS_DIR, "green_placeholder.png")
PHOTO_SLOTS = ("zdjecie_01", "zdjecie_02", "zdjecie_03", "zdjecie_04")
def ensure_green_placeholder():
"""Tworzy raz zielony PNG (#00FF00) jako placeholder dla brakujacego zdjecia."""
if os.path.exists(GREEN_PLACEHOLDER_PATH):
return GREEN_PLACEHOLDER_PATH
os.makedirs(ASSETS_DIR, exist_ok=True)
from PIL import Image
Image.new("RGB", (1000, 1000), (0, 255, 0)).save(GREEN_PLACEHOLDER_PATH)
return GREEN_PLACEHOLDER_PATH
def set_text(layer, new_text):
"""Zmienia tekst zachowujac srodek bounding boxa (centrowane warstwy)."""
b = [float(x) for x in layer.bounds]
cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2
layer.textItem.contents = new_text
b2 = [float(x) for x in layer.bounds]
cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2
dx, dy = cx - cx2, cy - cy2
if dx or dy:
layer.translate(dx, dy)
def set_layer_text(container, layer_name, new_text):
if new_text is None:
return
layer = container.artLayers[layer_name]
old = layer.textItem.contents
set_text(layer, new_text)
print(f' {layer_name}: "{old}" -> "{new_text}"')
def replace_smart_object_contents(app, file_path):
"""Wykonuje akcje placedLayerReplaceContents na aktywnej warstwie SO."""
desc = ps.ActionDescriptor()
desc.putPath(app.charIDToTypeID("null"), file_path)
desc.putInteger(app.charIDToTypeID("PgNm"), 1)
app.executeAction(app.stringIDToTypeID("placedLayerReplaceContents"), desc)
def replace_photo_cover(app, so_layer, photo_path):
"""Podmienia zawartosc Smart Object i skaluje 'cover' do oryginalnych boundsow."""
target = [float(x) for x in so_layer.bounds]
target_w = target[2] - target[0]
target_h = target[3] - target[1]
target_cx = (target[0] + target[2]) / 2
target_cy = (target[1] + target[3]) / 2
app.activeDocument.activeLayer = so_layer
replace_smart_object_contents(app, photo_path)
new_b = [float(x) for x in so_layer.bounds]
new_w = new_b[2] - new_b[0]
new_h = new_b[3] - new_b[1]
if new_w <= 0 or new_h <= 0:
return
scale = max(target_w / new_w, target_h / new_h) * 100.0
so_layer.resize(scale, scale, ps.AnchorPosition.MiddleCenter)
cur = [float(x) for x in so_layer.bounds]
cur_cx = (cur[0] + cur[2]) / 2
cur_cy = (cur[1] + cur[3]) / 2
so_layer.translate(target_cx - cur_cx, target_cy - cur_cy)
def swap_photo_slot(app, container, slot_name, photo_path):
"""Podmienia zdjecie w slocie; brak/nieistnieje → zielony placeholder."""
so_layer = container.artLayers[slot_name]
if photo_path and os.path.isfile(photo_path):
print(f" {slot_name}: {photo_path}")
replace_photo_cover(app, so_layer, photo_path)
else:
if photo_path:
print(f" {slot_name}: UWAGA plik nie istnieje ({photo_path}) — zielony placeholder")
else:
print(f" {slot_name}: brak — zielony placeholder")
replace_photo_cover(app, so_layer, ensure_green_placeholder())
def generate(klient, imiona, data, naglowek=None, zyczenia=None,
zdjecie1=None, zdjecie2=None, zdjecie3=None, zdjecie4=None):
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}")
try:
w1 = doc.layerSets["Warstwa 1"]
print(" Podmiana tekstow:")
set_layer_text(w1, "naglowek", naglowek)
set_layer_text(w1, "imiona", imiona)
set_layer_text(w1, "data", data)
set_layer_text(w1, "zyczenia", zyczenia)
print(" Podmiana zdjec:")
zdjecia = [zdjecie1, zdjecie2, zdjecie3, zdjecie4]
for slot, photo in zip(PHOTO_SLOTS, zdjecia):
swap_photo_slot(app, w1, slot, photo)
psd_opts = ps.PhotoshopSaveOptions()
doc.saveAs(output_path, psd_opts, True)
print(f"Zapisano: {output_path}")
finally:
try:
doc.close(ps.SaveOptions.DoNotSaveChanges)
except Exception:
pass
print("Gotowe!")
return output_path
def main():
parser = argparse.ArgumentParser(
description="Generator PSD - Akrylowa statuetka podziekowanie dla Rodzicow Wzor 1"
)
parser.add_argument("--klient", required=True, help="Nazwa pliku wyjsciowego (bez rozszerzenia)")
parser.add_argument("--imiona", required=True, help="Imiona pary mlodej (np. 'Kasia i Tomek')")
parser.add_argument("--data", required=True, help="Data uroczystosci (np. '10.08.2025')")
parser.add_argument("--naglowek", default=None, help="Naglowek (opcjonalnie, domyslnie 'Kochani Rodzice!')")
parser.add_argument("--zyczenia", default=None, help="Tresc podziekowania (opcjonalnie)")
parser.add_argument("--zdjecie1", default=None, help="Sciezka do zdjecia 1 (opcjonalnie; brak = zielony placeholder)")
parser.add_argument("--zdjecie2", default=None, help="Sciezka do zdjecia 2")
parser.add_argument("--zdjecie3", default=None, help="Sciezka do zdjecia 3")
parser.add_argument("--zdjecie4", default=None, help="Sciezka do zdjecia 4")
args = parser.parse_args()
generate(
klient=args.klient,
imiona=args.imiona,
data=args.data,
naglowek=args.naglowek,
zyczenia=args.zyczenia,
zdjecie1=args.zdjecie1,
zdjecie2=args.zdjecie2,
zdjecie3=args.zdjecie3,
zdjecie4=args.zdjecie4,
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,156 @@
"""
Generator PSD — Akrylowe podziekowanie na chrzest dla Matki Chrzestnej (Wzór 1).
Plaska struktura PSD: w "Warstwa 1" znajduja sie warstwy tekstowe
(imie, naglowek, podziekowanie, data) oraz Smart Object "zdjecie".
Podmiana zdjecia:
- jesli --zdjecie wskazuje na istniejacy plik graficzny → zostaje wstawione,
przeskalowane "cover" do oryginalnych boundsow placeholdera i wycentrowane
- jesli zdjecie nie zostalo podane lub plik nie istnieje → wstawiamy
zielony prostokat (#00FF00) jako sygnal, ze klient nie przeslal foto
Wymaga: uruchomiony Adobe Photoshop, photoshop-python-api, Pillow.
"""
import argparse
import os
import photoshop.api as ps
PROJEKT_DIR = os.path.join(
r"d:\pomysloweprezenty.pl\projekty\chrzest - podziękowania",
"Akrylowe podziękowanie na chrzest dla Matki Chrzestnej - Wzór 1",
)
SZABLON_PATH = os.path.join(PROJEKT_DIR, "Akrylowe podziękowanie na chrzest dla Matki Chrzestnej - Wzór 1 CMYK.psd")
GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe")
ASSETS_DIR = os.path.join(os.path.dirname(__file__), "_assets")
GREEN_PLACEHOLDER_PATH = os.path.join(ASSETS_DIR, "green_placeholder.png")
def ensure_green_placeholder():
"""Tworzy raz zielony PNG (#00FF00) jako placeholder dla brakujacego zdjecia."""
if os.path.exists(GREEN_PLACEHOLDER_PATH):
return GREEN_PLACEHOLDER_PATH
os.makedirs(ASSETS_DIR, exist_ok=True)
from PIL import Image
Image.new("RGB", (1000, 1000), (0, 255, 0)).save(GREEN_PLACEHOLDER_PATH)
return GREEN_PLACEHOLDER_PATH
def set_text(layer, new_text):
"""Zmienia tekst zachowujac srodek bounding boxa (centrowane warstwy)."""
b = [float(x) for x in layer.bounds]
cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2
layer.textItem.contents = new_text
b2 = [float(x) for x in layer.bounds]
cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2
dx, dy = cx - cx2, cy - cy2
if dx or dy:
layer.translate(dx, dy)
def set_layer_text(container, layer_name, new_text):
if new_text is None:
return
layer = container.artLayers[layer_name]
old = layer.textItem.contents
set_text(layer, new_text)
print(f' {layer_name}: "{old}" -> "{new_text}"')
def replace_smart_object_contents(app, file_path):
"""Wykonuje akcje placedLayerReplaceContents na aktywnej warstwie SO."""
desc = ps.ActionDescriptor()
desc.putPath(app.charIDToTypeID("null"), file_path)
desc.putInteger(app.charIDToTypeID("PgNm"), 1)
app.executeAction(app.stringIDToTypeID("placedLayerReplaceContents"), desc)
def replace_photo_cover(app, so_layer, photo_path):
"""Podmienia zawartosc Smart Object i skaluje 'cover' do oryginalnych boundsow."""
target = [float(x) for x in so_layer.bounds]
target_w = target[2] - target[0]
target_h = target[3] - target[1]
target_cx = (target[0] + target[2]) / 2
target_cy = (target[1] + target[3]) / 2
app.activeDocument.activeLayer = so_layer
replace_smart_object_contents(app, photo_path)
new_b = [float(x) for x in so_layer.bounds]
new_w = new_b[2] - new_b[0]
new_h = new_b[3] - new_b[1]
if new_w <= 0 or new_h <= 0:
return
scale = max(target_w / new_w, target_h / new_h) * 100.0
so_layer.resize(scale, scale, ps.AnchorPosition.MiddleCenter)
cur = [float(x) for x in so_layer.bounds]
cur_cx = (cur[0] + cur[2]) / 2
cur_cy = (cur[1] + cur[3]) / 2
so_layer.translate(target_cx - cur_cx, target_cy - cur_cy)
def generate(klient, imie, data, zdjecie=None, naglowek=None, podziekowanie=None):
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}")
w1 = doc.layerSets["Warstwa 1"]
print(" Podmiana tekstow:")
set_layer_text(w1, "imie", imie)
set_layer_text(w1, "data", data)
set_layer_text(w1, "naglowek", naglowek)
set_layer_text(w1, "podziekowanie", podziekowanie)
so_layer = w1.artLayers["zdjecie"]
if zdjecie and os.path.isfile(zdjecie):
print(f" Podmiana zdjecia: {zdjecie}")
replace_photo_cover(app, so_layer, zdjecie)
else:
if zdjecie:
print(f" UWAGA: plik zdjecia nie istnieje ({zdjecie}) — wstawiam zielony placeholder")
else:
print(" Brak --zdjecie — wstawiam zielony placeholder")
replace_photo_cover(app, so_layer, ensure_green_placeholder())
psd_opts = ps.PhotoshopSaveOptions()
doc.saveAs(output_path, psd_opts, True)
print(f"Zapisano: {output_path}")
doc.close(ps.SaveOptions.DoNotSaveChanges)
print("Gotowe!")
return output_path
def main():
parser = argparse.ArgumentParser(
description="Generator PSD - Akrylowe podziekowanie chrzest, Matka Chrzestna Wzor 1"
)
parser.add_argument("--klient", required=True, help="Nazwa pliku wyjsciowego")
parser.add_argument("--imie", required=True, help="Imie dziecka (np. Gabrysia)")
parser.add_argument("--data", required=True, help="Data uroczystosci (np. 21.09.2025)")
parser.add_argument("--zdjecie", default=None, help="Sciezka do zdjecia dziecka (opcjonalnie; brak = zielony placeholder)")
parser.add_argument("--naglowek", default=None, help="Naglowek (opcjonalnie, domyslnie 'Kochana Matko Chrzestna')")
parser.add_argument("--podziekowanie", default=None, help="Tresc podziekowania (opcjonalnie, domyslna z szablonu)")
args = parser.parse_args()
generate(
klient=args.klient,
imie=args.imie,
data=args.data,
zdjecie=args.zdjecie,
naglowek=args.naglowek,
podziekowanie=args.podziekowanie,
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,168 @@
"""
Generator PSD — Akrylowe podziekowanie na chrzest dla Matki Chrzestnej (Wzór 2).
Dwa warianty szablonu (chlopiec / dziewczynka) wybierane parametrem --plec.
Oba PSD maja identyczna strukture warstw w "Warstwa 1":
imie, data, naglowek, tytul, podziekowanie oraz Smart Object "zdjecie".
Podmiana zdjecia — jak w Wzorze 1: cover do oryginalnych boundsow,
zielony placeholder gdy brak zdjecia.
Wymaga: uruchomiony Adobe Photoshop, photoshop-python-api, Pillow.
"""
import argparse
import os
import photoshop.api as ps
PROJEKT_DIR = os.path.join(
r"d:\pomysloweprezenty.pl\projekty\chrzest - podziękowania",
"Akrylowe podziękowanie na chrzest dla Matki Chrzestnej - Wzór 2",
)
SZABLON_CHLOPIEC = os.path.join(
PROJEKT_DIR, "Akrylowe podziękowanie na chrzest dla Matki Chrzestnej - Wzór 2 CMYK - chłopiec.psd"
)
SZABLON_DZIEWCZYNKA = os.path.join(
PROJEKT_DIR, "Akrylowe podziękowanie na chrzest dla Matki Chrzestnej - Wzór 2 CMYK - dziewczynka.psd"
)
GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe")
ASSETS_DIR = os.path.join(os.path.dirname(__file__), "_assets")
GREEN_PLACEHOLDER_PATH = os.path.join(ASSETS_DIR, "green_placeholder.png")
def ensure_green_placeholder():
if os.path.exists(GREEN_PLACEHOLDER_PATH):
return GREEN_PLACEHOLDER_PATH
os.makedirs(ASSETS_DIR, exist_ok=True)
from PIL import Image
Image.new("RGB", (1000, 1000), (0, 255, 0)).save(GREEN_PLACEHOLDER_PATH)
return GREEN_PLACEHOLDER_PATH
def set_text(layer, new_text):
b = [float(x) for x in layer.bounds]
cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2
layer.textItem.contents = new_text
b2 = [float(x) for x in layer.bounds]
cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2
dx, dy = cx - cx2, cy - cy2
if dx or dy:
layer.translate(dx, dy)
def set_layer_text(container, layer_name, new_text):
if new_text is None:
return
layer = container.artLayers[layer_name]
old = layer.textItem.contents
set_text(layer, new_text)
print(f' {layer_name}: "{old}" -> "{new_text}"')
def replace_smart_object_contents(app, file_path):
desc = ps.ActionDescriptor()
desc.putPath(app.charIDToTypeID("null"), file_path)
desc.putInteger(app.charIDToTypeID("PgNm"), 1)
app.executeAction(app.stringIDToTypeID("placedLayerReplaceContents"), desc)
def replace_photo_cover(app, so_layer, photo_path):
target = [float(x) for x in so_layer.bounds]
target_w = target[2] - target[0]
target_h = target[3] - target[1]
target_cx = (target[0] + target[2]) / 2
target_cy = (target[1] + target[3]) / 2
app.activeDocument.activeLayer = so_layer
replace_smart_object_contents(app, photo_path)
new_b = [float(x) for x in so_layer.bounds]
new_w = new_b[2] - new_b[0]
new_h = new_b[3] - new_b[1]
if new_w <= 0 or new_h <= 0:
return
scale = max(target_w / new_w, target_h / new_h) * 100.0
so_layer.resize(scale, scale, ps.AnchorPosition.MiddleCenter)
cur = [float(x) for x in so_layer.bounds]
cur_cx = (cur[0] + cur[2]) / 2
cur_cy = (cur[1] + cur[3]) / 2
so_layer.translate(target_cx - cur_cx, target_cy - cur_cy)
def generate(klient, imie, data, plec, zdjecie=None, naglowek=None, tytul=None, podziekowanie=None):
if plec == "m":
szablon_path = SZABLON_CHLOPIEC
elif plec == "k":
szablon_path = SZABLON_DZIEWCZYNKA
else:
raise ValueError(f"--plec musi byc 'm' lub 'k', otrzymano: {plec!r}")
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}")
w1 = doc.layerSets["Warstwa 1"]
print(" Podmiana tekstow:")
set_layer_text(w1, "imie", imie)
set_layer_text(w1, "data", data)
set_layer_text(w1, "naglowek", naglowek)
set_layer_text(w1, "tytul", tytul)
set_layer_text(w1, "podziekowanie", podziekowanie)
so_layer = w1.artLayers["zdjecie"]
if zdjecie and os.path.isfile(zdjecie):
print(f" Podmiana zdjecia: {zdjecie}")
replace_photo_cover(app, so_layer, zdjecie)
else:
if zdjecie:
print(f" UWAGA: plik zdjecia nie istnieje ({zdjecie}) — wstawiam zielony placeholder")
else:
print(" Brak --zdjecie — wstawiam zielony placeholder")
replace_photo_cover(app, so_layer, ensure_green_placeholder())
psd_opts = ps.PhotoshopSaveOptions()
doc.saveAs(output_path, psd_opts, True)
print(f"Zapisano: {output_path}")
doc.close(ps.SaveOptions.DoNotSaveChanges)
print("Gotowe!")
return output_path
def main():
parser = argparse.ArgumentParser(
description="Generator PSD - Akrylowe podziekowanie chrzest, Matka Chrzestna Wzor 2 (chlopiec/dziewczynka)"
)
parser.add_argument("--klient", required=True, help="Nazwa pliku wyjsciowego")
parser.add_argument("--imie", required=True, help="Imie dziecka (np. Wojtus, Blanka)")
parser.add_argument("--data", required=True, help="Data uroczystosci (np. 19.04.2026)")
parser.add_argument("--plec", required=True, choices=["m", "k"],
help="Plec dziecka: 'm' = chlopiec, 'k' = dziewczynka")
parser.add_argument("--zdjecie", default=None, help="Sciezka do zdjecia (opcjonalnie; brak = zielony placeholder)")
parser.add_argument("--naglowek", default=None, help="Naglowek (opcjonalnie, domyslnie 'MATKO CHRZESTNA')")
parser.add_argument("--tytul", default=None, help="Tytul (opcjonalnie, domyslnie 'Dziękuję')")
parser.add_argument("--podziekowanie", default=None, help="Tresc podziekowania (opcjonalnie, domyslna z szablonu)")
args = parser.parse_args()
generate(
klient=args.klient,
imie=args.imie,
data=args.data,
plec=args.plec,
zdjecie=args.zdjecie,
naglowek=args.naglowek,
tytul=args.tytul,
podziekowanie=args.podziekowanie,
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,156 @@
"""
Generator PSD — Akrylowe podziekowanie na chrzest dla Ojca Chrzestnego (Wzór 1).
Plaska struktura PSD: w "Warstwa 1" znajduja sie warstwy tekstowe
(imie, naglowek, podziekowanie, data) oraz Smart Object "zdjecie".
Podmiana zdjecia:
- jesli --zdjecie wskazuje na istniejacy plik graficzny → zostaje wstawione,
przeskalowane "cover" do oryginalnych boundsow placeholdera i wycentrowane
- jesli zdjecie nie zostalo podane lub plik nie istnieje → wstawiamy
zielony prostokat (#00FF00) jako sygnal, ze klient nie przeslal foto
Wymaga: uruchomiony Adobe Photoshop, photoshop-python-api, Pillow.
"""
import argparse
import os
import photoshop.api as ps
PROJEKT_DIR = os.path.join(
r"d:\pomysloweprezenty.pl\projekty\chrzest - podziękowania",
"Akrylowe podziękowanie na chrzest dla Ojca Chrzestnego - Wzór 1",
)
SZABLON_PATH = os.path.join(PROJEKT_DIR, "Akrylowe podziękowanie na chrzest dla Ojca Chrzestnego - Wzór 1 CMYK.psd")
GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe")
ASSETS_DIR = os.path.join(os.path.dirname(__file__), "_assets")
GREEN_PLACEHOLDER_PATH = os.path.join(ASSETS_DIR, "green_placeholder.png")
def ensure_green_placeholder():
"""Tworzy raz zielony PNG (#00FF00) jako placeholder dla brakujacego zdjecia."""
if os.path.exists(GREEN_PLACEHOLDER_PATH):
return GREEN_PLACEHOLDER_PATH
os.makedirs(ASSETS_DIR, exist_ok=True)
from PIL import Image
Image.new("RGB", (1000, 1000), (0, 255, 0)).save(GREEN_PLACEHOLDER_PATH)
return GREEN_PLACEHOLDER_PATH
def set_text(layer, new_text):
"""Zmienia tekst zachowujac srodek bounding boxa (centrowane warstwy)."""
b = [float(x) for x in layer.bounds]
cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2
layer.textItem.contents = new_text
b2 = [float(x) for x in layer.bounds]
cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2
dx, dy = cx - cx2, cy - cy2
if dx or dy:
layer.translate(dx, dy)
def set_layer_text(container, layer_name, new_text):
if new_text is None:
return
layer = container.artLayers[layer_name]
old = layer.textItem.contents
set_text(layer, new_text)
print(f' {layer_name}: "{old}" -> "{new_text}"')
def replace_smart_object_contents(app, file_path):
"""Wykonuje akcje placedLayerReplaceContents na aktywnej warstwie SO."""
desc = ps.ActionDescriptor()
desc.putPath(app.charIDToTypeID("null"), file_path)
desc.putInteger(app.charIDToTypeID("PgNm"), 1)
app.executeAction(app.stringIDToTypeID("placedLayerReplaceContents"), desc)
def replace_photo_cover(app, so_layer, photo_path):
"""Podmienia zawartosc Smart Object i skaluje 'cover' do oryginalnych boundsow."""
target = [float(x) for x in so_layer.bounds]
target_w = target[2] - target[0]
target_h = target[3] - target[1]
target_cx = (target[0] + target[2]) / 2
target_cy = (target[1] + target[3]) / 2
app.activeDocument.activeLayer = so_layer
replace_smart_object_contents(app, photo_path)
new_b = [float(x) for x in so_layer.bounds]
new_w = new_b[2] - new_b[0]
new_h = new_b[3] - new_b[1]
if new_w <= 0 or new_h <= 0:
return
scale = max(target_w / new_w, target_h / new_h) * 100.0
so_layer.resize(scale, scale, ps.AnchorPosition.MiddleCenter)
cur = [float(x) for x in so_layer.bounds]
cur_cx = (cur[0] + cur[2]) / 2
cur_cy = (cur[1] + cur[3]) / 2
so_layer.translate(target_cx - cur_cx, target_cy - cur_cy)
def generate(klient, imie, data, zdjecie=None, naglowek=None, podziekowanie=None):
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}")
w1 = doc.layerSets["Warstwa 1"]
print(" Podmiana tekstow:")
set_layer_text(w1, "imie", imie)
set_layer_text(w1, "data", data)
set_layer_text(w1, "naglowek", naglowek)
set_layer_text(w1, "podziekowanie", podziekowanie)
so_layer = w1.artLayers["zdjecie"]
if zdjecie and os.path.isfile(zdjecie):
print(f" Podmiana zdjecia: {zdjecie}")
replace_photo_cover(app, so_layer, zdjecie)
else:
if zdjecie:
print(f" UWAGA: plik zdjecia nie istnieje ({zdjecie}) — wstawiam zielony placeholder")
else:
print(" Brak --zdjecie — wstawiam zielony placeholder")
replace_photo_cover(app, so_layer, ensure_green_placeholder())
psd_opts = ps.PhotoshopSaveOptions()
doc.saveAs(output_path, psd_opts, True)
print(f"Zapisano: {output_path}")
doc.close(ps.SaveOptions.DoNotSaveChanges)
print("Gotowe!")
return output_path
def main():
parser = argparse.ArgumentParser(
description="Generator PSD - Akrylowe podziekowanie chrzest, Ojciec Chrzestny Wzor 1"
)
parser.add_argument("--klient", required=True, help="Nazwa pliku wyjsciowego")
parser.add_argument("--imie", required=True, help="Imie dziecka (np. Franek)")
parser.add_argument("--data", required=True, help="Data uroczystosci (np. 26.10.2025)")
parser.add_argument("--zdjecie", default=None, help="Sciezka do zdjecia dziecka (opcjonalnie; brak = zielony placeholder)")
parser.add_argument("--naglowek", default=None, help="Naglowek (opcjonalnie, domyslnie 'Kochany Ojcze Chrzestny')")
parser.add_argument("--podziekowanie", default=None, help="Tresc podziekowania (opcjonalnie, domyslna z szablonu)")
args = parser.parse_args()
generate(
klient=args.klient,
imie=args.imie,
data=args.data,
zdjecie=args.zdjecie,
naglowek=args.naglowek,
podziekowanie=args.podziekowanie,
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,126 @@
"""
Generator PSD — Buteleczka ślubna "Młoda para".
Szablon 370x300 to multi-up layout: 8 instancji Smart Object linkujących do
jednego źródła `Warstwa 1.psb`. Edycja źródła propaguje się na wszystkie 8.
Imiona pary trzymamy w jednej warstwie tekstowej (string typu "Martyna i Patryk").
Wymaga: uruchomiony Adobe Photoshop, pakiet photoshop-python-api.
Użycie:
python buteleczki_slub_mloda_para.py --klient "Martyna Nowak" \\
--imiona "Martyna i Patryk" --data "06.06.2026"
python buteleczki_slub_mloda_para.py --klient "Martyna Nowak" \\
--imiona "Martyna i Patryk" --data "06.06.2026" \\
--podziekowanie "Dziękujemy za wspólną zabawę!"
"""
import argparse
import os
import photoshop.api as ps
PROJEKT_DIR = os.path.join(
r"d:\pomysloweprezenty.pl\projekty\ślub - buteleczki",
"Podziękowanie dla gości weselnych buteleczka z nadrukiem UV - Młoda para",
)
SZABLON_PATH = os.path.join(PROJEKT_DIR, "szablon 370x300.psd")
GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe")
def set_text(layer, new_text):
"""Zmienia tekst warstwy zachowując środek bounding boxa
(kompensacja dla wycentrowanych warstw)."""
b = [float(x) for x in layer.bounds]
cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2
layer.textItem.contents = new_text
b2 = [float(x) for x in layer.bounds]
cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2
dx, dy = cx - cx2, cy - cy2
if dx or dy:
layer.translate(dx, dy)
def open_smart_object_contents(app):
"""Otwiera zawartość 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 find_first_smart_object(doc):
for al in doc.artLayers:
if al.kind == 17:
return al
raise RuntimeError("Nie znaleziono warstwy Smart Object (kind=17) w szablonie")
def set_layer_text(container, layer_name, new_text):
if new_text is None:
return
layer = container.artLayers[layer_name]
old = layer.textItem.contents
set_text(layer, new_text)
print(f' {layer_name}: "{old}" -> "{new_text}"')
def generate(klient, imiona, data, podziekowanie=None):
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}")
so_layer = find_first_smart_object(doc)
app.activeDocument.activeLayer = so_layer
open_smart_object_contents(app)
so_doc = app.activeDocument
print(f" Wszedłem do SO: {so_doc.name}")
dane = so_doc.layerSets["dane"]
print(" Podmiana tekstów:")
set_layer_text(dane, "imiona", imiona)
set_layer_text(dane, "data", data)
set_layer_text(dane, "podziekowanie", podziekowanie)
so_doc.save()
so_doc.close()
print(" SO zapisany")
psd_opts = ps.PhotoshopSaveOptions()
app.activeDocument.saveAs(output_path, psd_opts, True)
print(f"Zapisano: {output_path}")
app.activeDocument.close(ps.SaveOptions.DoNotSaveChanges)
print("Gotowe!")
return output_path
def main():
parser = argparse.ArgumentParser(
description="Generator PSD - buteleczki ślubne (Młoda para)"
)
parser.add_argument("--klient", required=True, help="Nazwa pliku wyjściowego")
parser.add_argument("--imiona", required=True, help='Imiona pary (np. "Martyna i Patryk")')
parser.add_argument("--data", required=True, help="Data uroczystości (DD.MM.YYYY)")
parser.add_argument("--podziekowanie", default=None, help='Tekst podziękowania (opcjonalnie, domyślnie "Dziękujemy!")')
args = parser.parse_args()
generate(
klient=args.klient,
imiona=args.imiona,
data=args.data,
podziekowanie=args.podziekowanie,
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,179 @@
"""
Pobieranie zdjec od klientow z poczty IMAP.
Wspolny modul wykorzystywany przez generatory PSD ktore potrzebuja zdjecia
od klienta (np. akrylowe podziekowania). Lokalizuje maile od podanego adresu
nadawcy w ostatnich N dniach i pobiera pierwszy zalacznik graficzny.
Wymagane zmienne srodowiskowe (.env w katalogu projektu):
EMAIL_01_HOST - host serwera (ten sam dla SMTP i IMAP)
EMAIL_01_USERNAME - login (adres email skrzynki)
EMAIL_01_PASSWORD - haslo
EMAIL_01_IMAP_PORT - opcjonalnie, domyslnie 993 (standard IMAP SSL)
EMAIL_01_IMAP_FOLDER - opcjonalnie, domyslnie INBOX
Uzycie programowe:
from email_photo_fetcher import fetch_customer_photo
path = fetch_customer_photo("klient@example.com", "/tmp", days_back=60)
Uzycie z CLI (do testow):
python email_photo_fetcher.py --email klient@example.com --out C:/tmp
"""
import argparse
import email
import imaplib
import os
import re
import sys
from datetime import datetime, timedelta
from email.header import decode_header
IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png", ".heic", ".webp", ".tif", ".tiff", ".bmp"}
def _project_root():
return os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
def _load_env():
"""Lekka obsluga .env (KEY=VALUE), bez zaleznosci od python-dotenv."""
env_path = os.path.join(_project_root(), ".env")
if not os.path.isfile(env_path):
return {}
out = {}
with open(env_path, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
k, _, v = line.partition("=")
v = v.strip().strip('"').strip("'")
out[k.strip()] = v
return out
def _imap_config(account_prefix="EMAIL_01"):
env = _load_env()
return {
"host": env.get(f"{account_prefix}_HOST"),
"port": int(env.get(f"{account_prefix}_IMAP_PORT", "993")),
"user": env.get(f"{account_prefix}_USERNAME"),
"password": env.get(f"{account_prefix}_PASSWORD"),
"folder": env.get(f"{account_prefix}_IMAP_FOLDER", "INBOX"),
}
def _decode_filename(raw_name):
if not raw_name:
return ""
parts = decode_header(raw_name)
out = []
for chunk, enc in parts:
if isinstance(chunk, bytes):
try:
out.append(chunk.decode(enc or "utf-8", errors="replace"))
except LookupError:
out.append(chunk.decode("utf-8", errors="replace"))
else:
out.append(chunk)
return "".join(out)
def _safe_filename(name):
name = re.sub(r"[\\/:*?\"<>|]+", "_", name).strip()
return name or "attachment"
def _is_image(filename):
ext = os.path.splitext(filename)[1].lower()
return ext in IMAGE_EXTENSIONS
def fetch_customer_photo(customer_email, output_dir, days_back=60):
"""Szuka maili od customer_email z ostatnich `days_back` dni i pobiera
pierwszy zalacznik graficzny do output_dir. Zwraca sciezke lub None."""
cfg = _imap_config()
if not cfg["host"] or not cfg["user"] or not cfg["password"]:
raise RuntimeError(
"Brak konfiguracji konta w .env — wymagane: EMAIL_01_HOST, EMAIL_01_USERNAME, EMAIL_01_PASSWORD"
)
os.makedirs(output_dir, exist_ok=True)
imap = imaplib.IMAP4_SSL(cfg["host"], cfg["port"])
try:
imap.login(cfg["user"], cfg["password"])
imap.select(cfg["folder"])
since = (datetime.now() - timedelta(days=days_back)).strftime("%d-%b-%Y")
criteria = f'(FROM "{customer_email}" SINCE "{since}")'
status, data = imap.search(None, criteria)
if status != "OK" or not data or not data[0]:
return None
ids = data[0].split()
# Iterujemy od najnowszego do najstarszego
for msg_id in reversed(ids):
status, msg_data = imap.fetch(msg_id, "(RFC822)")
if status != "OK" or not msg_data or not msg_data[0]:
continue
msg = email.message_from_bytes(msg_data[0][1])
for part in msg.walk():
if part.get_content_maintype() == "multipart":
continue
disposition = str(part.get("Content-Disposition") or "")
filename = _decode_filename(part.get_filename())
if not filename:
continue
if "attachment" not in disposition.lower() and "inline" not in disposition.lower():
continue
if not _is_image(filename):
continue
payload = part.get_payload(decode=True)
if not payload:
continue
safe = _safe_filename(filename)
stamp = datetime.now().strftime("%Y%m%d%H%M%S")
local_name = f"{customer_email}_{stamp}_{safe}"
local_path = os.path.join(output_dir, local_name)
with open(local_path, "wb") as f:
f.write(payload)
return local_path
return None
finally:
try:
imap.logout()
except Exception:
pass
def main():
parser = argparse.ArgumentParser(description="Pobierz zdjecie klienta z poczty IMAP")
parser.add_argument("--email", required=True, help="Adres email klienta (nadawca)")
parser.add_argument("--out", required=True, help="Katalog wyjsciowy dla zdjecia")
parser.add_argument("--days", type=int, default=60, help="Ile dni wstecz szukac (domyslnie 60)")
args = parser.parse_args()
try:
path = fetch_customer_photo(args.email, args.out, days_back=args.days)
except Exception as exc:
print(f"BLAD: {exc}")
sys.exit(2)
if path:
print(f"OK: {path}")
else:
print("BRAK: nie znaleziono zdjecia w mailach od tego klienta")
sys.exit(0)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,121 @@
"""
Generator PSD — Pudełko na pieniądze z życzeniami (Chrzest, dziewczynka, Aniołek).
Makieta A3 — jedno pudełko, 6 ścianek (KL/KP + GL/GP + DL/DP).
Data jest w jednym miejscu: KP. DP nie ma daty (tylko imię i tytuł).
Wymaga: uruchomiony Adobe Photoshop, pakiet photoshop-python-api.
Użycie:
python pudelko_chrzest_dziewczynka_aniolek.py --klient "Anna Kowalska" \\
--imie "Lenka" --data "19.04.2026" --od-kogo "Babcia Anna"
"""
import argparse
import os
import photoshop.api as ps
PROJEKT_DIR = os.path.join(
r"d:\pomysloweprezenty.pl\projekty\chrzest - pudełka na pieniądze",
"Pudełko na pieniądze z życzeniami na Chrzest - Aniołek dziewczynka HDF UV",
)
SZABLON_PATH = os.path.join(PROJEKT_DIR, "pudełka na chrzest - makieta A3 CMYK.psd")
GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe")
def set_text(layer, new_text):
"""Zmienia tekst warstwy zachowując środek bounding boxa
(kompensacja dla wycentrowanych warstw — patrz uwagi w innych skryptach)."""
b = [float(x) for x in layer.bounds]
cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2
layer.textItem.contents = new_text
b2 = [float(x) for x in layer.bounds]
cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2
dx, dy = cx - cx2, cy - cy2
if dx or dy:
layer.translate(dx, dy)
def set_layer_text(container, layer_name, new_text):
if new_text is None:
return
layer = container.artLayers[layer_name]
old = layer.textItem.contents
set_text(layer, new_text)
print(f' {layer_name}: "{old}" -> "{new_text}"')
def generate(klient, imie, data, od_kogo, zyczenia=None, naglowek=None, tytul=None):
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}")
# KP — data (jedno źródło prawdy dla daty w całym projekcie)
print(" [KP] data:")
set_layer_text(doc.layerSets["KP"], "data", data)
# GL — życzenia (Layer 2 → dane)
print(" [GL] życzenia:")
gl_dane = doc.layerSets["GL"].layerSets["dane"]
set_layer_text(gl_dane, "od_kogo", od_kogo)
set_layer_text(gl_dane, "naglowek", naglowek)
set_layer_text(gl_dane, "zyczenia", zyczenia)
# GP — imię + tytuł (Layer 1 kopia → dane); brak daty na ściance
print(" [GP] imię/tytuł:")
gp_dane = doc.layerSets["GP"].layerSets["dane"]
set_layer_text(gp_dane, "imie", imie)
set_layer_text(gp_dane, "tytul", tytul)
# DL — życzenia (warstwy bezpośrednio w secie)
print(" [DL] życzenia:")
dl = doc.layerSets["DL"]
set_layer_text(dl, "od_kogo", od_kogo)
set_layer_text(dl, "naglowek", naglowek)
set_layer_text(dl, "zyczenia", zyczenia)
# DP — imię + tytuł; brak daty na ściance
print(" [DP] imię/tytuł:")
dp = doc.layerSets["DP"]
set_layer_text(dp, "imie", imie)
set_layer_text(dp, "tytul", tytul)
psd_opts = ps.PhotoshopSaveOptions()
doc.saveAs(output_path, psd_opts, True)
print(f"Zapisano: {output_path}")
doc.close(ps.SaveOptions.DoNotSaveChanges)
print("Gotowe!")
return output_path
def main():
parser = argparse.ArgumentParser(
description="Generator PSD - pudełko na pieniądze (Chrzest, dziewczynka Aniołek)"
)
parser.add_argument("--klient", required=True, help="Nazwa pliku wyjściowego")
parser.add_argument("--imie", required=True, help="Odmienione imię dziecka")
parser.add_argument("--data", required=True, help="Data uroczystości (DD.MM.YYYY)")
parser.add_argument("--od-kogo", dest="od_kogo", required=True, help="Kto składa życzenia")
parser.add_argument("--zyczenia", default=None, help="Treść życzeń (opcjonalnie, domyślnie z szablonu)")
parser.add_argument("--naglowek", default=None, help="Nagłówek życzeń (opcjonalnie, domyślnie z szablonu)")
parser.add_argument("--tytul", default=None, help="Tytuł (opcjonalnie, domyślnie z szablonu)")
args = parser.parse_args()
generate(
klient=args.klient,
imie=args.imie,
data=args.data,
od_kogo=args.od_kogo,
zyczenia=args.zyczenia,
naglowek=args.naglowek,
tytul=args.tytul,
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,98 @@
"""
Generator PSD - Pudelko na pieniadze z zyczeniami na Chrzest (Gołąbek HDF UV).
Makieta A3 z panelami:
- DL: od_kogo, naglowek, zyczenia
- DP: imie, data, tytul
Teksty sa bezposrednio w grupach DL/DP. Brak Smart Objectow.
Wymaga: uruchomiony Adobe Photoshop, photoshop-python-api.
"""
import argparse
import os
import photoshop.api as ps
PROJEKT_DIR = os.path.join(
r"d:\pomysloweprezenty.pl\projekty\chrzest - pudełka na pieniądze",
"Pudełko na pieniądze z życzeniami na Chrzest - Gołąbek HDF UV",
)
SZABLON_PATH = os.path.join(PROJEKT_DIR, "pudełka na chrzest - makieta A3.psd")
GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe")
def set_text(layer, new_text):
"""Zmienia tekst warstwy zachowujac srodek bounding boxa."""
b = [float(x) for x in layer.bounds]
cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2
layer.textItem.contents = new_text
b2 = [float(x) for x in layer.bounds]
cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2
dx, dy = cx - cx2, cy - cy2
if dx or dy:
layer.translate(dx, dy)
def set_layer_text(container, layer_name, new_text):
if new_text is None:
return
layer = container.artLayers[layer_name]
old = layer.textItem.contents
set_text(layer, new_text)
print(f' {layer_name}: "{old}" -> "{new_text}"')
def generate(klient, imie, data, od_kogo, zyczenia=None, naglowek=None, tytul=None):
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}")
dl = doc.layerSets["DL"]
print(" [DL] zyczenia:")
set_layer_text(dl, "od_kogo", od_kogo)
set_layer_text(dl, "naglowek", naglowek)
set_layer_text(dl, "zyczenia", zyczenia)
dp = doc.layerSets["DP"]
print(" [DP] imie/data/tytul:")
set_layer_text(dp, "imie", imie)
set_layer_text(dp, "data", data)
set_layer_text(dp, "tytul", tytul)
psd_opts = ps.PhotoshopSaveOptions()
doc.saveAs(output_path, psd_opts, True)
print(f"Zapisano: {output_path}")
doc.close(ps.SaveOptions.DoNotSaveChanges)
print("Gotowe!")
return output_path
def main():
parser = argparse.ArgumentParser(description="Generator PSD - Pudelko chrzest, Golabek HDF UV")
parser.add_argument("--klient", required=True, help="Nazwa pliku wyjsciowego")
parser.add_argument("--imie", required=True, help="Imie dziecka (odmienione, np. Gabrysi)")
parser.add_argument("--data", required=True, help="Data uroczystosci (np. 10.05.2026)")
parser.add_argument("--od-kogo", dest="od_kogo", required=True, help="Od kogo (np. Rodzice Chrzestni)")
parser.add_argument("--zyczenia", default=None, help="Tresc zyczen (opcjonalnie, domyslnie z szablonu)")
parser.add_argument("--naglowek", default=None, help="Naglowek zyczen (opcjonalnie, domyslnie z szablonu)")
parser.add_argument("--tytul", default=None, help="Tytul (opcjonalnie, domyslnie 'Pamiątka Chrztu Świętego')")
args = parser.parse_args()
generate(
klient=args.klient,
imie=args.imie,
data=args.data,
od_kogo=args.od_kogo,
zyczenia=args.zyczenia,
naglowek=args.naglowek,
tytul=args.tytul,
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,98 @@
"""
Generator PSD - Pudelko na pieniadze z zyczeniami na Chrzest (Gołąbek UV).
Makieta A3 z panelami:
- DL: od_kogo, naglowek, zyczenia
- DP: imie, data, tytul
Teksty sa bezposrednio w grupach DL/DP. Brak Smart Objectow.
Wymaga: uruchomiony Adobe Photoshop, photoshop-python-api.
"""
import argparse
import os
import photoshop.api as ps
PROJEKT_DIR = os.path.join(
r"d:\pomysloweprezenty.pl\projekty\chrzest - pudełka na pieniądze",
"Pudełko na pieniądze z życzeniami na Chrzest - Gołąbek UV",
)
SZABLON_PATH = os.path.join(PROJEKT_DIR, "pudełka na chrzest - makieta A3 CMYK.psd")
GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe")
def set_text(layer, new_text):
"""Zmienia tekst warstwy zachowujac srodek bounding boxa."""
b = [float(x) for x in layer.bounds]
cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2
layer.textItem.contents = new_text
b2 = [float(x) for x in layer.bounds]
cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2
dx, dy = cx - cx2, cy - cy2
if dx or dy:
layer.translate(dx, dy)
def set_layer_text(container, layer_name, new_text):
if new_text is None:
return
layer = container.artLayers[layer_name]
old = layer.textItem.contents
set_text(layer, new_text)
print(f' {layer_name}: "{old}" -> "{new_text}"')
def generate(klient, imie, data, od_kogo, zyczenia=None, naglowek=None, tytul=None):
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}")
dl = doc.layerSets["DL"]
print(" [DL] zyczenia:")
set_layer_text(dl, "od_kogo", od_kogo)
set_layer_text(dl, "naglowek", naglowek)
set_layer_text(dl, "zyczenia", zyczenia)
dp = doc.layerSets["DP"]
print(" [DP] imie/data/tytul:")
set_layer_text(dp, "imie", imie)
set_layer_text(dp, "data", data)
set_layer_text(dp, "tytul", tytul)
psd_opts = ps.PhotoshopSaveOptions()
doc.saveAs(output_path, psd_opts, True)
print(f"Zapisano: {output_path}")
doc.close(ps.SaveOptions.DoNotSaveChanges)
print("Gotowe!")
return output_path
def main():
parser = argparse.ArgumentParser(description="Generator PSD - Pudelko chrzest, Golabek UV")
parser.add_argument("--klient", required=True, help="Nazwa pliku wyjsciowego")
parser.add_argument("--imie", required=True, help="Imie dziecka (odmienione, np. Gabrysi)")
parser.add_argument("--data", required=True, help="Data uroczystosci (np. 10.05.2026)")
parser.add_argument("--od-kogo", dest="od_kogo", required=True, help="Od kogo (np. Rodzice Chrzestni)")
parser.add_argument("--zyczenia", default=None, help="Tresc zyczen (opcjonalnie, domyslnie z szablonu)")
parser.add_argument("--naglowek", default=None, help="Naglowek zyczen (opcjonalnie, domyslnie z szablonu)")
parser.add_argument("--tytul", default=None, help="Tytul (opcjonalnie, domyslnie 'Pamiątka Chrztu Świętego')")
args = parser.parse_args()
generate(
klient=args.klient,
imie=args.imie,
data=args.data,
od_kogo=args.od_kogo,
zyczenia=args.zyczenia,
naglowek=args.naglowek,
tytul=args.tytul,
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,36 @@
"""
Generator PSD — Pudełko na pieniądze (Komunia, chłopiec).
Cienki wrapper na _pudelko_komunia_core — tylko ścieżka do szablonu.
"""
import os
from _pudelko_komunia_core import build_arg_parser, generate
PROJEKT_DIR = os.path.join(
r"d:\pomysloweprezenty.pl\projekty\komunia święta - pudełka na pieniądze",
"Pudełko na pieniądze z życzeniami na Komunie Świętą z nadrukiem UV - Chłopiec",
)
SZABLON_PATH = os.path.join(PROJEKT_DIR, "pudełka na chrzest - makieta A3 CMYK.psd")
GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe")
def main():
parser = build_arg_parser("Generator PSD - pudełko na pieniądze (Komunia, chłopiec)")
args = parser.parse_args()
generate(
szablon_path=SZABLON_PATH,
gotowe_dir=GOTOWE_DIR,
imie=args.imie,
data=args.data,
od_kogo=args.od_kogo,
klient=args.klient,
zyczenia=args.zyczenia,
naglowek=args.naglowek,
tytul=args.tytul,
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,36 @@
"""
Generator PSD — Pudełko na pieniądze (Komunia, dziewczynka).
Cienki wrapper na _pudelko_komunia_core — tylko ścieżka do szablonu.
"""
import os
from _pudelko_komunia_core import build_arg_parser, generate
PROJEKT_DIR = os.path.join(
r"d:\pomysloweprezenty.pl\projekty\komunia święta - pudełka na pieniądze",
"Pudełko na pieniądze z życzeniami na Komunie Świętą z nadrukiem UV - Dziewczynka",
)
SZABLON_PATH = os.path.join(PROJEKT_DIR, "pudełka na chrzest - makieta A3 CMYK.psd")
GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe")
def main():
parser = build_arg_parser("Generator PSD - pudełko na pieniądze (Komunia, dziewczynka)")
args = parser.parse_args()
generate(
szablon_path=SZABLON_PATH,
gotowe_dir=GOTOWE_DIR,
imie=args.imie,
data=args.data,
od_kogo=args.od_kogo,
klient=args.klient,
zyczenia=args.zyczenia,
naglowek=args.naglowek,
tytul=args.tytul,
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,98 @@
"""
Generator PSD - Pudelko na pieniadze z zyczeniami (Komunia, wzor Kwiaty).
Makieta A3 z 6 panelami, ale tylko DL i DP sa uzywane:
- DL: imie, data, tytul
- DP: od_kogo, naglowek, zyczenia
Teksty sa bezposrednio w grupach DL/DP (brak subgrupy "dane"). Brak Smart Objectow.
Wymaga: uruchomiony Adobe Photoshop, photoshop-python-api.
"""
import argparse
import os
import photoshop.api as ps
PROJEKT_DIR = os.path.join(
r"d:\pomysloweprezenty.pl\projekty\komunia święta - pudełka na pieniądze",
"Pudełko na pieniądze z życzeniami na Komunie Świętą z nadrukiem UV - Kwiaty",
)
SZABLON_PATH = os.path.join(PROJEKT_DIR, "pudełka na chrzest - makieta A3.psd")
GOTOWE_DIR = os.path.join(PROJEKT_DIR, "_gotowe")
def set_text(layer, new_text):
"""Zmienia tekst warstwy zachowujac srodek bounding boxa."""
b = [float(x) for x in layer.bounds]
cx, cy = (b[0] + b[2]) / 2, (b[1] + b[3]) / 2
layer.textItem.contents = new_text
b2 = [float(x) for x in layer.bounds]
cx2, cy2 = (b2[0] + b2[2]) / 2, (b2[1] + b2[3]) / 2
dx, dy = cx - cx2, cy - cy2
if dx or dy:
layer.translate(dx, dy)
def set_layer_text(container, layer_name, new_text):
if new_text is None:
return
layer = container.artLayers[layer_name]
old = layer.textItem.contents
set_text(layer, new_text)
print(f' {layer_name}: "{old}" -> "{new_text}"')
def generate(klient, imie, data, od_kogo, zyczenia=None, naglowek=None, tytul=None):
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}")
dl = doc.layerSets["DL"]
print(" [DL] imie/data/tytul:")
set_layer_text(dl, "imie", imie)
set_layer_text(dl, "data", data)
set_layer_text(dl, "tytul", tytul)
dp = doc.layerSets["DP"]
print(" [DP] zyczenia:")
set_layer_text(dp, "od_kogo", od_kogo)
set_layer_text(dp, "naglowek", naglowek)
set_layer_text(dp, "zyczenia", zyczenia)
psd_opts = ps.PhotoshopSaveOptions()
doc.saveAs(output_path, psd_opts, True)
print(f"Zapisano: {output_path}")
doc.close(ps.SaveOptions.DoNotSaveChanges)
print("Gotowe!")
return output_path
def main():
parser = argparse.ArgumentParser(description="Generator PSD - Pudelko komunia, wzor Kwiaty")
parser.add_argument("--klient", required=True, help="Nazwa pliku wyjsciowego")
parser.add_argument("--imie", required=True, help="Imie dziecka (odmienione, np. Karolinki)")
parser.add_argument("--data", required=True, help="Data uroczystosci (np. 10.05.2026)")
parser.add_argument("--od-kogo", dest="od_kogo", required=True, help="Od kogo (np. Ciocia i Wujek)")
parser.add_argument("--zyczenia", default=None, help="Tresc zyczen (opcjonalnie, domyslnie z szablonu)")
parser.add_argument("--naglowek", default=None, help="Naglowek zyczen (opcjonalnie, domyslnie z szablonu)")
parser.add_argument("--tytul", default=None, help="Tytul (opcjonalnie, domyslnie z szablonu)")
args = parser.parse_args()
generate(
klient=args.klient,
imie=args.imie,
data=args.data,
od_kogo=args.od_kogo,
zyczenia=args.zyczenia,
naglowek=args.naglowek,
tytul=args.tytul,
)
if __name__ == "__main__":
main()