2014-10-14 4 views
0

브라우저가 HTML 캔버스의 내용을 어떻게 렌더링합니까? context.lineTo (x, y)와 같은 것들. 모든 함수 호출을 픽셀 데이터로 변환하는 일부 구성 요소가 있어야합니다. 실제로 알고 싶다면 실제로이 픽셀 데이터를 어딘지 렌더링하지 않고 얻을 수있는 방법이 있는지입니다.브라우저가 캔버스 요소의 내용을 렌더링하는 방법

독립형 자바 스크립트 엔진 (v8)을 실행하고 javascript 코드를 전달하여 출력으로 픽셀 데이터를 얻을 수 있는지 알고 싶습니다.

답변

2

실제적으로 어딘가에 렌더링하지 않고이 픽셀을 얻는 방법이 있다면 실제로 알고 싶습니다.

기본적으로 브라우저에서 벡터 데이터 (경로)를 래스터 화하기 위해 캔버스 (기술적으로 비트 맵)를 사용하는 것 외에는 픽셀 데이터를 가져올 방법이 없습니다.

브라우저는 일반적으로 래스터 화를 수행하기 위해 기본 그래픽 코어 시스템 (즉, DirectX 등)을 사용합니다. 브라우저 (V8/node.js를 수정하지 않는 이상)를 통해 액세스 할 수 없습니다. 이 하위 시스템은 선, 원, 호 및 타원의 픽셀에 대한 모든 래스터 라이 제이션을 처리 할뿐만 아니라 다각형 등을 채 웁니다. 그러나 점 위치 배열을 구축하는 것이 아니라 경사를 단순히 "걷는"방법으로 처리합니다 (코스 - 채우기는 라인 스캐닝을 기반으로하지만 다른 접근법을 사용합니다).

라인의 경우 이것은 현재 픽셀이 이전 픽셀과 상대적으로 임시로 등록된다는 것을 의미합니다. 원/타원의 경우 픽셀은 일반적으로 여기저기서 추가로 미러링됩니다. 그러나 본질적으로 래스터 화 이후에 추출 할 수있는 절대 또는 상대 픽셀 위치의 등록이 없습니다.

각 픽셀의 위치가 인 배열을 사용한 경우 일부 알고리즘의 자체 솔루션을 구현해야합니다. 그러나 매우 특별한 이유가 필요하지 않다면 왜 이렇게 빨리 할 캔버스를 사용하지 않거나 벡터 공간에서 직접 작업하고 필요한 경우에만 래스터화할 수 있는지 알 수 없습니다.

다양한 라인 알고리즘을 사용하여 JavaScript를 사용하여 구현할 수 있습니다. 초보자를위한 markE의 훌륭한 대답을보십시오. 나는 또한 Retro-Canvas에 대해 이것을 수행했다. 자바 스크립트에서 사용 된 알고리즘을 살펴볼 수있다. 그들은 최적화되어 있습니다.

캔버스의 유연성/호환성을 원한다면 그 외에도 회전, 크기 조정 및 변환을 위해 2D matrix을 구현해야합니다.

이 접근법을 사용하면 부드러운 결과를 얻으려면 인 앤티 앨리어싱을 제거 할 수 있다는 점에 유의해야합니다. 이것은 필요한 경우 상단에 추가해야 할 항목입니다 (내부 선을 캔버스에 그려진 선과 동기화하려고 시도 할 수도 있지만 그 단계에서 아마도 문제가 될 수있는 정확한 동일해야합니다). Linux, Mac, Windows 등은 결과에 사소한 차이가있는 다른 그래픽 하위 시스템을 사용함) 다른 색상/알파 값으로 추가 픽셀을 등록해야합니다.

일부 자원 :

이 (모든 일반 다각형의 기본 빌딩 블록 호는 원의 일부이므로 여기에 포함시키지 않았지만이를위한 최적의 접근 방법이 존재합니다.)

cardinal splines뿐만 아니라 Bezier뿐만 아니라 일반적으로 2 차 (2 차, 1 개 제어점) 및 3 차 차수 (2 개 제어점)로 구현되는 Catmull/Rom을 사용할 수 있습니다. 더 부드러운 모양, 글꼴 윤곽선 등.

또 다른 가능한 접근법은 검정색 또는 투명 배경 위에 흰색 색상의 오프 스크린 캔버스에 도형을 그린 다음 각 라인을 스캔하고 배열에서 위치와 상대 색상 (알파에 대한)과 함께 각 픽셀을 배치하는 것입니다 . 그러나, 이것은 당신에게 연속적인 라인을주지 않을 것이며, 각 픽셀의 위치는 그들이 무엇이든 관계없이 ...

+0

+1 좋은 답변 @Ken Fyrstenberg - 오신 것을 환영합니다! 안녕하세요, 귀하의 프로필에 링크 된 미술 작품을 확인했습니다 ... 인상적입니다! 내 작품이 스틱 인물보다 더 좋아질 수 있었으면 좋겠지 만 나는 그렇게 축복받은 사람이 아니 었습니다. – markE

