2013-01-31 11 views
6

Quindi la sfida che ho creato per me stesso è tale.Javascript - Elaborazione dati immagine e rendering div

Ho una foto fonte:

Source Photo http://f.cl.ly/items/012t1M250f0T101F2L0n/unicorn.jpg

Che io sto mappando i valori di colore e la creazione di una rappresentazione pixel di esso utilizzando div

Ecco il risultato:

Result Photo http://f.cl.ly/items/2t1F2Q0Y2w0K250L0t0v/Screen%20Shot%202013-01-31%20at%2010.52.19%20AM.png

Il codice con cui sto facendo questo è:

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

La variabile pixelDensity controlla quanto vicini sono i campioni di colore. Più piccolo è il numero, minore è il numero di campioni, impiegando meno tempo per produrre il risultato. Aumentando il numero, i campioni salgono e la funzione rallenta notevolmente.

Sono curioso di sapere cosa sta facendo questa cosa ci vuole così tanto tempo. Ho esaminato progetti leggermente simili, in particolare Jscii, che elaborano i dati dell'immagine molto più rapidamente, ma non riesco a capire quale sia la differenza che offre le prestazioni aggiuntive.

Grazie per il vostro aiuto!

+0

Non toccare il DOM a meno che non sia necessario. Costruisci il tuo modello di oggetto fuori schermo e poi aggiungilo una volta. Presumibilmente, più campioni, più div, più modifiche. Quindi, costruito tutto fuori dallo schermo, aggiungilo tutto in una volta, una volta. –

+0

Questo è quello che stavo facendo inizialmente, ma ho scoperto che tirare i dati dell'immagine era ciò che prendeva più tempo. Ci proverò di nuovo dato il consiglio qui sotto. Grazie per l'aiuto! – tylerdavis

+0

Un'altra cosa. Quando stai cercando di ottenere ogni possibile prestazione, allora ogni piccola cosa aiuta. Cache per le condizioni del ciclo. 'per (var j = pixelDensity/2; j

risposta

1

Il problema principale è che si accoda elementi DOM di una pagina a destra in un ciclo. Ciò funzionerebbe molto più velocemente se creerai un elemento wrapper con tutti i tuoi dati prima di aggiungerlo effettivamente alla pagina.

Edit: Ho anche notato che chiamate context.getImageData per ogni pixel, questo è quello che prende la maggior parte del tempo. Invece, dovresti memorizzare nella cache i dati dell'immagine in variabile e ottenere da essa valori di colore.Avrete anche bisogno di cache condizioni di loop come @Travis J menzionato e tondo:

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

Questo sarebbe ridurre il tempo da 6-9 secondi a 600-1000 millisecondi. Puoi anche usare plain javascript per manipolare elementi DOM invece di jquery per renderlo ancora più veloce.

+0

Questo era il problema. Grazie mille per la risposta! – tylerdavis

1

Perché non consideri di disegnare il risultato sulla tela invece di creare così tanti div? In teoria dovrebbe essere molto più veloce ...

0

Ho avuto problemi di velocità simili prima - Il motivo per cui ci vuole così tanto tempo è perché stai aggiungendo gli elementi dandogli l'HTML sotto forma di testo, che significa che deve analizzare quel testo ogni volta. Se usi il DOM JavaScript per aggiungere nuovi elementi noterai un aumento significativo della velocità.

EDIT: Nel caso in cui non hai familiarità con la creazione di nuovi elementi in questo modo, la sintassi è simile al seguente:

var newPixel = document.createElement('div'); 
newPixel.style.height = 3; 
newPixel.style.backgroundColor = 'black'; 
// etc... 
parentElement.appendChild(newPixel); 
0

Si potrebbe accelerare un po 'riducendo il numero di ricerche jQuery. Ad esempio, prima del primo loop start, fare questo:

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

Ora non c'è bisogno di guardare il contenitore ogni volta.

Inoltre, quando si crea una riga, usare lo stesso trucco per evitare il 'consecutive: ultima' ricerca:

var $row = $('<div class="row">'); 
$container.append($row); 
... 
$row.append($('<div class="block">')... 
Problemi correlati