NodeJS: Base64 kodlu bir görüntüyü diske kaydetme


162

Express uygulamam tarayıcıdan base64 kodlu bir PNG alıyor (toDataURL () ile tuvalden üretiliyor) ve bir dosyaya yazıyor. Ancak dosya geçerli bir görüntü dosyası değildir ve "dosya" yardımcı programı dosyayı "veri" olarak tanımlar.

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

1
İlk başta neye ihtiyacınız olduğunu düşünüyorum cevabı güncelledim;)
Alfred

Açıkçası bu istediğin şey değil, ama (benim durumumda) en iyi yaklaşımın sadece kodlanmış tüm dizeyi veritabanımda saklamak olduğunu fark ettim (her zaman kullanarak yükleyebilirsin <img src="data:image/png;base64,..." />). Bu konuyu referans olarak kullanan başkaları için bir seçenek.
JSideris

Yanıtlar:


324

Verileri, ihtiyacınız olandan biraz daha fazla dönüştürdüğünüzü düşünüyorum. Tamponu uygun kodlamayla oluşturduktan sonra, tamponu dosyaya yazmanız yeterlidir.

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

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

new Buffer (..., 'base64'), girdiyi base64 kodlu dize olarak yorumlayarak giriş dizesini yalnızca bayt dizisi olan bir Arabelleğe dönüştürür. Sonra bu bayt dizisini dosyaya yazabilirsiniz.

Güncelleme

Yorumlarda belirtildiği gibi, req.rawBodyartık bir şey değil. Eğer kullanıyorsanız express/ connectardından kullanmak gerektiğini bodyParser()ara katman ve kullanımını req.bodyve standart düğüm kullanırken bu yapıyorsanız o zaman gelen toplamak için gereken dataolay Buffernesneleri ve ayrıştırma bu görüntü verilerini yapmak endcallback'inde.


2
Ayrıca, örneğinizdeki writeFile bağımsız değişkeninde hafif bir yazım hatası vardır: "bufferData" -> "dataBuffer".
mahemoff

@RJ. req.rawBodyveri URL'si olarak kodlanan istek verilerini içerir: developer.mozilla.org/en-US/docs/data_URIs . Bu yüzden kaydetmek için sadece base64 verilerini elde etmek için başlangıç ​​kısmını çıkarmanız gerekir.
loganfsmyth

2
Bu mükemmel şeyler, teşekkürler! Gelecekte bunu bulanlar için rawBody artık req. Verileri almak için ekspres gövde ayrıştırıcısı ara katman yazılımını kullanmanız gerekir.
DigitalDesignDj

10
var base64Data = req.rawBody.split (',') [1];
Anja Ishmukhametova

@notgiorgi Sorununuzu yeniden oluşturmak için yeterli ayrıntıya sahip yeni bir soru sormak ve işe yarayamayacağınızı söyleyerek buna bağlantı vermek en iyisidir.
loganfsmyth

22

Bu herhangi bir base64 görüntü biçimini okumak ve veritabanında uygun biçimde kaydetmek benim tam çözümdür:

    // Save base64 image to disk
    try
    {
        // Decoding base-64 image
        // Source: http://stackoverflow.com/questions/20267939/nodejs-write-base64-image-file
        function decodeBase64Image(dataString) 
        {
          var matches = dataString.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/);
          var response = {};

          if (matches.length !== 3) 
          {
            return new Error('Invalid input string');
          }

          response.type = matches[1];
          response.data = new Buffer(matches[2], 'base64');

          return response;
        }

        // Regular expression for image type:
        // This regular image extracts the "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);
    }

bana cevap verecek kimse var mı ?? bu konuda ??
iam

Ben sadece kodunu değiştirdim. fs.writeFile ("test.jpg", imageBuffer.data, işlev (err) {json_response ['success'] = true; res.json (json_response);}); görüntü yüklendi, ancak sonuç beni beğenme değil .. hata: 502 Res.json kötü Ağ Geçidi aslında sorun, neden bu yazdırmıyor ...
iam

18

GÜNCELLEME

Ben PHP ilginç sorunu çözmek için bu ilginç bağlantı bulundu . Ben değiştirmek unuttum düşünüyorum spacetarafından +linkte görüldüğü gibi.

Bu daireyi http://images-mediawiki-sites.thefullwiki.org/04/1/7/5/6204600836255205.png adresinden aşağıdaki gibi örnek olarak aldım :

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

Sonra http://www.greywyvern.com/code/php/binary2base64 aracılığıyla beni döndürdü koydu :

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

base64okuduğum bu dizeyi koduma kaydetti .

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

Bir daire geri alıyorum, ama komik olan şey dosya boyutunun değişmiş olması:) ...

SON

Resmi okuduğunuzda, üstbilgileri ayarlamanız gerektiğini düşünüyorum

PHP sayfasından imagepng örneğini ele alalım :

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

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

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

Sanırım ikinci satır header('Content-Type: image/png');, resminizin tarayıcıda gösterilmemesi önemlidir, ancak tarayıcıya sadece bir çift ikili veri gösterilir.

In Express basitçe hemen altında gibi bir şey kullanmak. Http://www.gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG adresinde bulunan ve siz bir jpeg dosyası olan gravatarınızı göstereceğim curl --head http://www.gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG. Yalnızca üstbilgiler talep ediyorum çünkü başka curl bir grup ikili öğeyi görüntüleyecek (Google Chrome hemen indirilecek):

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