+0

한 캔버스의 픽셀 데이터를 다른 캔버스에 보내려고했습니다. 그래서 이것은 HTML 캔버스와 연관된 프레임 버퍼가 없다는 것을 이해합니다. 프레임 버퍼가 필요하다면 X 윈도우 시스템과 같은 디스플레이 시스템의 버퍼를 사용해야 할 것입니다. 서버에서 '줄'과 같은 신호를 내보내고 클라이언트에서 다시 그려서 제대로 작동합니다. 그러나 비 벡터 그래픽 (예를 들어 jpeg 이미지)이 포함 된 캔버스에는 동일한 작업을 수행 할 수 없습니다. 그럴 경우 프레임 버퍼를 갖는 것이 유일한 방법입니다. – lonesword

+0

질문 : 노드 버퍼 위에 프레임 버퍼를 구현하면 성능이 크게 저하됩니까? 또한 오프 스크린 캔버스를 사용하면 화면상의 캔버스를 사용하는 것보다 향상된 성능을 제공합니까? (실제로 화면에 그릴 필요가 없기 때문에). 좋은 답변을 주셔서 대단히 감사합니다. – lonesword

3

브라우저 (또는 그래픽 카드)는 수학적 알고리즘을 적용하여 픽셀을 설정하기 만합니다.

결과는 HTML 캔버스가 각 픽셀의 상태를 유지하기 위해 유지하는 배킹 배열에 저장됩니다.

각 캔버스 픽셀은 캔버스 픽셀 배열에있는 4 개의 요소 집합으로 표현됩니다. 4 픽셀 세트는 R, G, B, A 값입니다. 그래서 하나의 적색 픽셀은 픽셀 배열의 4 개 요소의 집합으로 표현 될 것이다 :

pixelArray=[...255,0,0,255...] // where 255==red, 0==green, 0==blue, alpha==255 

당신은 브라우저의 내부 픽셀 설정 알고리즘에 접근 할 수 없지만, 사용자가 설정 한 동일한 알고리즘을 실행할 수 있습니다 적절한 픽셀.

var width=500; 
var height=500; 
var pixels=new Array(width*height); 

당신은 배열 요소를 얻을 수있는 모든 픽셀에 해당 :

당신이 가상의 그리드의 모든 픽셀을 나타내는 배열이 있다고 가정 : 여기

는 것을 수행하는 방법의 개요이다

var x=200; 
var y=30; 
var arrayElement=y*width+x; 

당신을이 같은

function setPixel(x,y,colorObject){ 
    pixels[y*width+x]=colorObject; 
} 

setPixel(100,50,{r:255,g:0,b:0,a:255}); 

당신은 어떤 [X, Y]의 화소 설정을 얻을 수 이런 :

function getPixel(x,y){ 
    return(pixels[y*width+x]); 
} 

var theColor=getPixel(100,50); 

는 그런 다음 픽셀을 설정할 수있는이 같은 어레이 픽셀 요소를 설정할 수

// Refer to: http://rosettacode.org/wiki/Bitmap/Bresenham's_line_algorithm#JavaScript 

function bline(x0, y0, x1, y1) { 
    var dx = Math.abs(x1 - x0), sx = x0 < x1 ? 1 : -1; 
    var dy = Math.abs(y1 - y0), sy = y0 < y1 ? 1 : -1; 
    var err = (dx>dy ? dx : -dy)/2;   
    while (true) { 
    setPixel(x0,y0); 
    if (x0 === x1 && y0 === y1) break; 
    var e2 = err; 
    if (e2 > -dx) { err -= dy; x0 += sx; } 
    if (e2 < dy) { err += dx; y0 += sy; } 
    } 
} 

다른 html로 C : 이런 [X1, Y1]로 선분 접속점 [X0, Y0]에 anvas 경로 요소에는 경로를 따라 설정해야하는 각 [x, y] 픽셀을 계산하는 유사한 알고리즘이 있습니다.

html로 캔버스 커브 경로

각 곡선 경로 요소는 수학 식에 의해 정의된다. 이 방정식을 사용하여 간격을두고 오버 샘플링 값을 사용하여 각 [x, y]를 곡선을 따라 얻을 수 있습니다.

예를 들어, 수식 은 간격 (T)으로 이차 곡선을 따라 [x, y] 점을 가져옵니다. T는 0.00과 1.00 사이의 값이고 T == 0.00은 곡선의 시작점이고 T == 1.00은 곡선의 끝에 있습니다.

// Get [x,y] at interval T along a Quadratic Curve 
var x = Math.pow(1-T,2) * startPt.x + 2 * (1-T) * T * controlPt.x + Math.pow(T,2) * endPt.x; 
var y = Math.pow(1-T,2) * startPt.y + 2 * (1-T) * T * controlPt.y + Math.pow(T,2) * endPt.y; 

