HTML5 캔버스에서 단일 픽셀을 설정하는 가장 좋은 방법은 무엇입니까? 설정하는 방법이 없습니다. 매우 짧은 선을 사용하여

HTML5 Canvas에는 단일 픽셀을 명시 적으로 설정하는 방법이 없습니다.

매우 짧은 선을 사용하여 픽셀을 설정할 수는 있지만 앤티 앨리어싱 및 선 캡이 방해 될 수 있습니다.

또 다른 방법은 작은 ImageData객체 를 만들고 다음을 사용하는 것입니다 .

context.putImageData(data, x, y)

그것을 제자리에 두십시오.

누구나 효율적이고 신뢰할 수있는 방법을 설명 할 수 있습니까?



답변

두 가지 최고의 경쟁자가 있습니다.

  1. 1 × 1 이미지 데이터를 생성하고 색상을 설정 putImageData하고 위치를 지정하십시오.

    var id = myContext.createImageData(1,1); // only do this once per page
    var d  = id.data;                        // only do this once per page
    d[0]   = r;
    d[1]   = g;
    d[2]   = b;
    d[3]   = a;
    myContext.putImageData( id, x, y );     
  2. fillRect()픽셀을 그리는 데 사용 합니다 (별칭 문제가 없어야 함).

    ctx.fillStyle = "rgba("+r+","+g+","+b+","+(a/255)+")";
    ctx.fillRect( x, y, 1, 1 );

http://jsperf.com/setting-canvas-pixel/9 또는 https://www.measurethat.net/Benchmarks/Show/1664/1 에서 속도를 테스트 할 수 있습니다.

최대 속도를 원하는 브라우저에 대해 테스트하는 것이 좋습니다. 2017 년 7 월 현재 fillRect()Firefox v54 및 Chrome v59 (Win7x64)에서 5-6 배 더 빠릅니다.

다른 대안은 다음과 같습니다.

  • 사용하여 getImageData()/putImageData()전체 캔버스에; 다른 옵션보다 약 100 배 느립니다.

  • 데이터 URL을 사용하여 사용자 지정 이미지를 만들고 drawImage()이를 사용 하여 표시 :

    var img = new Image;
    img.src = "data:image/png;base64," + myPNGEncoder(r,g,b,a);
    // Writing the PNGEncoder is left as an exercise for the reader
  • 원하는 모든 픽셀로 채워진 다른 이미지 나 캔버스를 만들고 원하는 픽셀 drawImage()만 블리 팅 하는 데 사용 합니다. 아마도 매우 빠를 것이지만 필요한 픽셀을 미리 계산해야하는 한계가 있습니다.

내 테스트는 캔버스 컨텍스트를 저장 및 복원하지 않습니다 fillStyle. fillRect()성능 이 저하 될 수 있습니다. 또한 깨끗한 슬레이트로 시작하거나 각 테스트에 대해 정확히 동일한 픽셀 세트를 테스트하지 않습니다.


답변

언급되지 않은 한 가지 방법은 getImageData를 사용한 다음 putImageData를 사용하는 것입니다.
이 방법은 한 번에 많이 그리기를 원할 때 유용합니다.
http://next.plnkr.co/edit/mfNyalsAR2MWkccr

  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  var canvasWidth = canvas.width;
  var canvasHeight = canvas.height;
  ctx.clearRect(0, 0, canvasWidth, canvasHeight);
  var id = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
  var pixels = id.data;

    var x = Math.floor(Math.random() * canvasWidth);
    var y = Math.floor(Math.random() * canvasHeight);
    var r = Math.floor(Math.random() * 256);
    var g = Math.floor(Math.random() * 256);
    var b = Math.floor(Math.random() * 256);
    var off = (y * id.width + x) * 4;
    pixels[off] = r;
    pixels[off + 1] = g;
    pixels[off + 2] = b;
    pixels[off + 3] = 255;

  ctx.putImageData(id, 0, 0);


답변

나는 고려하지 fillRect()않았지만, 대답은 그것을 벤치마킹하도록 자극했다 putImage().

맥북 프로 (구)에 크롬 9.0.597.84으로, 임의의 위치에서 10 만 개 무작위 색깔의 픽셀을 퍼팅과 100ms의 채 걸리지 putImage()만, 거의 사용 900ms fillRect(). ( http://pastebin.com/4ijVKJcC의 벤치 마크 코드 ).

대신 루프 외부에서 단일 색상을 선택하고 임의의 위치에 해당 색상을 플롯하면에 putImage()대해 59ms 대 102ms가 걸립니다 fillRect().

구문에서 CSS 색상 사양을 생성하고 구문 분석하는 오버 헤드가 rgb(...)대부분의 차이를 담당 하는 것으로 보입니다 .

ImageData반면에 원시 RGB 값을 블록에 똑바로 넣으면 문자열 처리 또는 구문 분석이 필요하지 않습니다.


답변

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


답변

브라우저마다 다른 방법을 선호하는 것 같으므로 로딩 프로세스의 일부로 세 가지 방법 모두로 더 작은 테스트를 수행하여 어느 것이 가장 적합한 지 알아 낸 다음 응용 프로그램 전체에서 사용하는 것이 합리적 일 수 있습니다.


답변

이상하게 보이지만 HTML5는 선, 원, 사각형 및 기타 여러 기본 도형 그리기를 지원하지만 기본 점을 그리기에 적합한 것은 없습니다. 그렇게하는 유일한 방법은 당신이 가진 것을 가지고 포인트를 시뮬레이션하는 것입니다.

따라서 기본적으로 3 가지 가능한 솔루션이 있습니다.

  • 점을 선으로 그리다
  • 다각형으로 점을 그립니다
  • 점을 원으로 그리다

그들 각각은 단점이 있습니다


function point(x, y, canvas){
  canvas.beginPath();
  canvas.moveTo(x, y);
  canvas.lineTo(x+1, y+1);
  canvas.stroke();
}

우리는 남동쪽 방향으로 그림을 그리며, 이것이 가장자리라면 문제가있을 수 있습니다. 그러나 다른 방향으로 그릴 수도 있습니다.


직사각형

function point(x, y, canvas){
  canvas.strokeRect(x,y,1,1);
}

또는 렌더링 엔진이 한 픽셀 만 채울 수 있기 때문에 fillRect를 사용하는 더 빠른 방법입니다.

function point(x, y, canvas){
  canvas.fillRect(x,y,1,1);
}


서클의 문제 중 하나는 엔진이 렌더링하기가 어렵다는 것입니다.

function point(x, y, canvas){
  canvas.beginPath();
  canvas.arc(x, y, 1, 0, 2 * Math.PI, true);
  canvas.stroke();
}

채우기로 달성 할 수있는 사각형과 동일한 아이디어.

function point(x, y, canvas){
  canvas.beginPath();
  canvas.arc(x, y, 1, 0, 2 * Math.PI, true);
  canvas.fill();
}

이 모든 솔루션의 문제점 :

  • 그리려는 모든 점을 추적하기는 어렵습니다.
  • 확대하면보기 흉하게 보입니다.

점을 그리는 가장 좋은 방법 은 무엇입니까 ?비교 테스트와 함께jsperf 를 볼 수 있습니다 .


답변

사각형은 어떻습니까? 그것은 ImageData객체를 만드는 것보다 더 효율적이어야 합니다.