原因:canvas 生成图片,可通过toDataURL()方法。
canvas.toDataURL(type, encoderOptions);
1、type:图片格式,默认为 image/png,可以是其他image/jpeg等
2、encoderOptions:0到1之间的取值,主要用来选定图片的质量,默认值是0.92,超出范围也会选择默认值。
toDataURL()能把画布里的图案转变成base64编码格式的png,,然后返回 Data URL数据。即使把type改为bmp,生成后缀为bmp的文件,文件的本质还是png类型的。这是需要用到canvas2image.js 来进行转换。
大致的逻辑就是把生成base64链接再进行转化。
var oCanvas = document.getElementById("thecanvas");
Canvas2Image.saveAsPNG(oCanvas); // 这将会提示用户保存PNG图片
Canvas2Image.saveAsJPEG(oCanvas); // 这将会提示用户保存JPG图片
Canvas2Image.saveAsBMP(oCanvas); // 这将会提示用户保存BMP图片
// 返回一个包含PNG图片的<img>元素
var oImgPNG = Canvas2Image.saveAsPNG(oCanvas, true);
// 返回一个包含JPG图片的<img>元素
var oImgJPEG = Canvas2Image.saveAsJPEG(oCanvas, true);
// 返回一个包含BMP图片的<img>元素
var oImgBMP = Canvas2Image.saveAsBMP(oCanvas, true);
// 这些函数都可以接受高度和宽度的参数
// 可以用来调整图片大小
// 把画布保存成100x100的png格式
Canvas2Image.saveAsPNG(oCanvas, false, 100, 100);
以下是测试demo,多余部分自行去除
html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<script type="text/javascript"src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script type="text/javascript"src="./canvas2image.js"></script>
<style>
.doc {
width: 604px;
margin: 0 auto;
}
canvas {
border: 1px solid #888;
}
</style>
<body>
<div class="">
<div style="float: left;">
<p>
宽度 : <input type="number" value="1920" id="imgW" /><br/>
高度 : <input type="number" value="128" id="imgH" /><br/>
color: <select id="bgColor">
<option value="white">white</option>
<option value="black">black</option>
<option value="gray">gray</option>
<option value="yellow">yellow</option>
<option value="blue">blue</option>
<option value="red">red</option>
</select><br/>
<button onclick="setWh()">设置宽高</button>
<br/>
<br/>
文字行1 : <input type="text" value="第一行文字" id="text1" /> <br/>
X: <input type="text" id="t1X" value="0"/> <br/>
Y: <input type="text" id="t1Y" value="30"/><br/>
font-size: <select id="t1Size">
<option value="10px">10px</option>
<option value="15px">15px</option>
<option value="20px">20px</option>
<option value="25px">25px</option>
<option value="30px">30px</option>
<option value="40px">40px</option>
<option value="50px">50px</option>
</select>
font-style: <select id="t1Font">
<option value="Georgia">Georgia</option>
<option value="Verdana">Verdana</option>
<option value="宋体">宋体</option>
<option value="微软雅黑">微软雅黑</option>
</select><br/>
color: <select id="t1Color">
<option value="black">black</option>
<option value="white">white</option>
<option value="gray">gray</option>
<option value="yellow">yellow</option>
<option value="blue">blue</option>
<option value="red">red</option>
</select><br/>
<br/>
<br/>
文字行2 : <input type="text" value="" id="text2" /><br/>
X: <input type="text" id="t2X" value="50"/> <br/>
Y: <input type="text" id="t2Y" value="70"/><br/>
font-size: <select id="t2Size">
<option value="10px">10px</option>
<option value="15px">15px</option>
<option value="20px">20px</option>
<option value="25px">25px</option>
<option value="30px">30px</option>
<option value="40px">40px</option>
<option value="50px">50px</option>
</select>
font-style: <select id="t2Font">
<option value="Georgia">Georgia</option>
<option value="Verdana">Verdana</option>
<option value="宋体">宋体</option>
<option value="微软雅黑">微软雅黑</option>
</select><br/>
<br/>
<button onclick="setTest()" >显示文字</button>
<br/>
保存图片格式:
<select id="sel">
<option value="bmp">bmp</option>
<option value="png">png</option>
<option value="jpeg">jpeg</option>
</select>
<button style="display: none;" id="convert" >转换为 </button>
<button style="display: none;" id="save">保存</button>
</p>
<br/>
<br/>
<!--<button onclick="showImg()" >图片</button>-->
</div>
<div style="">
<canvas id="cvs" width="1920px" height="128px" onclick="clickBtn()"></canvas>
</div>
</div>
<script>
var canvas, ctx, bMouseIsDown = false, iLastX, iLastY,
$save, $imgs,
$convert, $imgW, $imgH,
$sel;
function init () {
$("#text1").css("width",window.innerWidth-100);
canvas = document.getElementById('cvs');
ctx = canvas.getContext('2d');
ctx.fillStyle="white";
ctx.fillRect(0,0,1920,128);
$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 setWh() {
var width = $("#imgW").val();
var height = $("#imgH").val();
$("#cvs").css("width",width+"px");
$("#cvs").css("height",height+"px");
ctx.clearRect(0,0,width,height);
ctx.fillStyle = $("#bgColor").val();
ctx.fillRect(0,0,width,height);
}
function setTest() {
var width = $("#imgW").val();
var height = $("#imgH").val();
var c=document.getElementById("cvs");
var ctx=c.getContext("2d");
ctx.clearRect(0,0,width,height);
ctx.fillStyle = $("#bgColor").val();
ctx.fillRect(0,0,width,height);
if($("#text1").val() != "") {
ctx.fillStyle = $("#t1Color").val(); // text color
ctx.font= $("#t1Size").val()+" "+$("#t1Font").val();
ctx.fillText($("#text1").val(),$("#t1X").val(),$("#t1Y").val());
}
if($("#text2").val() != "") {
ctx.fillStyle="white";
ctx.font= $("#t2Size").val()+" "+$("#t2Font").val();
var gradient=ctx.createLinearGradient(0,0,c.width,0);
gradient.addColorStop("0","magenta");
gradient.addColorStop("0.5","blue");
gradient.addColorStop("1.0","red");
ctx.fillStyle=gradient;
ctx.fillText($("#text2").val(),$("#t2X").val(),$("#t2Y").val());
}
}
function draw () {
}
function clickBtn () {
var oCanvas = document.getElementById("cvs");
var width = $("#imgW").val();
var height = $("#imgH").val();
var imgDom = Canvas2Image.convertToImage(oCanvas, width, height, $("#sel").val());
console.log( oCanvas.toDataURL("image/"+$("#sel").val()));
console.log( imgDom.src);
var imgUrl =imgDom.src;
var link = document.createElement("a");
link.href = imgUrl;
link.download = "XXXX."+$("#sel").val();
document.body.appendChild(link);
link.click();
URL.revokeObjectURL(link.href); // 释放URL 对象
document.body.removeChild(link);
}
onload = init;
</script>
</body>
</html>
canvas2image.js
/**
* 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 (oData) {
//
// BITMAPFILEHEADER: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx
// BITMAPINFOHEADER: http://msdn.microsoft.com/en-us/library/dd183376.aspx
//
var biWidth = oData.width;
var biHeight = oData.height;
var biSizeImage = biWidth * biHeight * 3;
var bfSize = biSizeImage + 54; // total header size = 54 bytes
//
// typedef struct tagBITMAPFILEHEADER {
// WORD bfType;
// DWORD bfSize;
// WORD bfReserved1;
// WORD bfReserved2;
// DWORD bfOffBits;
// } BITMAPFILEHEADER;
//
var BITMAPFILEHEADER = [
// WORD bfType -- The file type signature; must be "BM"
0x42, 0x4D,
// DWORD bfSize -- The size, in bytes, of the bitmap file
bfSize & 0xff, bfSize >> 8 & 0xff, bfSize >> 16 & 0xff, bfSize >> 24 & 0xff,
// WORD bfReserved1 -- Reserved; must be zero
0, 0,
// WORD bfReserved2 -- Reserved; must be zero
0, 0,
// DWORD bfOffBits -- The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits.
54, 0, 0, 0
];
//
// typedef struct tagBITMAPINFOHEADER {
// DWORD biSize;
// LONG biWidth;
// LONG biHeight;
// WORD biPlanes;
// WORD biBitCount;
// DWORD biCompression;
// DWORD biSizeImage;
// LONG biXPelsPerMeter;
// LONG biYPelsPerMeter;
// DWORD biClrUsed;
// DWORD biClrImportant;
// } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
//
var BITMAPINFOHEADER = [
// DWORD biSize -- The number of bytes required by the structure
40, 0, 0, 0,
// LONG biWidth -- The width of the bitmap, in pixels
biWidth & 0xff, biWidth >> 8 & 0xff, biWidth >> 16 & 0xff, biWidth >> 24 & 0xff,
// LONG biHeight -- The height of the bitmap, in pixels
biHeight & 0xff, biHeight >> 8 & 0xff, biHeight >> 16 & 0xff, biHeight >> 24 & 0xff,
// WORD biPlanes -- The number of planes for the target device. This value must be set to 1
1, 0,
// WORD biBitCount -- The number of bits-per-pixel, 24 bits-per-pixel -- the bitmap
// has a maximum of 2^24 colors (16777216, Truecolor)
24, 0,
// DWORD biCompression -- The type of compression, BI_RGB (code 0) -- uncompressed
0, 0, 0, 0,
// DWORD biSizeImage -- The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps
biSizeImage & 0xff, biSizeImage >> 8 & 0xff, biSizeImage >> 16 & 0xff, biSizeImage >> 24 & 0xff,
// LONG biXPelsPerMeter, unused
0,0,0,0,
// LONG biYPelsPerMeter, unused
0,0,0,0,
// DWORD biClrUsed, the number of color indexes of palette, unused
0,0,0,0,
// DWORD biClrImportant, unused
0,0,0,0
];
var iPadding = (4 - ((biWidth * 3) % 4)) % 4;
var aImgData = oData.data;
var strPixelData = '';
var biWidth4 = biWidth<<2;
var y = biHeight;
var fromCharCode = String.fromCharCode;
do {
var iOffsetY = biWidth4*(y-1);
var strPixelRow = '';
for (var x = 0; x < biWidth; x++) {
var iOffsetX = x<<2;
strPixelRow += fromCharCode(aImgData[iOffsetY+iOffsetX+2]) +
fromCharCode(aImgData[iOffsetY+iOffsetX+1]) +
fromCharCode(aImgData[iOffsetY+iOffsetX]);
}
for (var c = 0; c < iPadding; c++) {
strPixelRow += String.fromCharCode(0);
}
strPixelData += strPixelRow;
} while (--y);
var strEncoded = encodeData(BITMAPFILEHEADER.concat(BITMAPINFOHEADER)) + encodeData(strPixelData);
return strEncoded;
};
/**
* 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 (typeof canvas == "string") { canvas = document.getElementById(canvas); }
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 (typeof canvas == "string") { canvas = document.getElementById(canvas); }
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');
}
};
}();