解决canvas转base64/jpeg时,透明区域变成黑色背景问题

在用canvas将png图片转jpeg时,发现透明区域被填充成黑色。

代码如下:

<p>Canvas:</p>
<canvas id="canvas" style="border: 1px solid #ccc;"></canvas>
<br>
<p>Base64转码后的图片:</p>
<div id="base64Img"></div>

<script type="text/javascript">
    var base64Img = document.getElementById("base64Img"),
        canvas = document.getElementById("canvas"),
        context = canvas.getContext("2d");

    // 创建新图片
    var img = new Image();
    img.src = "1.png";

    img.addEventListener("load", function() {
        // 绘制图片到canvas上
        canvas.width = img.width;
        canvas.height = img.height;

        context.drawImage(img, 0, 0);

        getBase64(canvas, function(dataUrl) {
            // 展示base64位的图片
            var newImg = document.createElement("img");
                newImg.src = dataUrl;

            base64Img.appendChild(newImg);
        });
    }, false);

    // 获取canvas的base64图片的dataURL(图片格式为image/jpeg)
    function getBase64(canvas, callback) {
        var dataURL = canvas.toDataURL("image/jpeg");

        if(typeof callback !== undefined) {
            callback(dataURL);
        }
    }
</script>

为什么canvas会png的透明区域转成黑色呢?

canvas转换成jpeg之前移除alpha通道,所以透明区域被填充成了黑色。

但是,我们希望的是,canvas可以将png的透明区域填充成白色。

那么怎么将canvas中的透明区域填充成白色呢?

以下是我实践过的两种解决方案,希望对你有帮助。

解决方案一:将透明的pixel设成白色

因为png图片的背景都是透明的,所以我们可以寻找透明的pixel,然后将其全部设置成白色,核心代码如下:

// 将canvas的透明背景设置成白色
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
for(var i = 0; i < imageData.data.length; i += 4) {
    // 当该像素是透明的,则设置成白色
    if(imageData.data[i + 3] == 0) {
        imageData.data[i] = 255;
        imageData.data[i + 1] = 255;
        imageData.data[i + 2] = 255;
        imageData.data[i + 3] = 255;
    }
}
context.putImageData(imageData, 0, 0);

 

<p>Canvas:</p>
<canvas id="canvas" style="border: 1px solid #ccc;"></canvas>
<br>
<p>Base64转码后的图片:</p>
<div id="base64Img"></div>

<script type="text/javascript">
    var base64Img = document.getElementById("base64Img"),
        canvas = document.getElementById("canvas"),
        context = canvas.getContext("2d");

    // 创建新图片
    var img = new Image();
    img.src = "1.png";

    img.addEventListener("load", function() {
        // 绘制图片到canvas上
        canvas.width = img.width;
        canvas.height = img.height;

        context.drawImage(img, 0, 0);

        // 将canvas的透明背景设置成白色
        var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
        for(var i = 0; i < imageData.data.length; i += 4) {
            // 当该像素是透明的,则设置成白色
            if(imageData.data[i + 3] == 0) {
                imageData.data[i] = 255;
                imageData.data[i + 1] = 255;
                imageData.data[i + 2] = 255;
                imageData.data[i + 3] = 255;
            }
        }
        context.putImageData(imageData, 0, 0);

        // 展示base64位的图片
        getBase64(canvas, function(dataUrl) {
            var newImg = document.createElement("img");
                newImg.src = dataUrl;

            base64Img.appendChild(newImg);
        });
    }, false);

    // 获取canvas的base64图片的dataURL(图片格式为image/jpeg)
    function getBase64(canvas, callback) {
        var dataURL = canvas.toDataURL("image/jpeg");

        if(typeof callback !== undefined) {
            callback(dataURL);
        }
    }
</script>

 

缺点显而易见。当png图片上存在半透明区域时,会将其填充为黑色。这是我们不希望的。

解决方案二:在canvas绘制前填充白色背景

核心代码如下:

// 在canvas绘制前填充白色背景

context.fillStyle = "#fff";
context.fillRect(0, 0, canvas.width, canvas.height);
完整代码如下:

<p>Canvas:</p>
<canvas id="canvas" style="border: 1px solid #ccc;"></canvas>
<br>
<p>Base64转码后的图片:</p>
<div id="base64Img"></div>

<script type="text/javascript">
    var base64Img = document.getElementById("base64Img"),
        canvas = document.getElementById("canvas"),
        context = canvas.getContext("2d");

    // 创建新图片
    var img = new Image();
    img.src = "1.png";

    img.addEventListener("load", function() {
        // 绘制图片到canvas上
        canvas.width = img.width;
        canvas.height = img.height;

        // 在canvas绘制前填充白色背景
        context.fillStyle = "#fff";
        context.fillRect(0, 0, canvas.width, canvas.height);

        context.drawImage(img, 0, 0);

        // 展示base64位的图片
        getBase64(canvas, function(dataUrl) {
            var newImg = document.createElement("img");
                newImg.src = dataUrl;

            base64Img.appendChild(newImg);
        });
    }, false);

    // 获取canvas的base64图片的dataURL(图片格式为image/jpeg)
    function getBase64(canvas, callback) {
        var dataURL = canvas.toDataURL("image/jpeg");

        if(typeof callback !== undefined) {
            callback(dataURL);
        }
    }