사용자는 곡선을 따라서 간격 (T)을 오버 샘플링해야하거나 그 곡선을 따라 [X, y]는 점을 누락시킬 위험. 이는 선과 달리 곡선 공식이 균일 한 간격의 점을 가져 오지 않기 때문입니다. 다음은 0.00과 1.00 사이의 1000 T 웨이 포인트를 오버 샘플링하는 예제입니다. 다음

// Oversample T along a quadratic curve to be sure to catch all [x,y] 
// Some pixels will harmlessly be set more than once, 
// but it's likely that all desired pixels will be set 
for(var i=0;i<1000;i++){ 
    var T=i/1000; 
    var x = Math.pow(1-T,2) * startPt.x + 2 * (1-T) * T * controlPt.x + Math.pow(T,2) * endPt.x; 
    var y = Math.pow(1-T,2) * startPt.y + 2 * (1-T) * T * controlPt.y + Math.pow(T,2) * endPt.y; 
    setPixel(x,y,color); 
} 

을 수식 페치는 [X는 Y] 큐빅 베 지어 곡선을 따라 점이다. 다음

// De Casteljau's algorithm which calculates points along a cubic Bezier curve 
function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){ 
    var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x); 
    var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y); 
    return({x:x,y:y}); 
} 

// cubic helper formula at T distance 
function CubicN(T, a,b,c,d) { 
    var t2 = T * T; 
    var t3 = t2 * T; 
    return a + (-a * 3 + T * (3 * a - a * T)) * T 
    + (3 * b + T * (-6 * b + b * 3 * T)) * T 
    + (c * 3 - c * 3 * T) * t2 
    + d * t3; 
} 

을 수식 페치는 [X는 Y] 소정 각도 라디안에서 아크 따른 점이다. globalAlpha 설정 html로 캔버스 운영자

// Trigonometry to calculate [x,y] at a specified angle 
function get ArcXYatRadianAngle(centerX,centerY,radius,radianAngle){ 
    var x=centerX+radius*Math.cos(radianAngle); 
    var y=centerY+radius*Math.sin(radianAngle); 
} 

은 0과 255 (완전 투명하고 완전 불투명 사이) 사이에서 원하는 값으로 모든 화소의 alpha 요소를 설정하는 것만 큼 단순하다.

심지어 globalCompsiteOperation도 비교적 간단합니다.

  • 픽셀 배열에 적용 할 새 [x, y] 픽셀 값을 플롯합니다.
  • 픽셀 배열에서 기존 픽셀 값을 읽습니다.
  • 이 옵션의 사용 원하는 합성 효과를 적용 :
    • 0 (이 투명하게)
    • 에 픽셀의 알파 값을 설정 새로운 픽셀 값
    • 로 덮어 쓰기 기존의 픽셀 값을 유지

힌트 : 기존 픽셀과 교체 픽셀을 비교하는이 방법을 사용하여 픽셀에 블렌딩 필터를 적용 할 수 있습니다! ;-)

클리핑 클리핑 지정 클리핑 영역 내에서만 새 픽셀 값을 적용해야한다는 점에서 반드시 어렵습니다. 이미 (이하 "도면 배열"호출)

  • 가에 제 2 픽셀 배열을 만들기 제 1 화소 배열을

    • : 당신은 허용 도면 영역을 결정하기 위해 미적분을 사용할 수 있지만 더 간단이하는 것 클리핑 패스로 정의 된 픽셀을 유지합니다 (이 두 번째 배열을 "클리핑 배열"이라고 함).
    • 새 픽셀을 드로잉 배열에 적용하려면 먼저 클리핑 배열을 참조하십시오. 클리핑 배열 픽셀이 SET이면 도면 배열에 픽셀을 설정합니다. 클리핑 배열 픽셀이 UNSET 인 경우 드로잉 배열에서 해당 픽셀을 변경하지 마십시오.

    휴! 글쎄 그것은 당신을 시작해야합니다 ... 당신의 프로젝트에 행운을 빌어 요!

  • +0

    브릴리언트 설명! 이전에 선 그리기 알고리즘을 시도해 보았고 캔버스에서 내부적으로 사용되는 알고리즘만큼 빠르지 않다고 생각합니다. 그것은 내 알고리즘이 최적화되지 않았기 때문이거나 자바 스크립트에서 구현이 느리기 때문입니까? – lonesword

    +0

    당신이 발견 한 것처럼 "수동"드로잉은 캔버스 요소를 사용하는 네이티브 브라우저 드로잉보다 느립니다. 이는 브라우저 알고리즘이 하드웨어 가속 및 최적화이기 때문입니다. – markE

    +0

    그리고 nodejs 또는 v8을 사용하여 이러한 내부 함수에 액세스 할 수있는 방법이 없다고 가정합니다. – lonesword

    관련 문제