如何使用画布和 javascript 对图像进行像素化

IT技术 javascript canvas html5-canvas
2021-02-24 01:09:51

我一直在尝试使用 canvas 元素,并且很好奇如何实现效果。

我从一系列教程和演示中找到了我想要的东西,但我需要一些帮助才能完成剩下的工作。我正在寻找的是在 上对图像进行像素化mouseover,然后在 上重新聚焦/取消像素化mouseout将鼠标悬停在主转盘下方的块上时,您可以在http://www.cropp.com/ 上看到一个很好的效果示例

这是我开始的小提琴链接小提琴不起作用,因为您不能使用跨域图像(womp womp),但到目前为止您仍然可以看到我的代码。将鼠标悬停在我的画布对象上时,我可以对图像进行像素化,但这与我想要获得的效果有点倒退。任何帮助或建议将不胜感激。

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;
}
2个回答

您不需要迭代像素缓冲区来创建像素化效果。

只需关闭图像平滑并将图像的小版本放大到画布即可。这也意味着您可以使用任何图像作为源(CORS-wise)。

例子:

小提琴演示

// 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);

在演示中,您可以对这种效果进行动画处理,以查看与像素迭代方法相比性能非常好,因为浏览器在编译代码中内部处理“像素化”。

@brandongray toggleAnim 只是演示的一部分,用于为像素化设置动画以获得性能印象。我用内联注释更新了演示。requestAnimationFrame 是一种低级动画方法,它允许您同步动画以监控更新,使其更流畅、更高效。它比 setTimout/setInterval 效果更好。
2021-04-23 01:09:51
哇,这看起来很棒,而且代码比我要少得多。你介意解释一下代码吗?我了解 pixelate 方法在做什么,但对 toggleAnim 的工作原理和 requestAnimationFrame 有点好奇。我怎样才能让该函数动画到某个点(像素化)然后停止。或相反亦然?
2021-04-27 01:09:51
似乎这个答案已转换为成熟的库:github.com/43081j/pixelate.js
2021-05-08 01:09:51
@ken-abdias-software 啊,我明白你在那里做了什么,将一些东西移动到全局可访问以及 isPlaying 标志。现在完全有道理。绝对比我放在一起的要干净得多。非常感谢您的帮助!
2021-05-10 01:09:51
@ken-abdias-software 我很欣赏这些评论。如果你还有一分钟的时间并且愿意提供帮助,你可以看看这个小提琴我让它在鼠标悬停/移出上工作,但感觉很脏。例如,如果我快速将鼠标悬停在鼠标上方然后移出,则过渡看起来并不平滑。鼠标悬停功能在该点继续运行。关于如何让它顺利过渡的任何建议?例如,如果我快速悬停然后将鼠标移出,则过渡是从悬停效果达到的任何点开始的。希望这是有道理的。
2021-05-17 01:09:51

请记住,有一些 javascript 库具有相同的效果,例如pixelateclose-pixelate