JavaScript предоставляет встроенную функциональность для редактирования изображения и установки значения конкретных пикселей на canvas. В частности, мы можем изменить цветовые значения пикселя, его прозрачность. Для этого предназначены такие методы, как getImageData(), putImageData() и createImageData().
Метод getImageData() позволяет извлечь из canvas какую-либо часть изображеня. Он имеет следующее определение:
getImageData(sx, sy, sw, sh);
Здесь sx и sy - координаты верхнего левого угла области, из которой извлекаются данные на canvas, а sw и sh - соотвественно ширина и высота этой области.
Данные из определенной этими параметрами области извлекаются в виде объекта ImageData, который потом используется для манипуляции пикселями.
Пример использования:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); const img = new Image(); img.src = "forest.png"; img.onload = function() { context.drawImage(img, 0, 0); const imageData = context.getImageData(0,0, 100, 100); };
Все данные об изображении в объекте ImageData хранятся в массиве data
. Каждый пиксель на canvas характеризуется четырьмя компонентами в
формате RGBA: красной, зеленой, синей компонентой, которые устанавливают цвет, и альфа-компонентой, которая устанавливает прозрачность. Каждая компонента принимает
значени от 0 до 255. И чтобы получить значения цвета для самого первого пикселя в ImageData, нам надо последовательно получить четыре значения из массива data:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); const img = new Image(); img.src = "dubi.png"; img.onload = function() { context.drawImage(img, 0, 0); const imageData = context.getImageData(0,0, 100, 100); const red = imageData.data[0]; // компонента красного цвета const green = imageData.data[1]; // компонента зеленого цвета const blue = imageData.data[2]; // компонента синего цвета const alpha = imageData.data[3]; // компонента прозрачности };
В данном случае мы получаем информацию о самом первом пикселе, который находится в самом верхнем левом углу, то есть имеет координаты x=0 и y=0.
Чтобы получить информацию о втором пикселе, который имеет координаты x=1 и y=0, нам надо получить следующие четыре значения из массива data:
imageData.data[4]; // компонента красного цвета imageData.data[5]; // компонента зеленого цвета imageData.data[6]; // компонента синего цвета imageData.data[7]; // компонента прозрачности
И так далее мы можем получить информацию обо всех пикселях.
Метод putImageData() устанавливает на canvas новые данные. Этот метод имеет следующие виды:
putImageData(imageData, dx, dy) putImageData(imageData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight)
Параметры dx и dy указывают координаты верхнего левого угла условного прямоугольника imageData, в который размещается на canvas.
Дополнительные параметры dirtyX и dirtyY указывают соотвественно на координаты X и Y левого угла прямоугольной области, которая будет извлекаться из полученного изображения. А параметры dirtyWidth и dirtyHeight задают соотвественно ширину и высоту этой области.
Используем методы getImageData()
и putImageData()
для преобразования изображения:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>METANIT.COM</title> </head> <body> <canvas id="canvas" width="700" height="300"></canvas> <script> const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); const img = new Image(); img.src = "forest3.png"; img.onload = function() { context.drawImage(img, 0, 0); const imageData = context.getImageData(0,0, img.width, img.height); let red, green, blue, grayscale; for (let i = 0; i < imageData.data.length; i += 4) { red = imageData.data[i]; // получаем компоненту красного цвета green = imageData.data[i + 1]; // получаем компоненту зеленого цвета blue = imageData.data[i + 2]; // получаем компоненту синего цвета grayscale = red * 0.3 + green * 0.59 + blue * 0.11; // получаем серый фон imageData.data[i] = grayscale; // установка серого цвета imageData.data[i + 1] = grayscale; imageData.data[i + 2] = grayscale; } context.putImageData(imageData, img.width + 10, 0); }; </script> </body> </html>
Ключевым участком кода здесь является цикл, в котором и происходит преобразование изображения в серое:
let red, green, blue, grayscale; for (let i = 0; i < imageData.data.length; i += 4) { red = imageData.data[i]; // получаем компоненту красного цвета green = imageData.data[i + 1]; // получаем компоненту зеленого цвета blue = imageData.data[i + 2]; // получаем компоненту синего цвета grayscale = red * 0.3 + green * 0.59 + blue * 0.11; // получаем серый фон imageData.data[i] = grayscale; // установка серого цвета imageData.data[i + 1] = grayscale; imageData.data[i + 2] = grayscale; }
Здесь мы перемещаемся по всему массиву imageData.data
, обрабатывая за раз четыре элемента, которые и представляют отдельный пиксель. При этом
учитываются только три элемента, поскольку компонента прозрачности в данном случае нас не интересует.
Сначала мы получаем компоненты RGB. Затем, применяя математическую формулу, преобразуем значения RGB в серый цвет. И в конце серый цвет устанавливается для элементов пикселя.
Если мы попробуем просто кинуть файл веб-страницы с выше описанным кодом в браузер Google Chrome или попытаемся открыть файл по двойному клику, то Google Chrome не отобразит нам преобразованное серое изображение в связи с политикой браузера. Хотя в других браузерах, как Firefox или Microsoft Edge все может быть нормально. Дело в том, что в Google Chrome не позволяет манипулировать изображением сайта из одного домена пользователю из другого домена. По сути, когда мы загружаем файл по протоколу file:// (просто кинув файл в браузер или по двойному клику), браузер рассматривает пользователя и открытую веб-страницу как разные домены.
Если веб-страница будет расположена на веб-сервере и загружена по протоколу http, как это обычно бывает, то, конечно, проблемы не возникнет, так как пользователь и сайт будут работать в рамках одного домена. Но для тестирования опять же либо придется использовать веб-сервер, либо изменить соответствующим образом настройки браузера Google Chrome.
Метод createImageData() создает новый объект ImageData, который затем может использоваться на canvas. Метод createImageData() имеет две формы:
createImageData(width, height); createImageData(imagedata);
Первая форма принимает параметры width и height, которые устанавливают соотвественно ширину и высоту создаваемого объекта ImageData.
Вторая форма принимает в качестве параметра другой объект ImageData, по которому будет создан новый объект ImageData.
Пример использования:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); const img = new Image(); img.src = "river2.png"; img.onload = function() { context.drawImage(img, 0, 0); const imageData = context.getImageData(0,0, img.width, img.height); const newImageData = context.createImageData(imageData); for (let i = 0; i < newImageData.data.length; i++) { newImageData.data[i] = imageData.data[i]; // если это альфа-компонента if( (i+1)%4===0){ newImageData.data[i] = 120; } } context.putImageData(newImageData, img.width + 10, 0); };
В данном случае создаем новый объект newImageData
, в этот объект копируем все данные из текущего imageData, который представляет
изображение на canvas. При этом при копировании значения альфа-компоненты, которая отвечает за прозрачность, устанавливаем ей значение 120, то есть делаем пиксель
полупрозрачным.