Agamnentzar / ag-psd

Javascript library for reading and writing PSD files
Other
489 stars 66 forks source link

Trying to draw text from psd file by ag-psd #191

Closed SWhite0591 closed 1 month ago

SWhite0591 commented 1 month ago

I'm trying to draw text layers from a psd file to canvas, I'm using Konva lib instead of original canvas. But I found I can't render the text perfectly fit the canvas in psd drawn. See image below. Oringinal text is black and what I draw is red.

image

I'm not sure if I missed any of important logic in output or if I reached the limit of drawing text myself. Here is the code and the psd file I'm testing.

test-font.psd.zip

const { text, style, paragraphStyle } = psdLayer.text;
    const trackingToEm = style.tracking / 1000;
    const letterSpacingPx = trackingToEm * style.fontSize;

    const textNode = new Konva.Text({
      x: psdLayer.left,
      y: psdLayer.top,
      text: text,
      fontSize: style.fontSize,
      fontFamily: style.font.name,
      fontStyle: style.fauxBold ? 'bold' : 'normal',
      fill: style.fillColor ? `rgb(${style.fillColor.r}, ${style.fillColor.g}, ${style.fillColor.b})` : 'black',
      stroke: style.strokeColor ? `rgb(${style.strokeColor.r}, ${style.strokeColor.g}, ${style.strokeColor.b})` : 'black',
      fillAfterStrokeEnabled    : true,
      strokeWidth: style.strokeWidth ? style.strokeWidth : 1,
      align: paragraphStyle.justification,
      scaleX: style.horizontalScale,
      letterSpacing: style.tracking ? letterSpacingPx : 0,
      lineHeight: style.leading? (style.leading / style.fontSize) : 1.0,
    });

    layer.add(textNode);
SWhite0591 commented 1 month ago

If I add a letterspacing 0.4 without any reason, my second line "EXTRA STRENGTH DREAM...." fit almost perfectly. But...I didn't find any data in parsed format so I can't fill the letterspacing by program.

Agamnentzar commented 1 month ago

You should use values from transform instead of layer left/top, you skipped scaleY. There's also shapeType field, it can be "box" or "point" depending on the type of text layer used in photoshop and the layout will be different in each case. There is wordSpacing, letterSpacing and glyphSpacing fields in paragraphStyle.

SWhite0591 commented 1 month ago

You should use values from transform instead of layer left/top, you skipped scaleY. There's also shapeType field, it can be "box" or "point" depending on the type of text layer used in photoshop and the layout will be different in each case. There is wordSpacing, letterSpacing and glyphSpacing fields in paragraphStyle.

Thank you for your swift response. I'm totally surprised. I'll take your opinion into my code.

SWhite0591 commented 1 month ago

I used transform by guessing and it looks better than before. But I have no idea about how can I go further. I'm just wondering if there is a doc explaining how the fields work... Thanks in advanced.

image
const textNode = new Konva.Text({
      x: psdLayer.text.transform[4]+psdLayer.text.bounds.left.value,
      y: psdLayer.text.transform[5]+psdLayer.text.bounds.top.value,
      text: text,
      fontSize: style.fontSize,
      fontFamily: style.font.name,
      fill: style.fillColor ? `rgb(${style.fillColor.r}, ${style.fillColor.g}, ${style.fillColor.b})` : 'black',
      stroke: style.strokeColor ? `rgb(${style.strokeColor.r}, ${style.strokeColor.g}, ${style.strokeColor.b})` : 'black',
      fillAfterStrokeEnabled    : true,
      strokeWidth: style.strokeWidth ? style.strokeWidth : 1,
      align: paragraphStyle.justification,
      scaleX: style.horizontalScale,
      scaleY: psdLayer.text.transform[3],
      letterSpacing: style.tracking ? letterSpacingPx : 0,
      lineHeight: style.leading? (style.leading / style.fontSize) : 1.0,
    });
Agamnentzar commented 1 month ago

There's no explanation anywhere, you have to figure out how photoshop text rendering works, there's no guarantee that Konva will handle it the same way as photoshop either. I still don't know how photoshop calculates position of the first line, based on bounding box so it's all kind of guess work. You also need to make sure that transform is [1, 0, 0, 1, x, y] because it the first 4 values are not 1, 0, 0, 1 there's extra scaling or rotation involved there. You alsoneed to pass bounds.width/height to Konva, so it knows where to break lines

SWhite0591 commented 1 month ago

It seems like I'm on the right way because I started guessing and it was getting better. Really appreciate your help.

SWhite0591 commented 1 month ago

There's no explanation anywhere, you have to figure out how photoshop text rendering works, there's no guarantee that Konva will handle it the same way as photoshop either. I still don't know how photoshop calculates position of the first line, based on bounding box so it's all kind of guess work. You also need to make sure that transform is [1, 0, 0, 1, x, y] because it the first 4 values are not 1, 0, 0, 1 there's extra scaling or rotation involved there. You alsoneed to pass bounds.width/height to Konva, so it knows where to break lines

Thanks for the opinion about pass bounds width/height to Konva, it fixed an breaking line issue when I tried to pass layor.width. Give a feedback to you and leave a message here. It may help someone too.