Experiment about making graphs of route trips
[busui.git] / js / flotr / lib / canvas2image.js
blob:a/js/flotr/lib/canvas2image.js -> blob:b/js/flotr/lib/canvas2image.js
  /*
  * 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");
   
  // no canvas, bail out.
  if (!oCanvas.getContext) {
  return {
  saveAsBMP : function(){},
  saveAsPNG : function(){},
  saveAsJPEG : function(){}
  }
  }
   
  var bHasImageData = !!(oCanvas.getContext("2d").getImageData);
  var bHasDataURL = !!(oCanvas.toDataURL);
  var bHasBase64 = !!(window.btoa);
   
  var strDownloadMime = "image/octet-stream";
   
  // ok, we're good
  var readCanvasData = function(oCanvas) {
  var iWidth = parseInt(oCanvas.width);
  var 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 strData = "";
  if (typeof data == "string") {
  strData = data;
  } else {
  var aData = data;
  for (var i = 0; i < aData.length; i++) {
  strData += String.fromCharCode(aData[i]);
  }
  }
  return btoa(strData);
  }
   
  // creates a base64 encoded string containing BMP data
  // takes an imagedata object as argument
  var createBMP = function(oData) {
  var aHeader = [];
   
  var iWidth = oData.width;
  var iHeight = oData.height;
   
  aHeader.push(0x42); // magic 1
  aHeader.push(0x4D);
   
  var iFileSize = iWidth*iHeight*3 + 54; // total header size = 54 bytes
  aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
  aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
  aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
  aHeader.push(iFileSize % 256);
   
  aHeader.push(0); // reserved
  aHeader.push(0);
  aHeader.push(0); // reserved
  aHeader.push(0);
   
  aHeader.push(54); // data offset
  aHeader.push(0);
  aHeader.push(0);
  aHeader.push(0);
   
  var aInfoHeader = [];
  aInfoHeader.push(40); // info header size
  aInfoHeader.push(0);
  aInfoHeader.push(0);
  aInfoHeader.push(0);
   
  var iImageWidth = iWidth;
  aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
  aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
  aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
  aInfoHeader.push(iImageWidth % 256);
   
  var iImageHeight = iHeight;
  aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
  aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
  aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
  aInfoHeader.push(iImageHeight % 256);
   
  aInfoHeader.push(1); // num of planes
  aInfoHeader.push(0);
   
  aInfoHeader.push(24); // num of bits per pixel
  aInfoHeader.push(0);
   
  aInfoHeader.push(0); // compression = none
  aInfoHeader.push(0);
  aInfoHeader.push(0);
  aInfoHeader.push(0);
   
  var iDataSize = iWidth*iHeight*3;
  aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
  aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
  aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
  aInfoHeader.push(iDataSize % 256);
   
  for (var i = 0; i < 16; i++) {
  aInfoHeader.push(0); // these bytes not used
  }
   
  var iPadding = (4 - ((iWidth * 3) % 4)) % 4;
   
  var aImgData = oData.data;
   
  var strPixelData = "";
  var y = iHeight;
  do {
  var iOffsetY = iWidth*(y-1)*4;
  var strPixelRow = "";
  for (var x=0;x<iWidth;x++) {
  var iOffsetX = 4*x;
   
  strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+2]);
  strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+1]);
  strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX]);
  }
  for (var c=0;c<iPadding;c++) {
  strPixelRow += String.fromCharCode(0);
  }
  strPixelData += strPixelRow;
  } while (--y);
   
  return encodeData(aHeader.concat(aInfoHeader)) + encodeData(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);
  var strData = oScaledCanvas.toDataURL("image/png");
  if (bReturnImg) {
  return makeImageObject(strData);
  } else {
  saveFile(strData.replace("image/png", strDownloadMime));
  }
  return true;
  },
   
  saveAsJPEG : function(oCanvas, bReturnImg, iWidth, iHeight) {
  if (!bHasDataURL) {
  return false;
  }
   
  var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);
  var strMime = "image/jpeg";
  var 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(strData.replace(strMime, strDownloadMime));
  }
  return true;
  },
   
  saveAsBMP : function(oCanvas, bReturnImg, iWidth, iHeight) {
  if (!(bHasImageData && bHasBase64)) {
  return false;
  }
   
  var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);
   
  var oData = readCanvasData(oScaledCanvas);
  var strImgData = createBMP(oData);
  if (bReturnImg) {
  return makeImageObject(makeDataURI(strImgData, "image/bmp"));
  } else {
  saveFile(makeDataURI(strImgData, strDownloadMime));
  }
  return true;
  }
  };
   
  })();