目前流行的“你畫(huà)我猜”應用,你有沒(méi)有想過(guò)使用HTML5來(lái)實(shí)現過(guò)?那么不可避免的需要解決canvas保存圖片到硬盤(pán)或mongodb之類(lèi)的數據庫。本文主要介紹使用nodejs將html5 canvas base64編碼圖片保存為文件,同時(shí)提供兩種解決方案。
html5 canvas屬于客戶(hù)端API,沒(méi)有權限去保存圖片到硬盤(pán),只有canvas . toDataURL()這一個(gè)接口可導出畫(huà)布的base64編碼,以提供給服務(wù)端進(jìn)行處理保存,據我所知.net和php都有方法或類(lèi)來(lái)進(jìn)行簡(jiǎn)單的處理保存。nodejs呢?是的,沒(méi)錯!nodejs同樣有能力來(lái)保存base64編碼的圖片。
解決方案一:
使用new Buffer來(lái)創(chuàng )建對應編碼的緩沖,通過(guò)fs模塊將Buffer寫(xiě)成一個(gè)文件。
優(yōu)點(diǎn):簡(jiǎn)單易用,無(wú)需其它模塊的支持。
缺點(diǎn):不能對圖片的尺寸,水印,壓縮,格式等進(jìn)行處理。
注意點(diǎn):
1、new Buffer接收到base64編碼,不能帶data:URL,而使用canvas . toDataURL()導出的base64編碼會(huì )帶data:URL,所以需要先過(guò)濾掉
類(lèi)似這樣的一段“data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0”
需過(guò)濾成:“iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0”
2、’binary’ – 一種只使用每個(gè)字符前8個(gè)字節將原始的二進(jìn)制數據編碼進(jìn)字符串的方式。這個(gè)方式已經(jīng)廢棄,應當盡量使用buffer 對象。這個(gè)編碼將會(huì )在未來(lái)的node 中刪除。
看到有人把base64聲明的Buffer再轉換成binary,這個(gè)是完全沒(méi)必要的。
3、生成的圖片有size變化,但是打開(kāi)后是一個(gè)無(wú)效的圖像,這個(gè)看本文的第三點(diǎn)。
使用express搭建的/upload (POST)上傳保存接口,完成代碼如下:
var express = require('express');var fs = require("fs");var app = module.exports = express();//配置app.configure(function(){ app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(express.cookieParser('keyboard cat')); app.use(express.session()); app.use(app.router); app.use(express.static(__dirname + '/up')); //靜態(tài)文件目錄 app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));});//保存base64圖片POST方法app.post('/upload', function(req, res){ //接收前臺POST過(guò)來(lái)的base64 var imgData = req.body.imgData; //過(guò)濾data:URL var base64Data = imgData.replace(/^data:image\/\w+;base64,/, ""); var dataBuffer = new Buffer(base64Data, 'base64'); fs.writeFile("out.png", dataBuffer, function(err) { if(err){ res.send(err); }else{ res.send("保存成功!"); } });});if (!module.parent) { app.listen(8000); console.log('Express started on port 8000');}解決方案二:
使用node-canvas模塊進(jìn)行圖片處理和保存。
(node-canvas安裝見(jiàn)我的另一篇博文:http://www.2fz1.com/?p=246)
優(yōu)點(diǎn):能對圖片像html5 canvas一樣進(jìn)行處理,尺寸調整、水印、圖片反轉色、格式轉換
缺點(diǎn):需安裝模塊支持、當base64編碼有誤不能解析成圖片時(shí)會(huì )報錯并停止nodejs服務(wù)。
注意點(diǎn):canvas透明背景,默認為黑色;使用base64給img.src賦值時(shí),需帶上data:URL
使用express搭建的/upload (POST)上傳保存接口,完成代碼如下:
var Canvas = require('canvas'); //需安裝canvas模塊var express = require('express');var fs = require("fs");var app = module.exports = express();//配置app.configure(function(){ app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(express.cookieParser('keyboard cat')); app.use(express.session()); app.use(app.router); app.use(express.static(__dirname + '/up')); //靜態(tài)文件目錄 app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));});app.post('/upload', function(req, res){ var base64Data = req.body.imgData; var img = new Canvas.Image; img.onload = function(){ var w = img.width; var h = img.height; var canvas = new Canvas(w, h); var ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); var out = fs.createWriteStream(__dirname + '/crop.jpg'); var stream = canvas.createJPEGStream({ bufsize : 2048, quality : 80 }); stream.on('data', function(chunk){ out.write(chunk); }); stream.on('end', function(){ out.end(); res.send("上傳成功!"); }); } img.onerror = function(err){ res.send(err); } img.src = base64Data;});if (!module.parent) { app.listen(8000); console.log('Express started on port 3000');}容易出現的錯誤(base64編碼中,不容忽視的“+”號)
1、如果canvas沒(méi)有任何像素,則返回值為:“data:,”,這是最短的data:URL,代碼中最好做一下保護。
2、使用解決方案一實(shí)現圖片保存,生成的圖片有size,但是打開(kāi)后卻是不能識別的無(wú)效圖像。
使用解決方案二實(shí)現圖片保存,nodejs直接報錯,并且服務(wù)掛掉。
原因:
這個(gè)問(wèn)題,花了我很長(cháng)時(shí)間才找到原因,根本原因是base64編碼,使用express接收POST值后,base64編碼字符串中的“+”號被替換成空格了,引起編碼出錯,img.src = base64Data;直接把nodejs服務(wù)掛掉。如果你出現類(lèi)似問(wèn)題,請console.log(base64Data);看字符串是否有空格。
解決辦法:
將空格替換回“+”號
var base64Data = imgData.replace(/\s/g,"+");聯(lián)系客服