在Windows中的画布中呈现文本的Bug

时间:2014-12-08 23:54:14

标签: html5 canvas

我正在创建一个在画布中使用文本渲染的应用程序,但我遇到了一个奇怪的问题。我已经在许多计算机上进行了测试,它只发生在使用Windows的系统上。我会解释一下:

当我使用Times New Roman,使用某些字体大小,填充颜色,文本笔划和斜体样式时,某些字母会显示笔划位移。

起初我认为这是我用于画布的库的一个问题,但我已经使用原生画布进行了测试,它也正在发生。

以下是jsfiddle:http://jsfiddle.net/ekm3o977/1/(请记住,它只发生在Windows中)

<body>
    <canvas id="myCanvas" width="1000" height="400"></canvas>
    <script>
      var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');
      var x = 80;
      var y = 110;

      context.font = 'italic 70px Times New Roman';

      context.lineWidth = 1;
      // stroke color
      context.strokeStyle = 'red';
      context.fillStyle = 'blue';
      context.fillText('abcdefghijklmnñ', x, y);
      context.strokeText('abcdefghijklmnñ', x, y);
      context.fillText('opqrstuvwxyz', x, y+100);
      context.strokeText('opqrstuvwxyz', x, y+100);
    </script>
</body> 

有关如何解决的任何想法?感谢

1 个答案:

答案 0 :(得分:1)

导致此问题的主要原因无法解决,因为子系统(浏览器与之交互)的内部问题本身就存在问题。

你可以试试几种方法:

  1. 如评论中所述,请尝试使用它的网络字体版本(注意:requires license)。对于画布,您需要使用font-loader,以便在将文本绘制到画布之前知道字体何时正确加载。

  2. 我注意到问题在100px的大小完全消失了。我们可以使用它来创建一个包装函数来将其缩放到我们需要的大小。我在下面的解决方案中采取了一些妥协措施,例如降低基线和对齐方式。但是,如果需要,可以使用它们进行扩展。

  3. var ctx = canvas.getContext("2d");
    
    ctx.fillStyle = "blue";
    ctx.strokeStyle = "red";
    ctx.lineWidth = 1;
    ctx.font = "italic 70px Times New Roman";
    ctx.textBaseline = "top";
    ctx.fillText("This is native fillText/strokeText", 10, 10);
    ctx.strokeText("This is native fillText/strokeText", 10, 10);
    
    tnrWrapper(ctx, "This is wrapper function", 10, 80, 70, "italic");
    
    function tnrWrapper(ctx, txt, x, y, size, style) {
    
      var width, hf = 1.1, // height factor
          tcanvas = document.createElement("canvas"),
          tctx = tcanvas.getContext("2d");
    
      style = style || ""; // italic, bold or nothing
      
      tctx.font = style + " 100px Times New Roman"; // fixed at 100px here  
      width = tctx.measureText(txt).width;
      
      tcanvas.width = width; // this will reset font, optionally set a fixed width
      tcanvas.height = 100*hf;  // todo: find a better proportional factor
    
      tctx.font = style + " 100px Times New Roman";  // new width resets context
      tctx.textBaseline = "top";
      tctx.textAlign = "start";  // rtl sensitive, or use left/right
      
      tctx.lineWidth = ctx.lineWidth * (100/size);   // scale line width
      tctx.fillStyle = ctx.fillStyle;
      tctx.strokeStyle = ctx.strokeStyle;
    
      tctx.fillText(txt, 0, 0);
      tctx.strokeText(txt, 0, 0);
      
      ctx.drawImage(tcanvas, x, y, width * (size/100), 100*hf * (size/100));
    }
    <canvas id=canvas width=600 height=180></canvas>

    正如您所看到的,我们现在得到大致相同的尺寸但没有对齐问题。

    注1:字体的大小不是线性的。它们针对各种尺寸进行了优化。这会影响实际宽度等。所以不要指望它们在所有尺寸上都是相同的。但是它应该提供一个可行的解决方案,直到解决了这个问题(这可能需要一段时间,因为它似乎是Windows中的系统级别)。

    注2:字体设置两次。这是因为我们需要测量它并更新画布以匹配。当canvas获取新的维度上下文时,重置丢失设置的字体。您可以通过设置固定宽度的画布来避免这种情况。

    希望这有帮助!