画布图像线条模糊

时间:2012-01-02 00:53:55

标签: html5 canvas

我有一个<div style="border:1px solid border;" />和画布,使用:

绘制
context.lineWidth = 1;
context.strokeStyle = "gray";

绘图看起来相当模糊(lineWidth小于1会创建更糟糕的图片),并且没有任何靠近div的边框。是否可以使用画布获得与HTML相同的绘图质量?

var ctx = document.getElementById("canvas").getContext("2d");
ctx.lineWidth = 1;
ctx.moveTo(2, 2);
ctx.lineTo(98, 2);
ctx.lineTo(98, 98);
ctx.lineTo(2, 98);
ctx.lineTo(2, 2);
ctx.stroke();
div {
  border: 1px solid black;
  width: 100px;
  height: 100px;
}
canvas, div {background-color: #F5F5F5;}
canvas {border: 1px solid white;display: block;}
<table>
<tr><td>Line on canvas:</td><td>1px border:</td></tr>
<tr><td><canvas id="canvas" width="100" height="100"/></td><td><div>&nbsp;</div></td></tr>
</table>

11 个答案:

答案 0 :(得分:58)

我发现在CSS中设置画布大小会导致我的图像以模糊的方式显示。

试试这个:

<canvas id="preview" width="640" height="260"></canvas>

根据我的帖子:HTML Blurry Canvas Images

答案 1 :(得分:49)

更容易解决的问题就是使用它:

context = canvas.context2d;    
context.translate(0.5, 0.5);

从现在开始,您的坐标应该调整为0.5像素。

答案 2 :(得分:40)

在画布中绘制线条时,实际上需要跨越像素。在我看来,这是API中一个奇怪的选择,但易于使用:

而不是:

context.moveTo(10, 0);
context.lineTo(10, 30);

这样做:

context.moveTo(10.5, 0);
context.lineTo(10.5, 30);

dive into HTML5's canvas chapter talks about this nicely
(寻找'ASK PROFESSOR MARKUP'框大约1/4的方式)

答案 3 :(得分:7)

我使用视网膜显示器,我找到了一个适合我的解决方案here

小概述:

首先,您需要将画布的大小设置为您想要的两倍,例如:

canvas = document.getElementById('myCanvas');
canvas.width = 200;
canvas.height = 200;

然后使用CSS将其设置为所需的大小:

canvas.style.width = "100px";
canvas.style.height = "100px";

最后,您将绘图上下文缩放为2:

canvas.getContext('2d').scale(2,2);

答案 4 :(得分:3)

线条模糊,因为画布虚拟尺寸 已缩放为其HTML元素实际尺寸。要解决此问题,您需要在绘制之前调整画布虚拟大小:

&#13;
&#13;
function Draw () {
	var e, surface;
	e = document.getElementById ("surface");
	/* Begin size adjusting. */
	e.width = e.offsetWidth;
	e.height = e.offsetHeight;
	/* End size adjusting. */
	surface = e.getContext ("2d");
	surface.strokeRect (10, 10, 20, 20);
}
window.onload = Draw ()
&#13;
<!DOCTYPE html>
<html>
<head>
<title>Canvas size adjusting demo</title>
</head>
<body>
<canvas id="surface"></canvas>
</body>
</html>
&#13;
&#13;
&#13;

HTML:

答案 5 :(得分:2)

好的,我已经一劳永逸了。您需要做两件事:

  1. 将任何行放置在0.5像素上。请参考此内容,其中提供了很好的解释:

https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors#A_lineWidth_example

  1. 与画布相关联的基本上有两个高度和两个宽度。首先是画布的高度和宽度,然后是元素的css样式的高度和宽度。这些需要同步。

为此,您需要将css的高度和宽度计算为:

 var myCanvasEl = document.getElementById('myCanvas');
 var ctx = myCanvasEl.getContext('2d');
 myCanvasEl.style.height = myCanvasEl.height / window.devicePixelRatio + "px";
 myCanvasEl.style.width = myCanvasEl.width / window.devicePixelRatio + "px";
 

其中myCanvasEl.style.heightmyCanvasEl.style.width是元素的css样式高度和宽度,而myCanvasEl.heightmyCanvasEl.width是画布的高度和宽度。

旧答案(被以上内容取代):

这是我在2020年找到的最佳解决方案。请注意,我已将devicePixelRatio乘以2:

 var size = 100;
 var scale = window.devicePixelRatio*2;
 context.width = size * scale;
 cartesian_001El.style.height = cartesian_001El.height / window.devicePixelRatio + "px";
 cartesian_001El.style.height = cartesian_001El.height / window.devicePixelRatio + "px";
 context.height = size * scale;
 context.scale(scale, scale);

答案 6 :(得分:1)

要在动画中避免此问题,我想分享一个小demo

基本上我每次检查增量值&amp;通过删除浮点值来跳入一组1px。

HTML:

<canvas id="canvas" width="600" height="600"></canvas>

CSS:

  html, body{
    height: 100%;
  }
  body{
    font-family: monaco, Consolas,"Lucida Console", monospace;
    background: #000;
  }

  canvas{
    position: fixed;
    top: 0;
    left: 0;
    transform: translateZ(0);
  }

JS:

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

  ctx.translate(0.5, 0.5);

  var i = 0;
  var iInc = 0.005;
  var range = 0.5;

  raf = window.requestAnimationFrame(draw);

  function draw() {
    var animInc = EasingFunctions.easeInQuad(i) * 250;
    ctx.clearRect(0, 0, 600, 600);
    ctx.save();
    ctx.beginPath();
    ctx.strokeStyle = '#fff';
    var rectInc = 10 + animInc;

    // Avoid Half Pixel
    rectIncFloat = rectInc % 1; // Getting decimal value.
    rectInc = rectInc - rectIncFloat; // Removing decimal.

    // console.log(rectInc);
    ctx.rect(rectInc, rectInc, 130, 60);
    ctx.stroke();
    ctx.closePath();

    ctx.font = "14px arial";
    ctx.fillStyle = '#fff';
    ctx.textAlign = 'center';
    ctx.fillText("MAIN BUTTON", 65.5 + rectInc, 35.5 + rectInc);

    i += iInc;

    if (i >= 1) {
      iInc = -iInc;
    }
    if (i <= 0) {
      iInc = Math.abs(iInc);
    }

    raf = window.requestAnimationFrame(draw);
  }


  // Easing
  EasingFunctions = {
    // no easing, no acceleration
    linear: function(t) {
      return t
    },
    // accelerating from zero velocity
    easeInQuad: function(t) {
      return t * t
    },
    // decelerating to zero velocity
    easeOutQuad: function(t) {
      return t * (2 - t)
    },
    // acceleration until halfway, then deceleration
    easeInOutQuad: function(t) {
      return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t
    },
    // accelerating from zero velocity 
    easeInCubic: function(t) {
      return t * t * t
    },
    // decelerating to zero velocity 
    easeOutCubic: function(t) {
      return (--t) * t * t + 1
    },
    // acceleration until halfway, then deceleration 
    easeInOutCubic: function(t) {
      return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1
    },
    // accelerating from zero velocity 
    easeInQuart: function(t) {
      return t * t * t * t
    },
    // decelerating to zero velocity 
    easeOutQuart: function(t) {
      return 1 - (--t) * t * t * t
    },
    // acceleration until halfway, then deceleration
    easeInOutQuart: function(t) {
      return t < .5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t
    },
    // accelerating from zero velocity
    easeInQuint: function(t) {
      return t * t * t * t * t
    },
    // decelerating to zero velocity
    easeOutQuint: function(t) {
      return 1 + (--t) * t * t * t * t
    },
    // acceleration until halfway, then deceleration 
    easeInOutQuint: function(t) {
      return t < .5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t
    }
  }

答案 7 :(得分:0)

正如@langpavel在评论中提到的那样,Mozilla网站上有示例代码,说明了如何在画布中更正分辨率: https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio

enter image description here

var canvas = document.getElementById('canvas');

var ctx = canvas.getContext('2d');

// Set display size (css pixels).
var size = 200;
canvas.style.width = size + "px";
canvas.style.height = size + "px";

// Set actual size in memory (scaled to account for extra pixel density).
var scale = window.devicePixelRatio; // Change to 1 on retina screens to see blurry canvas.
canvas.width = size * scale;
canvas.height = size * scale;

// Normalize coordinate system to use css pixels.
ctx.scale(scale, scale);

ctx.fillStyle = "#bada55";
ctx.fillRect(10, 10, 300, 300);
ctx.fillStyle = "#ffffff";
ctx.font = '18px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';

var x = size / 2;
var y = size / 2;

var textString = "I love MDN";
ctx.fillText(textString, x, y);

答案 8 :(得分:0)

为了消除模糊,您需要以两种方式设置画布的大小: 首先是canvas.width = yourwidthhere;canvas.height = yourheighthere; 第二,通过js或样式表设置css属性

答案 9 :(得分:0)

HTML:

<canvas class="canvas_hangman"></canvas> 

JS:

function setUpCanvas(){
      canvas = document.getElementsByClassName("canvas_hangman")[0];
      ctx = canvas.getContext('2d');
      ctx.translate(0.5, 0.5);

      // Set display size (vw/vh).
      var sizeWidth = 80 * window.innerWidth / 100,
          sizeHeight = 100 * window.innerHeight / 100 || 766; 

      // console.log(sizeWidth, sizeHeight);
      //Setting the canvas site and width to be responsive 
      canvas.width = sizeWidth;
      canvas.height = sizeHeight;
      canvas.style.width = sizeWidth;
      canvas.style.height = sizeHeight;
 }
 window.onload = setUpCanvas();

这也以响应方式完美地设置了HTML画布以进行绘制:)

答案 10 :(得分:0)

当图像被缩放时(这是我的问题),这里没人讨论过的其他问题是 imageSmoothingEnabled

<块引用>

CanvasRenderingContext2D 接口的 imageSmoothingEnabled 属性,Canvas API 的一部分,确定缩放图像是否平滑(真,默认)或不平滑(假).在获取 imageSmoothingEnabled 属性时,将返回其设置的最后一个值。

此属性对于使用像素艺术的游戏和其他应用非常有用。放大图像时,默认的调整大小算法会模糊像素。将此属性设置为 false 以保留像素的清晰度。

https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingEnabled

要禁用它,只需将属性设置为 false:

ctx.imageSmoothingEnabled = false;