Skip to content

How can I draw special characters in the canvas? #2479

Open
@dinhduchuy-dev

Description

@dinhduchuy-dev

I realized a problem when working with canvas is that my special characters always become a square, I tried to find out and realized that the font format I am using is tff instead of woff2 but I still get the error in my code. Because I use canvas version 3.0.1 they don't support woff2 format fonts so tooii uses the included fontkit as a 3rd library. Here is my code

function drawAlignedText(ctx, text, x, y, font, options = {}) {
  const {
    fontSize = 30,
    color = "black",
    horizontalAlign = "start", // Căn chỉnh ngang: left, center, right
    verticalAlign = "top", // Căn chỉnh dọc: top, middle, bottom
  } = options;

  const scale = fontSize / font.unitsPerEm;

  if (isNaN(scale)) {
    console.error('Giá trị scale là NaN. Kiểm tra lại giá trị fontSize và font.unitsPerEm.');
    console.log('fontSize:', fontSize);
    console.log('font.unitsPerEm:', font.unitsPerEm);
  }
  

  // Tính glyphs và chiều rộng của văn bản
  const glyphs = font.glyphsForString(text);
  const textWidth =
    glyphs.reduce((width, glyph) => width + glyph.advanceWidth, 0) * scale;
  const textHeight = (font.ascent - font.descent) * scale;

  // Điều chỉnh vị trí bắt đầu vẽ dựa vào lựa chọn căn chỉnh
  let startX = x;
  let startY = y;

  // Căn chỉnh ngang
  if (horizontalAlign === "center") {
    startX = x - textWidth / 2; // Căn giữa theo chiều ngang
  } else if (horizontalAlign === "end") {
    startX = x - textWidth; // Căn phải
  }

  // Căn chỉnh dọc
  if (verticalAlign === "middle") {
    startY = y + textHeight / 2 - font.ascent * scale; // Căn giữa theo chiều dọc
  } else if (verticalAlign === "bottom") {
    startY = y - font.ascent * scale; // Căn dưới
  }

  // Vẽ từng glyph
  ctx.fillStyle = color;
  let currentX = startX;

  glyphs.forEach((glyph) => {
    ctx.save();
    ctx.translate(currentX, startY);
    ctx.scale(scale, -scale); // Lật theo trục y để đúng hướng
    ctx.beginPath();

    // Vẽ đường dẫn glyph lên canvas
    glyph.path.commands.forEach((cmd) => {
      if (cmd.command === "moveTo") {
        ctx.moveTo(cmd.args[0], cmd.args[1]);
      } else if (cmd.command === "lineTo") {
        ctx.lineTo(cmd.args[0], cmd.args[1]);
      } else if (cmd.command === "quadraticCurveTo") {
        ctx.quadraticCurveTo(
          cmd.args[0],
          cmd.args[1],
          cmd.args[2],
          cmd.args[3]
        );
      } else if (cmd.command === "bezierCurveTo") {
        ctx.bezierCurveTo(
          cmd.args[0],
          cmd.args[1],
          cmd.args[2],
          cmd.args[3],
          cmd.args[4],
          cmd.args[5]
        );
      } else if (cmd.command === "closePath") {
        ctx.closePath();
      }
    });

    ctx.fill();
    ctx.restore();
    currentX += glyph.advanceWidth * scale;
  });
}

Uh when I pass the parameter to the text as a string "AG丶NhanMBム" They get an error and no longer display the correct string I pass in, even when I use a font with woff2 format and this makes me quite sad. headache

Is there any way I can print all kinds of special characters on canvas images? I really need an answer because my Messenger Bot has to handle special data like this...

Because I used canvas's ctx.fillText and it was broken, I asked ChatGPT for advice. The above code is just ChatGPT's code that was modified by drawing each glyph.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions