2013-10-02 2 views
14

Я немного экспериментировал с элементом холста, и мне было любопытно, как снять эффект.Как пикселизовать изображение с холстом и javascript

У меня есть то, что я искал из коллекции учебников и демонстраций, но мне нужна помощь, чтобы проложить остальную часть пути. Я ищу, чтобы pixelate изображение на mouseover, затем перефокусировать/не-pixelate его на mouseout. Вы можете увидеть хороший пример эффекта на http://www.cropp.com/, когда мышь над блоками ниже основной карусели.

Вот link to a fiddle Я начал. Скрипка не будет работать, потому что вы не можете использовать изображения с перекрестными доменами (womp womp), но до сих пор вы можете видеть мой код. Когда мышь над моим объектом canvas, я могу выполнить пикселизацию изображения, но это отчасти обратное тому, что я пытаюсь получить. Любая помощь или совет будут очень признательны.

var pixelation = 40, 
    fps = 120, 
    timeInterval = 1000/fps, 
    canvas = document.getElementById('photo'), 
    context = canvas.getContext('2d'), 
    imgObj = new Image(); 

imgObj.src = 'images/me.jpg'; 
imgObj.onload = function() {  
    context.drawImage(imgObj, 0, 0); 
}; 

canvas.addEventListener('mouseover', function() { 
    var interval = setInterval(function() { 
     context.drawImage(imgObj, 0, 0); 

     if (pixelation < 1) { 
      clearInterval(interval); 
      pixelation = 40; 
     } else { 
      pixelate(context, canvas.width, canvas.height, 0, 0); 
     } 
    }, timeInterval); 
}); 

function pixelate(context, srcWidth, srcHeight, xPos, yPos) { 

    var sourceX = xPos, 
     sourceY = yPos, 
     imageData = context.getImageData(sourceX, sourceY, srcWidth, srcHeight), 
     data = imageData.data; 

    for (var y = 0; y < srcHeight; y += pixelation) { 
     for (var x = 0; x < srcWidth; x += pixelation) { 

      var red = data[((srcWidth * y) + x) * 4], 
       green = data[((srcWidth * y) + x) * 4 + 1], 
       blue = data[((srcWidth * y) + x) * 4 + 2]; 

      for (var n = 0; n < pixelation; n++) { 
       for (var m = 0; m < pixelation; m++) { 
        if (x + m < srcWidth) { 
         data[((srcWidth * (y + n)) + (x + m)) * 4] = red; 
         data[((srcWidth * (y + n)) + (x + m)) * 4 + 1] = green; 
         data[((srcWidth * (y + n)) + (x + m)) * 4 + 2] = blue; 
        } 
       } 
      } 
     } 
    } 

    // overwrite original image 
    context.putImageData(imageData, xPos, yPos); 
    pixelation -= 1; 
} 
+3

Обновлена ​​ваша скрипка, чтобы иметь реальное изображение, с помощью URL-адреса данных: http://jsfiddle.net/xDt7U/1/ – Chad

ответ

29

Вам не нужно итерировать буфер пикселей, чтобы создать эффект пикселизации.

Просто выключите сглаживание изображения и увеличьте небольшую версию изображения на холсте. Это также означает, что вы можете использовать любое изображение в качестве источника (CORS-wise).

Пример:

Fiddle demo

// get a block size (see demo for this approach) 
var size = blocks.value/100, 
    w = canvas.width * size, 
    h = canvas.height * size; 

// draw the original image at a fraction of the final size 
ctx.drawImage(img, 0, 0, w, h); 

// turn off image aliasing 
ctx.msImageSmoothingEnabled = false; 
ctx.mozImageSmoothingEnabled = false; 
ctx.webkitImageSmoothingEnabled = false; 
ctx.imageSmoothingEnabled = false; 

// enlarge the minimized image to full size  
ctx.drawImage(canvas, 0, 0, w, h, 0, 0, canvas.width, canvas.height); 

В демке вы можете анимировать этот эффект, чтобы увидеть, что производительность очень хорошо по сравнению с методом пикселей перебора как браузер берет на себя «пикселизация» внутри скомпилированного кода.

+0

Ничего себе, это выглядит великолепно и гораздо меньше кода, чем то, что у меня было. Не могли бы вы немного объяснить код? Я понимаю, что делает метод pixelate, но немного любопытно, как работает toggleAnim и requestAnimationFrame. Как я мог заставить эту функцию анимировать до определенной точки (pixelated), а затем остановиться. Или наоборот? – brandongray

+0

@brandongray toggleAnim - это всего лишь часть демонстрации для анимации пикселизации, чтобы получить представление о производительности. Я обновил демо с помощью встроенных комментариев. requestAnimationFrame - это низкоуровневый метод анимации, который позволяет синхронизировать анимацию для мониторинга обновлений, чтобы сделать ее более гладкой и более эффективной. Он работает лучше, чем setTimout/setInterval. – K3N

+0

@ ken-abdias-software Я ценю комментарии. Если у вас есть еще один мин и вы готовы помочь, можете взглянуть на [эту скрипку] (http://jsfiddle.net/Ra9KQ/). У меня есть работа над mouseover/out, но он чувствует себя грязным. Например, если я быстро наведите указатель мыши, а затем переход не выглядит гладко. Функция мыши над функцией продолжает работать в этой точке. Любые предложения о том, как я могу добиться плавного перехода? Например, если я быстро надвигаюсь, а затем вытаскиваю, переход происходит из любой точки, к которой пришел эффект зависания. Надеюсь, это имеет смысл. – brandongray

2

Просто имейте в виду, что есть несколько библиотек javascript, которые выполняют одинаковый эффект, например pixelate или close-pixelate.

Смежные вопросы