天道酬勤,学无止境

画布文本渲染(模糊)(Canvas text rendering (blurry))

问题

我知道这个问题已经被问过很多次了,但是我尝试了几乎所有可以在网上找到的东西,但是无论我尝试了什么(以及使用什么组合),仍然无法在画布上正确呈现文本。

对于模糊的线条和形状问题,只需将+ 0.5px添加到坐标即可解决该问题:但是,此解决方案似乎不适用于文本渲染。

注意:我从不使用CSS来设置画布的宽度和高度(只尝试过一次以检查在HTML和CSS中设置大小属性是否会改变任何内容)。 同样的问题似乎与浏览器无关。

我试过了 :

  • 用HTML创建画布,然后用javascript而不是html创建画布
  • 在HTML元素中设置宽度和高度,然后使用JS,然后同时使用HTML和JS
  • 使用所有可能的组合将0.5px添加到文本坐标
  • 更改字体系列和字体大小
  • 更改字体大小单位(px,pt,em)
  • 使用不同的浏览器打开文件以检查是否有任何更改
  • 使用canvas.getContext('2d', {alpha:false})禁用Alpha通道canvas.getContext('2d', {alpha:false})这只是使我的大多数图层消失而没有解决问题

在此处查看canvas和html字体渲染之间的比较:https://jsfiddle.net/balleronde/1e9a5xbf/

甚至有可能使画布中的文本像dom元素中的文本一样呈现吗? 任何意见或建议将不胜感激

回答1

画布上的DOM质量文本。

仔细看看

如果放大DOM文本,您将看到以下内容(顶部是画布,底部是DOM,希望中心位于像素大小(不在视网膜显示器上))

如您所见,底部文本上有彩色部分。 这是因为它是使用称为true type的技术进行渲染的

请注意,在浏览器和操作系统上,使用true type是可选设置。 如果您将其关闭或分辨率很低的设备,则上面的缩放文本将看起来相同(底部图像中没有彩色像素)

像素和子像素

当您仔细观察LCD显示屏时,您会发现每个像素由3个子像素组成,这些子像素排成一行,每个分别代表红色,绿色和蓝色。 要设置像素,您需要为每个颜色通道提供RGB强度,并设置适当的RGB子像素。 我们通常接受红色为第一,蓝色为最后,但现实情况是,只要颜色彼此接近,您获得相同的结果就无关紧要。

当您停止考虑颜色以及可控制的图像元素时,设备的水平分辨率将增加三倍。 由于大多数文本都是单色的,因此您不必太担心RGB子像素的对齐方式,并且可以将文本渲染到子像素而不是整个像素,从而获得高质量的文本。 子像素是如此之小,以至于大多数人不会注意到轻微的颜色失真,而这样做的好处是值得稍微脏一点的外观。

为什么没有真正的画布类型

使用子像素时,您需要完全控制每个像素,包括alpha值。 对于显示驱动程序,alpha适用于一个像素的所有子像素,alpha 0.2不能具有蓝色,alpha 0.7不能在同一像素具有红色。 但是,如果您知道每个子像素下的子像素值是多少,则可以执行alpha计算,而不是让硬件来进行。 这使您可以在子像素级别上进行algha控制。

不幸的是(幸运的是,在99.99%的情况下很幸运)画布允许透明,但是您无法知道画布下的子像素在做什么,它们可以是任何颜色,因此您无法进行Alpha计算需要有效地使用子像素。

自家种植的亚像素文字。

但是,您不必具有透明的画布,并且如果使所有像素都不透明(alpha = 1.0),则可以重新获得子像素alpha控件。

以下函数使用子像素绘制画布文本。 它的速度不是很快,但是可以得到质量更好的文本。

它通过以正常宽度的3倍渲染文本来工作。 然后,它使用多余的像素来计算子像素值,完成后将子像素数据放到画布上。

更新当我写下这个答案时,我完全忘记了缩放设置。 使用子像素需要在显示物理像素大小和DOM像素大小之间进行精确匹配。 如果放大或缩小的情况并非如此,因此定位子像素会变得更加困难。
我已经更新了演示以尝试检测缩放设置。 由于没有标准的方法,我只使用了devicePixelRatio ,它在FF和Chrome缩放时为!== 1 (并且由于我没有视网膜凹陷,所以我只能猜测底部的演示是否可以正常工作)。 如果您希望正确查看演示,尽管仍在缩放状态,但仍未收到缩放警告,请将缩放比例设置为1。
另外,您可能希望将缩放比例设置为200%,并使用底部的演示,因为似乎放大会明显降低DOM文本质量,而画布子像素会保持高质量。

顶部文本是普通的Canvas文本,中心是画布上的(自制)子像素文本,底部是DOM文本

请注意,如果您使用的是Retina显示屏或高分辨率显示屏,则如果看不到高质量的画布文本,则应查看该片段下方的代码片段。

