Пиксельная манипуляция с холстом
До сих пор мы не смотрели на фактические пиксели нашего объекта canvas (далее "холст"). С объектомImageData
вы можете напрямую читать и писать массив данных для управления пиксельными данными. Мы также рассмотрим, как можно сгладить сглаживание изображения (сглаживание) и как сохранить изображения с вашего холста.
ОбъектImageData
ОбъектImageData
представляет базовые пиксельные данные области объекта холста. Он содержит следующие атрибуты только для чтения:
width
Ширина изображения в пикселях.
height
Высота изображения в пикселях.
data
A
Uint8ClampedArray
представляет собой одномерный массив, содержащий данные в порядке RGBA, с целыми значениями от0
до255
(в комплекте).
Свойствоdata
возвращаетUint8ClampedArray
, к которому можно получить доступ, чтобы посмотреть на необработанные пиксельные данные; каждый пиксель представлен четырьмя однобайтовыми значениями (красный, зелёный, синий и альфа в этом порядке, то есть формат «RGBA»). Каждый компонент цвета представлен целым числом от 0 до 255. Каждому компоненту присваивается последовательный индекс внутри массива, причём красный компонент верхнего левого пикселя находится в индексе 0 внутри массива. Затем пиксели идут слева направо, затем вниз, по всему массиву.
Uint8ClampedArray
содержит высоту × ширину × 4 байта данных, значения индекса варьируются от 0 до (высота × ширина × 4) -1.
Например, чтобы прочитать значение синего компонента из пикселя в столбце 200, строка 50 на изображении, вы должны сделать следующее:
blueComponent = imageData.data[50 * (imageData.width * 4) + 200 * 4 + 2];
Вы можете получить доступ к размеру массива пикселей в байтах, прочитав атрибутUint8ClampedArray.length
:
var numBytes = imageData.data.length;
Создание объектаImageData
Чтобы создать новый пустой объектImageData
, вы должны использовать методcreateImageData ()
. Существуют две версии методаcreateImageData()
:
var myImageData = ctx.createImageData(width, height);
Это создаёт новый объектImageData
с указанными параметрами. Все пиксели заданы прозрачным черным.
Вы также можете создать новый объектImageData
ImageData с теми же размерами, что и объект, заданныйanotherImageData
. Все пиксели нового объекта установлены на прозрачный чёрный.Это не копирует данные изображения!
var myImageData = ctx.createImageData(anotherImageData);
Получение пиксельных данных для контекста
Чтобы получить объектImageData
, содержащий копию пиксельных данных для контекста холста, вы можете использовать методgetImageData()
:
var myImageData = ctx.getImageData(left, top, width, height);
Этот метод возвращает объектImageData
, представляющий пиксельные данные для области холста, углы которого представлены точками (left
,top
), (left+width
,top
), (left
,top+height
) и (left+width
,top+height
). Координаты задаются в единицах пространства координат холста.
Примечание:Любые пиксели за пределами холста возвращаются как прозрачный чёрный цвет в результирующий объектImageData
.
Этот метод также показан в статьеManipulating video using canvas.
Выбор цвета
В этом примере мы используем методgetImageData() для отображения цвета под курсором мыши. Для этого нам нужна текущая позиция мыши сlayerX
иlayerY
, затем мы просматриваем пиксельные данные в этой позиции в массиве пикселей, который предоставляет намgetImageData(). Наконец, мы используем данные массива для установки цвета фона и текста<div>
для отображения цвета.
<canvas width="300" height="227"></canvas><div></div>
var img = new Image();img.src = "rhino.jpg";var canvas = document.getElementById("canvas");var ctx = canvas.getContext("2d");img.onload = function () { ctx.drawImage(img, 0, 0); img.style.display = "none";};var color = document.getElementById("color");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;}canvas.addEventListener("mousemove", pick);
Отображение пиксельных данных в контекст
Вы можете использовать методputImageData() для рисования пиксельных данных в контексте:
ctx.putImageData(myImageData, dx, dy);
Параметрыdx
иdy
указывают координаты устройства в контексте, в котором будет отображаться верхний левый угол пиксельных данных, которые вы хотите нарисовать.
Например, чтобы нарисовать все изображение, представленноеmyImageData
, в верхнем левом углу контекста, вы можете просто сделать следующее:
ctx.putImageData(myImageData, 0, 0);
Оттенки серого цвета и инвертирование цветов
В этом примере мы перебираем все пиксели для изменения их значений, а затем помещаем модифицированный массив пикселей обратно в canvas с помощьюputImageData(). Функция инвертирования просто вычитает каждый цвет из максимального значения 255. Функция оттенков серого просто использует среднее значение красного, зелёного и синего. Вы также можете использовать средневзвешенное значение, заданное формулойx = 0.299r + 0.587g + 0.114b
, например. Для дополнительной информации смотритеОттенки серого в Википедии.
<canvas width="300" height="227"></canvas><div> <input value="Grayscale" type="button" /> <input value="Invert" type="button" /></div>
var img = new Image();img.src = "rhino.jpg";img.onload = function () { draw(this);};function draw(img) { var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0); img.style.display = "none"; var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); var data = imageData.data; var invert = function () { for (var i = 0; i < data.length; i += 4) { data[i] = 255 - data[i]; // red data[i + 1] = 255 - data[i + 1]; // green data[i + 2] = 255 - data[i + 2]; // blue } ctx.putImageData(imageData, 0, 0); }; var grayscale = function () { for (var i = 0; i < data.length; i += 4) { var avg = (data[i] + data[i + 1] + data[i + 2]) / 3; data[i] = avg; // red data[i + 1] = avg; // green data[i + 2] = avg; // blue } ctx.putImageData(imageData, 0, 0); }; var invertbtn = document.getElementById("invertbtn"); invertbtn.addEventListener("click", invert); var grayscalebtn = document.getElementById("grayscalebtn"); grayscalebtn.addEventListener("click", grayscale);}
Масштабирование и сглаживание
С помощью методаdrawImage ()
, второго холста и свойстваimageSmoothingEnabled
мы способны увеличить изображение и посмотреть его более детально.
Мы получаем положение мыши и обрезаем изображение на 5 пикселей левее и выше и на 5 пикселей правее и ниже положения мыши. Затем мы копируем его на другой холст и изменяем размер изображения до размера, который мы хотим. При масштабировании мы изменяем холст с исходного размера 10×10 пикселей до 200×200.
zoomctx.drawImage( canvas, Math.abs(x - 5), Math.abs(y - 5), 10, 10, 0, 0, 200, 200,);
Поскольку по умолчанию включено сглаживание, мы можем захотеть отключить сглаживание, чтобы увидеть чёткие пиксели. Вы можете переключить флажок, чтобы увидеть эффект свойстваimageSmoothingEnabled
(которому нужны префиксы для разных браузеров).
<canvas width="300" height="227"></canvas><canvas width="300" height="227"></canvas><div> <label for="smoothbtn"> <input type="checkbox" name="smoothbtn" checked="checked" /> Enable image smoothing </label></div>
var img = new Image();img.src = "rhino.jpg";img.onload = function () { draw(this);};function draw(img) { var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0); img.style.display = "none"; var zoomctx = document.getElementById("zoom").getContext("2d"); var smoothbtn = document.getElementById("smoothbtn"); var toggleSmoothing = function (event) { zoomctx.imageSmoothingEnabled = this.checked; zoomctx.mozImageSmoothingEnabled = this.checked; zoomctx.webkitImageSmoothingEnabled = this.checked; zoomctx.msImageSmoothingEnabled = this.checked; }; smoothbtn.addEventListener("change", toggleSmoothing); var zoom = function (event) { var x = event.layerX; var y = event.layerY; zoomctx.drawImage( canvas, Math.abs(x - 5), Math.abs(y - 5), 10, 10, 0, 0, 200, 200, ); }; canvas.addEventListener("mousemove", zoom);}
Сохранение изображений
HTMLCanvasElement
предоставляет методtoDataURL()
, который полезен при сохранении изображений. Он возвращаетdata URI, содержащий представление изображения в формате, заданном параметромtype
(по умолчанию используется вPNG ). Возвращаемое изображение имеет разрешение 96 точек на дюйм.
- Примечание:
Имейте в виду, что если холст содержит пиксели, полученные из другогоorigin без использования CORS, холст будетиспорчен, и его содержимое больше не будет считываться и сохраняться. СмотритеБезопасность и испорченные холсты
canvas.toDataURL('image/png')
Настройки по умолчанию. Создаёт изображение в формате PNG.
canvas.toDataURL('image/jpeg', quality)
Создаёт изображение в формате JPG. Дополнительно вы можете задать параметр "качество" (quality) в диапазоне от 0 до 1, причём единица задаёт лучшее качество и 0 - почти не распознаваемый, но небольшой по размеру файл.
После того как вы создали URI данные из своего холста, вы можете использовать его как источник любого<image>
или поместить его в гиперссылку сdownload attribute, чтобы сохранить его на диске, например.
Вы также можете создатьBlob
из холста.
canvas.toBlob(callback, type, encoderOptions)
Создаёт объект
Blob
, представляющий изображение, содержащееся в холсте.