web-dev-qa-db-fra.com

Le codage / décodage d'image NodeJS base64 ne fonctionne pas tout à fait

J'ai essayé de gérer les images enregistrées POSTed sur nodeJS (et le framework express) dans une base de données, et j'ai eu des problèmes. Ignorant tout le traitement Web, je pense que j'ai réduit le problème de la façon dont l'encodage base64 se produit dans le nœud. Je crois que l'exemple simplifié ci-dessous devrait fonctionner, mais l'image de sortie est toujours corrompue.

L'exemple (1) se charge dans une image (2) enregistre une copie de if (image_orig) pour confirmer que le nœud peut lire le fichier correctement. Cela fonctionne toujours. (3) Je prends l'image et base64 encode son contenu, (4) puis je la décode. L'image de sortie finale (image_decoded) est toujours corrompu.

Aidez-moi! (node.js 0.6.0 sur 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) {});
});
33
Evan

Je pense que vous comprenez un peu l'utilisation de l'argument de codage. Si vous allez spécifier le codage "binaire", vous devez le faire de manière cohérente. Mais vous n'en avez vraiment pas besoin du tout. Vous semblez confondre l'utilisation de Buffer vs les chaînes binaires.

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

Cet exemple suivant fonctionnera mais est très inefficace car il n'est pas nécessaire de changer tout le temps les encodages, mais je veux juste montrer que c'est clair. Si vous voulez vraiment DID voulez avoir un encodage spécifique, vous devez vous assurer que vous êtes cohérent. Chacune de ces fonctions a un argument d'encodage.

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

C'est la bonne façon de procéder. Gardez tout comme un tampon, sauf lorsque vous le faites en 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) {});
});
104
loganfsmyth

Une solution légèrement meilleure consistera à supprimer tous les types de mimes possibles:

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

C'est un ajout à la réponse de @ Herve.

16
simo