NodeJS : base64로 인코딩 된 이미지를 디스크에 저장


162

My Express 앱이 브라우저에서 base64로 인코딩 된 PNG를 가져오고 (toDataURL ()을 사용하여 canvas에서 생성) 파일에 씁니다. 그러나 파일은 유효한 이미지 파일이 아니며 "file"유틸리티는 단순히 "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
});

1
나는 당신이 처음에 필요한 것이라고 생각하는 답변을 업데이트했습니다.)
Alfred

분명히 이것은 당신이 요구 한 것이 아니지만 (내 경우에는) 가장 좋은 방법은 전체 인코딩 된 문자열을 내 데이터베이스에 저장하는 것임을 깨달았습니다 (항상을 사용하여로드 할 수 있음 <img src="data:image/png;base64,..." />). 이 스레드를 참조로 사용하는 다른 사람들에게 고려할 옵션입니다.
JSideris

답변:


324

나는 당신이 필요 이상으로 데이터를 조금 더 변환하고 있다고 생각합니다. 적절한 인코딩으로 버퍼를 만들면 버퍼를 파일에 쓰면됩니다.

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

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

new Buffer (..., 'base64')는 입력을 base64 인코딩 문자열로 해석하여 입력 문자열을 바이트 배열 인 버퍼로 변환합니다. 그런 다음 해당 바이트 배열을 파일에 쓸 수 있습니다.

최신 정보

의견에서 언급했듯이 req.rawBody더 이상 문제가되지 않습니다. 당신이 사용하는 경우 express/ connect당신은 사용해야 bodyParser()미들웨어 및 사용 req.body, 당신은 표준 노드를 사용하여이 작업을 수행하는 경우 당신은 들어오는 집계 할 필요가 data이벤트 Buffer객체와의 구문 분석이 이미지 데이터 할 end콜백을.


2
또한 예제의 writeFile 인수에 약간의 오타가 있습니다 : "bufferData"-> "dataBuffer".
mahemoff

@RJ. req.rawBody데이터 URL로 인코딩 된 요청 데이터가 포함되어 있습니다 ( developer.mozilla.org/en-US/docs/data_URIs) . 따라서 base64 데이터 만 저장하려면 시작 부분을 제거해야합니다.
loganfsmyth

2
감사합니다! 미래에 이것을 발견하는 사람들에게 rawBody는 더 이상 req의 속성이 아닙니다. 데이터를 가져 오려면 express body 구문 분석기 미들웨어를 사용해야합니다.
DigitalDesignDj

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

@notgiorgi 문제를 재현하기에 충분한 세부 정보가 포함 된 새로운 질문을하고 문제를 해결할 수 없다는 내용의 질문에 연결하는 것이 가장 좋습니다.
loganfsmyth

22

이것은 모든 base64 이미지 형식을 읽고 데이터베이스에 적절한 형식으로 저장하는 전체 솔루션입니다.

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

여기에 나에게 대답하는 사람이 있습니까 ?? 이것을 고려하면??
iam

방금 코드를 수정했습니다. fs.writeFile ( "test.jpg", imageBuffer.data, function (err) {json_response [ 'success'] = true; res.json (json_response);}); 이미지가 업로드되었지만 결과는 나에게 마음에 들지 않습니다. error : 502 잘못된 게이트웨이 res.json에서 실제로 문제가 발생하는 이유는 무엇입니까?
iam

18

최신 정보

PHP에서 문제를 해결하는 방법에 대한 흥미로운 링크를 찾았습니다 . 링크에 표시된대로 교체 space하는 것을 잊었다 고 생각합니다 +.

http://images-mediawiki-sites.thefullwiki.org/04/1/7/5/6204600836255205.png 에서이 원 을 다음과 같은 샘플로 가져 왔습니다 .

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

다음으로 http://www.greywyvern.com/code/php/binary2base64 를 통해 알려주었습니다.

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

base64코드에서 읽은 이 문자열을 저장했습니다 .

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

원을 다시 얻었지만 재미있는 것은 파일 크기가 변경되었다는 것입니다. :) ...

종료

이미지를 읽을 때 헤더를 설정해야한다고 생각합니다.

PHP 페이지에서 imagepng 를 예로 들어 보겠습니다 .

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

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

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

