diff --git a/ppl2psd.py b/ppl2psd.py index e1a14cb..6b93fe1 100644 --- a/ppl2psd.py +++ b/ppl2psd.py @@ -504,7 +504,7 @@ def font_ps_name(font_path: str) -> str: return os.path.basename(font_path) -def build_type_layer_tysh(ly: dict, font_ps: str) -> bytes: +def build_type_layer_tysh(ly: dict, font_ps: str, text_w: Optional[float] = None) -> bytes: """Build a TySh (TypeTool object setting) block for an editable text layer by mutating the reference template's engine data.""" tmpl = Path(__file__).parent / "tools_tysh_template.bin" @@ -525,13 +525,6 @@ def build_type_layer_tysh(ly: dict, font_ps: str) -> bytes: text_len = len(text) eng["StyleRun"]["RunLengthArray"] = List([Integer(text_len)]) eng["ParagraphRun"]["RunLengthArray"] = List([Integer(text_len)]) - # Template paragraph is justify (Justification=5), which spreads short - # text across the whole box. The ppl text is centered -> center align. - try: - props = eng["ParagraphRun"]["RunArray"][0]["ParagraphSheet"]["Properties"] - props["Justification"] = Integer(1) # center - except Exception: - pass prof = font_profile(_font_path_for(ly)) size_px = float(ly.get("textSize", "12") or 12) * prof["k"] @@ -554,18 +547,27 @@ def build_type_layer_tysh(ly: dict, font_ps: str) -> bytes: # DocumentResources mirrors ResourceDict; keep both font tables in sync # or PS flags the text layer as needing conversion. ed["DocumentResources"]["FontSet"][0]["Name"] = String(font_ps) + # StyleSheetSet preset: set color too (PS may read the preset style) + try: + res["StyleSheetSet"][0]["StyleSheetData"]["FillColor"] = fc + except Exception: + pass l, t, rr, bb2 = bounding_rect(ly) - tysh.transform = [1.0, 0.0, 0.0, 1.0, float(l), float(t)] + # transform origin = center of the ppl rect; boundingBox = the actual + # text box centered on it. This keeps the text centered and the edit box + # small (template bbox / justification would spread text across a huge + # frame or run off canvas). + cx, cy = (l + rr) / 2, (t + bb2) / 2 + tysh.transform = [1.0, 0.0, 0.0, 1.0, float(cx), float(cy)] tysh.left, tysh.top, tysh.right, tysh.bottom = int(l), int(t), int(rr), int(bb2) - # boundingBox is relative to the transform origin; PS shows the text at - # transform(boundingBox). Set it to (0,0)-(w,h) so the text lands on the - # ppl boundingRect (verified: l.psd display pos = transform x boundingBox). + tw = text_w if text_w else (rr - l) + th = size_px * 1.2 bbd = td[b"boundingBox"] - bbd[b"Left"].value = 0.0 - bbd[b"Top "].value = 0.0 - bbd[b"Rght"].value = float(rr - l) - bbd[b"Btom"].value = float(bb2 - t) + bbd[b"Left"].value = -tw / 2 + bbd[b"Top "].value = -th / 2 + bbd[b"Rght"].value = tw / 2 + bbd[b"Btom"].value = th / 2 return tysh.tobytes() @@ -836,7 +838,8 @@ def convert(ppl_path: str, out_path: str, preview_path: Optional[str] = None, if type_layer and ly["_type"] == "text" and _TYSHA: try: fp = _font_path_for(ly) - tysh = build_type_layer_tysh(ly, font_ps_name(fp)) + tysh = build_type_layer_tysh(ly, font_ps_name(fp), + text_w=img.width) except Exception as exc: print(f" warning: text layer {name} -> TySh failed: {exc}", file=sys.stderr)