【已知】
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 -> B imgHeader.push(0x4d); // 77 -> M var fsize = width * height * 3 + 54; // header size:54 bytes imgHeader.push(fsize % 256); // r fsize = Math.floor(fsize / 256); imgHeader.push(fsize % 256); // g fsize = Math.floor(fsize / 256); imgHeader.push(fsize % 256); // b fsize = Math.floor(fsize / 256); imgHeader.push(fsize % 256); // a imgHeader.push(0); imgHeader.push(0); imgHeader.push(0); imgHeader.push(0); imgHeader.push(54); // offset -> 6 imgHeader.push(0); imgHeader.push(0); imgHeader.push(0); // info header imgInfoHeader.push(40); // info header size imgInfoHeader.push(0); imgInfoHeader.push(0); imgInfoHeader.push(0); // 横向info var _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); // 纵向info var _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位bitmap imgInfoHeader.push(0); // no compression imgInfoHeader.push(0); imgInfoHeader.push(0); imgInfoHeader.push(0); imgInfoHeader.push(0); // pixel data var 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 space for (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>
相关推荐
本项目"基于html2canvas生成带二维码的活动海报"提供了一个纯前端解决方案,使得开发者无需后端支持也能快速实现此类功能。html2canvas是一个JavaScript库,它能够将网页的DOM(文档对象模型)渲染为图片,从而解决...
总的来说,canvas2image.js是Web开发中一个实用的工具,它扩展了canvas的功能,使开发者能够轻松地将动态图形保存为静态图像,提升了用户体验。结合indexss.js文件,可能是提供了一些示例代码或额外的功能,使得在...
本主题聚焦于使用canvas技术实现电子签名并将其保存为图片的功能。Canvas是HTML5提供的一种强大的图形绘制工具,它允许开发者通过JavaScript在网页上进行动态图形编程。以下是对这个知识点的详细阐述: 首先,我们...
在本文中,我们将探讨如何使用JavaScript和HTML5的Canvas API实现图片在线格式转换,包括WebP、PNG和JPEG。...此外,可以扩展此功能,实现批量图片转换或提供更丰富的图片调整选项,如压缩级别、尺寸调整等。
这可以通过调用`toDataURL()`方法完成,它会返回一个dataURL,表示canvas的内容,格式通常是`data:image/png;base64`。例如: ```javascript var dataURL = canvas.toDataURL(); ``` 有了dataURL,我们就可以创建...
5. **保存功能**: - 保存Canvas内容为图片,可以利用`toDataURL`方法,它会返回一个包含当前画布内容的data URL。 - 将这个URL转换为Blob对象,再使用FileSaver.js等库实现本地下载,或者通过Ajax发送到服务器...
以下我们将详细讲解如何使用canvas和JavaScript来实现这一功能。 首先,我们需要创建一个canvas元素,并将待处理的图片加载到canvas的上下文环境中。在JavaScript中,我们可以使用`<canvas>`的`getContext()`方法...
本话题主要关注如何在uniapp中实现一个功能,即“将网页保存为图片并保存到手机相册”。这个功能在很多场合都十分实用,例如用户想保存网页内容作为参考或者分享给他人。 首先,我们需要理解uniapp的架构。uniapp是...
HTML5 Canvas技术是Web开发中的一个关键特性,它允许开发者在网页上绘制图形,实现动态交互的效果。...通过研究这个游戏的源码,开发者可以深入理解Canvas绘图的原理,并且可以在此基础上扩展出更多有趣的互动功能。
这样,我们就实现了基于Canvas的对比度调整功能。这个例子中的"对比度demo"可能包含一个完整的示例代码,演示了如何在实际项目中应用上述逻辑。你可以通过下载并查看这个示例,进一步了解和学习如何在JavaScript中...
在某些情况下,我们可能需要将SVG图形转换为PNG格式,例如为了兼容不支持SVG的浏览器,或者在网页上实现特定功能。本文将详细介绍如何使用JavaScript实现SVG到PNG的转换,并提供一个实际的js实例。 首先,SVG到PNG...
总结来说,HTML5的拍照和上传功能实现涉及到的技术点包括:Media Capture API的使用、Video标签和getUserMedia方法的应用、Canvas元素的图像绘制和数据转换,以及前端AJAX与后端数据处理的交互。通过这些技术的组合...
这个方法会返回一个包含Canvas内容的data URL,其格式通常为"data:image/png;base64,",这是一种Base64编码的PNG图片数据。你可以直接将这个URL作为标签的src属性,或者通过AJAX发送到服务器保存。 以下是一个简单...
这可以通过Canvas的`toDataURL`方法实现,它会返回一个包含画布内容的data URL: ```javascript function exportImage() { var dataURL = canvas.toDataURL('image/png'); // 可以将dataURL设置为img元素的src,...
而Canvas to Blob则是一个JavaScript库,它扩展了Canvas的功能,使得我们可以将Canvas上的图形转换为Blob对象,这对于数据存储和传输非常有用。 Blob(Binary Large Object)是JavaScript中用于处理二进制数据的...
这可以通过在canvas上先绘制二维码,再在其指定位置绘制图片实现。例如,假设我们有一个`logo.png`作为中间的图片: ```javascript var logo = new Image(); logo.src = 'logo.png'; logo.onload = function() { ...
综上所述,通过结合AlloyFinger手势库和PHP,我们可以实现对Canvas图像的交互控制以及图片的保存功能。这不仅提高了用户的体验,也使得Web应用具备了更丰富的交互性。在实际项目中,开发者可以根据具体需求对这些...
在实现基于HTML5-Canvas的画图板时,开发者需要对Canvas元素有一个全面的理解,包括它的渲染上下文(context)、绘图路径(path)、像素操作(image data)等方面。通过这些接口,开发者可以构建出复杂的绘图应用。例如,...
为了实现图片下载功能,我们可以利用Canvas的`toDataURL`方法,将Canvas当前的内容转换为一个data URL,这是一个包含了图像数据的URL,通常以"data:image/png;base64,"开头。这个URL可以作为新窗口的来源,也可以...