web-dev-qa-db-ja.com

NodeJS base64画像のエンコード/デコードがまったく機能しない

NodeJS(およびexpressフレームワーク)にPOSTされた画像をデータベースに保存しようとしてきましたが、いくつかの問題がありました。すべてのWeb処理を無視して、base64エンコードがノードで発生する方法に問題を絞り込んだと思います。以下の単純化された例は機能するはずですが、出力イメージは常に破損しています。

例(1)はイメージをロードします(2)if(image_orig)のコピーを保存して、ノードがファイルを適切に読み取れることを確認します。これは常に機能します。 (3)画像を取得し、その内容をbase64でエンコードし、(4)それをデコードします。最終出力イメージ(image_decoded)は常に破損しています。

助けて! (OSX Lionのnode.js 0.6.0)

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

エンコード引数の使用法について少し誤解していると思います。エンコーディング「バイナリ」を指定する場合は、一貫して行う必要があります。しかし、実際にはまったく必要ありません。バッファとバイナリ文字列の使用法を混同しているようです。

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

この次の例は機能しますが、エンコーディングを常に変更する必要はないため、非常に非効率的ですが、明確にするためだけに示したいと思います。本当にDID特定のエンコーディングが必要な場合は、一貫性を保つ必要があります。これらの関数にはすべてエンコーディング引数があります。

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

これが正しい方法です。 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

少し良い解決策は、可能なすべてのMIMEタイプを削除することです。

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

これは、@ Herveの回答に追加されます。

16
simo