NodeJS: сохранение изображения в кодировке base64 на диск
Приложение My Express получает PNG-кодировку в формате base64 из браузера (сгенерированную из canvas с помощью toDataURL()) и записывает ее в файл. Но файл не является допустимым файлом изображения, и утилита "файл" просто определяет его как "данные".
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
});
10 ответов
Я думаю, что вы конвертируете данные немного больше, чем нужно. Как только вы создадите буфер с правильной кодировкой, вам просто нужно записать буфер в файл.
var base64Data = req.rawBody.replace(/^data:image\/png;base64,/, "");
require("fs").writeFile("out.png", base64Data, 'base64', function(err) {
console.log(err);
});
new Buffer (..., 'base64') преобразует входную строку в Buffer, который является просто массивом байтов, интерпретируя входные данные как строку в кодировке base64. Затем вы можете просто записать этот байтовый массив в файл.
Обновить
Как уже упоминалось в комментариях, req.rawBody
больше не вещь. Если вы используете express
/connect
тогда вы должны использовать bodyParser()
промежуточное программное обеспечение и использование req.body
и если вы делаете это с использованием стандартного узла, то вам нужно агрегировать входящие data
событие Buffer
объекты и сделать этот анализ данных изображения в end
Перезвоните.
Это мое полное решение, которое будет читать любой формат изображения base64 и сохранять его в нужном формате в базе данных:
// Save base64 image to disk
try
{
// Decoding base-64 image
// Source: http://stackru.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);
}
Это сделало это для меня просто и идеально.
Отличное объяснение Скотта Робинсона
От изображения к строке 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);
ОБНОВИТЬ
Я нашел эту интересную ссылку, как решить вашу проблему в PHP. Я думаю, что вы забыли заменить space
от +
как показано в ссылке.
Я взял этот круг из 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
});
Я получаю круг обратно, но забавно то, что размер файла изменился:)...
КОНЕЦ
Когда вы читаете обратно изображение, я думаю, что вам нужно настроить заголовки
Взять, к примеру, imagepng со страницы PHP:
<?php
$im = imagecreatefrompng("test.png");
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);
?>
Я думаю вторая строка header('Content-Type: image/png');
, важно, иначе ваше изображение не будет отображаться в браузере, но только бинарные данные отображаются в браузере.
В Экспресс вы просто используете что-то вроде ниже. Я собираюсь показать ваш граватар, который находится по адресу http://www.gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG и является файлом 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
Мне также пришлось сохранять изображения в кодировке Base64, которые являются частью URL-адресов данных, поэтому я сделал небольшой модуль npm для этого на тот случай, если мне (или кому-то еще) понадобится сделать это снова в будущем. Это называется ba64.
Проще говоря, он берет URL-адрес данных с изображением в кодировке Base64 и сохраняет изображение в вашей файловой системе. Это может сохранить синхронно или асинхронно. Он также имеет две вспомогательные функции, одну для получения расширения файла изображения, а другую для отделения кодировки Base64 от data:
префикс схемы.
Вот пример:
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
, Репо находится на GitHub: https://github.com/HarryStevens/ba64.
Позже мне пришло в голову, что ba64 - это, вероятно, плохое имя для модуля, поскольку люди могут предположить, что он выполняет кодирование и декодирование Base64, а это не так (многие модули уже это делают). Ну что ж.
Ниже функция сохранения файлов, просто передайте файл base64, он возвращает имя файла и сохраняет его в БД.
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;
}
Blockquote
Вы можете использовать стороннюю библиотеку, такую как base64-img или base64-to-image.
- 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
- base64-to-image
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
Преобразование из файла со строкой 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();
Простой способ конвертировать base64- изображение в файл и сохранить его как произвольный идентификатор или имя.
// 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
очень просто
const path = require('path');
const { readFile, stat, writeFile } = require("fs/promises");
(async () => {
try {
const contents = await readFile(path.join(__dirname, 'clau.jpg'), { encoding: 'base64' });
console.log(contents);
await writeFile(path.join(__dirname, 'claumia.jpg'), Buffer.from(contents, 'base64'));
} catch (error) {
console.log(error)
}
})()