canvas无法在chrome中生成bmp图像dataurl

时间:2015-04-15 13:59:16

标签: google-chrome canvas html5-canvas

我有从视频中绘制图像的代码。这是代码

<script type="text/javascript">

function capture() {

    var video  = document.getElementById("videoId");
    var canvas = capture(video, 1);
    var dataURL = canvas.toDataURL("image/bmp", 1.0);
    console.log("dataurl: "+dataURL);

}

</script>


<body>
 <input type="button" value="Capture" onClick="capture()"/>
 <video id="videoId" width="640" height="480"/>
</body>

在控制台上,dataurl显示为&#34; data:image / png; base64,...&#34;

问题?

为什么dataurl是以png格式生成的?

注意:   这发生在chrome浏览器[41.0.2272.89]中。   在firefox中,url是以bmp格式生成的。

1 个答案:

答案 0 :(得分:5)

支持

并非所有浏览器都支持BMP。没有要求支持 other formats than PNG (我强调):

  

用户代理必须支持PNG(&#34; image / png&#34;)。用户代理可能支持   其他类型。

任何未被识别的格式 will be saved as default PNG

  

第一个参数(如果提供)控制图像的类型   返回(例如PNG或JPEG)。默认为image / png;那种类型   如果不支持给定的类型,也会使用。

要检查是否支持格式,请检查返回数据的第一部分 - uri:

 var wantType = "image/bmp";
 var dataUri = canvas.toDataURL(wantType);
 if (dataUri.indexOf(wantType) < 0) {  // or use substr etc. data: + mime
      // Format NOT supported - provide workaround/inform user
      // See update below for workaround (or replacement)
 }

解决方法:手动低级别BMP生成

要另存为BMP,您必须从画布中提取像素数据,格式化文件标题,以正确格式附加数据,创建Blob并通过objectURL将其提供给用户。

<强>用法:

var bmpDataUri = CanvasToBMP.toDataURL(canvas);     // returns an data-URI

还可以选择将BMP图像作为原始ArrayBuffer

var bmpBuffer = CanvasToBMP.toArrayBuffer(canvas);

Blob

var bmpBlob = CanvasToBMP.toBlob(canvas);
var url = URL.createObjectURL(bmpBlob);             // example objectURL

Blobs当然可以与createObjectURL()一起使用,可以用作图像源和下载目标,并且比使用数据URI更快,因为他们不需要对Base-64进行编码/解码。

它写入支持alpha的32位BMP文件(Firefox目前忽略BMP文件中的alpha通道)。

无论如何,这是 -

演示和来源

&#13;
&#13;
/*! canvas-to-bmp version 1.0 ALPHA
    (c) 2015 Ken "Epistemex" Fyrstenberg
    MIT License (this header required)
*/

var CanvasToBMP = {

  /**
   * Convert a canvas element to ArrayBuffer containing a BMP file
   * with support for 32-bit (alpha).
   *
   * Note that CORS requirement must be fulfilled.
   *
   * @param {HTMLCanvasElement} canvas - the canvas element to convert
   * @return {ArrayBuffer}
   */
  toArrayBuffer: function(canvas) {

    var w = canvas.width,
        h = canvas.height,
        w4 = w * 4,
        idata = canvas.getContext("2d").getImageData(0, 0, w, h),
        data32 = new Uint32Array(idata.data.buffer), // 32-bit representation of canvas

        stride = Math.floor((32 * w + 31) / 32) * 4, // row length incl. padding
        pixelArraySize = stride * h,                 // total bitmap size
        fileLength = 122 + pixelArraySize,           // header size is known + bitmap

        file = new ArrayBuffer(fileLength),          // raw byte buffer (returned)
        view = new DataView(file),                   // handle endian, reg. width etc.
        pos = 0, x, y = 0, p, s = 0, a, v;

    // write file header
    setU16(0x4d42);          // BM
    setU32(fileLength);      // total length
    pos += 4;                // skip unused fields
    setU32(0x7a);            // offset to pixels

    // DIB header
    setU32(108);             // header size
    setU32(w);
    setU32(-h >>> 0);        // negative = top-to-bottom
    setU16(1);               // 1 plane
    setU16(32);              // 32-bits (RGBA)
    setU32(3);               // no compression (BI_BITFIELDS, 3)
    setU32(pixelArraySize);  // bitmap size incl. padding (stride x height)
    setU32(2835);            // pixels/meter h (~72 DPI x 39.3701 inch/m)
    setU32(2835);            // pixels/meter v
    pos += 8;                // skip color/important colors
    setU32(0xff0000);        // red channel mask
    setU32(0xff00);          // green channel mask
    setU32(0xff);            // blue channel mask
    setU32(0xff000000);      // alpha channel mask
    setU32(0x57696e20);      // " win" color space

    // bitmap data, change order of ABGR to BGRA
    while (y < h) {
      p = 0x7a + y * stride; // offset + stride x height
      x = 0;
      while (x < w4) {
        v = data32[s++];                     // get ABGR
        a = v >>> 24;                        // alpha channel
        view.setUint32(p + x, (v << 8) | a); // set BGRA
        x += 4;
      }
      y++
    }

    return file;

    // helper method to move current buffer position
    function setU16(data) {view.setUint16(pos, data, true); pos += 2}
    function setU32(data) {view.setUint32(pos, data, true); pos += 4}
  },

  /**
   * Converts a canvas to BMP file, returns a Blob representing the
   * file. This can be used with URL.createObjectURL().
   * Note that CORS requirement must be fulfilled.
   *
   * @param {HTMLCanvasElement} canvas - the canvas element to convert
   * @return {Blob}
   */
  toBlob: function(canvas) {
    return new Blob([this.toArrayBuffer(canvas)], {
      type: "image/bmp"
    });
  },

  /**
   * Converts the canvas to a data-URI representing a BMP file.
   * Note that CORS requirement must be fulfilled.
   *
   * @param canvas
   * @return {string}
   */
  toDataURL: function(canvas) {
    var buffer = new Uint8Array(this.toArrayBuffer(canvas)),
        bs = "", i = 0, l = buffer.length;
    while (i < l) bs += String.fromCharCode(buffer[i++]);
    return "data:image/bmp;base64," + btoa(bs);
  }
};


// -------- DEMO CODE -------------

var canvas = document.querySelector("canvas"),
  w = canvas.width,
  h = canvas.height,
  ctx = canvas.getContext("2d"),
  gr = ctx.createLinearGradient(0, 0, w, h),
  img = new Image();

gr.addColorStop(0, "hsl(" + (Math.random() * 360) + ", 90%, 70%)"); 
gr.addColorStop(1, "hsl(" + (Math.random() * 360) + ", 100%, 30%)"); 
ctx.fillStyle = gr;
ctx.fillRect(0, 0, w, h);

// append image from the data-uri returned by the CanvasToBMP code below:
img.src = CanvasToBMP.toDataURL(canvas);
document.body.appendChild(img);
&#13;
<h2>Canvas left, BMP from canvas as image right</h2>
<canvas width="299" height="200"></canvas>
&#13;
&#13;
&#13;