Оптимизация изображений с HTML5 Canvas

Изображения всегда был самый тяжелый компонент веб-сайтов.Даже если высокоскоростного доступа в Интернет становится дешевле и более доступны, веб-сайты получит тяжелые быстрее.Если вы действительно заботитесь о своих посетителях, то потратить некоторое время на выбор между хорошим качеством изображения, которые больше по размеру и худшего качества изображения, которые скачивают быстрее.И имейте в виду, что современные браузеры имеют достаточно сил, чтобы улучшать изображения прямо на computer.В этой статье я покажу одну из возможных solution.

Обратимся к изображению, которое я наткнулся недавно в моей работе.Как вы можете видеть, этот образ стадии шторы и имеет некоторые (преднамеренное) света шум:

Оптимизация изображения, как это было бы реальной боли, потому что он содержит много красного (которая вызывает больше артефакты в JPEG) и шума (который создает ужасную артефакты JPEG и это плохо для упаковки PNG).Лучше оптимизации я мог бы получить для этого изображения было 330 KB JPEG, который является довольно много для одного изображения.Итак, я решил сделать некоторые эксперименты с улучшения изображения прямо в профиль browser.

Если вы внимательно посмотрите на эту картинку, вы увидите, что он состоит из двух слоев: шум и стадии шторы.Если убрать шум, то изображение сжимается до 70 KB в JPEG, который действительно хорош.Таким образом, нашей целью становится проходят бесшумные изображения для пользователя, а затем добавить шум на изображение прямо в веб-browser.Это позволит значительно сократить время загрузки и делать веб-страницы выполнить better.

В Photoshop, создавая монохроматический шум очень легко: просто зайдите на FilterNoiseAdd Noise.Но в исходном изображении, шум на самом деле темнеет некоторых пикселей (т.е. нет белых точек).Это приносит новые проблемы:. применять шума слой с “Multiply” режим смешивания на сцене image

HTML5 Canvas

Все современные веб-браузеры поддерживают холсте element.В то время как ранние реализации холст предлагается только рисование API, современных реализаций позволяют авторам анализировать и обрабатывать каждый пиксель изображения.Это может быть сделано с ImageData интерфейсе, который представляет собой данные изображения, ширина, высота и массив pixels.

Массив пикселей холсте это обычный массив, содержащий RGBa каждого пикселя обработки данных.Вот то, что массив данных выглядит следующим образом:

pixelData = [pixel1_red, pixel1_green,
pixel1_blue, pixel1_alpha, pixel2_red,
pixel2_green, pixel2_blue, pixel2_alpha, …];

Таким образом, массив данных изображения содержит total_pixels×4 элементов.Например,200× 100 изображение будет содержать 200× 100× 4 = 80,000 элементов в этой array.

Для анализа и управления отдельными пикселями холст, мы должны получить изображение из него данные, а затем изменить массив пикселей, а затем поместить данные обратно в холст:

// Coordinates of image pixel that we will modify 
var x = 10, y = 20;
 
// Create a new canvas
var canvas = document.createElement('canvas');
canvas.width = canvas.height = 100;
document.body.appendChild(canvas);
 
// Get drawing context
var ctx = canvas.getContext('2d');
 
// Get image data
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
 
// Calculate offset for pixel
var offset = (x - 1 + (y - 1) * canvas.width) * 4;
 
// Set pixel color to opaque orange
imageData.data[offset]     = 255; // red channel
imageData.data[offset + 1] = 127; // green channel
imageData.data[offset + 2] = 0;   // blue channel
imageData.data[offset + 3] = 255; // alpha channel
 
// Put image data back into canvas
ctx.putImageData(imageData, 0, 0); 

Генерирующая Noise

Как только мы знаем, как управлять отдельными пикселями холст, мы можем легко создавать шум слой.Простая функция, которая генерирует монохроматическое шум может выглядеть следующим образом:

 
function addNoise(canvas) {
   var ctx = canvas.getContext('2d');
 
   // Get canvas pixels
   var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
   var pixels = imageData.data;
 
   for (var i = 0, il = pixels.length; i < il; i += 4) {
var color = Math.round(Math.random() * 255);
 
      // Because the noise is monochromatic, we should put the same value in the R, G and B channels
      pixels[i] = pixels[i + 1] = pixels[i + 2] = color;
 
      // Make sure pixels are opaque
      pixels[i + 3] = 255;
   }
 
   // Put pixels back into canvas
   ctx.putImageData(imageData, 0, 0);
}
 
// Set up canvas
var canvas = document.createElement('canvas');
canvas.width = canvas.height = 200;
document.body.appendChild(canvas);
 
addNoise(canvas);

