198 lines
6.3 KiB
JavaScript
198 lines
6.3 KiB
JavaScript
/*
|
|
* Canvas2Image v0.1
|
|
* Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com
|
|
* MIT License [http://www.opensource.org/licenses/mit-license.php]
|
|
*/
|
|
|
|
var Canvas2Image = (function() {
|
|
// check if we have canvas support
|
|
var oCanvas = document.createElement("canvas"),
|
|
sc = String.fromCharCode,
|
|
strDownloadMime = "image/octet-stream",
|
|
bReplaceDownloadMime = false;
|
|
|
|
// no canvas, bail out.
|
|
if (!oCanvas.getContext) {
|
|
return {
|
|
saveAsBMP : function(){},
|
|
saveAsPNG : function(){},
|
|
saveAsJPEG : function(){}
|
|
}
|
|
}
|
|
|
|
var bHasImageData = !!(oCanvas.getContext("2d").getImageData),
|
|
bHasDataURL = !!(oCanvas.toDataURL),
|
|
bHasBase64 = !!(window.btoa);
|
|
|
|
// ok, we're good
|
|
var readCanvasData = function(oCanvas) {
|
|
var iWidth = parseInt(oCanvas.width),
|
|
iHeight = parseInt(oCanvas.height);
|
|
return oCanvas.getContext("2d").getImageData(0,0,iWidth,iHeight);
|
|
}
|
|
|
|
// base64 encodes either a string or an array of charcodes
|
|
var encodeData = function(data) {
|
|
var i, aData, strData = "";
|
|
|
|
if (typeof data == "string") {
|
|
strData = data;
|
|
} else {
|
|
aData = data;
|
|
for (i = 0; i < aData.length; i++) {
|
|
strData += sc(aData[i]);
|
|
}
|
|
}
|
|
return btoa(strData);
|
|
}
|
|
|
|
// creates a base64 encoded string containing BMP data takes an imagedata object as argument
|
|
var createBMP = function(oData) {
|
|
var strHeader = '',
|
|
iWidth = oData.width,
|
|
iHeight = oData.height;
|
|
|
|
strHeader += 'BM';
|
|
|
|
var iFileSize = iWidth*iHeight*4 + 54; // total header size = 54 bytes
|
|
strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
|
|
strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
|
|
strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
|
|
strHeader += sc(iFileSize % 256);
|
|
|
|
strHeader += sc(0, 0, 0, 0, 54, 0, 0, 0); // data offset
|
|
strHeader += sc(40, 0, 0, 0); // info header size
|
|
|
|
var iImageWidth = iWidth;
|
|
strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
|
|
strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
|
|
strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
|
|
strHeader += sc(iImageWidth % 256);
|
|
|
|
var iImageHeight = iHeight;
|
|
strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
|
|
strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
|
|
strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
|
|
strHeader += sc(iImageHeight % 256);
|
|
|
|
strHeader += sc(1, 0, 32, 0); // num of planes & num of bits per pixel
|
|
strHeader += sc(0, 0, 0, 0); // compression = none
|
|
|
|
var iDataSize = iWidth*iHeight*4;
|
|
strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
|
|
strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
|
|
strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
|
|
strHeader += sc(iDataSize % 256);
|
|
|
|
strHeader += sc(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // these bytes are not used
|
|
|
|
var aImgData = oData.data,
|
|
strPixelData = "",
|
|
c, x, y = iHeight,
|
|
iOffsetX, iOffsetY, strPixelRow;
|
|
|
|
do {
|
|
iOffsetY = iWidth*(y-1)*4;
|
|
strPixelRow = "";
|
|
for (x = 0; x < iWidth; x++) {
|
|
iOffsetX = 4*x;
|
|
strPixelRow += sc(
|
|
aImgData[iOffsetY + iOffsetX + 2], // B
|
|
aImgData[iOffsetY + iOffsetX + 1], // G
|
|
aImgData[iOffsetY + iOffsetX], // R
|
|
aImgData[iOffsetY + iOffsetX + 3] // A
|
|
);
|
|
}
|
|
strPixelData += strPixelRow;
|
|
} while (--y);
|
|
|
|
return encodeData(strHeader + strPixelData);
|
|
}
|
|
|
|
// sends the generated file to the client
|
|
var saveFile = function(strData) {
|
|
if (!window.open(strData)) {
|
|
document.location.href = strData;
|
|
}
|
|
}
|
|
|
|
var makeDataURI = function(strData, strMime) {
|
|
return "data:" + strMime + ";base64," + strData;
|
|
}
|
|
|
|
// generates a <img> object containing the imagedata
|
|
var makeImageObject = function(strSource) {
|
|
var oImgElement = document.createElement("img");
|
|
oImgElement.src = strSource;
|
|
return oImgElement;
|
|
}
|
|
|
|
var scaleCanvas = function(oCanvas, iWidth, iHeight) {
|
|
if (iWidth && iHeight) {
|
|
var oSaveCanvas = document.createElement("canvas");
|
|
|
|
oSaveCanvas.width = iWidth;
|
|
oSaveCanvas.height = iHeight;
|
|
oSaveCanvas.style.width = iWidth+"px";
|
|
oSaveCanvas.style.height = iHeight+"px";
|
|
|
|
var oSaveCtx = oSaveCanvas.getContext("2d");
|
|
|
|
oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iWidth);
|
|
|
|
return oSaveCanvas;
|
|
}
|
|
return oCanvas;
|
|
}
|
|
|
|
return {
|
|
saveAsPNG : function(oCanvas, bReturnImg, iWidth, iHeight) {
|
|
if (!bHasDataURL) return false;
|
|
|
|
var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight),
|
|
strMime = "image/png",
|
|
strData = oScaledCanvas.toDataURL(strMime);
|
|
|
|
if (bReturnImg) {
|
|
return makeImageObject(strData);
|
|
} else {
|
|
saveFile(bReplaceDownloadMime ? strData.replace(strMime, strDownloadMime) : strData);
|
|
}
|
|
return true;
|
|
},
|
|
|
|
saveAsJPEG : function(oCanvas, bReturnImg, iWidth, iHeight) {
|
|
if (!bHasDataURL) return false;
|
|
|
|
var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight),
|
|
strMime = "image/jpeg",
|
|
strData = oScaledCanvas.toDataURL(strMime);
|
|
|
|
// check if browser actually supports jpeg by looking for the mime type in the data uri. if not, return false
|
|
if (strData.indexOf(strMime) != 5) return false;
|
|
|
|
if (bReturnImg) {
|
|
return makeImageObject(strData);
|
|
} else {
|
|
saveFile(bReplaceDownloadMime ? strData.replace(strMime, strDownloadMime) : strData);
|
|
}
|
|
return true;
|
|
},
|
|
|
|
saveAsBMP : function(oCanvas, bReturnImg, iWidth, iHeight) {
|
|
if (!(bHasDataURL && bHasImageData && bHasBase64)) return false;
|
|
|
|
var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight),
|
|
strMime = "image/bmp",
|
|
oData = readCanvasData(oScaledCanvas),
|
|
strImgData = createBMP(oData);
|
|
|
|
if (bReturnImg) {
|
|
return makeImageObject(makeDataURI(strImgData, strMime));
|
|
} else {
|
|
saveFile(makeDataURI(strImgData, strMime));
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
})(); |