자바스크립트: 캔버스(Canvas) 에서 픽셀 단위로 다루기
[caption id=”” align=”alignnone” width=”300”]
캔버스에서 사용되는 좌표 변수의 의미[/caption]
data 속성은 원시 픽셀 데이터를 보기 위해 액세스할 수 있는 Uint8ClindedArray를 반환합니다. 각 픽셀은 네 개의 1바이트 값(적색, 녹색, 파란색, 알파, 순서대로 “RGBA” 형식)으로 표현됩니다. 각 색상 구성요소는 0 ~ 255 사이의 정수로 표시됩니다. 각 구성요소는 배열 내에서 연속적인 색 바이트 값이 할당되며, 최상단 좌측 픽셀의 빨간색 구성요소는 배열 내의 인덱스 0에 있습니다. 픽셀은 배열 전체에 걸쳐 왼쪽에서 오른쪽으로, 그 다음 아래로 진행합니다.
Uint8ClindedArray는 높이 × 너비 × 4바이트를 포함합니다. 배열의 인덱스 번호는 0부터 (높이 × 너비 × 4바이트) - 1까지 의 범위를 가지고 있습니다.
- 그레이스케일: 각 픽셀에서 RGB 3개를 평균낸 값을 다시 RGB에 배분하면 됩니다. 예를 들어 어떤 픽셀의 R은 200, G는 140, B는 180이라면 이 셋의 평균은 173.33이며 이 값을 다시 배분하면 R 173.33, G 173.33, B 173.33 이 됩니다.
- 색상 반전(Invert): 각 색상 픽셀의 원래 값을 255에서 빼면 색상이 반전됩니다.
- 컬러라이즈 : https://stackoverflow.com/questions/7521058/colorize-grayscale-image
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<canvas id="canvas" width="1024" height="768" style="float:left"></canvas>
<div id="wrapper" style="width:200px;float:left">
<div id=color></div>
<button id=grayBtn data-next-state="grayscale">그레이스케일</button>
<button id=invertBtn>색 반전</button>
<hr><input type=checkbox id=aaBtn checked><label for=aaBtn>부드럽게 하기</label>
<canvas id="zoom" width="300" height="227"></canvas>
</div>
<script>
// 컨텍스트 생성 및 받아오기
var img = new Image();
img.src = './Hydrangeas.jpg';
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
img.onload = draw;
var color = document.getElementById('color');
var originalDataArray = [] // 그레이스케일 기능에서 원래 이미지를 저장하기 위한 배열
// 이미지 로딩 완료시 실행될 부분
function draw() {
ctx.drawImage(img, 0, 0);
img.style.display = 'none';
// ctx.getImageData(sx, sy, sw, sh);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = imageData.data;
var invertColor = function() {
for (var i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i]
data[i + 1] = 255 - data[i + 1]
data[i + 2] = 255 - data[i + 2]
}
// ctx.putImageData(imageData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
ctx.putImageData(imageData, 0, 0, 0, 0, 512, 768)
}
var grayscale = function(e) {
var nextState = e.target.getAttribute("data-next-state")
console.log(nextState)
if (nextState == "grayscale") {
for (var i = 0; i < data.length; i += 4) {
var avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
// 되돌리기 위해 원래 이미지를 백업
originalDataArray[i] = data[i]
originalDataArray[i + 1] = data[i + 1]
originalDataArray[i + 2] = data[i + 2]
data[i] = avg; // red
data[i + 1] = avg; // green
data[i + 2] = avg; // blue
}
e.target.setAttribute("data-next-state", "normal")
} else {
for (var i = 0; i < data.length; i += 4) {
data[i] = originalDataArray[i]
data[i + 1] = originalDataArray[i + 1]
data[i + 2] = originalDataArray[i + 2]
}
e.target.setAttribute("data-next-state", "grayscale")
}
ctx.putImageData(imageData, 0, 0);
};
// 돋보기 기
var zoomctx = document.getElementById('zoom').getContext('2d');
var zoom = function(event) {
var x = event.layerX;
var y = event.layerY;
// ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
var SPX = 20
var DPX = 200
zoomctx.drawImage(canvas,
Math.min(Math.max(0, x - SPX / 2), img.width - SPX),
Math.min(Math.max(0, y - SPX / 2), img.height - SPX),
SPX, SPX,
0, 0,
DPX, DPX);
};
var smoothbtn = document.getElementById('aaBtn');
// 기본 옵션은 앤티앨리어싱 적용 상태이므로 해제하기 위한 부분
var toggleSmoothing = function(event) {
zoomctx.imageSmoothingEnabled = this.checked;
zoomctx.mozImageSmoothingEnabled = this.checked;
zoomctx.webkitImageSmoothingEnabled = this.checked;
zoomctx.msImageSmoothingEnabled = this.checked;
};
// 이벤트 적용
var invertbtn = document.getElementById('invertBtn');
invertbtn.addEventListener('click', invertColor);
var invertbtn = document.getElementById('grayBtn');
invertbtn.addEventListener('click', grayscale);
canvas.addEventListener('mousemove', zoom);
smoothbtn.addEventListener('change', toggleSmoothing);
}
// 픽셀별 컬러 추출
function pick(event) {
var x = event.layerX;
var y = event.layerY;
var pixel = ctx.getImageData(x, y, 1, 1);
var data = pixel.data;
var rgba = 'rgba(' + data[0] + ', ' + data[1] +
', ' + data[2] + ', ' + (data[3] / 255) + ')';
color.style.background = rgba;
color.textContent = rgba;
if (data[0] + data[1] + data[2] < 480) {
color.style.color = "white";
} else {
color.style.color = "black";
}
}
canvas.addEventListener('mousemove', pick);
</script>
</body>
</html>
This post is licensed under
CC BY 4.0
by the author.
