<canvas>
要素をいじったり、線を引いたりしています。
対角線がアンチエイリアス処理されていることに気づきました。私がしていることにはギザギザの外観が好きです-この機能をオフにする方法はありますか?
<canvas>
要素をいじったり、線を引いたりしています。
対角線がアンチエイリアス処理されていることに気づきました。私がしていることにはギザギザの外観が好きです-この機能をオフにする方法はありますか?
回答:
画像については、現在あります。context.imageSmoothingEnabled
= false
ただし、線画を明示的に制御するものはありません。とを使用して、独自の線を引く必要がある場合があります(難しい方法)。getImageData
putImageData
putImageData
いますが、それでも近くのピクセルのエイリアシングが発生します。
の1-pixel
ような座標に線を引きますctx.lineTo(10.5, 10.5)
。ポイント上に1ピクセルの線を引くという(10, 10)
ことは、1
その位置にあるこのピクセルがそこから到達し9.5
、10.5
そこから2本の線がキャンバスに描かれることを意味します。
0.5
1ピクセルの線がたくさんある場合に、描画する実際の座標に常にを追加する必要がないという優れたトリックctx.translate(0.5, 0.5)
は、最初にキャンバス全体に追加することです。
ctx.translate(0.5,0.5)
うまくいきませんでした。FF39.0
これはMozillaFirefoxで実行できます。これをコードに追加します。
contextXYZ.mozImageSmoothingEnabled = false;
Operaでは現在機能リクエストですが、間もなく追加されることを願っています。
アンチエイリアスは、整数以外の座標(0.4、0.4)を含むベクターグラフィックを正しくプロットするために必要です。これは、ごく一部のクライアントを除いてすべて実行されます。
整数以外の座標が指定されている場合、キャンバスには2つのオプションがあります。
後者の戦略は静的グラフィックスで機能しますが、小さなグラフィックス(半径2の円)の場合、曲線は滑らかな曲線ではなく明確なステップを示します。
本当の問題は、グラフィックが変換(移動)されるときです-1つのピクセルと別のピクセルの間のジャンプ(1.6 => 2、1.4 => 1)は、形状の原点が親コンテナに対してジャンプする可能性があることを意味します(常にシフトします) 1ピクセル上下および左/右)。
ヒント1:キャンバスをスケーリングして(たとえばxで)アンチエイリアスを柔らかく(または固く)してから、(キャンバスを使用せずに)自分でジオメトリに逆数スケール(1 / x)を適用できます。
比較(スケーリングなし):
と(キャンバススケール:0.75;手動スケール:1.33):
および(キャンバススケール:1.33;手動スケール:0.75):
ヒント2:ギザギザの外観が本当に必要な場合は、各形状を数回(消去せずに)描画してみてください。描画するたびに、アンチエイリアスピクセルは暗くなります。
比較してください。一度描いた後:
3回描いた後:
ブレゼンハムの線アルゴリズムなどのカスタム線アルゴリズムを使用してすべてを描画します。このjavascriptの実装を確認してください:http: //members.chello.at/easyfilter/canvas.html
これで間違いなくあなたの問題は解決すると思います。
setPixel(x, y)
。私はここで受け入れられた答えを使用しました:stackoverflow.com/questions/4899799/…–
画像を縮小してキャンバスに描画するときに問題が発生したことを付け加えたいと思います。拡大時に使用していなかったにもかかわらず、スムージングを使用していました。
私はこれを使用して解決しました:
function setpixelated(context){
context['imageSmoothingEnabled'] = false; /* standard */
context['mozImageSmoothingEnabled'] = false; /* Firefox */
context['oImageSmoothingEnabled'] = false; /* Opera */
context['webkitImageSmoothingEnabled'] = false; /* Safari */
context['msImageSmoothingEnabled'] = false; /* IE */
}
この関数は次のように使用できます。
var canvas = document.getElementById('mycanvas')
setpixelated(canvas.getContext('2d'))
多分これは誰かに役立つでしょう。
ctx.translate(0.5, 0.5);
ctx.lineWidth = .5;
このコンボで、1pxの細い線を描くことができます。
非常に限られたトリックに注意してください。2色の画像を作成する場合は、色#000000の背景に色#010101で任意の形状を描画できます。これが完了したら、imageData.data []の各ピクセルをテストし、0x00以外の値を0xFFに設定できます。
imageData = context2d.getImageData (0, 0, g.width, g.height);
for (i = 0; i != imageData.data.length; i ++) {
if (imageData.data[i] != 0x00)
imageData.data[i] = 0xFF;
}
context2d.putImageData (imageData, 0, 0);
結果は、アンチエイリアス処理されていない白黒画像になります。いくつかのアンチエイリアシングが行われるため、これは完全ではありませんが、このアンチエイリアシングは非常に制限され、形状の色は背景の色と非常によく似ています。
まだ答えを探している人のために。これが私の解決策です。
画像が1チャンネルグレーであると仮定します。ctx.stroke()の後にしきい値を設定しました。
ctx.beginPath();
ctx.moveTo(some_x, some_y);
ctx.lineTo(some_x, some_y);
...
ctx.closePath();
ctx.fill();
ctx.stroke();
let image = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height)
for(let x=0; x < ctx.canvas.width; x++) {
for(let y=0; y < ctx.canvas.height; y++) {
if(image.data[x*image.height + y] < 128) {
image.data[x*image.height + y] = 0;
} else {
image.data[x*image.height + y] = 255;
}
}
}
画像チャンネルが3または4の場合、次のように配列インデックスを変更する必要があります。
x*image.height*number_channel + y*number_channel + channel
StashOfCodeの答えに関する2つのメモ:
代わりにこれを行うことをお勧めします。
ストロークして塗りつぶし#FFFFFF
、次にこれを行います。
imageData.data[i] = (imageData.data[i] >> 7) * 0xFF
これにより、幅が1pxの行で解決されます。
それ以外は、StashOfCodeのソリューションは、独自のラスタライズ関数を作成する必要がないため完璧です(線だけでなく、ベジエ、円弧、穴のある塗りつぶされたポリゴンなどを考えてください)。
これは、JavaScriptでのブレゼンハムのアルゴリズムの基本的な実装です。これは、このウィキペディアの記事で説明されている整数演算バージョンに基づいています:https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
function range(f=0, l) {
var list = [];
const lower = Math.min(f, l);
const higher = Math.max(f, l);
for (var i = lower; i <= higher; i++) {
list.push(i);
}
return list;
}
//Don't ask me.
//https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
function bresenhamLinePoints(start, end) {
let points = [];
if(start.x === end.x) {
return range(f=start.y, l=end.y)
.map(yIdx => {
return {x: start.x, y: yIdx};
});
} else if (start.y === end.y) {
return range(f=start.x, l=end.x)
.map(xIdx => {
return {x: xIdx, y: start.y};
});
}
let dx = Math.abs(end.x - start.x);
let sx = start.x < end.x ? 1 : -1;
let dy = -1*Math.abs(end.y - start.y);
let sy = start.y < end.y ? 1 : - 1;
let err = dx + dy;
let currX = start.x;
let currY = start.y;
while(true) {
points.push({x: currX, y: currY});
if(currX === end.x && currY === end.y) break;
let e2 = 2*err;
if (e2 >= dy) {
err += dy;
currX += sx;
}
if(e2 <= dx) {
err += dx;
currY += sy;
}
}
return points;
}
のようなものを試してくださいcanvas { image-rendering: pixelated; }
。
アンチエイリアス処理されていない1行だけを作成しようとしている場合、これは機能しない可能性があります。
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.fillRect(4, 4, 2, 2);
canvas {
image-rendering: pixelated;
width: 100px;
height: 100px; /* Scale 10x */
}
<html>
<head></head>
<body>
<canvas width="10" height="10">Canvas unsupported</canvas>
</body>
</html>
ただし、これは多くのブラウザでテストしていません。