Teşekkürler Alfred, ama bu minimal test durumunda, sunucudan hiçbir şey geri göndermiyorum. Sadece dosyayı sunucuda diske yazıyorum ve dosyanın kendisi geçerli bir görüntü değil gibi görünüyor. Base64'ün doğru olduğundan eminim, ancak ikili olarak yazarken bir sorun var gibi görünüyor.
mahemoff

1
Üzgünüm soruyu yanlış anladım: $. Yeniden deneyeceğim.
Alfred

1
Güncelleme için teşekkürler, ancak yer değiştirme benim için işe yaramadı ve Logan'ın çözümünü uyguladığımda aslında gerekli değildi. Referans olarak, tuval test durumumda çok basittir: var context = canvas.getContext ('2d'); context.fillStyle = "# f89"; context.fillRect (50,50,100,100);
mahemoff

Tamam çünkü bunu yaptığımda görüntüyü geri aldım, ama en azından problemin çözüldü: P
Alfred

İlginç, toString'in ("ikili") neden sizin durumunuzda bunu bozmadığından emin değilim. Her halükarda, base64'de boşluklar doğal olarak görünmemelidir, bu nedenle değiştirme tartışmalıdır. Yine de vermiş olduğum örnekle. (Ben MIME spec okuduktan sonra, elle yerleştirilen satırsonu ile bir varyant çalıştım çizgileri çoğunlukla paranoya üzerinden 72 karakterden daha büyük gerektirir ... o çalışmak çıkıyor veya toString sürece, satırbaşıyla olmadan ( "ikili" ) bırakılır.)
mahemoff

6

Ayrıca veri URL'lerinin bir parçası olan Base64 kodlu görüntüleri kaydetmek zorunda kaldım, bu yüzden gelecekte tekrar yapmak zorunda kaldım diye küçük bir npm modülü yapmakla sonuçlandım. Buna ba64 deniyor .

Basitçe söylemek gerekirse, Base64 kodlu bir görüntüye sahip bir veri URL'si alır ve görüntüyü dosya sisteminize kaydeder. Senkronize veya asenkronize olarak kaydedebilir. Ayrıca, biri görüntünün dosya uzantısını almak için diğeri de Base64 kodlamasını data:şema önekinden ayırmak için iki yardımcı işlevi vardır .

İşte bir örnek:

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

Kurun: npm i ba64 -S. Repo GitHub'da: https://github.com/HarryStevens/ba64 .

PS Daha sonra ba64 muhtemelen modül için kötü bir isim oldu çünkü insanlar Base64 kodlama ve kod çözme yaptığını varsayabilir, ki bunu yapmaz (zaten bunu yapan birçok modül vardır). Oh iyi.


2

Bu benim için basit ve mükemmel bir şekilde yaptı.

Scott Robinson'ın mükemmel açıklaması

Görüntüden base64 dizesine

let buff = fs.readFileSync('stack-abuse-logo.png');
let base64data = buff.toString('base64');

Base64 dizesinden resme

let buff = new Buffer(data, 'base64');
fs.writeFileSync('stack-abuse-logo-out.png', buff);

1

Base64 görüntüsünü dosyaya dönüştürmenin ve bazı rastgele kimlik veya ad olarak kaydetmenin kolay yolu .

// 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

Base64 dizesi ile dosyadan png görüntüsüne dönüştürme.

4 çeşit çalışır.

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

Dosyaları kaydetme fonksiyonunun altında, sadece base64 dosyanızı iletin, dosya adını DB'ye kaydedin.

import fs from 'fs';
 const uuid = require('uuid/v1');

/*Download the base64 image in the server and returns the filename and path of image.*/
function saveImage(baseImage) {
    /*path of the folder where your project is saved. (In my case i got it from config file, root path of project).*/
    const uploadPath = "/home/documents/project";
    //path of folder where you want to save the image.
    const localPath = `${uploadPath}/uploads/images/`;
    //Find extension of file
    const ext = baseImage.substring(baseImage.indexOf("/")+1, baseImage.indexOf(";base64"));
    const fileType = baseImage.substring("data:".length,baseImage.indexOf("/"));
    //Forming regex to extract base64 data of file.
    const regex = new RegExp(`^data:${fileType}\/${ext};base64,`, 'gi');
    //Extract base64 data.
    const base64Data = baseImage.replace(regex, "");
    const filename = `${uuid()}.${ext}`;

    //Check that if directory is present or not.
    if(!fs.existsSync(`${uploadPath}/uploads/`)) {
        fs.mkdirSync(`${uploadPath}/uploads/`);
    }
    if (!fs.existsSync(localPath)) {
        fs.mkdirSync(localPath);
    }
    fs.writeFileSync(localPath+filename, base64Data, 'base64');
    return filename;
}

1
Benim için çalıştı. Ve herhangi bir base64 dönüşümü için kullanılabilir. Her dosyayı genel olarak ele alır. Teşekkür ederim!
Guilherme Sampaio

1

Base64-img veya base64-to-image gibi bir üçüncü taraf kitaplığı kullanabilirsiniz .

  1. base64-img
const base64Img = require('base64-img');

const data = 'data:image/png;base64,...';
const destpath = 'dir/to/save/image';
const filename = 'some-filename';

base64Img.img(data, destpath, filename, (err, filepath) => {}); // Asynchronous using

const filepath = base64Img.imgSync(data, destpath, filename); // Synchronous using
  1. base64-to-görüntü
const base64ToImage = require('base64-to-image');

const base64Str = 'data:image/png;base64,...';
const path = 'dir/to/save/image/'; // Add trailing slash
const optionalObj = { fileName: 'some-filename', type: 'png' };

const { imageType, fileName } = base64ToImage(base64Str, path, optionalObj); // Only synchronous using
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.