계산 된 스타일과 같은 색으로 캔버스에 그리려고합니다.
같은 색상의 경우 괜찮습니다.
rgb (0, 255, 255) "
그러나 같은 것을 위해
rgba (0, 0, 0, 0)
캔버스에서는 검은 색이지만 브라우저에서는 흰색입니다.
빨강, 녹색, 파랑 및 알파 채널
대부분의 경우 브라우저에 표시되는 모든 그래픽은 4 개의 채널로 구성됩니다. 처음 3 개는 색상 채널이며 각 구성 요소 색상, 빨간색, 녹색 및 파란색의 강도를 나타냅니다. 네 번째 채널은 알파 채널이며 픽셀의 투명도를 나타냅니다. 메모리에 저장된 각 채널은 8 비트 폭으로 256 개의 개별 값을 허용합니다. 색상 채널의 경우 0은 기여하지 않음을 나타내며 255는 최대 강도를 나타냅니다. 알파 채널에는 완전 투명 0부터 완전 불투명 255까지 가능한 256 개의 값이 있습니다. 그러나 알파는 0에서 1까지의 단위 값으로 표시되는 것이 일반적입니다.
CSS 색상 문자열 rgba(red,green,blue,alpha)
을 사용하여 픽셀 색상을 나타낼 수 있습니다 .
소스 오버 블렌딩
픽셀의 알파 값이 1 미만 (바이트 값 <255)이면 그 아래에있는 픽셀과 혼합되고 (이 작업은 하드웨어에서 수행됨) 화면의 결과 픽셀은 두 픽셀의 혼합입니다.
픽셀 혼합을위한 표준 공식은 1984 년 Porter-Duff 합성 논문을 기반으로합니다.
가장 간단한 형식으로 한 픽셀을 다른 픽셀 위에 그릴 때 모든 채널에 대한 바이트 값을 사용하는 다음 절차가 사용되며 '소스 오버'라고합니다. ref W3C 단순 알파 합성
// the destination is the pixel being drawn over
var destination = {r : 255, g : 0, b : 0, a : 255}; // red opaque
// source is the pixel being put on top
var source = {r : 0, g : 255, b : 0, a : 127}; // green about half transparent
// normalised means brought to a unit value ranging between 0-1 inclusive
var ad = destination.a / 255; // normalise the destination alpha
var as = source.a / 255; // and source
// get the normalised alpha value for the resulting pixel
var ar = as + ad * (1 - as);
// the resulting pixel
var result = {};
// calculate the colour channels.
result.r = (source.r * as + destination.r * ad * (1 - as)) / ar;
result.g = (source.g * as + destination.g * ad * (1 - as)) / ar;
result.b = (source.b * as + destination.b * ad * (1 - as)) / ar;
// calculate the alpha channel
result.a = ar * 255; // bring alpha back to the byte value
// Though it may seem silly to convert to 8 bit range
// it is important to do so because there is a
// considerable loss of precision in all these
// calculations
// convert to a pixel value a used in 2D context getImageData
var pixel = new Uint8ClampedArray([
result.r,
result.g,
result.b,
result.a,
]);
같은 일을 할 함수에 두 개의 도우미 함수를 넣으십시오.
function blendSourceOver(s,d){
var ad = d.a / 255; // normalise the destination alpha
var as = s.a / 255; // and source
var ar = as + ad * (1 - as);
var r = {};
r.r = Math.round((s.r * as + d.r * ad * (1 - as)) / ar);
r.g = Math.round((s.g * as + d.g * ad * (1 - as)) / ar);
r.b = Math.round((s.b * as + d.b * ad * (1 - as)) / ar);
r.a = Math.round(ar * 255);
return r;
}
function rgbaToColour(col){
col = col.replace("rgba(","").replace(")","").split(",");
var r = {};
r.r = Number(col[0]);
r.g = Number(col[1]);
r.b = Number(col[2]);
r.a = Math.round(Number(col[3]) * 255);
return r;
}
function colourTorgba(col){
return `rgba(${col.r},${col.g},${col.b},${col.a / 255})`;
}
캔버스에서 일치하는 DOM 결과.
문제는 캔버스가 DOM과 일치하도록하는 것입니다. 두 가지 요소를 하나씩 고려해 보겠습니다. 첫 번째 div는 빨간색이고 두 번째 div는 알파가 0.5 인 파란색입니다.
DOM 색상 혼합 예
.exm { width : 100px; height: 30px; color: white; text-align: center;}
<div style = "background : rgba(255, 0, 0, 1);" class = "exm">
<div style = "background : rgba(0, 0, 255, 0.5); position : relative; top : 0px; left : 0px;" class = "exm">
Red + Blue
</div>
</div>
결과 색상은 무엇입니까?
이제 결과 색상을 캔버스에 렌더링하고 싶다고 가정합니다. 내가 아는 한 색상을 샘플링하는 직접적인 방법이 없으므로 알려진 색상으로 만들어야합니다.
이를 수행 할 수있는 두 가지 방법이 있습니다.
렌더 복제로
첫 번째는 DOM에서 일어나는 일을 복제하는 것입니다. 빨간색을 추가 한 다음 그 위에 파란색을 그립니다.
렌더링 단계를 복제하여 DOM 색상을 일치시키는 예
var ctx = can.getContext("2d");
ctx.fillStyle = "rgba(255, 0, 0, 1)";
ctx.fillRect(0, 0, 100, 30);
ctx.fillStyle = "rgba(0, 0, 255, 0.5)";
ctx.fillRect(0, 0, 100, 30);
ctx.font = "18px arial";
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.fillText("Canvas", 50, 22);
var dat = ctx.getImageData(1,1,1,1).data;
colResult.textContent = `Resulting colour rgba(${dat[0]},${dat[1]},${dat[2]},${dat[3]/255})`;
.exm { width : 100px; height: 30px; color: white; text-align: center; font : 18px arial;}
.text {color : black; font-size: xx-small;}
<p class="exm text"> Match DOM and Canvas colours via rendering replication</p>
<div style = "background : rgba(255, 0, 0, 1);" class = "exm">
<div style = "background : rgba(0, 0, 255, 0.5); position : relative; top : 0px; left : 0px;" class = "exm"> DOM
</div>
</div>
<canvas id = "can" width = "100" height = "30" class = "exm"></canvas>
<p class="exm text" id="colResult"></p>
계산으로
두 번째는 소스 오버 블렌드 기능을 사용하여 색상을 계산하는 것입니다.
Porter-Duff "source-over"
블렌딩 을 사용하여 색상을 계산하는 예 .
function blendSourceOver(s,d){
var ad = d.a / 255; // normalise the destination alpha
var as = s.a / 255; // and source
var ar = as + ad * (1 - as);
var r = {};
r.r = Math.round((s.r * as + d.r * ad * (1 - as)) / ar);
r.g = Math.round((s.g * as + d.g * ad * (1 - as)) / ar);
r.b = Math.round((s.b * as + d.b * ad * (1 - as)) / ar);
r.a = Math.round(ar * 255);
return r;
}
function rgbaToColour(col){
col = col.replace("rgba(","").replace(")","").split(",");
var r = {};
r.r = Number(col[0]);
r.g = Number(col[1]);
r.b = Number(col[2]);
r.a = Math.round(Number(col[3]) * 255);
return r;
}
function colourTorgba(col){
return `rgba(${col.r},${col.g},${col.b},${col.a / 255})`;
}
var colour = colourTorgba(
blendSourceOver(
rgbaToColour("rgba(0, 0, 255, 0.5)"), // source
rgbaToColour("rgba(255, 0, 0, 1)") // destination
)
);
var ctx = can.getContext("2d");
ctx.fillStyle = colour;
ctx.fillRect(0, 0, 100, 30);
ctx.font = "18px arial";
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.fillText("Canvas", 50, 22);
colResult.textContent = "Resulting colour "+colour;
.exm { width : 100px; height: 30px; color: white; text-align: center; font : 18px arial;}
.text {color : black; font-size: xx-small;}
<p class="exm text"> Match DOM and Canvas colours by calculation</p>
<div style = "background : rgba(255, 0, 0, 1);" class = "exm">
<div style = "background : rgba(0, 0, 255, 0.5); position : relative; top : 0px; left : 0px;" class = "exm"> DOM
</div>
</div>
<canvas id = "can" width = "100" height = "30" class = "exm"></canvas>
<p class="exm text" id="colResult"></p>
알파 = 1 확인
이제 모든 계산을 수행 할 때 항상 알파 값이 1 인 색상으로 끝나야하므로주의해야합니다. 그렇지 않은 경우 일부 정보가 누락 된 것입니다. 모든 DOM 색상 블렌딩의 최종 결과는 Alpha = 1 (배경)이며, 추가 투명도는 DOM의 컨텍스트를 벗어나 브라우저 창의 일부입니다.
계산 순서
두 개 이상의 색상을 계산하려면 DOM에서 수행 한 것과 동일한 순서로 계산해야합니다. 주문이 잘못된 경우 결과 색상도 올바르지 않습니다.
예를 들어 빨간색 배경이 있고 0.5 알파가있는 파란색 div가 있고 그 위에 0.5 알파가있는 녹색 div가 있다고 가정합니다. 계산 순서는 상향식입니다.
background = rgbaToColour("rgba(255,0,0,1)");
div1 = rgbaToColour("rgba(0,0,255,0.5)");
div2 = rgbaToColour("rgba(0,255,0,0.5)");
먼저 배경과 div1의 결과를 div2와 혼합합니다.
var temp = blendSourceOver(div1,background); // source then destination
var result = blendSourceOver(div2,temp); // source then temp destination
console.log(colourTorgb(result)); // => "rgba(63,128,64,1)"
다른 방법으로하면 완전히 다른 색상이됩니다.
var temp = blendSourceOver(div1,background); // source then destination
var result = blendSourceOver(div1,temp); // source then temp destination
console.log(colourTorgb(result)); // => "rgba(63,64,128,1)"
추가 읽기
W3C (서스펜스 충전) 합성 및 블렌딩 레벨 2 에 대해 알아야 할 모든 내용 은이 주제를보다 자세하게 다룹니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다