initial commit
This commit is contained in:
279
webroot/js/jscharting/canvas2image.js
Normal file
279
webroot/js/jscharting/canvas2image.js
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* 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, filename) {
|
||||
var save_link = document.createElement('a');
|
||||
save_link.href = strData;
|
||||
save_link.download = filename;
|
||||
var event = new MouseEvent('click', { "bubbles": false, "cancelable": false });
|
||||
save_link.dispatchEvent(event);
|
||||
|
||||
}
|
||||
|
||||
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 {[obj]} canvas [canvasElement]
|
||||
* @param {[Number]} width [optional] png width
|
||||
* @param {[Number]} height [optional] png height
|
||||
* @param {[String]} type [image type]
|
||||
* @param {[String]} filename [image filename]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
var saveAsImage = function(canvas, width, height, type, filename) {
|
||||
if ($support.canvas && $support.dataURL) {
|
||||
if (typeof canvas == "string") { canvas = document.getElementById(canvas); }
|
||||
if (type == undefined) { type = 'png'; }
|
||||
filename = filename == undefined || filename.length === 0 ? Date.now() + '.' + type : filename + '.' + type
|
||||
type = fixType(type);
|
||||
|
||||
if (/bmp/.test(type)) {
|
||||
var data = getImageData(scaleCanvas(canvas, width, height));
|
||||
var strData = genBitmapImage(data);
|
||||
|
||||
saveFile(makeURI(strData, downloadMimedownloadMime), filename);
|
||||
} else {
|
||||
var strData = getDataURL(canvas, type, width, height);
|
||||
saveFile(strData.replace(type, downloadMime), filename);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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, fileName) {
|
||||
return saveAsImage(canvas, width, height, 'png', fileName);
|
||||
},
|
||||
saveAsJPEG: function(canvas, width, height, fileName) {
|
||||
return saveAsImage(canvas, width, height, 'jpeg', fileName);
|
||||
},
|
||||
saveAsGIF: function(canvas, width, height, fileName) {
|
||||
return saveAsImage(canvas, width, height, 'gif', fileName);
|
||||
},
|
||||
saveAsBMP: function(canvas, width, height, fileName) {
|
||||
return saveAsImage(canvas, width, height, 'bmp', fileName);
|
||||
},
|
||||
|
||||
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');
|
||||
}
|
||||
};
|
||||
|
||||
}();
|
||||
Reference in New Issue
Block a user