canvas保存为data:image功能扩展实现

【已知】

canvas提供了toDataURL的接口,可以方便的将canvas画布转化成base64编码的image。目前支持的最好的是png格式,jpeg格式的现代浏览器基本也支持,但是支持的不是很好。

【想要的】
往往这么简单直接的接口通常都满足不了需求。我想要的不仅是简单的通过画布生成一个png,我不想新开一个tab,然后还要右键另存为...

我还需要更方便的自由的配置生成的图片的大小,比例等。

另外如果我还要别的图片格式,比如位图bmp,gif等怎么办...

【解决办法】
a)想直接把图片生成后download到本地,其实办法也很简单。直接改图片的mimeType,强制改成steam流类型的。比如‘image/octet-stream’,浏览器就会自动帮我们另存为.. 

b)图片大小,及比例的可控倒也好办,我们新建一个我们想要大小的canvas,把之前的canvas画布重新按照所要的比例,及大小draw到新的canvas上,然后用新的canvas来toDataURL即可。

c)想要bmp位图会麻烦些... 没有直接的接口,需要我们自己来生成。生成图片的响应头和响应体有一定的规则,略显麻烦。不过还能接受。剩下的就是性能问题,按像素级别来操作,对于一个大图来说计算量很有压力。

代码:

/**
 * 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 (data) {
        var imgHeader = [],
            imgInfoHeader = [];
        
        var width = data.width,
            height = data.height;


        imgHeader.push(0x42); // 66 -> B
        imgHeader.push(0x4d); // 77 -> M


        var fsize = width * height * 3 + 54; // header size:54 bytes
        imgHeader.push(fsize % 256); // r
        fsize = Math.floor(fsize / 256);
        imgHeader.push(fsize % 256); // g
        fsize = Math.floor(fsize / 256);
        imgHeader.push(fsize % 256); // b
        fsize = Math.floor(fsize / 256);
        imgHeader.push(fsize % 256); // a


        imgHeader.push(0);
        imgHeader.push(0);
        imgHeader.push(0);
        imgHeader.push(0);


        imgHeader.push(54); // offset -> 6
        imgHeader.push(0);
        imgHeader.push(0);
        imgHeader.push(0);


        // info header
        imgInfoHeader.push(40); // info header size
        imgInfoHeader.push(0);
        imgInfoHeader.push(0);
        imgInfoHeader.push(0);


        // 横向info
        var _width = width;
        imgInfoHeader.push(_width % 256);
        _width = Math.floor(_width / 256);
        imgInfoHeader.push(_width % 256);
        _width = Math.floor(_width / 256);
        imgInfoHeader.push(_width % 256);
        _width = Math.floor(_width / 256);
        imgInfoHeader.push(_width % 256);


        // 纵向info
        var _height = height;
        imgInfoHeader.push(_height % 256);
        _height = Math.floor(_height / 256);
        imgInfoHeader.push(_height % 256);
        _height = Math.floor(_height / 256);
        imgInfoHeader.push(_height % 256);
        _height = Math.floor(_height / 256);
        imgInfoHeader.push(_height % 256);


        imgInfoHeader.push(1);
        imgInfoHeader.push(0);
        imgInfoHeader.push(24); // 24位bitmap
        imgInfoHeader.push(0);


        // no compression
        imgInfoHeader.push(0);
        imgInfoHeader.push(0);
        imgInfoHeader.push(0);
        imgInfoHeader.push(0);


        // pixel data
        var dataSize = width * height * 3;
        imgInfoHeader.push(dataSize % 256);
        dataSize = Math.floor(dataSize / 256);
        imgInfoHeader.push(dataSize % 256);
        dataSize = Math.floor(dataSize / 256);
        imgInfoHeader.push(dataSize % 256);
        dataSize = Math.floor(dataSize / 256);
        imgInfoHeader.push(dataSize % 256);


        // blank space
        for (var i = 0; i < 16; i ++) {
            imgInfoHeader.push(0);
        }


        var padding = (4 - ((width * 3) % 4)) % 4;
        var imgData = data.data;
        var strPixelData = '';
        var y = height;
        do {
            var offsetY = width * (y - 1) * 4;
            var strPixelRow = '';
            for (var x = 0; x < width; x ++) {
                var offsetX = 4 * x;
                strPixelRow += String.fromCharCode(imgData[offsetY + offsetX + 2]);
                strPixelRow += String.fromCharCode(imgData[offsetY + offsetX + 1]);
                strPixelRow += String.fromCharCode(imgData[offsetY + offsetX]);
            }
            for (var n = 0; n < padding; n ++) {
                strPixelRow += String.fromCharCode(0);
            }


            strPixelData += strPixelRow;
        } while(-- y);


        return (encodeData(imgHeader.concat(imgInfoHeader)) + encodeData(strPixelData));


    };


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

}();

cocos creator 中的截屏实现:

captureScreen: function () {

//注意,EditBox,VideoPlayer,Webview 等控件无法被包含在截图里面

//因为这是 OpenGL 的渲染到纹理的功能,上面提到的控件不是由引擎绘制的

if(CC_JSB) {

//如果待截图的场景中含有 mask,请使用下面注释的语句来创建 renderTexture

// var renderTexture = cc.RenderTexture.create(1280,640, cc.Texture2D.PIXEL_FORMAT_RGBA8888,

            gl.DEPTH24_STENCIL8_OES);

    var renderTexture = cc.RenderTexture.create(1280,640);

   //实际截屏的代码

            renderTexture.begin();

         //this.richText.node 是我们要截图的节点,如果要截整个屏幕,可以把 this.richText 换成 Canvas 切点即可

    this.richText.node._sgNode.visit();

    renderTexture.end();

            renderTexture.saveToFile("demo.png",cc.ImageFormat.PNG, true, function () {

cc.log("capture screen successfully!");

     });

      //打印截图路径

            cc.log(jsb.fileUtils.getWritablePath());

         }

            }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值