두 번째 줄 header('Content-Type: image/png');은 중요합니다. 그렇지 않으면 이미지가 브라우저에 표시되지 않지만 이진 데이터가 브라우저에 표시됩니다.

Express 에서는 간단히 다음과 같은 것을 사용합니다. http://www.gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG 에있는 Gravatar를 표시 하고 jpeg 파일 curl --head http://www.gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG입니다. curl은 콘솔에 바이너리 파일 (Google Chrome 즉시 다운로드로 이동)을 표시하기 때문에 헤더 만 요청합니다.

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

감사합니다 Alfred, 그러나이 최소한의 테스트 사례에서는 서버에서 아무것도 다시 보내지 않습니다. 파일을 서버의 디스크에 쓰는 것만으로 파일 자체가 유효한 이미지가 아닌 것 같습니다. 나는 base64가 옳다는 것을 확신하지만 바이너리로 쓰는 데 문제가있는 것으로 보입니다.
mahemoff

1
: $ 질문을 오해해서 죄송합니다. 다시 시도하겠습니다.
Alfred

1
업데이트 해 주셔서 감사하지만 공간 대체가 효과가 없었으며 Logan의 솔루션을 적용 할 때 실제로 필요하지 않았습니다. 참고로 캔버스는 테스트 사례에서 매우 간단합니다. var context = canvas.getContext ( '2d'); context.fillStyle = "# f89"; context.fillRect (50,50,100,100);
mahemoff

좋아, 내가 이렇게했을 때 이미지를 다시 얻을 수 있지만 적어도 당신의 문제가 해결되었습니다 : P
Alfred

흥미롭게도, 왜 toString ( "binary")이 당신의 경우에 그것을 망쳐 놓지 않았는지 확실하지 않습니다. 어쨌든 공백은 base64에 자연스럽게 나타나지 않아야하므로 교체해야합니다. 어쨌든 내가 제공 한 예와 같습니다. (필자는 MIME 사양을 읽은 후, 수동으로 삽입 줄 바꿈과 변형을 시도했다가 라인을 주로 편집증 중 72 개 문자보다 크지 필요하지 않습니다 ... 그것은 함께 작동하도록 밝혀 또는 toString만큼의 줄 바꿈없이 ( "바이너리" )가 삭제되었습니다.)
mahemoff

6

또한 데이터 URL의 일부인 Base64 인코딩 이미지를 저장해야했기 때문에 나중에 (또는 다른 사람이) 나중에 다시 수행해야 할 경우에 대비하여 작은 npm 모듈을 만들었습니다. 이름은 ba64 입니다.

간단히 말해 Base64로 인코딩 된 이미지가있는 데이터 URL을 가져와 이미지를 파일 시스템에 저장합니다. 동기식 또는 비동기식으로 저장할 수 있습니다. 또한 이미지의 파일 확장자를 가져 오는 것과 다른 하나는 data:스키마 접두사 와 Base64 인코딩을 분리하는 두 가지 도우미 기능이 있습니다 .

예를 들면 다음과 같습니다.

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

설치하십시오 : npm i ba64 -S. Repo는 GitHub에 있습니다 ( https://github.com/HarryStevens/ba64) .

추신 : 사람들이 Base64 인코딩 및 디코딩을 수행한다고 가정 할 수 있기 때문에 ba64는 아마도 모듈의 나쁜 이름 일 것입니다. 오 잘


2

이것은 간단하고 완벽하게 나를 위해했습니다.

Scott Robinson의 훌륭한 설명

이미지에서 base64 문자열로

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

base64 문자열에서 이미지로

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

1

base64 이미지를 파일 로 변환 하고 임의의 ID 또는 이름으로 저장하는 쉬운 방법 .

// 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 문자열이있는 파일에서 png 이미지로 변환

작동하는 4 가지 변형.

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

파일을 저장하는 함수 아래에서 base64 파일을 전달하면 파일 이름이 DB에 저장됩니다.

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
나를 위해 일했다. 또한 모든 base64 변환에 사용할 수 있습니다. 모든 파일을 일반적으로 처리합니다. 감사합니다!
Guilherme Sampaio

1

base64-img 또는 base64-to-image 와 같은 타사 라이브러리를 사용할 수 있습니다 .

  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에서 이미지로
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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.