Canavas2Image.js save base64 img as png via elemen

2019-04-21 12:25发布

问题:

I'm unsing the canvas2Image.js plugin:

/*
 * Canvas2Image v0.1
 * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk
 * MIT License [http://www.opensource.org/licenses/mit-license.php]
 */

var Canvas2Image = (function() {

    // check if we have canvas support
    var bHasCanvas = false;
    var oCanvas = document.createElement("canvas");
    if (oCanvas.getContext("2d")) {
        bHasCanvas = true;
    }

    // no canvas, bail out.
    if (!bHasCanvas) {
        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); // dataoffset
        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);

        var strEncoded = encodeData(aHeader.concat(aInfoHeader)) + encodeData(strPixelData);

        return strEncoded;
    }
*/

    // sends the generated file to the client
    var saveFile = function(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, iHeight);
            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;
        }*/
    };

})();

in html i do:

  <script type="text/javascript">
  $(document).ready(function(){
    var _txt = "hey";
    $('#qrcode').qrcode({
      text  :_txt
    });
    $("#qrcode-canvas").attr("download","file.png");
    var oCanvas = document.getElementById("qrcode-canvas");  
    $("#download-qrcode").on('click',function(){
      Canvas2Image.saveAsPNG(oCanvas);
    })
  });
  </script>

<div id="qrcode" class="" style="" ></div>
 <a class="btn btn-large btn-inverse" id="download-qrcode"><i class="icon icon-download-alt icon-white"></i> download</a>

I'm having problem, i'm using macosx FF,Chrome Opera and Safari, then i call the saveAsPNG() method via element click

The image returns a document without extension to be saved:

data:image/octet-stream;base64,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

I would like to save it as image, would like png :/

is that possible?

cause i kow i can fix that using data:image/png;etc.. but it will open new window in browser.

回答1:

Based on this question: Name a PNG file saved from Canvas using an "open with" dialog, you can use the download attribute of an a element to indicate that the href should be downloaded with the given name.

Better still, we can set the href to the return value of toDataURL which will ensure the image is in fact downloaded as a PNG.

<a class="btn btn-large btn-inverse" id="download-qrcode" download="my_file.png">
    <i class="icon icon-download-alt icon-white"></i>
    download
</a>

$("#download-qrcode").on('click',function(){
    var dataUrl = oCanvas[0].toDataURL();
    $(this).attr('href', dataUrl);
});

When the link is clicked, the file will be downloaded as my_file.png. As stated in that question, the download attribute is not that widely supported - the above code only worked in Chrome even though Firefox apparently supports that attribute.

I'm not really sure how to work around this as you can't set a Content-Disposition in a data: URL, which means that you can't force the download like you can with a server-side.

You could also check out this: http://www.joeltrost.com/blog/2012/01/29/html5-canvas-save-a-jpeg-with-extension/, which deals with the same problem using a post-back approach. The nice thing with this is that it takes advatage of the server's ability to specify the Content-Disposition so you can force the image to be downloaded.

Edit:

So the idea of the post-back approach is basically to send the data Url back to the server which essentially echos it back. The trick is that when doing so, a Content-Disposition is set, forcing the image to be downloaded.

Now the link shows a solution in PHP, so you could probably reuse the script to do the same thing.