Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The height of the text when using react-konva and konva is not the same, causing the text to appear skewed #1798

Open
htran844 opened this issue Jul 24, 2024 · 8 comments

Comments

@htran844
Copy link

htran844 commented Jul 24, 2024

I want to use react-konva to preview and drag text. Additionally, I plan to use konva in a Node.js server to render a PDF file with thousands of pages. However, when I render a test page, there is a problem: the height of some fonts is not consistent. As a result, the text "hg" with a custom font appears skewed.

Is there anything else you need help with?

image in react web:
react

image in nodejs server:
nodejs

My custom font I use is SVN-Pateglamt-Script, you can download at:
https://drive.google.com/file/d/1YmEdMiq4H5ESV7503EN8ZDjHjMun9shO/view?usp=sharing
This is my code in react version and nodejs version:
React code:

import React, { useState } from "react";
import { Stage, Layer, Text } from "react-konva";
import "./App.css";
const widthGiay = 1240;
const heightGiay = 874;

function App() {
  const stageRef = React.useRef(null);
  return (
    <div>
      <div
        style={{
          width: widthGiay,
          height: heightGiay,
          border: "1px solid red"
        }}
      >
        <Stage width={widthGiay} height={heightGiay} ref={stageRef}>
          <Layer>
          <Text
              text="Hg"
              x={0}
              y={0}
              fontFamily="Calibri"
              fontSize={360}
              draggable
            />
            <Text
              text="Hg"
              x={500}
              y={0}
              fontFamily="SVN-Pateglamt-Script"
              fontSize={360}
              draggable
            />
          </Layer>
        </Stage>
      </div>
    </div>
  );
}

export default App;

nodejs code:

import { registerFont } from "canvas";
import Konva from "konva";

var stage = new Konva.Stage({
  width: 1240,
  height: 874,
});

// add canvas element
var layer = new Konva.Layer();
stage.add(layer);
registerFont("./fonts/SVN-Pateglamt-Script.ttf", {
  family: "SVN-Pateglamt-Script",
});
var simpleText = new Konva.Text({
  x: 0,
  y: 0,
  text: "Hg",
  fontSize: 360,
  fontFamily: "Calibri",
});
var simpleText2 = new Konva.Text({
  x: 500,
  y: 0,
  text: "Hg",
  fontSize: 360,
  fontFamily: "SVN-Pateglamt-Script",
  draggable: true,
});
layer.add(simpleText);
layer.add(simpleText2);
console.log("uri", stage.toDataURL());

I am using Nodejs 20.15.0
"konva": "^9.3.14"
"react-konva": "^18.2.10"

@lavrton
Copy link
Member

lavrton commented Jul 25, 2024

I don't think we can do much from Konva side. canvas library in Node.js renders fonts differently. Possible solutions I see:

  1. Use puppeteer. Slow, consumes a lot of CPU and memory. But will give you almost 100% the same result.
  2. Monkey patch konva in node to use skia-canvas instead of canvas.

Something like this:

const Konva = require('konva');
const { Canvas, DOMMatrix, Image } = require('skia-canvas');

global.DOMMatrix = DOMMatrix;
Konva.Util['createCanvasElement'] = () => {
  const node = new Canvas(300, 300);
  if (!node['style']) {
    node['style'] = {};
  }
  return node;
};

@htran844
Copy link
Author

I try the solutions 2 but can't fix :((

// import { registerFont } from "canvas";
import Konva from "konva";
import pkg from 'skia-canvas';
const { Canvas, DOMMatrix, Image, FontLibrary } = pkg
global.DOMMatrix = DOMMatrix;
Konva.Util['createCanvasElement'] = () => {
  const node = new Canvas(300, 300);
  if (!node['style']) {
    node['style'] = {};
  }
  return node;
};

var stage = new Konva.Stage({
  width: 1240,
  height: 874,
});

// add canvas element
var layer = new Konva.Layer();
stage.add(layer);

// registerFont("./fonts/PlaywriteBEVLG-VariableFont-wght.ttf", {
//   family: "PlaywriteBEVLG",
// });

// registerFont("./fonts/SVN-Pateglamt-Script.ttf", {
//   family: "SVN-Pateglamt-Script",
// });
FontLibrary.use('PlaywriteBEVLG','./fonts/PlaywriteBEVLG-VariableFont-wght.ttf');
FontLibrary.use('SVN-Pateglamt-Script','./fonts/SVN-Pateglamt-Script.ttf');
var box = new Konva.Rect({
    x: 0,
    y: 0,
    width: 1240,
    height: 874,
    fill: "lightgray"
})
var simpleText = new Konva.Text({
  x: 0,
  y: 0,
  text: "Hg",
  fontSize: 360,
  fontFamily: "PlaywriteBEVLG",
});
var simpleText2 = new Konva.Text({
  x: 500,
  y: 0,
  text: "Hg",
  fontSize: 360,
  fontFamily: "SVN-Pateglamt-Script",
  draggable: true,
});
layer.add(box);
layer.add(simpleText);
layer.add(simpleText2);
console.log("uri", stage.toDataURL().then(uri=>{
  console.log(uri)
}));
// console.log("uri", stage.toDataURL());

@htran844 htran844 reopened this Jul 26, 2024
@lavrton
Copy link
Member

lavrton commented Jul 26, 2024

Does it produce the result? Like you have an image output?

@htran844
Copy link
Author

this is result, font "SVN-Pateglamt-Script" not like react-konva when I use x=0 and y=0. (the second text)
skia

@lavrton
Copy link
Member

lavrton commented Jul 26, 2024

Well, I don't think there is much to do. Only the first option is left.
Different render engines may produce different results. Like, even Chrome vs Firefox vs Safari sometimes render different output. Also, you can try to use Konva._fixTextRendering = true. It was made for a different issue, but it may change something for you.

If nothing works, I would go with puppeteer.

@htran844
Copy link
Author

Konva._fixTextRendering = true cannot fix. I think puppeteer will get bad perfomance. I will try export png in client or switch to use canvas in both side. thank you for your help!

@lavrton
Copy link
Member

lavrton commented Jul 26, 2024

switch to use canvas in both side

What do you mean by that? You can't use canvas library directly on the client side. It will give you back just the native browser API, not its node.js implementation.

@htran844
Copy link
Author

I use the native canvas in HTML, and on the server, I use a canvas library. The x and y positions render the same

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants