CSS властивості
ГлавнаяCanvasПіксельні буфери та інші ефекти в Canvas

Піксельні буфери та інші ефекти в Canvas

185

Все, що ми робили досі, використовувало зображення чи фігури. Це досить високий рівень. Тим не менш, полотно також дає вам прямий доступ до пікселів, якщо це потрібно. Ви можете отримати пікселі з усього полотна або його частин, маніпулювати цими пікселями, а потім повернути їх назад. Це дозволяє робити всілякі цікаві ефекти.

Генерація текстур

Припустимо, що ми хотіли б створити шахівну текстуру розміром 300х200 пікселів.

<code data-language="javascript">//створюємо новий буфер 300x200 пікселів var data=c.createImageData(300,200); //обходимо в циклі кожен піксель for(var x=0; x<data.width; x++) { for(var y=0; y<data.height; y++) { var val=0; var horz=(Math.floor(x/4) % 2==0); //цикл кожні 4 пікселі var vert=(Math.floor(y/4) % 2==0); //цикл кожні 4 пікселі if( (horz && !vert) || (!horz && vert)) { val=255; } 
else { val=0; } 
var index=(y*data.width+x)*4; //обчислюємо індекс data.data[index]=val; //червоний data.data[index+1]=val; //зелений data.data[index+2]=val; //синій data.data[index+3]=255; //явно ставимо альфу як 255 } 
} 
//встановлюємо дані назад c.putImageData(data,0,0);

Досить просто. Ми створюємо новий буфер, проходимо в циклі пікселів, щоб задати колір залежно від координат х і у, потім встановлюємо буфер на полотно. Зауважте тепер, що хоч ми працюємо з двомірною графікою, буфер є простим одновимірним масивом. Ми повинні обчислювати координати пікселів на основі їх індексу.

Дані полотна — це просто дуже довгий одновимірний масив з цілим значенням для кожного компонента пікселя. Пікселі червоної, зеленої, синьої та альфа компоненти йдуть по порядку, так що для розрахунку індексу червоної компоненти конкретного пікселя ви повинні рахувати за такою формулою: (y * width + x) * 4. Для пікселя 8,10 у растровом зображенні шириною 20 пікселів буде (10 * 20 + 8) * 4. Розмноження на 4 потрібно тому, що кожен піксель містить чотири колірні компоненти (RGB і прозорість або компонент «альфа»). Об'єкт даних містить ширину зображення, так що ви можете записати у вигляді (10 * data.width + 8) * 4. Після того, як ви знайшли червону компоненту, ви можете знайти інші, збільшуючи індекс, як показано у наведеному вище коді для зелених , синіх та альфа компонент.

Ось результат коду вище.

Генерація текстур

Додавання шуму

Тепер модифікуємо, щоб це виглядало трохи грубіше. Додамо трохи випадкового шуму, який робиться з пікселів дещо іншого кольору.

Ось. Трохи забруднено.

Додавання шуму

Інверсія фото

Ось так утворюються нові зображення через буфери пікселів. Ми також можемо маніпулювати наявними даними Canvas. Це означає, що на полотні може бути майже будь-який вид фільтра Фотошопу. Припустимо наприклад, що ви хочете інвертувати зображення, це просте рівняння. Кожен піксель складається з набору значень RGBA, кожен від 0 до 255. Для інверсії ми просто заберемо з 255 значення кожного компонента. Ось як це виглядає:

Вихідна фотографія

<code data-language="javascript">var img=new Image(); img.onload=function() { //малюємо зображення на полотні c.drawImage(img,0,0); //отримуємо дані полотна var data=c.getImageData(0,0,canvas.width,canvas.height); //інвертуємо кожен піксель for(n=0; n<data.width*data.height; n++) { var index=n*4; data.data[index]=255-data.data[index]; data.data[index+1]=255-data.data[index+1]; data.data[index+2]=255-data.data[index+2]; //Не чіпайте альфу } 
//Повертаємо дані назад c.putImageData(data,0,0); } 
img.src="baby_original.png";

Зверніть увагу, що ми змінюємо лише компоненти RGB. Альфу ми даємо спокій, оскільки хочемо тільки змінити колір. Ось як це виглядає.

Інвертована фотографія

Чорно-біла фотографія

Ось ще один приклад. По суті, це той самий код, просто інше рівняння. Воно перетворить кольорове зображення на чорно-біле.

<code data-language="javascript">for(n=0; n<data.width*data.height; n++) { var index=n* 4; var r=data.data [index]; var g=data.data[index+1]; var b=data.data[index+2]; var v=r * 0.21 + g * 0.71 + b * 0.07; //Середньозважена data.data[index]=v; data.data[index+1]=v; data.data[index+2]=v; //не чіпайте альфу }

Зверніть увагу, що ми не вибираємо значення сірого простим усереднення кольору. Виявляється, наші очі більш чутливі до певних кольорів, ніж до інших, тому рівняння враховує це додаючи більше зеленої компоненти. Ось кінцевий результат.

Чорно-біла фотографія

З буфером пікселів ви можете краще малювати або маніпулювати графікою, як вам подобається, єдиним обмеженням виступає швидкість. На жаль, маніпуляція з двійковими даними не є сильною стороною JavaScript, але браузери стають все швидше і швидше, тому деякі маніпуляції із зображеннями в стилі Фотошоп можливі вже сьогодні. Пізніше в розділі про інструменти я покажу вам деякі бібліотеки, які роблять такі речі простіше і швидше. Фотошопі. Кожного разу, коли ви малюєте фігуру, кожен піксель порівнюється з наявним пікселем, потім обчислюється кінцевий піксель, заснований на деякому рівнянні. Зазвичай ми використовуємо SrcOver, тобто вихідний піксель (той, який ви малюєте) малюватиметься поверх кінцевого пікселя. Якщо ваш вихідний піксель частково прозорий, то два пікселі змішуються пропорційно до прозорості. SrcOver є лише одним з багатьох режимів накладання, однак. Ось приклад використання режиму lighter при малюванні кіл, що перетинаються. lighter складає два пікселі разом із максимальним значенням білого кольору.

<code data-language="javascript">c.globalCompositeOperation="lighter"; //встановлюємо режим накладання c.fillStyle="#ff6699"; //заливаємо рожевим //малюємо 50 випадкових кіл for(var i=0; i<50; i++) { c.beginPath(); c.arc( Math.random()*400, //випадковий x Math.random()*400, //випадковий y 40, //радіус 0, Math.PI*2); //повне коло c.closePath(); c.fill(); }

Режим накладання

Ефект тіні

Canvas також підтримує тіні, схожі на CSS. Ви можете встановити колір, зсув та радіус розмиття тіні для імітації різних ефектів. У цьому прикладі створюється біле світіння позаду деякого зеленого тексту.

<code data-language="javascript">c.fillStyle="black"; c.fillRect(0,0,canvas.width,canvas.height); c.shadowColor="white"; c.shadowOffsetX=0; c.shadowOffsetY=0; c.shadowBlur=30; c.font='bold 80pt Arial'; c.fillStyle="#55cc55"; c.fillText("ALIEN",30,200);

d Ефект тіні