【已知】
canvas提供了toDataURL的接口,可以方便的将canvas画布转化成base64编码的image。目前支持的最好的是png格式,jpeg格式的现代浏览器基本也支持,但是支持的不是很好。

【想要的】
往往这么简单直接的接口通常都满足不了需求。我想要的不仅是简单的通过画布生成一个png,我不想新开一个tab,然后还要右键另存为...

我还需要更方便的自由的配置生成的图片的大小,比例等。

另外如果我还要别的图片格式,比如位图bmp,gif等怎么办...

【解决办法】
a)想直接把图片生成后download到本地,其实办法也很简单。直接改图片的mimeType,强制改成steam流类型的。比如‘image/octet-stream’,浏览器就会自动帮我们另存为..

b)图片大小,及比例的可控倒也好办,我们新建一个我们想要大小的canvas,把之前的canvas画布重新按照所要的比例,及大小draw到新的canvas上,然后用新的canvas来toDataURL即可。

c)想要bmp位图会麻烦些... 没有直接的接口,需要我们自己来生成。生成图片的响应头和响应体有一定的规则,略显麻烦。不过还能接受。剩下的就是性能问题,按像素级别来操作,对于一个大图来说计算量很有压力。

【实现】

/*** covert canvas to image* and save the image file*/var Canvas2Image = function () {// check if support sth.var $support = function () {var canvas = document.createElement('canvas'),ctx = canvas.getContext('2d');return {canvas: !!ctx,imageData: !!ctx.getImageData,dataURL: !!canvas.toDataURL,btoa: !!window.btoa};}();var downloadMime = 'image/octet-stream';function scaleCanvas (canvas, width, height) {var w = canvas.width,h = canvas.height;if (width == undefined) {width = w;}if (height == undefined) {height = h;}var retCanvas = document.createElement('canvas');var retCtx = retCanvas.getContext('2d');retCanvas.width = width;retCanvas.height = height;retCtx.drawImage(canvas, 0, 0, w, h, 0, 0, width, height);return retCanvas;}function getDataURL (canvas, type, width, height) {canvas = scaleCanvas(canvas, width, height);return canvas.toDataURL(type);}function saveFile (strData) {document.location.href = strData;}function genImage(strData) {var img = document.createElement('img');img.src = strData;return img;}function fixType (type) {type = type.toLowerCase().replace(/jpg/i, 'jpeg');var r = type.match(/png|jpeg|bmp|gif/)[0];return 'image/' + r;}function encodeData (data) {if (!window.btoa) { throw 'btoa undefined' }var str = '';if (typeof data == 'string') {str = data;} else {for (var i = 0; i < data.length; i ++) {str += String.fromCharCode(data[i]);}}return btoa(str);}function getImageData (canvas) {var w = canvas.width,h = canvas.height;return canvas.getContext('2d').getImageData(0, 0, w, h);}function makeURI (strData, type) {return 'data:' + type + ';base64,' + strData;}/*** create bitmap image* 按照规则生成图片响应头和响应体*/var genBitmapImage = function (data) {var imgHeader = [],imgInfoHeader = [];var width = data.width,height = data.height;imgHeader.push(0x42); // 66 -> BimgHeader.push(0x4d); // 77 -> Mvar fsize = width * height * 3 + 54; // header size:54 bytesimgHeader.push(fsize % 256); // rfsize = Math.floor(fsize / 256);imgHeader.push(fsize % 256); // gfsize = Math.floor(fsize / 256);imgHeader.push(fsize % 256); // bfsize = Math.floor(fsize / 256);imgHeader.push(fsize % 256); // aimgHeader.push(0);imgHeader.push(0);imgHeader.push(0);imgHeader.push(0);imgHeader.push(54); // offset -> 6imgHeader.push(0);imgHeader.push(0);imgHeader.push(0);// info headerimgInfoHeader.push(40); // info header sizeimgInfoHeader.push(0);imgInfoHeader.push(0);imgInfoHeader.push(0);// 横向infovar _width = width;imgInfoHeader.push(_width % 256);_width = Math.floor(_width / 256);imgInfoHeader.push(_width % 256);_width = Math.floor(_width / 256);imgInfoHeader.push(_width % 256);_width = Math.floor(_width / 256);imgInfoHeader.push(_width % 256);// 纵向infovar _height = height;imgInfoHeader.push(_height % 256);_height = Math.floor(_height / 256);imgInfoHeader.push(_height % 256);_height = Math.floor(_height / 256);imgInfoHeader.push(_height % 256);_height = Math.floor(_height / 256);imgInfoHeader.push(_height % 256);imgInfoHeader.push(1);imgInfoHeader.push(0);imgInfoHeader.push(24); // 24位bitmapimgInfoHeader.push(0);// no compressionimgInfoHeader.push(0);imgInfoHeader.push(0);imgInfoHeader.push(0);imgInfoHeader.push(0);// pixel datavar dataSize = width * height * 3;imgInfoHeader.push(dataSize % 256);dataSize = Math.floor(dataSize / 256);imgInfoHeader.push(dataSize % 256);dataSize = Math.floor(dataSize / 256);imgInfoHeader.push(dataSize % 256);dataSize = Math.floor(dataSize / 256);imgInfoHeader.push(dataSize % 256);// blank spacefor (var i = 0; i < 16; i ++) {imgInfoHeader.push(0);}var padding = (4 - ((width * 3) % 4)) % 4;var imgData = data.data;var strPixelData = '';var y = height;do {var offsetY = width * (y - 1) * 4;var strPixelRow = '';for (var x = 0; x < width; x ++) {var offsetX = 4 * x;strPixelRow += String.fromCharCode(imgData[offsetY + offsetX + 2]);strPixelRow += String.fromCharCode(imgData[offsetY + offsetX + 1]);strPixelRow += String.fromCharCode(imgData[offsetY + offsetX]);}for (var n = 0; n < padding; n ++) {strPixelRow += String.fromCharCode(0);}strPixelData += strPixelRow;} while(-- y);return (encodeData(imgHeader.concat(imgInfoHeader)) + encodeData(strPixelData));};/*** saveAsImage* @param canvasElement* @param {String} image type* @param {Number} [optional] png width* @param {Number} [optional] png height*/var saveAsImage = function (canvas, width, height, type) {if ($support.canvas && $support.dataURL) {if (type == undefined) { type = 'png'; }type = fixType(type);if (/bmp/.test(type)) {var data = getImageData(scaleCanvas(canvas, width, height));var strData = genBitmapImage(data);saveFile(makeURI(strData, downloadMime));} else {var strData = getDataURL(canvas, type, width, height);saveFile(strData.replace(type, downloadMime));}}}var convertToImage = function (canvas, width, height, type) {if ($support.canvas && $support.dataURL) {if (type == undefined) { type = 'png'; }type = fixType(type);if (/bmp/.test(type)) {var data = getImageData(scaleCanvas(canvas, width, height));var strData = genBitmapImage(data);return genImage(makeURI(strData, 'image/bmp'));} else {var strData = getDataURL(canvas, type, width, height);return genImage(strData);}}}return {saveAsImage: saveAsImage,saveAsPNG: function (canvas, width, height) {return saveAsImage(canvas, width, height, 'png');},saveAsJPEG: function (canvas, width, height) {return saveAsImage(canvas, width, height, 'jpeg');            },saveAsGIF: function (canvas, width, height) {return saveAsImage(canvas, width, height, 'gif')           },saveAsBMP: function (canvas, width, height) {return saveAsImage(canvas, width, height, 'bmp');           },convertToImage: convertToImage,convertToPNG: function (canvas, width, height) {return convertToImage(canvas, width, height, 'png');},convertToJPEG: function (canvas, width, height) {return convertToImage(canvas, width, height, 'jpeg');               },convertToGIF: function (canvas, width, height) {return convertToImage(canvas, width, height, 'gif');              },convertToBMP: function (canvas, width, height) {return convertToImage(canvas, width, height, 'bmp');              }};}();

【Demo】
http://hongru.github.com/proj/canvas2image/index.html
可以试着在canvas上涂涂画画,然后保存看看。如果用bmp格式的话,需要支持 btoa 的base64编码,关于base64编码规则可看上一篇博文

【不完美的地方】
1)jpeg接口本身就不完善,当canvas没有填充颜色或图片时,保存的jpeg由于是直接由png的alpha通道强制转换过来的,所以在png的透明部分在jpeg里面就是黑色的。

