canvas2image.js将canvas保存为图片

论坛 期权论坛 脚本     
匿名技术用户   2021-1-5 04:54   64   0

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');
  }
 };

}();
<!DOCTYPE html>
<html>
<head> 
    <meta charset="utf-8"> 
    <title>demo</title> 
    <script src="../js/canvas2image/canvas2image.js"></script>
    <style>
        .doc {
            width: 604px;
            margin: 0 auto;
        }
        canvas {
            display: block;
            border: 2px solid #888;
        }
    </style>
<body>
<div class="doc">
    <canvas width="300" height="200" id="cvs"></canvas>
    <div>
        <p>
            <button id="save">保存</button> 或者 <button id="convert">转换为</button> :
            <select id="sel">
                <option value="png">png</option>
                <option value="jpeg">jpeg</option>
                <option value="bmp">bmp</option>
            </select><br/>
            宽度 : <input type="number" value="300" id="imgW" /><br/>
            高度 : <input type="number" value="200" id="imgH" />
        </p>

    </div>
    <div id="imgs">

    </div>
</div>
<script>
    var canvas, ctx, bMouseIsDown = false, iLastX, iLastY,
        $save, $imgs,
        $convert, $imgW, $imgH,
        $sel;
    function init () {
        canvas = document.getElementById('cvs');
        ctx = canvas.getContext('2d');
        $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 draw () {
        ctx.fillStyle = '#ffffff';
        ctx.fillRect(0, 0, 600, 400);
        ctx.fillStyle = 'red';
        ctx.fillRect(100, 100, 50, 50);
    }


    onload = init;
</script>
</body>
</html>

效果:

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP