2011-11-13 20 views
27

ho cercato di gestire il salvataggio delle immagini inviati ad nodeJS (e il quadro espresso) a un database, e stanno avendo qualche problema. Ignorando tutta l'elaborazione web, penso di aver ristretto il problema al modo in cui la codifica base64 sta accadendo nel nodo. Credo che l'esempio semplificato semplificato di seguito dovrebbe funzionare, ma l'immagine di output è sempre danneggiata.NodeJS codifica Base64 immagine/decodifica non del tutto funzionante

L'esempio (1) carica in un'immagine (2) salva una copia di if (image_orig) per confermare che il nodo può leggere correttamente il file. Funziona sempre. (3) Prendo l'immagine e base64 ne codifico il contenuto, (4) quindi lo decodifico. L'immagine di output finale (image_decoded) è sempre danneggiata.

Help! (Node.js 0.6.0 su OSX Lion)

console.log("starting"); 
process.chdir(__dirname); 

var fs = require("fs"); 

var image_origial = "image.jpg"; 
fs.readFile(image_origial, function(err, original_data){ 
    fs.writeFile('image_orig.jpg', original_data, function(err) {}); 
    var base64Image = new Buffer(original_data, 'binary').toString('base64'); 
    var decodedImage = new Buffer(base64Image, 'base64').toString('binary'); 
    fs.writeFile('image_decoded.jpg', decodedImage, function(err) {}); 
}); 

risposta

95

Penso che tu sia equivoco l'uso dell'argomento codifica un po '. Se hai intenzione di specificare la codifica "binario", devi farlo in modo coerente. Ma davvero non ne hai affatto bisogno. Sembra che tu stia confondendo l'uso delle stringhe Buffer vs binary.

// This tells node to load the file into a Buffer 'original_data' because you 
// have not specified an encoding for the returned values. If you provided an 
// encoding, then original_data would be a string with that encoding. 
fs.readFile(image_origial, function(err, original_data){ 

    // This tells node to take that buffer, and write it to the new filename. 
    // Again no encoding is provided, so it will assume a Buffer or utf8 string. 
    fs.writeFile('image_orig.jpg', original_data, function(err) {}); 

    // This tells node to create a new buffer from the old buffer, which means 
    // it will iterate over original_data copying the bytes one at a time. But 
    // they will be identical buffers. It will ignore the 'binary' argument 
    // since the object you are passing isn't a string. 
    // Then it encodes the content of that Buffer to base64, which is fine. 
    var base64Image = new Buffer(original_data, 'binary').toString('base64'); 

    // Here you decode the base64 to a buffer, which is fine, but then you 
    // convert the buffer into a string with encoding 'binary'. This means that 
    // it is a string object whose code points are bytes of the buffer. 
    var decodedImage = new Buffer(base64Image, 'base64').toString('binary'); 

    // Here you try to write that String object to a file. Since the argument you 
    // have given is a string and you have not given an encoding argument for the 
    // write command, then it will assume that 'utf8' is the encoding. It will try to 
    // decode your binary string into a utf8 encoded buffer, and write that buffer. 
    // This will cause it to fail because that encoding conversion is wrong. 
    // Really through, 'binary' is just wrong to use. Buffers are already binary. 
    fs.writeFile('image_decoded.jpg', decodedImage, function(err) {}); 
}); 

Il prossimo esempio funziona ma è molto inefficiente perché cambiare codifiche non è necessaria per tutto il tempo, ma ho solo voglia di mostrarlo per essere chiari. Se davvero volevi avere una codifica specifica, devi assicurarti di essere coerente. Ognuna di queste funzioni ha un argomento di codifica.

fs.readFile(image_origial, 'binary', function(err, original_data){ 
    fs.writeFile('image_orig.jpg', original_data, 'binary', function(err) {}); 
    var base64Image = new Buffer(original_data, 'binary').toString('base64'); 
    var decodedImage = new Buffer(base64Image, 'base64').toString('binary'); 
    fs.writeFile('image_decoded.jpg', decodedImage, 'binary', function(err) {}); 
}); 

Questo è il modo giusto per farlo. Mantieni tutto come un Buffer, tranne quando lo fai base64.

fs.readFile(image_origial, function(err, original_data){ 
    fs.writeFile('image_orig.jpg', original_data, function(err) {}); 
    var base64Image = original_data.toString('base64'); 
    var decodedImage = new Buffer(base64Image, 'base64'); 
    fs.writeFile('image_decoded.jpg', decodedImage, function(err) {}); 
}); 
+3

Grazie! Questo l'ha risolto! – Evan

+0

Grazie per questa risposta super informativa! Sono stato in grado di codificare le immagini su base64 usando anche le tue linee guida. – zzaman

+1

come scrivere il 'decodedImage' nel flusso di risposta? –

11

soluzione Leggermente migliore sarà quello di rimuovere tutti i tipi mime possibile:

var buff = new Buffer(req.body.imageFile 
    .replace(/^data:image\/(png|gif|jpeg);base64,/,''), 'base64'); 
fs.writeFile('/file/path/', buff, function (err) { 
    console.log('done'); 
}); 

Questa è aggiunta alla @ risposta di Herve.

+0

perché è necessario rimuovere i tipi mime ?? – user1575921

+2

I metadati sono usati solo nel browser. Nel caso in cui non lo si rimuove Nodo memorizza l'immagine danneggiata. – simo

+0

grazie, ho capito – user1575921