Advertisement
  1. Code
  2. Web Development

Вивчення Canvas з нуля: робота з пікселями

by
Read Time:12 minsLanguages:
This post is part of a series called Canvas From Scratch.
Canvas From Scratch: Transformations and Gradients

Ukrainian (українська мова) translation by Nadia Gonzales (you can also view the original English article)

У попередньому посібнику ви всесторонньо вивчили роботу з трансформаціями, тінями та градієнтами. Сьогодні я розкажу вам, як працювати з пікселями у Сanvas: від простого отримання значень компонентів кольору до того редагування зображень на «полотні», що виконуємо у редакторі зображень.

Це безумовно одна з найпотужніших вбудованих можливостей Canvas, і я вам гарантую, що одразу після її опанування у вас з'явиться безліч надзвичайних ідей.


Підготовлюємо сторінку

Ви будете використовувати той самий шаблон HTML, що й у попередньому посібнику, тому відкрийте свій улюблений редактор та скопіюйте наступний код: 

Це всього-на-всього базова HTML-сторінка з елементом canvas та деяким кодом JavaScript, що виконується одразу після завантаження моделі DOM (* Document Object Model – об'єктна модель документа. Тут і надалі примітка перекладача). Нічого фантастичного тут нема.


Розміщуємо зображення на «полотні»

Ви можете маніпулювати значеннями пікселів будь-чого, що прорисовано на «полотні», проте для досягнення цілей цього посібника ми будемо використовувати зображення. Це так почасти через те, що мені важливо показати вам, як завантажувати зображення до canvas, а також тому, що здатність виконувати маніпуляції з зображеннями (наприклад редагування зображень) – це великий плюс розглядуваної технології. 

Перед тим, як я покажу вам, як отримувати значення пікселів, давайте розташуємо зображення на «полотні». Ви запросто можете використовувати будь-яке зображення, проте для досягнення цілей цього посібника я буду використовувати одне з моїх власних з Flickr.

One of my photos from FlickrOne of my photos from FlickrOne of my photos from Flickr

За бажанням можете використовувати це зображення, яке доступне для завантаження у різних розмірах.

Завантаження зображення на «полотно» виконується у два етапи. Перший – завантаження зображення до елементу HTML image, що можна виконати за допомогою HTML або створення нового елементу DOM безпосередньо в коді JavaScript. У нашому прикладі ми створимо новий елемент DOM – це надзвичайно просто:

Тут ми всього-на-всього створюємо новий елемент DOM типу Image та задаємо його в якості значення змінної. Далі ми використовуємо цю змінну для завантаження вашого зображення, задаючи в якості значення атрибута src зображення необхідний путь до файлу (* щоб почалося завантаження зображення, елемент не потрібно додавати до документу – воно починає завантажуватися, як тільки задано значення властивості src). Варто зазначити, що за допомогою цієї техніки ми би могли завантажити зображення з віддаленого комп'ютера, проте при цьому пізніше у нас виникли би деякі проблеми, так що ми зупинимося на використанні зображення з локального комп'ютера.  Другий етап – прослуховування події load, яку буде згенеровано, як тільки зображення завантажено та готове для використання.

Одразу після завантаження зображення ми можемо розташувати його на «полотні» одним махом. Для цього нам потрібно лише передати змінну image, яку тільки-но створили, в якості аргументу методу drawImage 2-мірного контексту відображення. Розташуйте цей код в обробнику події завантаження для image наступним чином:

У цьому випадку метод drawImage приймає три аргументи: елемент із зображенням та значення координат x і y для визначення позиції зображення на «полотні». Завдяки цьому коду зображення буде відображено у повному розмірі (ширина складає 500px у нашому прикладі) та у зазначеній позиції.

Placing an imagePlacing an imagePlacing an image

Проте у дійсності drawImage може приймати ще два аргументи, завдяки яким задаються значення ширини та висоти відображуваного зображення, наступним чином:

Завдяки цьому коду зображення було би відображено у половину свого початкового розміру (ширина складає 250px у нашому прикладі):

Placing and resizing an imagePlacing and resizing an imagePlacing and resizing an image

Ви можете піти ще далі та скористатися всіма дев'ятьма аргументами методу drawImage для прорисовування тільки невеликої частини початкового зображення ось так:

Завдяки цьому коду буде вибрано квадрат зі значенням сторони 200px угорі зліва зображення та прорисовано на «полотні» у квадраті за значенням сторони 500px:

Placing only part of an imagePlacing only part of an imagePlacing only part of an image

У псевдокоді (* мова, що нагадує мову програмування і яку використовують для опису структури програми) всі дев'ять аргументів drawImage можна описати наступним чином (s – для позначання джерела (source) та d – для позначання місця призначення (destination)):

Результат наведено на наступній ілюстрації:

Taking drawImage to the extremeTaking drawImage to the extremeTaking drawImage to the extreme

Все просто, чи не так? Правду кажучи, розуміння будь-якого аспекту роботи Сanvas не викликає труднощів, тільки-но ви його проаналізуєте та розглянете кожний момент окремо.


Отримуємо значення компонентів кольору пікселів 

Тепер, коли в нас є зображення на «полотні», настав час отримати значення компонентів кольору пікселів, завдяки чому ви зможете ними маніпулювати.Проте давайте зараз забудемо про маніпулювання та зосередимося виключно на отриманні значень компонентів кольору пікселів, оскільки для розуміння цієї концепції потрібен деякий час.

Питання безпеки

Якщо ви хочете отримати значення компонентів кольору пікселів за допомогою canvas, то повинні бути в курсі про наявні обмеження, пов'язані з безпекою. Згідно з ними ви можете отримати дані тільки зображень, завантажених з того ж домену, що й JavaScript. Через це ви не можете отримувати зображення з віддаленого комп'ютера з подальшим аналізом значень компонентів кольору його пікселів, хоча є щось на зразок обхідного шляху цього обмеження. На жаль, не в усіх браузерах код JavaScript та зображення, які завантажуються локально з файлової системи (тобто без використання доменного імені), розглядаються в якості файлів, отримуваних з того ж самого домену, так що у вас можуть виникнути помилки, пов'язані з порушенням безпеки. Щоб уникнути цього вам потрібно або запускати решту коду посібника за допомогою серверного програмного забезпечення на вашому локальному комп'ютері (на зразок MAMP, WAMP або XAMPP) або віддаленого веб-сервера та отримувати файли за допомогою доменного імені (наприклад example.com).

Розібравшись з цим, давайте продовжимо та отримаємо деякі значення компонентів кольору пікселів!

Спосіб отримання значень компонентів кольору пікселів дивнуватий

Як я вже згадав на початку цього розділу, для розуміння способу отримання значень компонентів кольору пікселя «полотна» потрібен деякий час. Це так через спосіб, згідно з яким пікселі зберігаються в Сanvas; вони зовсім не зберігаються як цільні пікселі. Замість цього кожний піксель розбивається на чотири окремі компоненти (червоний, зелений, синій та альфа (* у комп'ютерній графіці - четвертий компонент кольору, використовуваний для контролю змішування кольорів з фоном або підлеглим об'єктом. У цьому разі його значення, що дорівнює 1,0, означає цілковиту непрозорість, а 0,0 - цілковиту прозорість об'єкта)), і ці значення зберігаються в одномірному масиві з усіма значеннями компонентів кольору для інших пікселів. Тому ви не можете просто запитати дані з певного пікселя, принаймні за налаштуванням. Давайте поясню.

Для отримання значень компонентів кольору пікселів вам потрібно викликати метод getImageData 2-мірного контексту відображення наступним чином:

Цей метод приймає чотири аргументи, за допомогою яких задається прямокутна область «полотна», значення пікселів якої ви хочете отримати: координати x та y початку відліку, за якими йдуть значення ширини та висоти. Цей метод повертає масив CanvasPixelArray, в якому містяться всі значення компонентів кольору пікселів заданої області. Перше, на що варто звернути увагу при роботі з CanvasPixelArray, – це те, що для кожного пікселя задається чотири значення компонентів кольору, так що індексом першого компоненту кольору кожного пікселя масиву буде кратне 4 число (0 для першого значення першого пікселя, 4 для першого значення другого пікселя і т.д.):

Index values in the CanvasPixelArrayIndex values in the CanvasPixelArrayIndex values in the CanvasPixelArray

Цікаво (або роздратовує, в залежності від того, як ви дивитесь на масив) те, що тут не використовується концепція позиції координат (x, y), через що отримати значення компонентів кольору для певного пікселя трохи важче, ніж отримати певне значення двовимірного масиву (наприклад використовуючи pixelArray[0][3] для отримання значення пікселя в координаті (1, 4)). Замість цього повинні використовувати невелику формулу, яку в дійсності дуже проста для розуміння, якщо її правильно пояснено:

Accessing a specific pixel from the CanvasPixelArrayAccessing a specific pixel from the CanvasPixelArrayAccessing a specific pixel from the CanvasPixelArray

Можете розібратися, що тут відбувається? Давайте проаналізуємо формулу та уявимо, що ми хочемо отримати значення компонентів кольору для внутрішнього пікселя в таблиці пікселів 3x3 – піксель в координаті (2, 2).

Якщо ви подивитеся на попередні два зображення, то побачите, що значення компонентів кольору для цього пікселя починаються з індексу 16, і для реалізації цього у коді вам потрібно виконати два кроки: перший – вирахувати індекс потрібного пікселя (координату у) на початку ряду, і потім додати до цього індексу кількість значень компонентів кольору між пікселем та початком ряду (координата х). Прозвучало трохи заплутано, але проявіть терпіння.

Перша частина формули проста: ви вже знаєте, що на один піксель припадає чотири значення кольору, а також що ширина таблиці складає 3 пікселі. Для вирахування індексу у ряду у (2) ви підставляєте ці значення у першу частину формули, яка при цьому буде виглядати наступним чином:

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

Наступний крок – визначення кількості значень компонентів кольору, які знаходяться перед потрібним вам пікселем. Для цього ви просто перемножуєте кількість пікселів, що знаходяться перед потрібним вам пікселем, на чотири. Все просто. У нашому прикладі друга частина формули виглядала би наступним чином:

Можете порахувати та отримаєте, що в сумі з попереднім значенням дає значення індексу 16. Круто, чи не так?

Я би особливо не турбувався про повне її розуміння, просто знайте, що ця надзвичайна невелика формула існує та дозволяє вам легко отримати індекс значення червоної компоненти кольору для будь-якого пікселя. Для отримання індексу значення решти компонентів кольору пікселя (червоний, синій або альфа) ви просто додаєте 1, 2 або 3 до обчисленого індексу відповідно.

Починаємо застосовувати отримання знання

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

Код для нашого прикладу доволі ясний, так що давайте напишемо його весь одразу:

Ви впізнаєте декілька перших рядків із попередніх прикладів. Новий код розташовується в обробнику події click для canvas, що реалізується за допомогою невеликої кількості коду jQuery, щоб повідомити вам, коли відбулося натискання по «полотну».

Всередині обробника ми хочемо визначити піксель, по якому було здійснено натискання на «полотні». Для цього нам потрібно для початку вирахувати зміщення в пікселях верхньої лівої координати «полотна» відносно верхнього лівого кута вікна браузера; для цього можна скористатися методом offset jQuery. Далі ми можемо визначити піксель, по якому було виконано натискання на «полотні», шляхом віднімання значення зміщення з початкових координат, що містяться в об'єкті для події click (pageX та pageY). Вам безумовно варто витратити трохи часу на вивчення інформації про подію click JavaScript для поглиблення своїх пізнань про нього.

У наступних чотирьох рядках відбувається отримання CanvasPixelArray для «полотна» (getImageData), його зберігання до змінної, знаходження індексу значення червоної компоненти кольору пікселя, по якому було виконано натискання, шляхом його віднімання за допомогою формули, яку ви вже бачили раніше, і потім зберігання значень компонентів кольору пікселя у вигляді рядка rgba CSS.  Нарешті, останній етап – встановлення в якості значень компонентів кольору фону елемента body значень компонентів кольору пікселя, по якому було виконано натискання.

Creating a basic color pickerCreating a basic color pickerCreating a basic color picker

І після цього все готово. Протестуйте результат самостійно; натисніть по зображенню на «полотні» та поспостерігайте, як змінюється колір фону веб-веб-сайту. Якщо не працює, то впевніться, що ви запустили демоверсію на сервері з доменним іменем, як описано в розділі, присвяченому питанням безпеки.

Ми багато розглянули, і тепер ви вмієте швидко та легко отримувати значення компонентів кольору будь-якого пікселя на «полотні». Чи згадував я, що ви також можете змінювати значення компонентів кольору пікселів на «полотні». Ні? Ой! Тоді давайте тепер розглянемо цей прийом; за допомогою нього створюються дуже круті ефекти.


Додаємо до зображень ефекти 

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

Для початку підготуйте код, як у попередньому розділі. У цьому коді відбувається завантаження зображення, його прорисовування на «полотно» та отримання даних його пікселів:

Поки що все повинно бути зрозумілим. Далі потрібно перебрати кожний піксель «полотна» та змінити значення компонентів його кольору. У нашому прикладі ви переставите значення компонентів кольорів шляхом віднімання поточного значення компонента кольору (від 0 до 255) від 255:

Тут не відбувається нічого фантастичного; ви просто перемножуєте номер пікселя (i) на 4 для отримання індексу значення червоного компонента кольору для поточного пікселя у CanvasPixelArray.  Завдяки додаванню 1 або 2 до цього числа ви можете отримати та змінити значення зеленого та синього компонентів кольору відповідно.

І, нарешті, все, що вам тепер залишилося, так це очистити «полотно» (щоб позбавитися початкового зображення) і потім скористатися методом putImageData 2-мірного контексту відображення для прорисовування збереженого CanvasPixelArray на «полотно».

На цьому, власне, все; перезавантажте ваш браузер та погляньте. Круто, чи не так?

Inverting the pixels of an imageInverting the pixels of an imageInverting the pixels of an image

Підведення підсумків

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

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

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.