TypeLayer: center via transform origin + text-size boundingBox
Keep justification untouched (user: don't force center - it made the edit box huge / run off canvas). Instead center the text by putting the transform origin at the boundingRect center and the boundingBox as the actual text box (-w/2..w/2, -h/2..h/2): small edit box, centered text, no justification spreading, last glyph fits.
This commit is contained in:
1 parent
6af94c24b4
commit
4e994802bf
1 file changed
+20
-17
+20
-17
@@ -504,7 +504,7 @@ def font_ps_name(font_path: str) -> str:
|
|||||||
return os.path.basename(font_path)
|
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
|
"""Build a TySh (TypeTool object setting) block for an editable text layer
|
||||||
by mutating the reference template's engine data."""
|
by mutating the reference template's engine data."""
|
||||||
tmpl = Path(__file__).parent / "tools_tysh_template.bin"
|
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)
|
text_len = len(text)
|
||||||
eng["StyleRun"]["RunLengthArray"] = List([Integer(text_len)])
|
eng["StyleRun"]["RunLengthArray"] = List([Integer(text_len)])
|
||||||
eng["ParagraphRun"]["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))
|
prof = font_profile(_font_path_for(ly))
|
||||||
size_px = float(ly.get("textSize", "12") or 12) * prof["k"]
|
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
|
# DocumentResources mirrors ResourceDict; keep both font tables in sync
|
||||||
# or PS flags the text layer as needing conversion.
|
# or PS flags the text layer as needing conversion.
|
||||||
ed["DocumentResources"]["FontSet"][0]["Name"] = String(font_ps)
|
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)
|
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)
|
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
|
tw = text_w if text_w else (rr - l)
|
||||||
# transform(boundingBox). Set it to (0,0)-(w,h) so the text lands on the
|
th = size_px * 1.2
|
||||||
# ppl boundingRect (verified: l.psd display pos = transform x boundingBox).
|
|
||||||
bbd = td[b"boundingBox"]
|
bbd = td[b"boundingBox"]
|
||||||
bbd[b"Left"].value = 0.0
|
bbd[b"Left"].value = -tw / 2
|
||||||
bbd[b"Top "].value = 0.0
|
bbd[b"Top "].value = -th / 2
|
||||||
bbd[b"Rght"].value = float(rr - l)
|
bbd[b"Rght"].value = tw / 2
|
||||||
bbd[b"Btom"].value = float(bb2 - t)
|
bbd[b"Btom"].value = th / 2
|
||||||
return tysh.tobytes()
|
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:
|
if type_layer and ly["_type"] == "text" and _TYSHA:
|
||||||
try:
|
try:
|
||||||
fp = _font_path_for(ly)
|
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:
|
except Exception as exc:
|
||||||
print(f" warning: text layer {name} -> TySh failed: {exc}",
|
print(f" warning: text layer {name} -> TySh failed: {exc}",
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
|
|||||||
Reference in new issue
Block a user