HTML5 캔버스 및 앤티 앨리어싱
어떻게 켭니다 앤티 앨리어싱 온 캔버스 .
다음 코드는 부드러운 선을 그리지 않습니다.
var context = mainCanv.getContext("2d");
if (context) {
context.moveTo(0,0);
context.lineTo(100,75);
context.strokeStyle = "#df4b26";
context.lineWidth = 3;
context.stroke();
}
앤티 앨리어싱은 켜거나 끌 수 없으며 브라우저에서 제어합니다.
HTML <canvas> 요소에서 앤티 앨리어싱을 끌 수 있습니까?
반 픽셀 거리로 캔버스를 번역 할 수 있습니다.
ctx.translate(0.5, 0.5);
처음에는 실제 픽셀 사이의 캔버스 위치 지정 지점입니다.
안티 앨리어싱은 기본적으로 켜져 있기 때문에 켤 필요가 없었지만 끄고 싶었습니다. 끌 수있는 경우 켜도됩니다.
ctx.imageSmoothingEnabled = true;
캔버스 롤 플레잉 작업을 할 때 보통 꺼서 이미지를 확대해도 흐릿하게 보이지 않습니다.
이제 2018 년이되었고 드디어 저렴한 방법으로 문제를 해결할 수 있습니다 ...
실제로 2d 컨텍스트 API에는 이제 filter
속성이 있고이 필터 속성이 SVGFilters 를 허용 할 수 있으므로 도면에서 완전히 불투명 한 픽셀 만 유지하여 기본 앤티 앨리어싱을 제거하는 SVGFilter를 빌드 할 수 있습니다.
따라서 앤티 앨리어싱 자체를 비활성화하지는 않지만, 그리는 동안 모든 반투명 픽셀을 제거하는 구현 및 성능 측면에서 저렴한 방법을 제공합니다.
저는 실제로 SVGFilters의 전문가가 아니기 때문에 더 나은 방법이있을 수 있지만 예를 들어 <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>
<svg>
DOM에 요소 를 추가하고 싶지 않은 경우 외부 svg 파일로 저장하고 filter
속성을 path/to/svg_file.svg#remove-alpha
.
다음은 픽셀 단위로 선을 그려야하지만 안티 앨리어싱을 방지하는 해결 방법입니다.
// 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)
캔버스에 대한 픽셀 수준 제어가 필요한 경우 createImageData 및 putImageData를 사용하여 수행 할 수 있습니다 .
HTML :
<canvas id="qrCode" width="200", height="200">
QR Code
</canvas>
그리고 자바 스크립트 :
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);
그래서 저는 이것이 현재 사용되지 않는다고 가정하고 있지만 실제로 사용하는 한 가지 방법은 실제로 사용하는 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);
}
Hope this helps!
Also, a sidenote: this can be used to sharpen circle edges as well so that they don't look as blurred. Just use a zoom such as 0.5!
ReferenceURL : https://stackoverflow.com/questions/4261090/html5-canvas-and-anti-aliasing
'programing' 카테고리의 다른 글
Eclipse Android 변경 API 레벨 (0) | 2021.01.19 |
---|---|
브라우저 콘솔에서 모든 JavaScript 이벤트 모니터링 (0) | 2021.01.19 |
이메일 템플릿으로 Razor보기 (0) | 2021.01.19 |
Code First에서 데이터베이스 이름을 지정하는 방법은 무엇입니까? (0) | 2021.01.19 |
DOUBLE_MAX는 어떻게 받습니까? (0) | 2021.01.19 |