标准的1到1像素演示。

 var createCanvas =function(w,h){ var c = document.createElement("canvas"); c.width = w; c.height = h; c.ctx = c.getContext("2d"); // document.body.appendChild(c); return c; } // converts pixel data into sub pixel data var subPixelBitmap = function(imgData){ var spR,spG,spB; // sub pixels var id,id1; // pixel indexes var w = imgData.width; var h = imgData.height; var d = imgData.data; var x,y; var ww = w*4; var ww4 = ww+4; for(y = 0; y < h; y+=1){ for(x = 0; x < w; x+=3){ var id = y*ww+x*4; var id1 = Math.floor(y)*ww+Math.floor(x/3)*4; spR = Math.sqrt(d[id + 0] * d[id + 0] * 0.2126 + d[id + 1] * d[id + 1] * 0.7152 + d[id + 2] * d[id + 2] * 0.0722); id += 4; spG = Math.sqrt(d[id + 0] * d[id + 0] * 0.2126 + d[id + 1] * d[id + 1] * 0.7152 + d[id + 2] * d[id + 2] * 0.0722); id += 4; spB = Math.sqrt(d[id + 0] * d[id + 0] * 0.2126 + d[id + 1] * d[id + 1] * 0.7152 + d[id + 2] * d[id + 2] * 0.0722); d[id1++] = spR; d[id1++] = spG; d[id1++] = spB; d[id1++] = 255; // alpha always 255 } } return imgData; } // Assume default textBaseline and that text area is contained within the canvas (no bits hanging out) // Also this will not work is any pixels are at all transparent var subPixelText = function(ctx,text,x,y,fontHeight){ var width = ctx.measureText(text).width + 12; // add some extra pixels var hOffset = Math.floor(fontHeight *0.7); var c = createCanvas(width * 3,fontHeight); c.ctx.font = ctx.font; c.ctx.fillStyle = ctx.fillStyle; c.ctx.fontAlign = "left"; c.ctx.setTransform(3,0,0,1,0,0); // scale by 3 // turn of smoothing c.ctx.imageSmoothingEnabled = false; c.ctx.mozImageSmoothingEnabled = false; // copy existing pixels to new canvas c.ctx.drawImage(ctx.canvas,x -2, y - hOffset, width,fontHeight,0,0, width,fontHeight ); c.ctx.fillText(text,0,hOffset); // draw thw text 3 time the width // convert to sub pixel c.ctx.putImageData(subPixelBitmap(c.ctx.getImageData(0,0,width*3,fontHeight)),0,0); ctx.drawImage(c,0,0,width-1,fontHeight,x,y-hOffset,width-1,fontHeight); // done } var globalTime; // render loop does the drawing function update(timer) { // Main update loop globalTime = timer; ctx.setTransform(1,0,0,1,0,0); // set default ctx.globalAlpha= 1; ctx.fillStyle = "White"; ctx.fillRect(0,0,canvas.width,canvas.height) ctx.fillStyle = "black"; ctx.fillText("Canvas text is Oh hum "+ globalTime.toFixed(0),6,20); subPixelText(ctx,"Sub pixel text is best "+ globalTime.toFixed(0),6,45,25); div.textContent = "DOM is off course perfect "+ globalTime.toFixed(0); requestAnimationFrame(update); } function start(){ document.body.appendChild(canvas); document.body.appendChild(div); ctx.font = "20px Arial"; requestAnimationFrame(update); // start the render } var canvas = createCanvas(512,50); // create and add canvas var ctx = canvas.ctx; // get a global context var div = document.createElement("div"); div.style.font = "20px Arial"; div.style.background = "white"; div.style.color = "black"; if(devicePixelRatio !== 1){ var dir = "in" var more = ""; if(devicePixelRatio > 1){ dir = "out"; } if(devicePixelRatio === 2){ div.textContent = "Detected a zoom of 2. You may have a Retina display or zoomed in 200%. Please use the snippet below this one to view this demo correctly as it requiers a precise match between DOM pixel size and display physical pixel size. If you wish to see the demo anyways just click this text. "; more = "Use the demo below this one." }else{ div.textContent = "Sorry your browser is zoomed "+dir+".This will not work when DOM pixels and Display physical pixel sizes do not match. If you wish to see the demo anyways just click this text."; more = "Sub pixel display does not work."; } document.body.appendChild(div); div.style.cursor = "pointer"; div.title = "Click to start the demo."; div.addEventListener("click",function(){ start(); var divW = document.createElement("div"); divW.textContent = "Warning pixel sizes do not match. " + more; divW.style.color = "red"; document.body.appendChild(divW); }); }else{ start(); }

1至2像素比例演示。

对于视网膜,非常高分辨率,或缩放200%的浏览器。

 var createCanvas =function(w,h){ var c = document.createElement("canvas"); c.width = w; c.height = h; c.ctx = c.getContext("2d"); // document.body.appendChild(c); return c; } // converts pixel data into sub pixel data var subPixelBitmap = function(imgData){ var spR,spG,spB; // sub pixels var id,id1; // pixel indexes var w = imgData.width; var h = imgData.height; var d = imgData.data; var x,y; var ww = w*4; var ww4 = ww+4; for(y = 0; y < h; y+=1){ for(x = 0; x < w; x+=3){ var id = y*ww+x*4; var id1 = Math.floor(y)*ww+Math.floor(x/3)*4; spR = Math.sqrt(d[id + 0] * d[id + 0] * 0.2126 + d[id + 1] * d[id + 1] * 0.7152 + d[id + 2] * d[id + 2] * 0.0722); id += 4; spG = Math.sqrt(d[id + 0] * d[id + 0] * 0.2126 + d[id + 1] * d[id + 1] * 0.7152 + d[id + 2] * d[id + 2] * 0.0722); id += 4; spB = Math.sqrt(d[id + 0] * d[id + 0] * 0.2126 + d[id + 1] * d[id + 1] * 0.7152 + d[id + 2] * d[id + 2] * 0.0722); d[id1++] = spR; d[id1++] = spG; d[id1++] = spB; d[id1++] = 255; // alpha always 255 } } return imgData; } // Assume default textBaseline and that text area is contained within the canvas (no bits hanging out) // Also this will not work is any pixels are at all transparent var subPixelText = function(ctx,text,x,y,fontHeight){ var width = ctx.measureText(text).width + 12; // add some extra pixels var hOffset = Math.floor(fontHeight *0.7); var c = createCanvas(width * 3,fontHeight); c.ctx.font = ctx.font; c.ctx.fillStyle = ctx.fillStyle; c.ctx.fontAlign = "left"; c.ctx.setTransform(3,0,0,1,0,0); // scale by 3 // turn of smoothing c.ctx.imageSmoothingEnabled = false; c.ctx.mozImageSmoothingEnabled = false; // copy existing pixels to new canvas c.ctx.drawImage(ctx.canvas,x -2, y - hOffset, width,fontHeight,0,0, width,fontHeight ); c.ctx.fillText(text,0,hOffset); // draw thw text 3 time the width // convert to sub pixel c.ctx.putImageData(subPixelBitmap(c.ctx.getImageData(0,0,width*3,fontHeight)),0,0); ctx.drawImage(c,0,0,width-1,fontHeight,x,y-hOffset,width-1,fontHeight); // done } var globalTime; // render loop does the drawing function update(timer) { // Main update loop globalTime = timer; ctx.setTransform(1,0,0,1,0,0); // set default ctx.globalAlpha= 1; ctx.fillStyle = "White"; ctx.fillRect(0,0,canvas.width,canvas.height) ctx.fillStyle = "black"; ctx.fillText("Normal text is Oh hum "+ globalTime.toFixed(0),12,40); subPixelText(ctx,"Sub pixel text is best "+ globalTime.toFixed(0),12,90,50); div.textContent = "DOM is off course perfect "+ globalTime.toFixed(0); requestAnimationFrame(update); } var canvas = createCanvas(1024,100); // create and add canvas canvas.style.width = "512px"; canvas.style.height = "50px"; var ctx = canvas.ctx; // get a global context var div = document.createElement("div"); div.style.font = "20px Arial"; div.style.background = "white"; div.style.color = "black"; function start(){ document.body.appendChild(canvas); document.body.appendChild(div); ctx.font = "40px Arial"; requestAnimationFrame(update); // start the render } if(devicePixelRatio !== 2){ var dir = "in" var more = ""; div.textContent = "Incorrect pixel size detected. Requiers zoom of 2. See the answer for more information. If you wish to see the demo anyways just click this text. "; document.body.appendChild(div); div.style.cursor = "pointer"; div.title = "Click to start the demo."; div.addEventListener("click",function(){ start(); var divW = document.createElement("div"); divW.textContent = "Warning pixel sizes do not match. "; divW.style.color = "red"; document.body.appendChild(divW); }); }else{ start(); }

以获得更好的结果。

为了获得最佳结果,您将需要使用webGL。 这是从标准抗锯齿到子像素抗锯齿的相对简单的修改。 使用WebGL进行标准矢量文本渲染的示例可以在WebGL PDF中找到。

WebGL API会很高兴地坐在2D canvas API旁边,并且将webGl渲染的内容的结果复制到2D canvas就像渲染图像context.drawImage(canvasWebGL,0,0)一样简单context.drawImage(canvasWebGL,0,0)

回答2

但是,有一个更简单的解决方案。

    context.scale(0.3, 0.3)
    context.fillText("Hello there", canvas.width / 2 * 1 / 0.3, canvas.height * 2.8 / 4 * 1 / 0.3, canvas.width * 0.9 * 1 / 0.3);
    context.font = canvas.width / 15 + "px Arial";
    context.fillText("Want to talk? Mail me at mher@movsisyan.info", canvas.width / 2 * 1 / 0.3, canvas.height * 3.6 / 4 * 1 / 0.3, canvas.width * 0.9 * 1 / 0.3);
    context.fillText("Want to see my code? Find me on GitHub as MovsisyanM", canvas.width / 2 * 1 / 0.3, canvas.height * 3.8 / 4 * 1 / 0.3, canvas.width * 0.9 * 1 / 0.3);
    context.scale(1, 1)

在这里,我按比例缩小了画布上下文,这使我可以使用较高的字体px,从而获得更好的文本质量。

我实际上发现了这种技术,因为photoshop或某些类似的图像编辑程序存在相同的问题。 我希望这有帮助!

回答3

最简单的解决方案是使用window.devicePixelRatio来缩放画布分辨率(与其实际大小相比)。

例如,具有canvas元素:

<canvas id="canvas"></canvas>

将画布大小设置为其物理大小的2比例( window.devicePixelRatio的值):

const canvas = document.getElementById('canvas')
canvas.width = canvas.clientWidth * 2
canvas.height = canvas.clientHeight * 2

并将画布上下文缩放为2:

const context = canvas.getContext('2d')
context.scale(2, 2)

演示:

  1. 比例为1x1

  2. 比例为1x2

回答4

非常感谢所有这些解释!

令人难以置信的是,默认的fillText()不支持以整齐的方式在画布上显示“简单字符串”,而我们必须做这些技巧才能获得正确的显示,也就是说,一点点的显示模糊或模糊。 有点像画布中的“ 1px线条绘制问题”(为此,使+0.5进行协调会有所帮助,但无法完全解决问题)...

我修改了您在上面提供的代码,以使其支持彩色文本(不仅限于黑白文本)。 希望对您有所帮助。

在功能subPixelBitmap() ,有一些算法可以对红色/绿色/蓝色进行平均。 它改善了画布上的字符串显示(在Chrome上),特别是对于小字体。 也许还有其他更好的算法:如果您找到一个,我会很感兴趣。

该图显示了显示效果:改进了画布中的字符串显示

这是一个可以在线运行的工作示例:jsfiddle.net上的工作示例

关联的代码是此代码(请查看上面的工作示例以获取最新版本):

  canvas = document.getElementById("my_canvas");
  ctx = canvas.getContext("2d");
  ...

  // Display a string:
  // - nice way:
  ctx.font = "12px Arial";
  ctx.fillStyle = "red";
  subPixelText(ctx,"Hello World",50,50,25);  
  ctx.font = "bold 14px Arial";
  ctx.fillStyle = "red";
  subPixelText(ctx,"Hello World",50,75,25);
  // - blurry default way:  
  ctx.font = "12px Arial";
  ctx.fillStyle = "red";
  ctx.fillText("Hello World", 50, 100);    
  ctx.font = "bold 14px Arial";
  ctx.fillStyle = "red";
  ctx.fillText("Hello World", 50, 125);

var subPixelBitmap = function(imgData){
    var spR,spG,spB; // sub pixels
    var id,id1; // pixel indexes
    var w = imgData.width;
    var h = imgData.height;
    var d = imgData.data;
    var x,y;
    var ww = w*4;
    for(y = 0; y < h; y+=1){ // (go through all y pixels)
        for(x = 0; x < w-2; x+=3){ // (go through all groups of 3 x pixels)
            var id = y*ww+x*4; // (4 consecutive values: id->red, id+1->green, id+2->blue, id+3->alpha)
            var output_id = y*ww+Math.floor(x/3)*4;
            spR = Math.round((d[id + 0] + d[id + 4] + d[id + 8])/3);
            spG = Math.round((d[id + 1] + d[id + 5] + d[id + 9])/3);
            spB = Math.round((d[id + 2] + d[id + 6] + d[id + 10])/3);
            // console.log(d[id+0], d[id+1], d[id+2] + '|' + d[id+5], d[id+6], d[id+7] + '|' + d[id+9], d[id+10], d[id+11]);                        
            d[output_id] = spR;
            d[output_id+1] = spG;
            d[output_id+2] = spB;
            d[output_id+3] = 255; // alpha is always set to 255
        }
    }
    return imgData;
}

var subPixelText = function(ctx,text,x,y,fontHeight){

    var width = ctx.measureText(text).width + 12; // add some extra pixels
    var hOffset = Math.floor(fontHeight);

    var c = document.createElement("canvas");
    c.width  = width * 3; // scaling by 3
    c.height = fontHeight;
    c.ctx    = c.getContext("2d");    
    c.ctx.font = ctx.font;
    c.ctx.globalAlpha = ctx.globalAlpha;
    c.ctx.fillStyle = ctx.fillStyle;
    c.ctx.fontAlign = "left";
    c.ctx.setTransform(3,0,0,1,0,0); // scaling by 3
    c.ctx.imageSmoothingEnabled = false;    
    c.ctx.mozImageSmoothingEnabled = false; // (obsolete)
    c.ctx.webkitImageSmoothingEnabled = false;
    c.ctx.msImageSmoothingEnabled = false;
    c.ctx.oImageSmoothingEnabled = false; 
    // copy existing pixels to new canvas
    c.ctx.drawImage(ctx.canvas,x,y-hOffset,width,fontHeight,0,0,width,fontHeight);
    c.ctx.fillText(text,0,hOffset-3 /* (harcoded to -3 for letters like 'p', 'g', ..., could be improved) */); // draw the text 3 time the width
    // convert to sub pixels 
    c.ctx.putImageData(subPixelBitmap(c.ctx.getImageData(0,0,width*3,fontHeight)), 0, 0);
    ctx.drawImage(c,0,0,width-1,fontHeight,x,y-hOffset,width-1,fontHeight);
}

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 如何修复HTML5画布中的模糊文本?(How do I fix blurry text in my HTML5 canvas?)
    问题 我总的n00b HTML5和我有工作canvas渲染形状,颜色和文字。 在我的应用程序中,我有一个视图适配器,可以动态创建画布,并用内容填充它。 效果非常好,除了我的文本非常模糊/模糊/拉伸。 我还看到了许多其他文章,说明为什么在CSS定义宽度和高度会导致此问题,但我在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
  • 缩放a时禁用插值(Disable Interpolation when Scaling a <canvas>)
    问题 注意:这与放大时现有画布元素的呈现方式有关,而与线条或图形在画布表面上的呈现方式无关。 换句话说,这与缩放元素的插值有关,而与在画布上绘制的图形的抗锯齿无关。 我不关心浏览器如何画线; 我关心的是浏览器在放大时如何渲染canvas元素本身。 是否有画布属性或浏览器设置,可以在缩放<canvas>元素时以编程方式更改以禁用插值? 跨浏览器的解决方案是理想的,但不是必需的。 基于Webkit的浏览器是我的主要目标。 性能非常重要。 这个问题最相似,但不能充分说明问题。 对于它的价值,我尝试了image-rendering: -webkit-optimize-contrast无济于事。 该应用程序将是一个用HTML5 + JS编写的“复古” 8位样式游戏,以明确我的需求。 为了说明,这是一个示例。 (实况版本) 假设我有一张21x21的画布... <canvas id='b' width='21' height='21'></canvas> ...具有CSS的元素使元素大5倍(105x105): canvas { border: 5px solid #ddd; } canvas#b { width: 105px; height: 105px; } /* 5 * 21 = 105 */ 我在画布上绘制一个简单的“ X”,如下所示: $('canvas').each(function
  • HTML5中的画布宽度和高度(Canvas width and height in HTML5)
    问题 是否可以固定HTML5 canvas元素的宽度和高度? 通常的方法如下: <canvas id="canvas" width="300" height="300"></canvas> 回答1 canvas DOM元素具有.height和.width属性,它们与height="…"和width="…"属性相对应。 在JavaScript代码中将它们设置为数值,以调整画布的大小。 例如: var canvas = document.getElementsByTagName('canvas')[0]; canvas.width = 800; canvas.height = 600; 请注意,这将清除画布,尽管您应遵循ctx.clearRect( 0, 0, ctx.canvas.width, ctx.canvas.height); 来处理那些没有完全清除画布的浏览器。 尺寸更改后,您需要重绘要显示的所有内容。 进一步注意的是,高度和宽度是用于绘制逻辑帆布尺寸和来自不同style.height和style.width CSS属性。 如果您未设置CSS属性,则画布的固有大小将用作其显示大小; 如果您确实设置了CSS属性,并且它们与画布尺寸不同,则将在浏览器中缩放内容。 例如: // Make a canvas that has a blurry pixelated zoom-in //
  • Draw text in OpenGL ES(Draw text in OpenGL ES)
    问题 我目前正在为Android平台开发一款小型OpenGL游戏,想知道是否有一种简便的方法可以在渲染的框架上渲染文本(例如带有玩家得分的HUD等)。 文本也需要使用自定义字体。 我已经看到了一个使用“视图”作为叠加层的示例,但是我不知道是否要这样做,因为我以后可能想将游戏移植到其他平台上。 有任何想法吗? 回答1 Android SDK没有在OpenGL视图上绘制文本的任何简便方法。 为您提供以下选择。 将TextView放在SurfaceView上。 这既缓慢又糟糕,但却是最直接的方法。 将常见的字符串渲染为纹理,然后简单地绘制这些纹理。 到目前为止,这是最简单,最快,但最不灵活的。 基于Sprite的自行编写文本呈现代码。 如果没有选择2,可能是第二好的选择。 弄湿脚的一种好方法,但请注意,虽然它看起来很简单(并且具有基本功能),但随着添加更多功能(纹理对齐,换行符,可变宽度字体等),它变得更加困难且更具挑战性。 )-如果您选择这条路线,请尽量简化路线! 使用现成的/开源库。 如果您在Google上狩猎,周围会有一些麻烦的地方是使它们集成并运行。 但是,至少,一旦这样做,您将拥有它们提供的所有灵活性和成熟度。 回答2 将文本渲染到纹理比Sprite Text演示看起来更简单,基本思想是使用Canvas类渲染到Bitmap,然后将Bitmap传递给OpenGL纹理: //
  • WPF模糊字体问题-解决方案(WPF Blurry fonts issue- Solutions)
    问题 在以下链接上描述并演示了该问题: Paul Stovell WPF:模糊文本渲染 www.gamedev.net论坛 Microsoft Connect:WPF文本渲染器以小字体产生严重模糊的文本 说明:WPF中的文本清晰度。 此链接具有字体比较。 我想收集这个问题的所有可能的解决方案。 Microsoft Expression Blend使用WPF,但字体看起来可读。 如Microsoft Expression Blend中的深色背景增加字体大小并更改字体(Calibri ...)[链接] 嵌入Windows表单[链接] 使用GDI +和/或Windows Forms TextRenderer类将文本呈现为位图,然后将该位图呈现为WPF控件。 [关联] 还有其他解决方案吗? 这将在VS2010(和WPF4)测试版2中修复 它看起来像已经解决了! 斯科特·汉塞尔曼(Scott Hanselman)的ComputerZen.com:WPF和文本模糊,现在完全清晰 回答1 技术背景 在Windowsclient.net上有一篇有关WPF文本呈现的深入文章,来自WPF文本程序管理器之一:WPF中的文本清晰度。 问题归结为WPF,需要线性缩放的字体渲染器来平滑动画。 另一方面,Pure ClearType在字体方面具有相当大的自由度,可将垂直词干推入下一个像素。 如果人们比较经典的
  • 透明的模糊视图,模糊了下面的布局(Transparent blurry view which blurs layout underneath)
    问题 我有一个Linearlayout,我已经将其设为透明,现在我正在寻找一种使其具有Blur效果的方法,因此其下方的内容将变得模糊。 就像Windows 7 Aero的外观一样(请参见屏幕截图)。 我知道您可以像这样进行模糊效果: getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 但这仅适用于出现对话框时使背景模糊的情况。 我已经搜寻了将近一个小时,却找不到任何东西。 有人对如何执行此操作有任何建议吗? 谢谢 回答1 这在我脑海中已经存在了一段时间,由于您的问题,我才实施了它。 为此,我们需要将模糊布局下方的布局绘制为位图。 比起使用模糊算法,我们需要对位图进行模糊处理,最后绘制模糊的位图作为模糊布局的背景。 幸运的是,android具有缓存绘制机制,因此第一部分很简单。 我们可以简单地为下面的布局启用缓存的图形,并使用getDrawingCache()从中获取位图。 现在我们需要一种快速模糊算法。 我用了这个https://stackoverflow.com/a/10028267/3133545 这里是。 import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics
  • HTML2canvas生成模糊图像(HTML2canvas generates Blurry images)
    问题 我正在使用jsPDF,它使用html2canvas从某些html元素生成图像并插入.pdf文件中。 但是html2canvas上存在问题,它会从html生成模糊图像。 请参见下面的示例: HTML内容: http://puu.sh/7SZz4.png html2canvas生成的图像: http://puu.sh/7SZAT.png 有什么办法可以解决它,还是有更好的选择来获取图像形式的html? 谢谢! 回答1 您可以在html2canvas中使用缩放比例选项。 在最新版本v1.0.0-alpha.1中,您可以使用scale选项来提高分辨率(scale:2将使分辨率从默认的96dpi翻倍)。 // Create a canvas with double-resolution. html2canvas(element, { scale: 2, onrendered: myRenderFunction }); // Create a canvas with 144 dpi (1.5x resolution). html2canvas(element, { dpi: 144, onrendered: myRenderFunction }); 回答2 我有这个问题,因为我在视网膜显示器上。 我在这里使用MisterLamb的解决方案解决了。 $(window).load
  • 是否可以在THREE.js中启用无限数量的渲染器?(Is it possible to enable unbounded number of renderers in THREE.js?)
    问题 为了避免XY问题,让我解释一下我来自哪里。 我想使用THREE.js在同一时间轴上绘制大量彼此叠加的波形。 波形只是三行。我正在通过修改正交摄影机的视界来实现这些波形的缩放/平移/缩放。 为此,我最初尝试创建多个固定高度的画布元素,这些画布元素彼此堆叠,然后将THREE.WebGLRenderer附加到每个画布上。 这非常有效,直到我尝试将其缩放到超过15个左右的波形为止,在这里THREE.js向我发出警告“活动的webgl上下文太多”,并开始删除旧的上下文。 考虑到此处应用的相同技术,我认为这是不错的做法:http://threejs.org/examples/#webgl_multiple_canvases_grid 在此示例中,创建了4个WebGLRenderer,每个画布一个。 因此,是否有可能以某种方式覆盖此警告,并创建无数个画布元素,每个画布元素都有自己的渲染器? 在旁边: 我考虑过使用一个场景并在其中相应地定位波形,并使用类似于http://threejs.org/examples/#webgl_multiple_views的方法使用多个摄像机。 问题有两个: (1)我失去了按每个波形进行dom操纵和轻松附加按键和鼠标侦听器的能力。 (2)此解决方案似乎也无法扩展。 一旦渲染器的高度超过6000px高度,它将开始进入某种类型的损坏状态,并且场景的一部分将不显示
  • 将HTML元素渲染到(Rendering HTML elements to <canvas>)
    问题 有没有一种方法可以在画布中呈现任意HTML元素(然后访问其缓冲区...)。 回答1 当前,您将无法获得真正的HTML渲染到<canvas>本身,因为canvas上下文没有渲染HTML元素的功能。 有一些模拟: html2canvas项目http://html2canvas.hertzen.com/index.html(基本上是基于Javascript + canvas构建的HTML渲染器尝试) 从HTML到SVG到<canvas>可能取决于您的用例: https://github.com/miohtama/Krusovice/blob/master/src/tools/html2svg2canvas.js 另外,如果您使用的是Firefox,则可以破解一些扩展权限,然后将DOM窗口呈现为<canvas> https://developer.mozilla.org/zh-CN/docs/HTML/Canvas/Drawing_Graphics_with_Canvas?redirectlocale=zh-CN&redirectslug=Drawing_Graphics_with_Canvas#Rendering_Web_Content_Into_A_Canvas 回答2 看看MDN 它将使用创建SVG图像呈现html元素。 例如:有<em>I</em> like <span
  • Firefox使用drawImage将SVG图像渲染到HTML5画布时出错(Firefox error rendering an SVG image to HTML5 canvas with drawImage)
    问题 我正在尝试使用画布将外部svg图标转换为base64 png。 它可在除Firefox之外的所有浏览器中运行,Firefox会引发错误“ NS_ERROR_NOT_AVAILABLE”。 var img = new Image(); img.src = "icon.svg"; img.onload = function() { var canvas = document.createElement("canvas"); canvas.width = this.width; canvas.height = this.height; var ctx = canvas.getContext("2d"); ctx.drawImage(this, 0, 0); var dataURL = canvas.toDataURL("image/png"); return dataURL; }; 有人可以帮我吗? 提前致谢。 回答1 Firefox不支持在画布上绘制SVG图像,除非svg文件在根<svg>元素上具有width / height属性,并且这些width / height属性不是百分比。 这是一个长期存在的错误。 您需要编辑icon.svg文件,使其符合上述条件。 回答2 如前所述,这是一个开放的错误,是由于在绘制到画布上时Firefox接受的SVG尺寸规范的限制所致。
  • 绘图文字到 @ font-face第一次无法使用(Drawing text to <canvas> with @font-face does not work at the first time)
    问题 当我在具有通过@ font-face加载的字体的画布中绘制文本时,该文本无法正确显示。 它根本不显示(在Chrome 13和Firefox 5中),或者字体错误(Opera 11)。 这种类型的意外行为仅在带有字体的第一个图形上发生。 之后,一切正常。 这是标准行为还是什么? 谢谢你。 PS:以下是测试用例的源代码 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>@font-face and <canvas></title> <style id="css"> @font-face { font-family: 'Press Start 2P'; src: url('fonts/PressStart2P.ttf'); } </style> <style> canvas, pre { border: 1px solid black; padding: 0 1em; } </style> </head> <body> <h1>@font-face and <canvas></h1> <p> Description: click the button several times, and you will see the problem. The first line won't show at all, or
  • 使用CSS转换后的文本模糊:scale(); 在Chrome中(Blurry text after using CSS transform: scale(); in Chrome)
    问题 似乎最近对Google Chrome浏览器进行了更新,该更新在执行以下transform: scale()后导致文本模糊transform: scale() 。 具体来说,我正在这样做: @-webkit-keyframes bounceIn { 0% { opacity: 0; -webkit-transform: scale(.3); } 50% { opacity: 1; -webkit-transform: scale(1.05); } 70% { -webkit-transform: scale(.9); } 100% { -webkit-transform: scale(1); } } 如果您在Chrome中访问http://rourkery.com,则应该在主要文本区域中看到问题。 它以前没有这样做,并且似乎也没有影响其他Webkit浏览器(例如Safari)。 还有其他一些关于人们在使用3d变换时遇到类似问题的帖子,但找不到像这样的关于2d变换的任何信息。 任何想法将不胜感激,谢谢! 回答1 我多次遇到此问题,似乎有2种解决方法(如下所示)。 您可以使用这两个属性之一来修复渲染,也可以同时使用这两个属性。 隐藏的背面可见性解决了该问题,因为它将动画简化为仅位于对象的正面,而默认状态为正面和背面。 backface-visibility: hidden
  • CSS过渡效果会导致图像模糊/在Chrome中将图像移动1px?(CSS transition effect makes image blurry / moves image 1px, in Chrome?)
    问题 我有一些CSS,在悬停时,CSS过渡效果将移动div。 正如您在示例中看到的那样,问题在于translate过渡具有可怕的副作用,即使div中的图像向下/向右移动1px(并且可能会略微调整大小吗?),从而使其看起来不合适。而且没有重点... 毛刺似乎一直在应用悬停效果的整个过程中,并且从反复试验的过程中,我可以肯定地说,似乎只有在平移过渡移动div时才会出现(也应用了框阴影和不透明度,但对删除后的错误)。 该问题似乎仅在页面具有滚动条时发生。 因此,仅使用一个div实例的示例就可以了,但是一旦添加了更多相同的div,并且页面因此需要滚动条,问题就会再次出现... 回答1 2020年更新 如果图像模糊,请务必从下面检查答案,尤其是image-rendering CSS属性。 为了获得最佳实践的可访问性和SEO,您可以使用对象适合的CSS属性用<img>标签替换背景图片。 原始答案 在您的CSS中尝试一下: .your-class-name { /* ... */ -webkit-backface-visibility: hidden; -webkit-transform: translateZ(0) scale(1, 1); } 这样做是为了使除法器表现为“更多2D”。 默认情况下绘制背面,以允许通过旋转等翻转事物。 如果只向左,向右,向上,向下,缩放或顺时针旋转,则无需这样做
  • 画布toDataURL()返回空白图像(Canvas toDataURL() returns blank image)
    问题 我正在使用glfx.js编辑我的图像,但是当我尝试使用toDataURL()函数获取该图像的数据时,我得到了一个空白图像(宽度与原始图像相同)。 奇怪的是,在Chrome中,脚本可以完美运行。 我要提及的是,使用onload事件将图像加载到canvas : img.onload = function(){ try { canvas = fx.canvas(); } catch (e) { alert(e); return; } // convert the image to a texture texture = canvas.texture(img); // draw and update canvas canvas.draw(texture).update(); // replace the image with the canvas img.parentNode.insertBefore(canvas, img); img.parentNode.removeChild(img); } 另外,我的图片的路径在同一域中; 问题(在Firefox中)是当我按下“保存”按钮时。 Chrome返回预期结果,但Firefox返回以下结果: data:image/png;base64
  • 我的图像模糊! WPF的SnapsToDevicePixels为什么不起作用?(My images are blurry! Why isn't WPF's SnapsToDevicePixels working?)
    问题 我在WPF应用程序中使用了一些图像。 XAML: <Image Name="ImageOrderedList" Source="images/OrderedList.png" ToolTip="Ordered List" Margin="0,0,5,5" Width="20" Height="20" SnapsToDevicePixels="True" MouseUp="Image_MouseUp" MouseEnter="Image_MouseEnter" MouseLeave="Image_MouseLeave" /> 但是,它们显得模糊。 为什么SnapsToDevicePixels="True"行不能阻止此问题? 回答1 您可能要考虑尝试WPF4中现在可用的新属性。 离开RenderOptions.BitmapScalingMode到高质量或者只是不申报。 NearestNeighbor为我工作,但在放大应用程序时会导致锯齿状的位图。 它似乎也没有解决任何以奇怪的方式调整图标大小的故障。 在您的根元素(即主窗口)上添加以下属性: UseLayoutRounding="True" 。 以前仅在Silverlight中可用的属性现已解决了所有位图大小调整问题。 :) 回答2 我没有使用SnapsToDevicePixels ,而是使用了RenderOptions
  • 将HTML渲染到图像(Render HTML to an image)
    问题 有没有一种方法可以将html渲染为类似PNG的图像? 我知道画布是可能的,但我想呈现例如div之类的标准html元素。 回答1 有很多选择,它们各有利弊。 选项1:使用API ApiFlash(基于Chrome) EvoPDF(具有html的选项) Grabzit HTML / CSS到图像API ... 优点 执行Javascript 接近完美的渲染正确使用缓存选项时速度很快规模由API处理精确的时间,视口,... 大多数时候,他们提供免费计划 缺点 如果您打算大量使用它们,它不是免费的 选项2:使用众多可用库之一 图片到图片 wkhtmltoimage(包含在wkhtmltopdf工具中) IMGKit(用于ruby,基于wkhtmltoimage) imgkit(用于python并基于wkhtmltoimage) python-webkit2png ... 优点 在大多数情况下,转换速度都非常快 缺点 渲染效果不佳不执行javascript 不支持最新的Web功能(FlexBox,高级选择器,Webfonts,Box大小调整,媒体查询等) 有时安装起来不太容易规模复杂 选项3:使用PhantomJs以及包装器库 幻影 node-webshot(PhantomJs的javascript包装器库) ... 优点 执行Javascript 蛮快 缺点
  • 如何从Three.js画布中保存图像?(How do you save an image from a Three.js canvas?)
    问题 如何从Three.js画布中保存图像? 我正在尝试使用Canvas2Image,但它不喜欢与Threejs一起玩。 由于只有在画布具有用于将画布对象附加到其的div时,画布才被定义。 http://ajaxian.com/archives/canvas2image-save-out-your-canvas-data-to-images 回答1 由于toDataURL是canvas html元素的方法,因此也适用于3d上下文。 但是,您必须照顾好几件事。 确保在初始化3D上下文时,将preserveDrawingBuffer标志设置为true,如下所示: var context = canvas.getContext("experimental-webgl", {preserveDrawingBuffer: true}); 然后用户canvas.toDataURL()获取图像 在threejs中,实例化渲染器时必须执行以下操作: new THREE.WebGLRenderer({ preserveDrawingBuffer: true }); 另外,请记住,这可能会对性能产生影响。 (阅读:https://github.com/mrdoob/three.js/pull/421#issuecomment-1792008) 这仅适用于webgl渲染器,但是对于threejs
  • Chrome字体显示模糊(Chrome Font appears Blurry)
    问题 它正在我的眼睛! 在IE和Firefox中看起来不错 铬(以上) 运行版本39的chrome,仅在模态框中显示模糊,如果我更改字体系列,则没有任何区别。 这是CSS(用于标签“开始”),浏览器呈现以下内容 box-sizing: border-box; color: rgb(85, 85, 85); cursor: default; display: block; float: left; font-family: sans-serif; font-size: 12px; font-weight: 600; height: 24px; line-height: 17.142858505249px; margin-bottom: 0px; margin-top: 0px; min-height: 1px; padding-left: 15px; padding-right: 15px; padding-top: 7px; position: relative; text-align: right; visibility: visible; width: 89.65625px; 是浏览器还是CSS? - 更新 - - 好的看起来像这个CSS .md-modal { position: fixed; top: 50%; left: 50%; width: 50%; max
  • HTML5画布与SVG与div(HTML5 Canvas vs. SVG vs. div)
    问题 即时创建元素并能够四处移动的最佳方法是什么? 例如,假设我要创建一个矩形,圆形和多边形,然后选择这些对象并四处移动。 我了解HTML5提供了三个使之成为可能的元素:svg,canvas和div。 对于我想做什么,这些元素中的哪一个将提供最佳性能? 为了比较这些方法,我正在考虑创建三个视觉上相同的网页,每个网页中都有页眉,页脚,小部件和文本内容。 第一页中的小部件将完全使用canvas元素创建,第二页将完全使用svg元素创建,而第三页将使用纯div元素HTML和CSS创建。 回答1 简短的答案: SVG对您来说将更加容易,因为已经内置了选择和移动它的功能。SVG对象是DOM对象,因此它们具有“ click”处理程序等。 DIV可以,但是笨重,并且在大量情况下具有糟糕的性能加载。 Canvas具有最佳的性能,但是您必须自己实现托管状态(对象选择等)的所有概念,或者使用库。 长答案: HTML5 Canvas只是位图的绘图表面。 您设置进行绘制(用颜色和线条粗细说),绘制该东西,然后Canvas不知道该东西:它不知道它在哪里或刚刚绘制的是什么,它是只是像素。 如果要绘制矩形并使其移动或可以选择,则必须从头开始编写所有代码,包括要记住已绘制矩形的代码。 另一方面,SVG必须维护对其呈现的每个对象的引用。 您创建的每个SVG / VML元素都是DOM中的真实元素。 默认情况下
  • 文本模糊时,Android BlurMaskFilter在canvas.drawOval中不起作用(Android BlurMaskFilter has no effect in canvas.drawOval while text is blurred)
    问题 我一直在尝试创建一个自定义视图,该视图在文本下具有模糊的形状。 问题在于BlurMaskFilter对我在画布上绘制的任何形状都没有影响。 这是我如何在构造函数中初始化Paint对象的方法: paint = new Paint(0); paint.setColor(0xffffffff); paint.setMaskFilter(new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL)); mShadowPaint = new Paint(0); mShadowPaint.setColor(0xff333333); mShadowPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL)); 我在onDraw()中调用这样的函数: canvas.drawOval(mShadowBounds,mShadowPaint); canvas.drawText("hello", x, y, paint); 但这就是我所看到的。 使用android 4.0 sdk并在4.0.4银河系设备(英国)上进行测试。 我想知道这是否是4.0.4中的错误,因为我确实在4.0和4.0.3的模拟器上对其进行了测试,并且在它们上的模糊效果很好,除非我做的是完全错误的事情? 编辑