Результат может выглядеть следующим образом:

Довольно хорошо для начала.Но мы не можем просто создать шум слой и поместите его над сценой изображения.Напротив, мы должны смешайте его в “Multiply” mode.

Смесь Modes

Любой, кто работал с Adobe Photoshop или любой другой продвинутый редактор изображений знает, что режимы смешивания являются:

Некоторые люди считают режимов изображения смесь как своего рода ракетостроение, но в большинстве случаев алгоритмы за ними довольно просто.Например, вот что алгоритм смешивания Multiply выглядит следующим образом:

(colorA * colorB) / 255

То есть, мы должны умножить два цвета (стоимость каждого канала) и разделите его на 255.

Давайте изменим из фрагмента кода: загрузить изображение, создавать шум и применять его с помощью “Multiply” Blend Mode:

 
// Load image. Waiting for onload event is important
var img = new Image;
img.onload = function() {
addNoise(img);
};
img.src = "stage-bg.jpg";
 
function addNoise(img) {
   var canvas = document.createElement('canvas');
   canvas.width = img.width;
   canvas.height = img.height;
 
   var ctx = canvas.getContext('2d');
 
   // Draw image on canvas to get its pixel data
   ctx.drawImage(img, 0, 0);
 
   // Get image pixels
   var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
   var pixels = imageData.data;
 
   for (var i = 0, il = pixels.length; i < il; i += 4) {
      // generate "noise" pixel
      var color = Math.random() * 255;
 
      // Apply noise pixel with Multiply blending mode for each color channel
      pixels[i] =     pixels[i] * color / 255;
      pixels[i + 1] = pixels[i + 1] * color / 255;
      pixels[i + 2] = pixels[i + 2] * color / 255;
   }
 
   ctx.putImageData(imageData, 0, 0);
   document.body.appendChild(canvas);
}

Результат будет выглядеть так:

Выглядит хорошо, но шум очень грубый.Мы должны применить прозрачность к it.

Alpha Compositing

Процесс объединения двух цветов с прозрачностью называется “. Альфа композиции« В простейшем случае композиции, алгоритм будет выглядеть следующим образом:

colorA * alpha + colorB * (1 - alpha)

Здесь alpha является композиция коэффициент (прозрачности) от 0 до 1.Выбор, какой цвет будет фоном (colorB) и который будет наложение (colorA) имеет важное значение.В этом случае фон будет занавески изображение, и звук будет overlay.

Давайте добавим еще один аргумент в пользу addNoise() функция, которая будет контролировать альфа-смешения и изменить основные функции соблюдать прозрачность в то время как смешивание изображений:

var img = new Image;
   img.onload = function() {
   addNoise(img, 0.2); // pass 'alpha' argument
};
img.src = "stage-bg.jpg";
 
function addNoise(img, alpha) { // new 'alpha' argument
   var canvas = document.createElement('canvas');
   canvas.width = img.width;
   canvas.height = img.height;
 
   var ctx = canvas.getContext('2d');
   ctx.drawImage(img, 0, 0);
 
   var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
   var pixels = imageData.data, r, g, b;
 
   for (var i = 0, il = pixels.length; i < il; i += 4) {
      // generate "noise" pixel
      var color = Math.random() * 255;
 
      // Calculate the target color in Multiply blending mode without alpha composition
      r = pixels[i] * color / 255;
      g = pixels[i + 1] * color / 255;
      b = pixels[i + 2] * color / 255;
 
      // alpha compositing
      pixels[i] =     r * alpha + pixels[i] * (1 - alpha);
      pixels[i + 1] = g * alpha + pixels[i + 1] * (1 - alpha);
      pixels[i + 2] = b * alpha + pixels[i + 2] * (1 - alpha);
   }
 
   ctx.putImageData(imageData, 0, 0);
   document.body.appendChild(canvas);
}

В результате именно то, что мы хотим: шум слой, нанесенный на фоновое изображение в режим смешивания Multiply с прозрачностью 20%:

Optimization

В то время как полученное изображение выглядит идеально, выполнение этого сценария является довольно бедным.На моем компьютере, она занимает около 300 миллисекунд (мс).На компьютере среднестатистического пользователя, это может занять еще больше времени.Таким образом, мы должны оптимизировать этот сценарий.Половина код использует браузер API вызовов, например, для создания холста, получение данных изображения и отправка его обратно, поэтому мы не можем сделать счто.Другая половина основного цикла для применения шум на сцене образ, и он может быть совершенно optimized.

Наш тест размер изображения 1293× 897, что прив …

Если вы хотите прочитать полностью статью, посетите сайт наших спонсоров

Comments are closed.