NodeJS: sauvegarder une image encodée en base64 sur un disque

Mon Express application reçoit des encodée en base64, PNG à partir du navigateur (généré à partir d'une toile avec toDataURL() ) et l'écrire dans un fichier. Mais le fichier n'est pas un fichier image valide, et l'utilitaire "file" l'identifie simplement comme "data".

var body = req.rawBody,
  base64Data = body.replace(/^data:image/png;base64,/,""),
  binaryData = new Buffer(base64Data, 'base64').toString('binary');

require("fs").writeFile("out.png", binaryData, "binary", function(err) {
  console.log(err); // writes out file without error, but it's not a valid image
});
103
demandé sur mahemoff 2011-08-03 15:53:05

6 réponses

je pense que vous convertissez les données un peu plus que vous n'en avez besoin. Une fois que vous créez le tampon avec le codage approprié, vous avez juste besoin d'écrire le tampon dans le fichier.

var base64Data = req.rawBody.replace(/^data:image\/png;base64,/, "");

require("fs").writeFile("out.png", base64Data, 'base64', function(err) {
  console.log(err);
});

nouveau Tampon(..., 'base64') convertit la chaîne d'entrée à un Tampon, qui est juste un tableau d'octets, en l'interprétant comme une chaîne encodée en base64. Ensuite, vous pouvez simplement écrire ce tableau octet dans le fichier.

mise à Jour

As mentionné dans les commentaires, req.rawBody n'est plus une chose. Si vous utilisez express / connect , alors vous devez utiliser le middleware bodyParser() et utiliser req.body , et si vous faites cela en utilisant le noeud standard, alors vous devez agréger les objets entrants data event Buffer et faire cette analyse de données d'image dans le callback end .

223
répondu loganfsmyth 2014-06-17 05:24:10

c'est ma solution complète qui pourrait lire n'importe quel format d'image base64 et le sauvegarder dans le format approprié dans la base de données:

    // Save base64 image to disk
    try
    {
        // Decoding base-64 image
        // Source: /q/nodejs-write-base64-image-file-54227/"jpeg" from "image/jpeg"
        var imageTypeRegularExpression      = /\/(.*?)$/;      

        // Generate random string
        var crypto                          = require('crypto');
        var seed                            = crypto.randomBytes(20);
        var uniqueSHA1String                = crypto
                                               .createHash('sha1')
                                                .update(seed)
                                                 .digest('hex');

        var base64Data = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAZABkAAD/4Q3zaHR0cDovL25zLmFkb2JlLmN...';

        var imageBuffer                      = decodeBase64Image(base64Data);
        var userUploadedFeedMessagesLocation = '../img/upload/feed/';

        var uniqueRandomImageName            = 'image-' + uniqueSHA1String;
        // This variable is actually an array which has 5 values,
        // The [1] value is the real image extension
        var imageTypeDetected                = imageBuffer
                                                .type
                                                 .match(imageTypeRegularExpression);

        var userUploadedImagePath            = userUploadedFeedMessagesLocation + 
                                               uniqueRandomImageName +
                                               '.' + 
                                               imageTypeDetected[1];

        // Save decoded binary image to disk
        try
        {
        require('fs').writeFile(userUploadedImagePath, imageBuffer.data,  
                                function() 
                                {
                                  console.log('DEBUG - feed:message: Saved to disk image attached by user:', userUploadedImagePath);
                                });
        }
        catch(error)
        {
            console.log('ERROR:', error);
        }

    }
    catch(error)
    {
        console.log('ERROR:', error);
    }
18
répondu Placeholder 2014-10-16 06:26:17

UPDATE

j'ai trouvé ce lien intéressant comment résoudre votre problème en PHP . Je pense que vous avez oublié de remplacer space par + comme montré dans le lien.

j'ai pris ce cercle de http://images-mediawiki-sites.thefullwiki.org/04/1/7/5/6204600836255205.png comme échantillon qui ressemble à:

http://images-mediawiki-sites.thefullwiki.org/04/1/7/5/6204600836255205.png

Ensuite je l'ai mis dans http://www.greywyvern.com/code/php/binary2base64 qui m'a rendu:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAAAAACPAi4CAAAAB3RJTUUH1QEHDxEhOnxCRgAAAAlwSFlzAAAK8AAACvABQqw0mAAAAXBJREFUeNrtV0FywzAIxJ3+K/pZyctKXqamji0htEik9qEHc3JkWC2LRPCS6Zh9HIy/AP4FwKf75iHEr6eU6Mt1WzIOFjFL7IFkYBx3zWBVkkeXAUCXwl1tvz2qdBLfJrzK7ixNUmVdTIAB8PMtxHgAsFNNkoExRKA+HocriOQAiC+1kShhACwSRGAEwPP96zYIoE8Pmph9qEWWKcCWRAfA/mkfJ0F6dSoA8KW3CRhn3ZHcW2is9VOsAgoqHblncAsyaCgcbqpUZQnWoGTcp/AnuwCoOUjhIvCvN59UBeoPZ/AYyLm3cWVAjxhpqREVaP0974iVwH51d4AVNaSC8TRNNYDQEFdlzDW9ob10YlvGQm0mQ+elSpcCCBtDgQD7cDFojdx7NIeHJkqi96cOGNkfZOroZsHtlPYoR7TOp3Vmfa5+49uoSSRyjfvc0A1kLx4KC6sNSeDieD1AWhrJLe0y+uy7b9GjP83l+m68AJ72AwSRPN5g7uwUAAAAAElFTkSuQmCC

a enregistré cette chaîne de caractères en base64 que j'ai lu dans mon code.

var fs      = require('fs'),
data        = fs.readFileSync('base64', 'utf8'),
base64Data,
binaryData;

base64Data  =   data.replace(/^data:image\/png;base64,/, "");
base64Data  +=  base64Data.replace('+', ' ');
binaryData  =   new Buffer(base64Data, 'base64').toString('binary');

fs.writeFile("out.png", binaryData, "binary", function (err) {
    console.log(err); // writes out file without error, but it's not a valid image
});

je reçois un cercle en arrière, mais le plus drôle, c'est que la taille du fichier a changé :)...

END

quand vous relisez l'image en arrière je pense que vous devez configurer les en-têtes

prendre par exemple imagepng de la page PHP:

<?php
$im = imagecreatefrompng("test.png");

header('Content-Type: image/png');

imagepng($im);
imagedestroy($im);
?>

je pense que la deuxième ligne header('Content-Type: image/png'); , est importante sinon votre image ne sera pas affichée dans le navigateur, mais juste un tas de données binaires est affiché au navigateur.

Dans Express , vous devez simplement utiliser quelque chose comme ci-dessous. Je vais afficher votre gravatar qui se trouve à http://www.gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG et est un fichier jpeg lorsque vous curl --head http://www.gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG . Je demande seulement des en-têtes parce que sinon curl affichera un tas de trucs binaires(Google Chrome va immédiatement à télécharger) à la console:

curl --head "http://www.gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG"
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 03 Aug 2011 12:11:25 GMT
Content-Type: image/jpeg
Connection: keep-alive
Last-Modified: Mon, 04 Oct 2010 11:54:22 GMT
Content-Disposition: inline; filename="cabf735ce7b8b4471ef46ea54f71832d.jpeg"
Access-Control-Allow-Origin: *
Content-Length: 1258
X-Varnish: 2356636561 2352219240
Via: 1.1 varnish
Expires: Wed, 03 Aug 2011 12:16:25 GMT
Cache-Control: max-age=300
Source-Age: 1482

$ mkdir -p ~/tmp/6922728
$ cd ~/tmp/6922728/
$ touch app.js

app.js

var app = require('express').createServer();

app.get('/', function (req, res) {
    res.contentType('image/jpeg');
    res.sendfile('cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG');
});

app.get('/binary', function (req, res) {
    res.sendfile('cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG');
});

app.listen(3000);

$ wget "http://www.gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG"
$ node app.js
14
répondu Alfred 2011-08-03 21:02:38

j'ai aussi dû sauvegarder des images codées en Base64 qui font partie des URLs de données, donc j'ai fini par créer un petit module npm pour le faire au cas où je (ou quelqu'un d'autre) aurait besoin de le faire à nouveau dans le futur. Ça s'appelle ba64 .

simplement dit, il prend une URL de données avec une image encodée Base64 et sauve l'image à votre système de fichiers. Il peut enregistrer de façon synchrone ou asynchrone. Il dispose également de deux fonctions d'aide, l'un pour obtenir l'extension de fichier de l'image, et l'autre pour séparer L'encodage Base64 du préfixe de schéma data: .

voici un exemple:

var ba64 = require("ba64"),
    data_url = "data:image/jpeg;base64,[Base64 encoded image goes here]";

// Save the image synchronously.
ba64.writeImageSync("myimage", data_url); // Saves myimage.jpeg.

// Or save the image asynchronously.
ba64.writeImage("myimage", data_url, function(err){
    if (err) throw err;

    console.log("Image saved successfully");

    // do stuff
});

installez-le: npm i ba64 -S . Repo est sur GitHub: https://github.com/HarryStevens/ba64 .

P.S. il m'est apparu plus tard que ba64 est probablement un mauvais nom pour le module car les gens peuvent supposer qu'il ne base64 encodage et le décodage, ce qui n'est pas le cas (il ya beaucoup de modules que déjà le faire). Oh bien.

3
répondu Harry Stevens 2017-10-15 16:30:26

manière facile de convertir base64 image dans le fichier et enregistrer comme un nom aléatoire.

// to create some random id or name for your image name
const imgname = new Date().getTime().toString();

// to declare some path to store your converted image
const path = yourpath.png    

// image takes from body which you uploaded
const imgdata = req.body.image;    

// to convert base64 format into random filename
const base64Data = imgdata.replace(/^data:([A-Za-z-+/]+);base64,/, '');
fs.writeFile(path, base64Data, 'base64', (err) => {
    console.log(err);
});

// assigning converted image into your database
req.body.coverImage = imgname
1
répondu Carlos 2017-08-24 13:37:36

conversion de fichier avec chaîne base64 en Image png.

4 variantes qui fonctionnent.

var {promisify} = require('util');
var fs = require("fs");

var readFile = promisify(fs.readFile)
var writeFile = promisify(fs.writeFile)

async function run () {

  // variant 1
  var d = await readFile('./1.txt', 'utf8')
  await writeFile("./1.png", d, 'base64')

  // variant 2
  var d = await readFile('./2.txt', 'utf8')
  var dd = new Buffer(d, 'base64')
  await writeFile("./2.png", dd)

  // variant 3
  var d = await readFile('./3.txt')
  await writeFile("./3.png", d.toString('utf8'), 'base64')

  // variant 4
  var d = await readFile('./4.txt')
  var dd = new Buffer(d.toString('utf8'), 'base64')
  await writeFile("./4.png", dd)

}

run();
1
répondu Vladimir Buskin 2018-04-06 08:37:43