首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何修复HTML5画布中的模糊文本?

如何修复HTML5画布中的模糊文本?
EN

Stack Overflow用户
提问于 2013-03-27 22:25:47
回答 12查看 91.9K关注 0票数 99

我是一个使用HTML5的n00b,正在使用canvas渲染形状、颜色和文本。在我的应用程序中,我有一个视图适配器,它动态创建一个画布,并用内容填充它。这真的很好用,除了我的文本呈现得非常模糊/模糊/拉伸。我已经看过很多其他的关于为什么用CSS定义宽度和高度会导致这个问题的帖子,但我用javascript来定义它。

相关代码(查看Fiddle):

代码语言:javascript
复制
var width  = 500;//FIXME:size.w;
var height = 500;//FIXME:size.h;
    
var canvas = document.createElement("canvas");
//canvas.className="singleUserCanvas";
canvas.width=width;
canvas.height=height;
canvas.border = "3px solid #999999";
canvas.bgcolor = "#999999";
canvas.margin = "(0, 2%, 0, 2%)";
    
var context = canvas.getContext("2d");

//////////////////
////  SHAPES  ////
//////////////////
    
var left = 0;

//draw zone 1 rect
context.fillStyle = "#8bacbe";
context.fillRect(0, (canvas.height*5/6)+1, canvas.width*1.5/8.5, canvas.height*1/6);

left = left + canvas.width*1.5/8.5;

//draw zone 2 rect
context.fillStyle = "#ffe381";
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width*2.75/8.5, canvas.height*1/6);

left = left + canvas.width*2.75/8.5 + 1;

//draw zone 3 rect
context.fillStyle = "#fbbd36";
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width*1.25/8.5, canvas.height*1/6);

left = left + canvas.width*1.25/8.5;

//draw target zone rect
context.fillStyle = "#004880";
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width*0.25/8.5, canvas.height*1/6);

left = left + canvas.width*0.25/8.5;
    
//draw zone 4 rect
context.fillStyle = "#f8961d";
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width*1.25/8.5, canvas.height*1/6);

left = left + canvas.width*1.25/8.5 + 1;

//draw zone 5 rect
context.fillStyle = "#8a1002";
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width-left, canvas.height*1/6);

////////////////
////  TEXT  ////
////////////////

//user name
context.fillStyle = "black";
context.font = "bold 18px sans-serif";
context.textAlign = 'right';
context.fillText("User Name", canvas.width, canvas.height*.05);

//AT:
context.font = "bold 12px sans-serif";
context.fillText("AT: 140", canvas.width, canvas.height*.1);

//AB:
context.fillText("AB: 94", canvas.width, canvas.height*.15);
       
//this part is done after the callback from the view adapter, but is relevant here to add the view back into the layout.
var parent = document.getElementById("layout-content");
parent.appendChild(canvas);
代码语言:javascript
复制
<div id="layout-content"></div>

我看到的结果(在Safari中)比在Fiddle中显示的要扭曲得多:

矿山

小提琴

我做错了什么?每个文本元素都需要单独的画布吗?是字体的问题吗?是否需要首先在HTML5布局中定义画布?有打字错误吗?我迷路了。

EN

回答 12

Stack Overflow用户

回答已采纳

发布于 2013-03-28 02:03:37

画布元素独立于设备或监视器的像素比率运行。

在iPad 3+上,这个比率是2。这实际上意味着你的1000px宽度画布现在需要填充2000px才能与iPad显示屏上声明的宽度匹配。对我们来说幸运的是,这是由浏览器自动完成的。另一方面,这也是为什么您在图像和画布元素上看到的清晰度较少的原因,这些图像和画布元素是直接适合其可见区域的。因为您的画布只知道如何填充1000px,但被要求绘制到2000px,所以浏览器现在必须智能地填充像素之间的空白,以便以适当的大小显示元素。

我强烈建议你阅读来自HTML5Rocksthis article,它更详细地解释了如何创建高清元素。

tl;dr?下面是一个示例(基于上面的tut),我在自己的项目中使用它来生成一个具有适当分辨率的画布:

代码语言:javascript
复制
var PIXEL_RATIO = (function () {
    var ctx = document.createElement("canvas").getContext("2d"),
        dpr = window.devicePixelRatio || 1,
        bsr = ctx.webkitBackingStorePixelRatio ||
              ctx.mozBackingStorePixelRatio ||
              ctx.msBackingStorePixelRatio ||
              ctx.oBackingStorePixelRatio ||
              ctx.backingStorePixelRatio || 1;

    return dpr / bsr;
})();


createHiDPICanvas = function(w, h, ratio) {
    if (!ratio) { ratio = PIXEL_RATIO; }
    var can = document.createElement("canvas");
    can.width = w * ratio;
    can.height = h * ratio;
    can.style.width = w + "px";
    can.style.height = h + "px";
    can.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0);
    return can;
}

//Create canvas with the device resolution.
var myCanvas = createHiDPICanvas(500, 250);

//Create canvas with a custom resolution.
var myCustomCanvas = createHiDPICanvas(500, 200, 4);

希望这能有所帮助!

票数 177
EN

Stack Overflow用户

发布于 2013-03-27 22:44:50

已解决!

我决定看看是什么改变了我在javascript中设置的宽度和高度属性,以了解这对画布大小有何影响--但它没有。它改变了分辨率。

为了获得我想要的结果,我还必须设置canvas.style.width属性,该属性更改canvas的物理大小

代码语言:javascript
复制
canvas.width=1000;//horizontal resolution (?) - increase for better looking text
canvas.height=500;//vertical resolution (?) - increase for better looking text
canvas.style.width=width;//actual width of canvas
canvas.style.height=height;//actual height of canvas
票数 30
EN

Stack Overflow用户

发布于 2020-12-03 19:16:39

虽然@MyNameIsKo的答案仍然有效,但它在2020年已经有点过时了,可以改进:

代码语言:javascript
复制
function createHiPPICanvas(w, h) {
    let ratio = window.devicePixelRatio;
    let cv = document.createElement("canvas");
    cv.width = w * ratio;
    cv.height = h * ratio;
    cv.style.width = w + "px";
    cv.style.height = h + "px";
    cv.getContext("2d").scale(ratio, ratio);
    return cv;
}

总的来说,我们做了以下改进:

  • 我们删除了backingStorePixelRatio引用,因为这些引用并没有以任何重要的方式在任何浏览器中实现(事实上,只有Safari返回undefined以外的其他东西,这个版本在Safari中仍然可以完美地工作);
  • 我们用window.devicePixelRatio替换了所有的比例代码,window.devicePixelRatio还意味着我们少声明了一个全局属性-万岁!!
  • 我们还可以删除window.devicePixelRatio上的|| 1回退,因为它是没有意义的:所有不支持该属性的浏览器也不支持.setTransform.scale,所以这个函数对它们不起作用,不管回退与否;
  • 我们可以用.scale代替.setTransform,因为传入一个宽度和高度比传入一个转换矩阵更直观一些。
  • 该函数已从createHiDPICanvas重命名为createHiPPICanvas。正如@MyNameIsKo自己在他们的答案中提到的那样,DPI (每英寸点数)是打印术语(因为打印机由彩色墨水的小点组成图像)。类似地,显示器使用像素来显示图像,因此对于我们的用例来说,PPI (每英寸像素)是一个更好的缩写。

这些简化的一个很大的好处是,这个答案现在可以在没有// @ts-ignore的TypeScript中使用(因为TS没有backingStorePixelRatio的类型)。

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15661339

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档