The implementation of canvas Save as Data:image extension feature

Source: Internet
Author: User

Known
Canvas provides a todataurl interface that makes it easy to convert canvas canvases into base64 encoded image. Currently the best supported is the PNG format, the JPEG format of the modern browser is basically supported, but the support is not very good.

"What you want."
Often such simple and straightforward interfaces usually do not meet the requirements. What I want is not only simple to create a PNG from the canvas, I don't want to open a new tab, and then right-click Save As ...

I also need more convenient free configuration to generate pictures of size, scale etc.

Also if I want other picture format, such as Bitmap bmp,gif ...

"Solution"
A) want to directly download the image after the local, in fact, the method is very simple. Change the mimetype of the image directly to the steam stream type. such as ' Image/octet-stream ', the browser will automatically help us save as.

b) The picture size, and the proportion of the controllable inverted, we create a new canvas we want to size, the previous canvas canvas to the desired proportions, and size draw to the new canvas, and then use the new canvas to Todataurl.

c) Want BMP bitmap will be more trouble ... Without a direct interface, we need to generate it ourselves. Generating a picture of the response header and the response body has certain rules, slightly cumbersome. But it can be accepted. The rest is the performance issue, which operates at the pixel level and is very stressful for a large graph.

Achieve

/**
* 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
* Generate picture response header and response body according to rules
*/
var genbitmapimage = function (data) {
var imgheader = [],
Imginfoheader = [];

var width = data.width,
Height = data.height;

Imgheader.push (0x42); B
Imgheader.push (0X4D); 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);

Landscape 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);

Portrait 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-bit 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 <; 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
Try painting on the canvas, and then save the look. If the BMP format, you need to support Btoa base64 encoding, about Base64 coding rules can be a blog post

"Perfect place to be"
1) The JPEG interface itself is not perfect, when the canvas is not filled with color or picture, the saved JPEG is directly converted from the PNG alpha channel, so the transparent part of PNG is black in the JPEG.

2) GIF has too many restrictions. And the availability is small, PNG is enough

3) BMP bitmap generation, the calculation amount is slightly larger.

4) because it is forced to change the mimetype to achieve automatic download, so the file type is not automatically recognized when downloading.

HTML5 <a> has download properties

1234567 vara = document.createElement(‘a‘);a.download = ‘我是文件名‘ + _suffix;a.href = _canvas.toDataURL();a.click();_suffix表示图片后缀_canvas canvas对象

The implementation of canvas Save as Data:image extension feature

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.