【问题标题】:Poor anti-aliasing of text drawn on Canvas在画布上绘制的文本抗锯齿效果不佳
【发布时间】:2011-07-12 20:11:35
【问题描述】:

我正在 Canvas 上绘制文本,但我对抗锯齿的质量感到失望。据我所知,浏览器不会对 Canvas 上的文本进行亚像素抗锯齿处理。

这准确吗?

这在 iPhone 和 Android 上尤为明显,生成的文本不像其他 DOM 元素呈现的文本那样清晰。

对在 Canvas 上输出高质量文本有何建议?

朱伯特

【问题讨论】:

标签: html canvas antialiasing typography subpixel


【解决方案1】:

已经完成了一些亚像素抗锯齿,但这取决于浏览器/操作系统。

这里有一点 earlier discussion 可能对你有帮助。

我没有 android 或 iOS 设备,但只是为了好玩,在绘制之前尝试将上下文翻译 (.5, 0) 像素,看看这是否会对文本的呈现方式产生影响。

【讨论】:

    【解决方案2】:

    尝试将以下 META 标记添加到您的页面。这似乎解决了我在 iPhone Safari 上遇到的抗锯齿问题:

    <meta name="viewport" content="user-scalable=no, width=device-width,
          initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5" />
    

    【讨论】:

    • 谢谢!!这让我发疯了
    【解决方案3】:

    我意识到这是一个老问题,但我今天解决了这个问题并且让它运行良好。我在上面使用了 Alix Axel 的答案,并将在那里找到的代码(在 web.archive.org 链接上)剥离为最基本的要素。

    我稍微修改了解决方案,使用了两个画布,一个隐藏的画布用于原始文本,第二个画布实际显示抗锯齿文本。

    这就是我想出的...http://jsfiddle.net/X2cKa/

    代码如下所示;

    function alphaBlend(gamma, c1, c2, alpha) {
        c1 = c1/255.0;
        c2 = c2/255.0;
        var c3 = Math.pow(
        Math.pow(c1, gamma) * (1 - alpha)
            + Math.pow(c2, gamma) * alpha,
        1/gamma
        );
        return Math.round(c3 * 255);
     }
    
    function process(textPixels, destPixels, fg, bg) {
        var gamma = 2.2;
        for (var y = 0; y < textPixels.height; y ++) {
            var history = [255, 255, 255];
            var pixel_number = y * textPixels.width;
            var component = 0;
            for (var x = 0; x < textPixels.width; x ++) {
                var alpha = textPixels.data[(y * textPixels.width + x) * 4 + 1] / 255.0;
                alpha = Math.pow(alpha, gamma);
                history[component] = alpha;
                alpha = (history[0] + history[1] + history[2]) / 3;
                out = alphaBlend(gamma, bg[component], fg[component], alpha);
                destPixels.data[pixel_number * 4 + component] = out;    
                /* advance to next component/pixel */
                component ++;
                if (component == 3) {
                pixel_number ++;
                component = 0;
                }
            }
        }
    }
    
    function toColor(colorString) {
        return [parseInt(colorString.substr(1, 2), 16),
        parseInt(colorString.substr(3, 2), 16),
        parseInt(colorString.substr(5, 2), 16)];
    }
    
    function renderOnce() {
        var phrase = "Corporate GOVERNANCE"
        var c1 = document.getElementById("c1"); //the hidden canvas
        var c2 = document.getElementById("c2"); //the canvas
        var textSize=40;
    
        var font = textSize+"px Arial"
        var fg = "#ff0000";
        var bg = "#fff9e1";
    
        var ctx1 = c1.getContext("2d");
        var ctx2 = c2.getContext("2d");
        ctx1.fillStyle = "rgb(255, 255, 255)";
        ctx1.fillRect(0, 0, c1.width, c1.height);
    
        ctx1.save();
        ctx1.scale(3, 1);
        ctx1.font = font;
        ctx1.fillStyle = "rgb(255, 0, 0)";
        ctx1.fillText(phrase, 0, textSize);
        ctx1.restore();
    
        var textPixels = ctx1.getImageData(0, 0, c1.width, c1.height);
    
        var colorFg = toColor(fg);
        var colorBg = toColor(bg);
        var destPixels3 = ctx1.getImageData(0, 0, c1.width, c1.height);
        process(textPixels, destPixels3, colorBg, colorFg);
        ctx2.putImageData(destPixels3, 0, 0);
    
    
        //for comparison, show Comparison Text without anti aliaising
        ctx2.font = font;
        ctx2.fillStyle = "rgb(255, 0, 0)";
        ctx2.fillText(phrase, 0, textSize*2);
    
    };
    
    renderOnce();
    

    我还添加了一个比较文本对象,以便您可以看到抗锯齿效果。

    希望这对某人有所帮助!

    【讨论】:

      【解决方案4】:

      我的答案来自此链接,也许它会对其他人有所帮助。 http://www.html5rocks.com/en/tutorials/canvas/hidpi/

      重要代码如下。

      // finally query the various pixel ratios
          devicePixelRatio = window.devicePixelRatio || 1,
          backingStoreRatio = context.webkitBackingStorePixelRatio ||
                              context.mozBackingStorePixelRatio ||
                              context.msBackingStorePixelRatio ||
                              context.oBackingStorePixelRatio ||
                              context.backingStorePixelRatio || 1,
      
          ratio = devicePixelRatio / backingStoreRatio;
      
      // upscale the canvas if the two ratios don't match
      if (devicePixelRatio !== backingStoreRatio) {
      
          var oldWidth = canvas.width;
          var oldHeight = canvas.height;
      
          canvas.width = oldWidth * ratio;
          canvas.height = oldHeight * ratio;
      
          canvas.style.width = oldWidth + 'px';
          canvas.style.height = oldHeight + 'px';
      
          // now scale the context to counter
          // the fact that we've manually scaled
          // our canvas element
          context.scale(ratio, ratio);
      
      }
      

      【讨论】:

      • 感谢代码!它工作得很好。我站到了这一点,但没有缩放画布。
      猜你喜欢
      • 1970-01-01
      • 2012-11-16
      • 2013-12-04
      • 1970-01-01
      • 2013-03-26
      • 2011-08-27
      • 2010-12-19
      • 1970-01-01
      相关资源
      最近更新 更多