</script>

 

显然,在canvas绘制前填充白色背景这种方法,不仅简单,而且对png图片的半透明区域填充难看的黑色块。推荐这种解决方案。

另:canvas.toDataURL()方法不允许处理跨域图片。否则会报错。

时间: 2024-10-09 11:47:55

解决canvas转base64/jpeg时,透明区域变成黑色背景问题的相关文章

canvas画好几张图片时,叠层关系的问题

我们知道canvas画好几张图片时,按我们的思维应该是先画的在下面,后画的在最上面,可是事实不是这样的,细心的人会发现,叠层关系是随机的. 为什么呢? 这样想,我们画图片时是不是有这段代码 img.onload=function(){ ctx.drawImage(img,x,y); } 其实就是这段代码的问题,我们先分析一下这段代码,其意思是图片加载完成之后再把它画到我们的画布上, 好几张图片时,由于图片的加载的时间不一样,先加载完的先画,后加载完的后画,所以就会形成图片在画布上显示的叠层顺序和

快速解决Canvas.toDataURL 图片跨域的问题_基础知识

如题,在将页面的图片地址进行本地输出时(Html2Canvas.js),因不同源存在跨域问题,会出现toDataURL访问权限问题: [Redirect at origin 'http://sub1.xx.com' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested res

解决word文档工作时跳出word已关闭的办法

解决word文档工作时跳出word已关闭的办法: 1.在电脑桌面找开始,打开运行. 2.在运行命令行输入regedit,然后确定. 3. 显示注册表编辑器,在里面依次打开HKEY_CURRENT_USERSoftwareMicrosoftOffice12.0. 4.在12.0里面找到word项,然后用鼠标右键单击word项,显示下拉栏,在里面点击重命名. 5.在重命名里输入word0.名称更改成word0. 6.然后在返回到注册表编辑器里依次打开HKEY_LOCAL_MACHINESOFTWAR

如何解决Win8打开代理软件时蓝屏问题

  在Win8系统中蓝屏的原因有很多种,有一种蓝屏是你一开代理软件,Win8就蓝屏.而且那么多种代理软件,使用哪一种代理软件都会导致Win8蓝屏.这个时候该怎么办呢? 解决方法 通过蓝屏分析工具得知,蓝屏是由于驱动程序所导致 : NETIO.SYS,那么原因就比较明了了. 首先我们可以使用其他代理软件来进行测试,看是否会蓝屏,如果不会那么只需要更换一下代理软件即可. 如果使用大多数代理软件都会蓝屏的话,则建议先卸载网卡驱动,然后重新安装,注意:如果你的系统中有其他虚拟网卡的话请一起卸载. 以上就

解决MindManager打开或保存时出现错误问题

  用户在使用MindManager时,会因为版本.系统等问题而造成操作上的故障,常见的一个就是MindManager打开或保存时出现错误.本文就讲解了如何解决MindManager打开或保存时出现错误的问题. 问题描述:当试图用保存,另存为或者打开命令来保存或者打开导图文件时,MindManager 出错并且关闭. 问题分析:Windows显示主题无法显示MindManager客户端的"保存打开"的对话窗口. 解决措施:改变Windows显示设置为标准模式,例如Windows Cla

如何解决mysql查询百万数据时出现大量sleep的进程

问题描述 如何解决mysql查询百万数据时出现大量sleep的进程 如何解决mysql查询百万数据时出现大量sleep的进程: 当使用jdbc 查询数据量为100多万的数据时,mysql会出现大量sleep的进程,然后程序便会卡死在那儿 解决方案 描述的有点泛泛,如果能把使用场景.涉及库表定义发一下会更容易分析. 大量sleep进程可能并不是问题,因为如果使用到连接池的话,一开始就是初始化一些连接,这些连接没有使用的话,在mysql看可能就是sleep的. 从你描述,感觉"查询数据量为100多万

Android开发中如何解决加载大图片时内存溢出的问题

Android开发中如何解决加载大图片时内存溢出的问题    在Android开发过程中,我们经常会遇到加载的图片过大导致内存溢出的问题,其实类似这样的问题已经屡见不鲜了,下面将一些好的解决方案分享给大家.   尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存. 因此,改用先通过Bitmap

asp.net-如何解决数据字段为空时sqldatasource找不到相应数据值的问题

问题描述 如何解决数据字段为空时sqldatasource找不到相应数据值的问题 两个表,表一包含有表二ID字段且原数据为空值,表二有数据,在利用detailsview控件中呈现表一,其字段ID以表二ID对应名称呈现,ID字段利用dropdownlist控件,此控件数据源是sqldatasource控件.运行时如果有对应数据则没问题,否则出现错误,请问如何解决? 解决方案 绑定这种东西刚开始用觉得很简单,但是它牺牲了灵活性,更糟糕的是,你熟练掌握了它解决不了什么问题,你想解决问题还是得从头学起.

解决编译imagick-3.0.1时Cannot locate header file MagickWand.h错误

解决编译imagick-3.0.1时Cannot locate header file http://www.aliyun.com/zixun/aggregation/16764.html">MagickWand.h错误 ImageMagick 6.8之后的版本目录结构改变了,我们查询到ImageMagick的结果如下 [root@localhost ~]# ll /usr/local/include/总用量 48-rw-r--r--. 1 root root  9343 6月   8 1