2)gif的限制太多。且可用性不大,有png就够了

3)bmp位图生成,计算量稍显大了。

4)由于是强制改mimeType来实现的自动下载,所以下载的时候文件类型不会自动识别。

原文:http://www.cnblogs.com/hongru/archive/2012/01/14/2322540.html

index.html

<!doctype html>
<html>
<meta charset="utf-8" />
<script src="canvas2image.js"></script>
<style>.doc {width: 604px;margin: 0 auto;}canvas {display: block;border: 2px solid #888;}
</style>
<body>
<div class="doc"><canvas width="600" height="400" id="cvs"></canvas><div><p><button id="save">save</button> or <button id="convert">convert to</button> as: <select id="sel"><option value="png">png</option><option value="jpeg">jpeg</option><option value="bmp">bmp</option></select><br/>width : <input type="number" value="300" id="imgW" /><br/>height : <input type="number" value="200" id="imgH" /></p></div><div id="imgs"></div>
</div>
<script>var canvas, ctx, bMouseIsDown = false, iLastX, iLastY,$save, $imgs,$convert, $imgW, $imgH,$sel;function init () {canvas = document.getElementById('cvs');ctx = canvas.getContext('2d');$save = document.getElementById('save');$convert = document.getElementById('convert');$sel = document.getElementById('sel');$imgs = document.getElementById('imgs');$imgW = document.getElementById('imgW');$imgH = document.getElementById('imgH');bind();draw();}function bind () {canvas.onmousedown = function(e) {bMouseIsDown = true;iLastX = e.clientX - canvas.offsetLeft + (window.pageXOffset||document.body.scrollLeft||document.documentElement.scrollLeft);iLastY = e.clientY - canvas.offsetTop + (window.pageYOffset||document.body.scrollTop||document.documentElement.scrollTop);}canvas.onmouseup = function() {bMouseIsDown = false;iLastX = -1;iLastY = -1;}canvas.onmousemove = function(e) {if (bMouseIsDown) {var iX = e.clientX - canvas.offsetLeft + (window.pageXOffset||document.body.scrollLeft||document.documentElement.scrollLeft);var iY = e.clientY - canvas.offsetTop + (window.pageYOffset||document.body.scrollTop||document.documentElement.scrollTop);ctx.moveTo(iLastX, iLastY);ctx.lineTo(iX, iY);ctx.stroke();iLastX = iX;iLastY = iY;}};$save.onclick = function (e) {var type = $sel.value,w = $imgW.value,h = $imgH.value;Canvas2Image.saveAsImage(canvas, w, h, type);}$convert.onclick = function (e) {var type = $sel.value,w = $imgW.value,h = $imgH.value;$imgs.appendChild(Canvas2Image.convertToImage(canvas, w, h, type))}}function draw () {ctx.fillStyle = '#ffffff';ctx.fillRect(0, 0, 600, 400);ctx.fillStyle = 'red';ctx.fillRect(100, 100, 50, 50);}onload = init;
</script>
</body>
</html>

canvas保存为data:image扩展功能的实现相关推荐

  1. uniapp 小程序 APP 实现手写板 签名 画图 canvas 保存为图片格式

    文章目录 uniapp 小程序 APP 实现手写板 签名 画图 canvas 保存为图片格式 一.手写板 1.H5代码 2.JS代码 总结 uniapp 小程序 APP 实现手写板 签名 画图 can ...

  2. canvas保存到本地图片三种方法

    canvas保存到本地图片三种方法 canvas保存本地图片 第一种方法(修改图片的媒体类型,window.open直接下载) 第二种方法(创建a标签,通过自己触发点击来下载) 第三种方法(将图片数据 ...

  3. js将canvas保存成图片并下载

    <canvas id="canvas" width="400" height="400"></canvas> < ...

  4. js大屏导出图片_js将canvas保存成图片并下载

    保存 var arr = [ {locations:[[0,0],[200,200],[0,400]],color:"red"}, {locations:[[0,0],[400,0 ...

  5. 图片在canvas中显示,给canvas添加文字,文字描边,将canvas保存成图片下载到本地

    Canvas简介 HTML5新增标签 Canvas API(画布)是在HTML5中新增的标签用于在网页实时生成图像,并且可以操作图像内容,基本上它是一个可以用JavaScript操作的位图(bitma ...

  6. Web开发之用canvas2image.js将canvas保存为图片(实现页面截图下载功能)

    关于实现页面截图常用的几个js插件库 canvas2image.js html2canvas.js convertImgToBase64.js 废话不多说,直接上demo代码 index.html: ...

  7. html canvas保存为图片,在HTML5 Canvas中放入图片和保存为图片的方法

    第一种方式 如果是使用的图片的话,就会涉及到canvas的图片跨域问题,因为canvas是禁止跨域的,如果图像来自其他域,调用toDataURL()会抛出一个错误 需要添加"img.cros ...

  8. js实现将canvas保存成图片并下载到本地

    //图片导出为 png 格式 var type = 'png'; var imgData = canvas.toDataURL(type);/*** 获取mimeType* @param {Strin ...

  9. vue使用canvas保存页面为图片,得到图片url

    bug:后台返的网络图片路径保存不下来,返回base64格式即可 保存图片的方式 import html2canvas from "html2canvas"; // 点击上传,获取 ...

最新文章

  1. 通讯系统经验谈【一】TCP连接状态分析:SYNC_RECV,CLOSE_WAIT,TIME_WAIT
  2. c语言equal,C ++中的ratio_equal()示例
  3. spring整合ehcache2.5.2缓存异常-- net.sf.ehcache.CacheException
  4. go reflect 取指针_Go之如何操作结构体的非导出字段
  5. gulp-cli命令安装出错_一个牛逼的数据库操作命令行工具:mycli
  6. vue 设置背景图地址_vue-生成自动铺满的背景图
  7. python进程数上限_在多处理python中限制进程数
  8. 新人如何适应自己的领导
  9. 2020还有必要学JSP吗?
  10. gms认证流程_GMS测试认证的具体操作流程
  11. mysql命令行备份数据库
  12. Pycharm Debug调试(纯干货)
  13. Tomcat启动报Exception in thread “main“ java.lang.UnsatisfiedLinkError: no secure-tomcat in java.library
  14. uvalive 6657 GCD XOR
  15. python+selenium高级教程
  16. B - 爆零(×)大力出奇迹(√) HDU - 2093
  17. 古城南京,加“数”前进——CDEC2021中国数字智能生态大会走进南京
  18. 用python制作微信机器人程序编写_Python制作微信聊天机器人
  19. 许家印的中秋行程单,恒大造车的“全球化”
  20. CSS3:图片的高斯模糊效果

热门文章

  1. Catch That Cow(POJ-3278)
  2. 信息学奥赛C++语言: 趣味整数3(回文数)
  3. 基于theano的keras安装
  4. 35 SD配置-销售凭证设置-定义项目类别组
  5. easypoi 如何合并相同的列_easy_poi合并行以及样式调整
  6. keep健身软件电脑版_电脑软件:优酷 (优化版)
  7. NOIP 2007 普及组初赛试题(C++)(无答案)
  8. python有什么用途视频_使用Python管理多平台视频流的最佳方法是什么?
  9. opencv学习笔记3
  10. IDEA查看Scala的源码