Js изменить цвет пикселя
В предыдущем руководстве вы всесторонне изучили работу с трансформациями, тенями и градиентами. Сегодня я покажу вам, как работать с пикселями в Сanvas: от простого получения значений компонентов цвета до того редактирования изображений на «холсте», которое выполняем в редакторе изображений.
Это несомненно одна из наиболее мощных встроенных возможностей Canvas, и я вам гарантирую, что сразу после ее освоения у вас появится целый ряд потрясающих идей.
Объект ImageData
Объект ImageData представляет базовые пиксельные данные области объекта холста. Он содержит следующие атрибуты только для чтения:
width Ширина изображения в пикселях. height Высота изображения в пикселях. data A Uint8ClampedArray представляет собой одномерный массив, содержащий данные в порядке RGBA, с целыми значениями от 0 до 255 (в комплекте).
Свойство data возвращает Uint8ClampedArray , к которому можно получить доступ, чтобы посмотреть на необработанные пиксельные данные; каждый пиксель представлен четырьмя однобайтовыми значениями (красный, зелёный, синий и альфа в этом порядке, то есть формат «RGBA»). Каждый компонент цвета представлен целым числом от 0 до 255. Каждому компоненту присваивается последовательный индекс внутри массива, причём красный компонент верхнего левого пикселя находится в индексе 0 внутри массива. Затем пиксели идут слева направо, затем вниз, по всему массиву.
Uint8ClampedArray содержит высоту × ширину × 4 байта данных, значения индекса варьируются от 0 до (высота × ширина × 4) -1.
Например, чтобы прочитать значение синего компонента из пикселя в столбце 200, строка 50 на изображении, вы должны сделать следующее:
Вы можете получить доступ к размеру массива пикселей в байтах, прочитав атрибут Uint8ClampedArray.length :
Отображение пиксельных данных в контекст
Вы можете использовать метод putImageData() для рисования пиксельных данных в контексте:
Параметры dx и dy указывают координаты устройства в контексте, в котором будет отображаться верхний левый угол пиксельных данных, которые вы хотите нарисовать.
Например, чтобы нарисовать все изображение, представленное myImageData , в верхнем левом углу контекста, вы можете просто сделать следующее:
Creating an ImageData object
To create a new, blank ImageData object, you should use the createImageData() method. There are two versions of the createImageData() method:
This creates a new ImageData object with the specified dimensions. All pixels are preset to transparent black (all zeroes i.e rgba(0,0,0,0)).
You can also create a new ImageData object with the same dimensions as the object specified by anotherImageData . The new object's pixels are all preset to transparent black. This does not copy the image data!
Способ получения значений компонентов цвета пикселей странноватый
Как я уже упомянул в начале данного раздела, для понимания способа получения значений компонентов цвета пикселя «холста» необходимо некоторое время. Это так из-за способа, согласно которому пиксели сохраняются в Сanvas; они вовсе не хранятся как цельные пиксели. Вместо этого каждый пиксель разбивается на четыре отдельных компонента (красный, зеленый, синий и альфа (* в компьютерной графике - четвёртый компонент цвета, используемый для контроля смешивания цветов с фоном или нижележащим объектом. При этом его значение 1,0 означает полную непрозрачность, а 0,0 - полную прозрачность объекта)), и эти значения сохраняются в одномерном массиве со всеми значениями компонентов цвета для других пикселей. Поэтому вы не можете просто запросить данные из определенного пикселя, по крайней мере по умолчанию. Давайте поясню.
Для получения значений компонентов цвета пикселей вам необходимо вызвать метод getImageData 2-мерного контекста отображения следующим образом:
Этот метод принимает четыре аргумента, при помощи которых задается прямоугольная область «холста», значения пикселей которой вы хотите получить: координаты x и y начала отсчета, за которыми следуют значения ширины и высоты. Этот метод возвращает массив CanvasPixelArray , в котором содержатся все значения компонентов цвета пикселей заданной области. Первое, на что следует обратить внимание при работе с CanvasPixelArray , – это то, что для каждого пикселя задается четыре значения компонентов цвета, так что индексом первого компонента цвета каждого пикселя массива будет кратное 4 число (0 для первого значения первого пикселя, 4 для первого значения второго пикселя и т.д.):
Интересно (или раздражает, в зависимости от того, как вы смотрите на массив) то, что тут не используется концепция позиции координат (x, y), из-за чего получить значения компонентов цвета для определенного пикселя немного тяжелее, чем получить определенное значение двухмерного массива (например используя pixelArray[0][3] для получения значения пикселя в координате (1, 4)). Вместо этого вы должны использовать небольшую формулу, которая в действительности очень проста для понимания, если правильно объяснена:
Можете разобраться, что тут происходит? Давайте проанализируем формулу и представим, что мы хотим получить значения компонентов цвета для внутреннего пикселя в таблице пикселей 3x3 – пиксель в координате (2, 2).
Если вы посмотрите на предыдущие два изображения, то увидите, что значения компонентов цвета для этого пикселя начинаются с индекса 16, и для реализации этого в коде вам необходимо выполнить два шага: первый – вычислить индекс необходимого пикселя (координату y) в начале ряда, и затем добавить к этому индексу количество значений компонентов цвета между пикселем и началом ряда (координата х). Прозвучало немного запутанно, но проявите терпение.
Первая часть формулы проста: вы уже знаете, что на один пиксель приходится четыре значения цвета, а также что ширина таблицы составляет 3 пикселя. Для вычисления индекса пикселя в ряду у (2) вы подставляете эти значения в первую часть формулы, которая при этом будет выглядеть следующим образом:
В результате вы получаете значение индекса 12, которое соответствует индексу первого пикселя второго ряда в предыдущем изображении. Пока все должно быть понятно.
Следующий шаг – определение числа значений компонентов цвета, которые находятся перед необходимым вам пикселем. Для этого вы просто перемножаете число пикселей, находящихся перед необходимым вам пикселем, на четыре. Все просто. В нашем примере вторая часть формулы выглядела бы следующим образом:
Можете посчитать и получите 4, что в сумме с предыдущим значением дает значение индекса 16. Круто, да?
Я бы особо не переживал о полном ее понимании, просто знайте, что эта потрясающая небольшая формула существует и позволяет вам легко получить индекс значения красной компоненты цвета для любого пикселя. Для получения индекса значений остальных компонентов цвета пикселя (зеленый, синий или альфа) вы просто добавляете 1, 2 или 3 к вычисленному индексу соответственно.
Метод getImageData()
Метод getImageData() позволяет извлечь из canvas какую-либо часть изображеня. Он имеет следующее определение:
Здесь sx и sy - координаты верхнего левого угла области, из которой извлекаются данные на canvas, а sw и sh - соотвественно ширина и высота этой области.
Данные из определенной этими параметрами области извлекаются в виде объекта ImageData , который потом используется для манипуляции пикселями.
Все данные об изображении в объекте ImageData хранятся в массиве data . Каждый пиксель на canvas характеризуется четырьмя компонентами в формате RGBA: красной, зеленой, синей компонентой, которые устанавливают цвет, и альфа-компонентой, которая устанавливает прозрачность. Каждая компонента принимает значени от 0 до 255. И чтобы получить значения цвета для самого первого пикселя в ImageData, нам надо последовательно получить четыре значения из массива data:
В данном случае мы получаем информацию о самом первом пикселе, который находится в самом верхнем левом углу, то есть имеет координаты x=0 и y=0.
Чтобы получить информацию о втором пикселе, который имеет координаты x=1 и y=0, нам надо получить следующие четыре значения из массива data:
И так далее мы можем получить информацию обо всех пикселях.
Сохранение изображений
HTMLCanvasElement предоставляет метод toDataURL() , который полезен при сохранении изображений. Он возвращает data URI, содержащий представление изображения в формате, заданном параметром type (по умолчанию используется в PNG ). Возвращаемое изображение имеет разрешение 96 точек на дюйм.
Примечание: Имейте в виду, что если холст содержит пиксели, полученные из другого origin без использования CORS, холст будет испорчен, и его содержимое больше не будет считываться и сохраняться. Смотрите Безопасность и испорченные холсты в Allowing cross-origin use of images and canvas canvas.toDataURL('image/png') Настройки по умолчанию. Создаёт изображение в формате PNG. canvas.toDataURL('image/jpeg', quality) Создаёт изображение в формате JPG. Дополнительно вы можете задать параметр "качество" (quality) в диапазоне от 0 до 1, причём единица задаёт лучшее качество и 0 - почти не распознаваемый, но небольшой по размеру файл.
После того как вы создали URI данные из своего холста, вы можете использовать его как источник любого или поместить его в гиперссылку с download attribute, чтобы сохранить его на диске, например.
Вы также можете создать Blob из холста.
canvas.toBlob(callback, type, encoderOptions) Создаёт объект Blob , представляющий изображение, содержащееся в холсте.
Until now we haven't looked at the actual pixels of our canvas. With the ImageData object you can directly read and write a data array to manipulate pixel data. We will also look into how image smoothing (anti-aliasing) can be controlled and how to save images from your canvas.
Метод putImageData()
Метод putImageData() устанавливает на canvas новые данные. Этот метод имеет следеющее определение:
Параметры dx и dy указывают координаты верхнего левого угла условного прямоугольника imageData, в который размещается на canvas.
Используем методы getImageData() и putImageData() для преобразования изображения:
Ключевым участком кода здесь является цикл, в котором и происходит преобразование изображения в серое:
Здесь мы перемещаемся по всему массиву imageData.data , обрабатывая за раз четыре элемента, которые и представляют отдельный пиксель. При этом учитываются только три элемента, поскольку компонента прозрачности в данном случае нас не интересует.
Сначала мы получаем компоненты RGB. Затем, применяя математическую формулу, преобразуем значения RGB в серый цвет. И в конце серый цвет устанавливается для элементов пикселя.
Подготавливаем страницу
Вы будете использовать тот же самый шаблон HTML, что и в предыдущем руководстве, поэтому откройте свой любимый редактор и скопируйте следующий код:
Это всего лишь базовая HTML-страница с элементом canvas и некоторым кодом JavaScript, который выполняется после загрузки модели DOM (* Document Object Model – Объектная модель документа. Тут и далее примеч. пер.). Ничего фантастического тут нет.
A color picker
In this example we are using the getImageData() method to display the color under the mouse cursor. For this, we need the current position of the mouse with layerX and layerY , then we look up the pixel data on that position in the pixel array that getImageData() provides us. Finally, we use the array data to set a background color and a text in the to display the color. Clicking on the image will do the same operation but remember what the selected color was.
The code's usage is demonstrated in the following live example:
Also see the source code — HTML, JavaScript.
Zooming and anti-aliasing
With the help of the drawImage() method, a second canvas and the imageSmoothingEnabled property, we are able to zoom into our picture and see the details. A third canvas without imageSmoothingEnabled is also drawn onto to be able to have a side by side comparison
We get the position of the mouse and crop an image of 5 pixels left and above to 5 pixels right and below. Then we copy that one over to another canvas and resize the image to the size we want it to. In the zoom canvas we resize a 10×10 pixel crop of the original canvas to 200×200.
The code's usage is demonstrated in the following live example:
Also see the source code — HTML, JavaScript.
Saving images
The HTMLCanvasElement provides a toDataURL() method, which is useful when saving images. It returns a data URI containing a representation of the image in the format specified by the type parameter (defaults to PNG). The returned image is in a resolution of 96 dpi.
Note: Be aware that if the canvas contains any pixels that were obtained from another origin without using CORS, the canvas is tainted and its contents can no longer be read and saved. See Security and tainted canvases in Allowing cross-origin use of images and canvas
Default setting. Creates a PNG image.
Creates a JPG image. Optionally, you can provide a quality in the range from 0 to 1, with one being the best quality and with 0 almost not recognizable but small in file size.
Once you have generated a data URI from you canvas, you are able to use it as the source of any or put it into a hyper link with a download attribute to save it to disc, for example.
HTML5 предоставляет встроенную функциональность для редактирования изображения и установки значения конкретных пикселей на canvas. В частности, мы можем изменить цветовые значения пикселя, его прозрачность. Для этого предназначены такие методы, как getImageData() , putImageData() и createImageData() .
Вопросы безопасности
Если мы попробуем просто кинуть файл веб-страницы с выше описанным кодом в браузер Google Chrome или попытаемся открыть файл по двойному клику, то Google Chrome не отобразит нам преобразованное серое изображение в связи с политикой браузера. Хотя в других браузерах, как Firefox или Microsoft Edge все может быть нормально. Дело в том, что в Google Chrome не позволяет манипулировать изображением сайта из одного домена пользователю из другого домена. По сути, когда мы загружаем файл по протоколу file:// (просто кинув файл в браузер или по двойному клику), браузер рассматривает пользователя и открытую веб-страницу как разные домены.
Создание объекта ImageData
Чтобы создать новый пустой объект ImageData , вы должны использовать метод createImageData () (en-US). Существуют две версии метода createImageData() :
Это создаёт новый объект ImageData с указанными параметрами. Все пиксели заданы прозрачным черным.
Вы также можете создать новый объект ImageData ImageData с теми же размерами, что и объект, заданный anotherImageData . Все пиксели нового объекта установлены на прозрачный чёрный. Это не копирует данные изображения!
Добавляем к изображениям эффекты
Теперь, когда вы умеете получать значения цвета пикселей «холста», их изменение не должно составить особого труда. По сути, изменение этих значений цвета сводится к изменению значений в CanvasPixelArray и их дальнейшему прорисовыванию обратно на «холст». Давайте рассмотрим, как это осуществить.
Для начала подготовьте код, как в предыдущем разделе. В этом коде происходит загрузка изображения, его прорисовка на «холст» и получение данных его пикселей:
Пока все должно быть понятно. Далее необходимо перебрать каждый пиксель «холста» и изменить значения компонентов его цвета. В нашем примере вы переставите значения компонентов цветов путем вычитания текущего значения компонента цвета (от 0 до 255) из 255:
Тут не происходит ничего фантастического; вы просто перемножаете номер пикселя (i) на 4 для получения индекса значения красного компонента цвета для текущего пикселя в CanvasPixelArray . За счет добавления 1 или 2 к этому числу вы можете получить и изменить значения зеленого и синего компонентов цвета соответственно.
И, наконец, все, что вам теперь осталось, так это очистить «холст» (чтобы избавиться от изначального изображения) и затем воспользоваться методом putImageData 2-мерного контекста отображения для прорисовывания сохраненного CanvasPixelArray на «холст»:
И на этом, собственно, все; перезагрузите ваш браузер и взгляните. Круто, правда ведь?
Выбор цвета
В этом примере мы используем метод getImageData() для отображения цвета под курсором мыши. Для этого нам нужна текущая позиция мыши с layerX и layerY , затем мы просматриваем пиксельные данные в этой позиции в массиве пикселей, который предоставляет нам getImageData() . Наконец, мы используем данные массива для установки цвета фона и текста для отображения цвета.
Оттенки серого цвета и инвертирование цветов
В этом примере мы перебираем все пиксели для изменения их значений, а затем помещаем модифицированный массив пикселей обратно в canvas с помощью putImageData(). Функция инвертирования просто вычитает каждый цвет из максимального значения 255. Функция оттенков серого просто использует среднее значение красного, зелёного и синего. Вы также можете использовать средневзвешенное значение, заданное формулой x = 0.299r + 0.587g + 0.114b , например. Для дополнительной информации см. Grayscale в Википедии.
Получение пиксельных данных для контекста
Чтобы получить объект ImageData , содержащий копию пиксельных данных для контекста холста, вы можете использовать метод getImageData() :
Этот метод возвращает объект ImageData , представляющий пиксельные данные для области холста, углы которого представлены точками ( left , top ), ( left+width , top ), ( left , top+height ) и ( left+width , top+height ). Координаты задаются в единицах пространства координат холста.
Примечание: Любые пиксели за пределами холста возвращаются как прозрачный чёрный цвет в результирующий объект ImageData .
Этот метод также показан в статье Manipulating video using canvas.
Метод createImageData()
Метод createImageData() создает новый объект ImageData, который затем может использоваться на canvas. Метод createImageData() имеет две формы:
Первая форма принимает параметры width и height, которые устанавливают соотвественно ширину и высоту создаваемого объекта ImageData.
Вторая форма принимает в качестве параметра другой объект ImageData, по которому будет создан новый объект ImageData.
В данном случае создаем новый объект newImageData , в этот объект копируем все данные из текущего imageData, который представляет изображение на canvas. При этом при копировании значения альфа-компоненты, которая отвечает за прозрачность, устанавливаем ей значение 120, то есть делаем пиксель полупрозрачным.
Размещаем изображение на «холсте»
Вы можете манипулировать значениями пикселей чего-угодно, что прорисовано на «холсте», однако для достижения целей этого руководства мы будем использовать изображения. Это так отчасти из-за того, что мне важно показать вам, как загружать изображения в canvas, а также потому, что способность выполнять манипуляции с изображениями (например редактирование изображений) – это большой плюс рассматриваемой технологии.
Перед тем, как я покажу вам, как получать значения пикселей, давайте разместим изображение на «холсте». Вы запросто можете использовать любое изображение, однако для достижения целей этого руководства я буду использовать одно из моих собственных с Flickr.
При желании можете использовать это изображение, которое доступно для скачивания в различных размерах.
Загрузка изображения на «холст» выполняется в два этапа. Первый – загрузка изображения в элемент HTML image , что можно осуществить при помощи HTML или создания нового элемента DOM непосредственно в коде JavaScript. В нашем примере мы создадим новый элемент DOM – это чрезвычайно просто:
Здесь мы всего лишь создаем новый элемент DOM типа Image и задаем его в качестве значения переменной. Далее мы используем эту переменную для загрузки вашего изображения, задавая в качестве значения атрибута src изображения необходимый путь к файлу (* чтобы началась загрузка изображения, элемент не нужно добавлять к документу – оно начинает загружаться, как только задано значение свойства src). Стоит отметить, что при помощи этой техники мы бы могли загрузить изображение с удаленного компьютера, однако при этом позже у нас возникли бы некоторые проблемы, так что мы остановимся на использовании изображения с локального компьютера. Второй этап – прослушивание события load , которое будет сгенерировано, как только изображение загружено и готово к использованию.
Сразу после загрузки изображения мы можем разместить его на «холсте» одним махом. Для этого нам всего лишь необходимо передать переменную image , которую только что создали, в качестве аргумента метода drawImage 2-мерного контекста отображения. Разместите этот код в обработчике события загрузки для image следующим образом:
В данном случае метод drawImage принимает три аргумента: элемент с изображением и значения координат x и y для задания позиции изображения на «холсте». За счет этого кода изображение будет отображено в полном размере (ширина составляет 500px в нашем примере) и в указанной позиции:
Однако на самом деле drawImage может принимать еще два аргумента, за счет которых задаются значения ширины и высоты отображаемого изображения, следующим образом:
За счет этого кода изображение было бы отображено в половину своего изначального размера (ширина составляет 250px в нашем примере):
Вы можете пойти еще дальше и воспользоваться всеми девятью аргументами метода drawImage для прорисовывания только небольшой части изначального изображения вот так:
За счет этого кода будет выбран квадрат со значением стороны 200px вверху слева изображения и прорисован на «холсте» в квадрате со значением стороны 500px:
В псевдокоде (* язык, напоминающий императивный язык программирования и используемый в качестве нотации для описания алгоритмов и/или структуры программы) все девять аргументов drawImage можно описать следующим образом (s – для обозначения источника (source) и d – для обозначения места назначения (destination)):
Результат приведен на следующей иллюстрации:
Все просто, не так ли? По правде говоря, понимание любого аспекта работы Сanvas не вызывает трудностей, как только вы его проанализируете и рассмотрите каждый момент по отдельности.
Получаем значения компонентов цвета пикселей
Теперь, когда у вас имеется изображение на «холсте», пришло время получить значения компонентов цвета пикселей, благодаря чему вы сможете ими манипулировать.Однако давайте сейчас забудем о манипулировании и сосредоточимся исключительно на получении значений компонентов цвета пикселей, поскольку для понимания этой концепции необходимо некоторое время.
Painting pixel data into a context
You can use the putImageData() method to paint pixel data into a context:
The dx and dy parameters indicate the device coordinates within the context at which to paint the top left corner of the pixel data you wish to draw.
For example, to paint the entire image represented by myImageData to the top left corner of the context, you can do the following:
Вопросы безопасности
Разобравшись с этим, давайте продолжим и получим некоторые значения компонентов цвета пикселей!
Getting the pixel data for a context
To obtain an ImageData object containing a copy of the pixel data for a canvas context, you can use the getImageData() method:
This method returns an ImageData object representing the pixel data for the area of the canvas whose corners are represented by the points ( left , top ), ( left+width , top ), ( left , top+height ), and ( left+width , top+height ). The coordinates are specified in canvas coordinate space units.
Note: Any pixels outside the canvas are returned as transparent black in the resulting ImageData object.
This method is also demonstrated in the article Manipulating video using canvas.
Масштабирование и сглаживание
С помощью метода drawImage () , второго холста и свойства imageSmoothingEnabled (en-US) мы способны увеличить изображение и посмотреть его более детально.
Мы получаем положение мыши и обрезаем изображение на 5 пикселей левее и выше и на 5 пикселей правее и ниже положения мыши. Затем мы копируем его на другой холст и изменяем размер изображения до размера, который мы хотим. При масштабировании мы изменяем холст с исходного размера 10×10 пикселей до 200×200.
Поскольку по умолчанию включено сглаживание, мы можем захотеть отключить сглаживание, чтобы увидеть чёткие пиксели. Вы можете переключить флажок, чтобы увидеть эффект свойства imageSmoothingEnabled (которому нужны префиксы для разных браузеров).
Zoom example
Подведение итогов
Мы рассмотрели лишь некоторые аспекты работы с пикселями, однако я надеюсь, что в этом руководстве вы почерпнули достаточно информации для получения вдохновения. Я настоятельно рекомендую вам копнуть в этом вопросе поглубже и посмотреть, что еще вы можете делать с пикселями. Почему? Потому что все техники по работе с пикселями можно также применить к видео HTML5 и изображениям. Теперь вы поняли, какие возможности открываются перед вами за счет умения манипулировать пикселями.
В следующем руководстве, последнем в этой серии, мы будем рассматривать другие аспекты Canvas. Вы узнаете, как анимировать фигуры на «холсте», после чего у вас будет база, необходимая для создания мультипликаций, анимаций и игр. Это, бесспорно, мой любимый вариант использования Canvas.
Простейший путь обрабатывать данные с изображения – это брать каждый пиксель и изменять значение одного или нескольких из его каналов: красный, зеленый, синий и альфа (прозрачность), для краткости будем называть их R, G, B и A.
Пример: изменим какие-нибудь значения, например поменяем B и G:
Было rgb(100, 50, 30, 255) станет rgb(100, 30, 50, 255)
Манипуляцию как таковую можно представить простейшей callback-функцией. Для приведенного выше примера:
Здесь мы игнорируем альфа-канал, он нам не нужен и будет установлен равным 255.
Предположим, мы хотим изменить альфа-канал и сделать изображение частично прозрачным. Тогда функция будет выглядеть:
Здесь мы используем переменную factor, с помощью которой будем задавать прозрачность изображения. Значение этой переменной будет возвращаться как альфа-канал:
и более сложный пример. Здесь мы будем дополнительно задавать, к какой части изображения применить прозрачность:
Если сделаем factor=111, получим:
this ссылается на созданный нами объект, который можно было немного увидеть. Он хранит в себе кое-какую нужную информацию, которая может пригодиться, как рассмотренном примере.
Холст
Рассмотрим структуру нашего холста. Начнем с конструктора:
Используем это, чтоб передать ссылку на элемент холста, находящийся где-нибудь на странице, а также url изображения.
Изображение должно быть в том же домене, где идет обработка его данных:
Конструктор создает объект new Image, и после загрузки изображение отрисовывается на холсте. Затем сохраняем некоторые вещи на будущее такие как context, объект image и оригинальные данные об изображении. ‘this’ – тот же самый, к которому манипулятор пикселями имеет доступ в примере выше.
Далее используем 3 простых метода для установки, получения и сброса данных изображения с холста:
Мозг всей обработки – это метод transform(). Он обрабатывает callback-вызов манипулятора пикселями и factor, который в сущности является конфигурационной настройкой для манипулятора. Затем он проходит по всем пикселям, передает значение olddata rgba-канала в callback-функцию и использует вернувшиеся значения как newdata. В конце newdata записывается на холст.
Довольно просто, не так ли? Единственный смущающий момент должен быть инкремент i+=4 в цикле. Данные возвращаются через getImageData().data как массив с 4 элементами для каждого пикселя.
Предположим, у изображения есть всего 2 пикселя: красный и синий, и нет прозрачности. Тогда данные для этого изображения выглядят как:
Callback
Дальнейший код просто показывает различные варианты callback-функции, и создает UI для их использования. Рассмотрим несколько из них:
Градации серого
Градации серого – это равное количество красного, синего, зеленого. Самый простой способ добиться этого – посчитать среднее значение:
var agv = (r + g + b) / 3;
Этого вполне достаточно. Но есть секретная формула для обработки фотографий с людьми, она устанавливает разную чувствительность для каналов:
Сепия
Простейший вариант: сделать серую версию и добавить немного цвета на неё – равного количества rgb для каждого пикселя. Я добавил 100 красного, 50 зеленого, но вы можете выбрать другие значения.
Вот другой вариант, который возможно и лучше, но мне не очень нравится:
Негатив
Вычтем значение каждого канала из 255 для получения негатива
Добавить шум. Это просто развлечение, берем случайное значение между –factor и factor и добавляем его к каждому каналу:
Ваш ход
Сам пример опубликован по ссылке. Некоторые из манипуляций предлагает рассмотреть самостоятельно, используя исходный код и воображение.
В качестве шаблона берем следующее:
Попробуйте, например, сделать изображение черно-белым (не градациями серого, а черно-белым, где каждый пиксель либо 0,0,0, либо 255,255,255).
До сих пор мы не смотрели на фактические пиксели нашего объекта canvas (далее "холст"). С объектом ImageData вы можете напрямую читать и писать массив данных для управления пиксельными данными. Мы также рассмотрим, как можно сгладить сглаживание изображения (сглаживание) и как сохранить изображения с вашего холста.
Grayscaling and inverting colors
In this example we iterate over all pixels to change their values, then we put the modified pixel array back to the canvas using putImageData(). The invert function subtracts each color from the max value 255. The grayscale function uses the average of red, green and blue. You can also use a weighted average, given by the formula x = 0.299r + 0.587g + 0.114b , for example. See Grayscale on Wikipedia for more information.
The code's usage is demonstrated in the following live example:
Also see the source code — HTML, JavaScript.
The ImageData object
The ImageData object represents the underlying pixel data of an area of a canvas object. It contains the following read-only attributes:
The width of the image in pixels.
The height of the image in pixels.
A Uint8ClampedArray representing a one-dimensional array containing the data in the RGBA order, with integer values between 0 and 255 (included).
The data property returns a Uint8ClampedArray which can be accessed to look at the raw pixel data; each pixel is represented by four one-byte values (red, green, blue, and alpha, in that order; that is, "RGBA" format). Each color component is represented by an integer between 0 and 255. Each component is assigned a consecutive index within the array, with the top left pixel's red component being at index 0 within the array. Pixels then proceed from left to right, then downward, throughout the array.
The Uint8ClampedArray contains height × width × 4 bytes of data, with index values ranging from 0 to ( height × width ×4)-1.
For example, to read the blue component's value from the pixel at column 200, row 50 in the image, you would do the following:
If given a set of coordinates (X and Y), you may end up doing something like this:
Or, if ES2015 is appropriate:
You may also access the size of the pixel array in bytes by reading the Uint8ClampedArray.length attribute:
Начинаем применять полученные знания
Теперь, когда вы знаете, как получить значения компонентов цвета любого необходимого вам пикселя, давайте применим эти знания и получим эти значения из изображения для изменения цвета фона веб-сайта. Подобная как бы техника хорошо бы подошла для реализации цветоподборщика (* диалоговое окно для выбора нового текущего цвета спрайтов, рисунков и закрашиваемых областей, а также для определения пользовательской цветовой палитры) веб-приложения для редактирования изображений.
Код для нашего примера довольно ясный, так что давайте напишем его весь сразу:
Вы узнаете первые несколько строк из предыдущих примеров. Новый код располагается в обработчике события click для canvas , который реализуется при помощи небольшого количества кода jQuery, чтобы сообщить вам, когда произошло нажатие по «холсту».
Внутри обработчика мы хотим определить пиксель, по которому было выполнено нажатие на «холсте». Для этого нам необходимо для начала вычислить смещение в пикселях верхней левой координаты «холста» относительно верхнего левого угла окна браузера; для этого можно воспользоваться методом offset jQuery. Далее мы можем определить пиксель, по которому было выполнено нажатие на «холсте», путем вычитания значения смещения из значений координат, содержащихся в объекте для события click ( pageX и pageY ). Вам несомненно стоит потратить немного времени на освоение информации о событии click JavaScript для углубления своих познаний о нем.
В следующих четырех строках происходит получение CanvasPixelArray для «холста» ( getImageData ), его сохранение в переменной, нахождение индекса значения красной компоненты цвета пикселя, по которому было выполнено нажатие, путем его вычисления при помощи ранее виденной вами формулы, и затем сохранение значений компонентов цвета пикселя в виде строки rgba CSS. Наконец, последний этап – установление в качестве значений компонентов цвета фона элемента body значений компонентов цвета пикселя, по которому было выполнено нажатие.
И после этого все готово. Протестируйте результат самостоятельно; нажмите по изображению на «холсте» и пронаблюдайте, как изменяется цвет фона веб-сайта. Если не работает, то убедитесь, что вы запустили демоверсию на сервере с доменным именем, как описано в разделе, посвященном вопросам безопасности.
Мы многое рассмотрели, и теперь вы умеете быстро и легко получать значения компонентов цвета любого пикселя на «холсте». Упоминал ли я, что вы также можете изменять значения компонентов цвета пикселей на «холсте». Нет? Ой! Тогда давайте теперь рассмотрим этот прием; с его помощью создаются очень крутые эффекты.
Читайте также: