如何将 base64 编码的图像保存到磁盘?
Posted
技术标签:
【中文标题】如何将 base64 编码的图像保存到磁盘?【英文标题】:How can I save a base64-encoded image to disk? 【发布时间】:2011-10-19 01:18:09 【问题描述】:我的 Express 应用正在从浏览器接收 base64 编码的 PNG(使用 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
);
【问题讨论】:
我更新了答案,我认为这是您首先需要的;) 显然这不是您要求的,但是(就我而言)我意识到最好的方法是将整个编码字符串存储到我的数据库中(您始终可以使用 @ 加载它987654322@)。只是一个选项供其他使用此线程作为参考的人考虑。 【参考方案1】:更新
我发现了这个interesting link how to solve your problem in 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+49uos-s-ryjfvc0A1kLx4KC6sNSeDieD1AWhrJLe0y+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 的头像
当您curl --head http://www.gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=32&d=identicon&r=PG
时,它是一个 jpeg 文件。我只请求标头,因为否则 curl 会向控制台显示一堆二进制内容(谷歌浏览器立即去下载):
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 是正确的,但将其写成二进制似乎存在问题。 对不起,我误解了问题:$。我会再试一次。 感谢您的更新,但空间替换对我不起作用,并且在我应用 Logan 的解决方案时实际上没有必要。作为参考,画布在我的测试用例中非常简单: var context = canvas.getContext('2d'); context.fillStyle = "#f89"; context.fillRect(50,50,100,100); 好的,因为我这样做的时候得到了图像,但至少你的问题已经解决了:P 有趣,不知道为什么 toString("binary") 在你的情况下没有搞砸。无论如何,空格不应该自然地出现在base64中,所以替换应该是没有意义的。无论如何,这是我提供的示例。 (我确实尝试过手动插入换行符的变体,在阅读 MIME 规范后,要求行数不超过 72 个字符,主要是出于偏执……结果证明可以在没有换行符的情况下使用 或,因为只要 toString("binary") 被删除。)【参考方案2】:我认为您转换数据的次数超出了您的需要。使用正确编码创建缓冲区后,只需将缓冲区写入文件即可。
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 编码字符串,将输入字符串转换为 Buffer,它只是一个字节数组。然后你可以将该字节数组写入文件。
更新
正如 cmets 中所述,req.rawBody
不再是一个东西。如果您使用express
/connect
,那么您应该使用bodyParser()
中间件并使用req.body
,如果您使用标准Node 执行此操作,那么您需要聚合传入的data
事件Buffer
对象并在end
回调中进行此图像数据解析。
【讨论】:
另外,您的示例中的 writeFile 参数有一个小错误:“bufferData”->“dataBuffer”。 @RJ。req.rawBody
包含编码为数据 URL 的请求数据:developer.mozilla.org/en-US/docs/data_URIs。因此,您必须剥离开始部分才能只保存要保存的 base64 数据。
这是很棒的东西,谢谢!对于将来发现这一点的人来说,rawBody 不再是 req 的属性。您必须使用 express body parser 中间件来获取数据。
var base64Data = req.rawBody.split(',')[1];
@notgiorgi 最好提出一个新问题,并提供足够详细的信息来重现您的问题,并链接到此问题,说明您无法使其正常工作。【参考方案3】:
这是我的完整解决方案,它可以读取任何 base64 图像格式并将其以适当的格式保存在数据库中:
// Save base64 image to disk
try
// Decoding base-64 image
// Source: http://***.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);
【讨论】:
有人来回答我吗?关于这个?? 我刚刚修改了你的代码。 fs.writeFile("test.jpg", imageBuffer.data, function(err) json_response['success'] = true; res.json(json_response); );图片已上传,但结果不是我喜欢的那样.. 错误:res.json 中的 502 Bad Gateway 实际上有问题,为什么不打印... 这个答案是救命稻草!【参考方案4】:将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
【讨论】:
【参考方案5】:我还必须保存作为数据 URL 一部分的 Base64 编码图像,因此我最终制作了一个小型 npm 模块来执行此操作,以防我(或其他人)将来需要再次执行此操作。它叫做ba64。
简单地说,它需要一个带有 Base64 编码图像的数据 URL,并将图像保存到您的文件系统中。它可以同步或异步保存。它还有两个辅助函数,一个用来获取图片的文件扩展名,另一个用来将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
。 Repo 在 GitHub 上:https://github.com/HarryStevens/ba64。
附:后来我想到 ba64 可能是该模块的一个坏名字,因为人们可能会认为它进行 Base64 编码和解码,但事实并非如此(有很多模块已经这样做了)。哦,好吧。
【讨论】:
【参考方案6】:从带有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();
【讨论】:
【参考方案7】:下面的函数保存文件,只需传递你的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;
【讨论】:
为我工作。它可以用于任何 base64 转换。它一般处理每个文件。谢谢!【参考方案8】:这对我来说简单而完美。
Excellent explanation by 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);
【讨论】:
通过将 new 替换为 .from 来更新答案,以消除安全警告【参考方案9】:您可以使用第三方库,例如 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 到图像
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 编码的图像保存到磁盘?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 PHP 从 base64 编码的数据/字符串创建图像并将其保存到网站文件夹
在 Django Rest Framework 中接收 Base64 编码的图像并保存到 ImageField
Python 3图像base64而不保存到html img标签