web-dev-qa-db-ja.com

HTML5 Canvasとアンチエイリアス

canvasanti-aliasingを有効にする方法。

次のコードは滑らかな線を描画しません。

var context = mainCanv.getContext("2d");
if (context) {
   context.moveTo(0,0);
   context.lineTo(100,75);

   context.strokeStyle = "#df4b26";
   context.lineWidth = 3;
   context.stroke();
}
53
KRouane

アンチエイリアスはオンまたはオフにできず、ブラウザによって制御されます。

HTML <canvas>要素でアンチエイリアスをオフにできますか?

26
Gaurav

キャンバスを半ピクセルの距離で移動できます。

ctx.translate(0.5, 0.5);

最初は、物理的なピクセル間のキャンバスの位置決めポイント。

38
Bacher

アンチエイリアスはデフォルトでオンになっているため、オンにする必要はありませんが、オフにする必要があります。また、オフにできる場合は、オンにすることもできます。

ctx.imageSmoothingEnabled = true;

キャンバスのRPGで作業しているときは、通常はオフにします。そのため、画像を拡大してもぼやけて見えません。

20
zachdyer

今は2018年です、そして私たちはついにそれを回避する安価な方法を持っています...

実際、2dコンテキストAPIには filter プロパティがあり、このフィルタープロパティは SVGFilters を受け入れることができるため、のみを保持するSVGFilterを構築できます図面から完全に不透明なピクセル、したがってデフォルトのアンチエイリアスを削除します。

そのため、アンチエイリアシング自体は無効になりませんが、実装とパフォーマンスの両方の面で、描画中にすべての半透明ピクセルを削除する安価な方法を提供します。

私は実際にはSVGFilterの専門家ではないため、より良い方法があるかもしれませんが、この例では <feComponentTransfer> ノードを使用して完全に不透明なピクセルのみを取得します。

var ctx = canvas.getContext('2d');
ctx.fillStyle = '#ABEDBE';
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = 'black';
ctx.font = '14px sans-serif';
ctx.textAlign = 'center';

// first without filter
ctx.fillText('no filter', 60, 20);
drawArc();
drawTriangle();
// then with filter
ctx.setTransform(1, 0, 0, 1, 120, 0);
ctx.filter = 'url(#remove-alpha)';
// and do the same ops
ctx.fillText('no alpha', 60, 20);
drawArc();
drawTriangle();

// to remove the filter
ctx.filter = 'none';


function drawArc() {
  ctx.beginPath();
  ctx.arc(60, 80, 50, 0, Math.PI * 2);
  ctx.stroke();
}

function drawTriangle() {
  ctx.beginPath();
  ctx.moveTo(60, 150);
  ctx.lineTo(110, 230);
  ctx.lineTo(10, 230);
  ctx.closePath();
  ctx.stroke();
}
// unrelated
// simply to show a zoomed-in version
var zCtx = zoomed.getContext('2d');
zCtx.imageSmoothingEnabled = false;
canvas.onmousemove = function drawToZoommed(e) {
  var x = e.pageX - this.offsetLeft,
    y = e.pageY - this.offsetTop,
    w = this.width,
    h = this.height;
    
  zCtx.clearRect(0,0,w,h);
  zCtx.drawImage(this, x-w/6,y-h/6,w, h, 0,0,w*3, h*3);
}
<svg width="0" height="0" style="position:absolute;z-index:-1;">
  <defs>
    <filter id="remove-alpha" x="0" y="0" width="100%" height="100%">
      <feComponentTransfer>
        <feFuncA type="discrete" tableValues="0 1"></feFuncA>
      </feComponentTransfer>
      </filter>
  </defs>
</svg>

<canvas id="canvas" width="250" height="250" ></canvas>
<canvas id="zoomed" width="250" height="250" ></canvas>

また、DOMに<svg>要素を追加したくない場合は、外部svgファイルとして保存し、filterプロパティをpath/to/svg_file.svg#remove-alphaに設定することもできます。

12
Kaiido

これは、ピクセルごとに線を描画する必要があるが、アンチエイリアシングを防ぐ回避策です。

// some helper functions
// finds the distance between points
function DBP(x1,y1,x2,y2) {
    return Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}
// finds the angle of (x,y) on a plane from the Origin
function getAngle(x,y) { return Math.atan(y/(x==0?0.01:x))+(x<0?Math.PI:0); }
// the function
function drawLineNoAliasing(ctx, sx, sy, tx, ty) {
    var dist = DBP(sx,sy,tx,ty); // length of line
    var ang = getAngle(tx-sx,ty-sy); // angle of line
    for(var i=0;i<dist;i++) {
        // for each point along the line
        ctx.fillRect(Math.round(sx + Math.cos(ang)*i), // round for perfect pixels
                     Math.round(sy + Math.sin(ang)*i), // thus no aliasing
                     1,1); // fill in one pixel, 1x1
    }
}

基本的に、行の長さを見つけて、その行をステップごとにトラバースし、各位置を丸め、ピクセルを埋めます。

で呼び出す

var context = cv.getContext("2d");
drawLineNoAliasing(context, 20,30,20,50); // line from (20,30) to (20,50)
8
Overcode

キャンバスでピクセルレベルの制御が必要な場合は、 createImageData および putImageData を使用して実行できます。

HTML:

<canvas id="qrCode" width="200", height="200">
  QR Code
</canvas>

そしてJavaScript:

function setPixel(imageData, pixelData) {
  var index = (pixelData.x + pixelData.y * imageData.width) * 4;
    imageData.data[index+0] = pixelData.r;
    imageData.data[index+1] = pixelData.g;
    imageData.data[index+2] = pixelData.b;
    imageData.data[index+3] = pixelData.a;
}

element = document.getElementById("qrCode");
c = element.getContext("2d");

pixcelSize = 4;
width = element.width;
height = element.height;


imageData = c.createImageData(width, height);

for (i = 0; i < 1000; i++) {
  x = Math.random() * width / pixcelSize | 0; // |0 to Int32
  y = Math.random() * height / pixcelSize| 0;

  for(j=0;j < pixcelSize; j++){
    for(k=0;k < pixcelSize; k++){
     setPixel( imageData, {
         x: x * pixcelSize + j,  
         y: y * pixcelSize + k,
         r: 0 | 0,
         g: 0 | 0,
         b: 0 * 256 | 0,
         a: 255 // 255 opaque
       });
      }
  }
}

c.putImageData(imageData, 0, 0);

ここで作業サンプル

2
Jordan

だから今これはちょっと使い物にならないと思っていますが、それを行う1つの方法は実際に_document.body.style.zoom=2.0;_を使用することですが、これを行う場合はキャンバスの測定値をすべてズームで分割する必要があります。また、エイリアスを増やすにはズームを高く設定します。これは調整可能であるため便利です。また、この方法を使用する場合は、ctx.fillRect()などと同じように機能するが、ズームを考慮に入れることをお勧めします。例えば。

_function fillRect(x, y, width, height) {
    var zoom = document.body.style.zoom;
    ctx.fillRect(x/zoom, y/zoom, width/zoom, height/zoom);
}
_

お役に立てれば!

また、注:これは、円のエッジをシャープにするために使用して、ぼやけたように見えないようにすることもできます。 0.5などのズームを使用するだけです!

0
TOGD