6

所以我为自己创造的挑战就是这样。

我有一张源照片:

来源照片

我正在映射颜色值并使用 div 创建它的像素化表示

结果如下:

结果照片

我正在完成此操作的代码是:

'use strict';

var imageSource = 'images/unicorn.jpg';

var img = new Image();
img.src = imageSource;
var canvas = $('<canvas/>')[0];
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
var context = canvas.getContext('2d');

console.log('img height: ' + img.height);
console.log('img width: ' + img.width);

var pixelDensity = 70;

var timerStart = new Date();


for (var i = pixelDensity/2; i < img.height; i += (img.height/pixelDensity) ) {
    $('.container').append($('<div class="row">'));
    for(var j = pixelDensity/2; j < img.width; j += img.height/pixelDensity) {
        var value = context.getImageData(j, i, 1, 1).data;
        var colorValue = 'rgb(' + value[0] + ', ' + value[1] + ', ' + value[2] + ')';
        $('.row:last').append($('<div class="block">').css({'background-color' : colorValue}));
    }
}

var timerStop = new Date();

console.log(timerStop - timerStart + ' ms');

pixelDensity 变量控制颜色样本的接近程度。数字越小,样本越少,产生结果所需的时间就越少。随着数量的增加,样本会增加,并且功能会大大减慢。

我很想知道是什么让这件事花费了这么长时间。我看过稍微相似的项目——最著名的是Jscii——它们处理图像数据的速度要快得多,但我无法弄清楚提供额外性能的区别是什么。

谢谢你的帮助!

4

4 回答 4

1

为什么不考虑在画布上绘制结果而不是创建这么多 div?理论上它应该更快...

于 2013-01-31T19:12:03.847 回答
1

主要问题是您在循环中将 DOM 元素附加到页面。如果您在实际将其添加到页面之前使用所有数据创建包装器元素,这将运行得更快。

编辑: 我也注意到你要求context.getImageData每个像素,这是大部分时间。相反,您应该将图像数据缓存在变量中并从中获取颜色值。您还需要像@Travis J 提到的那样缓存循环条件并将它们四舍五入:

var wrapper = $('<div class="container">');
var imgData = context.getImageData(0, 0, img.width, img.height).data;
var getRGB = function(i) { return [imgData[i], imgData[i+1], imgData[i+2]]; };
var start = Math.round(pixelDensity/2),
    inc = Math.round(img.height/pixelDensity);

for (var i = start; i < img.height; i += inc) {
    var row = $('<div class="row">');
    for(var j = start; j < img.width; j += inc) {
        var colorValue = getRGB((i * (img.width*4)) + (j*4));
        row.append($('<div class="block">').css({'background-color' : 'rgb('+(colorValue.join(','))+')'}));
    }
    wrapper.append(row);
}

$('body').append(wrapper);

这会将时间从 6-9 秒减少到 600-1000 毫秒。您还可以使用纯 javascript 来操作 DOM 元素而不是 jquery 以使其更快。

于 2013-01-31T19:22:18.240 回答
0

我之前也遇到过类似的速度问题 - 之所以需要这么长时间是因为您通过以文本形式提供 HTML 来添加元素,这意味着它必须每次都解析该文本。如果您使用 JavaScript DOM 添加新元素,您会发现速度显着提高。

编辑:如果您不熟悉以这种方式创建新元素,语法如下所示:

var newPixel = document.createElement('div');
newPixel.style.height = 3;
newPixel.style.backgroundColor = 'black';
// etc...
parentElement.appendChild(newPixel);
于 2013-01-31T19:15:41.250 回答
0

您可以通过减少 jquery 查找的数量来加快速度。例如,在您的第一个循环开始之前,请执行以下操作:

var $container = $('.container');

现在您不必每次都查找容器。

此外,当您创建一行时,使用相同的技巧来避免 'row:last' 查找:

var $row = $('<div class="row">');
$container.append($row);
...
$row.append($('<div class="block">')...
于 2013-01-31T19:17:13.810 回答