如何解决image-conversion插件压缩图片后背景变成黑色

项目需求

对用户上传的图片,压缩后再上传到服务器。

发现的问题

如果选择的图片背景图是透明的,压缩后的图片,背景竟然变成了黑色!!!
案例:随便选择一张透明图片,发现,压缩后,背景变成黑色。ps:图片的高宽,暂时随便设置的,导致图片变形了,不用理会。我们只关注背景色。
在这里插入图片描述

分析原因

查看image-conversion源码,发现

/**
 * 将一个Canvas对象转变为一个dataURL字符串
 * 该方法可以做压缩处理
 *
 * @param {canvas} canvas
 * @param {number=} quality - 传入范围 0-1,表示图片压缩质量,默认0.92
 * @param {string=} type - 确定转换后的图片类型,选项有 "image/png", "image/jpeg", "image/gif",默认"image/jpeg"
 * @returns {Promise(string)} Promise含有一个dataURL字符串参数
 */
export default async function canvastoDataURL(canvas: HTMLCanvasElement, quality: number = 0.92, type: EImageType = EImageType.JPEG): Promise<string> {
  if (!checkImageType(type)) {
    type = EImageType.JPEG; // 没有指定类型默认是jpeg
  }
  console.log('122 canvastoDataURL',type)
  return canvas.toDataURL(type, quality);
};

可以看到不指定类型的话默认是使用image/jpeg格式转的,但是jpeg格式不能没有底色, 所以默认会填充黑色。
如果将官方设置提供配置参数 type, 设置成’image/png’,可不可行?
设置了这个确实不会出现黑底的情况了, 但是压缩效果又没了, 原因就是我们设置了 image/png 格式后, 那么cavans转base646就是按照png格式转,但png格式不管怎么转,转出的大小还是和原来一样。因为png格式不支持设置清晰度,也就是这个方法:

canvas.toDataURL(type, quality);

怎么办?

解决方案

思路:先将图片转成白色底图,再调用image-conversion方法对图片压缩。
先创建一个file.js文件,代码如下:

import * as imageConversion from 'image-conversion'; 

export const compressImageConversion = (file, base64, callBack) => {
    compressPic(file, base64).then(handleFile => {
        // 将图片压缩到100kb
        imageConversion.compressAccurately(handleFile, 100).then(res => {
            res = new File([res], file.name);
            callBack(res)
        })
    })
}

export const compressPic = (file, base64) => {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = () => {
      const img = new Image();
      img.src = base64;
      img.onload = () => {
        const canvas = document.createElement("canvas");
        const ctx = canvas.getContext("2d");
        canvas.width = img.width;
        canvas.height = img.height;
        // ctx.fillStyle ctx.fillRect 这两行代码是重点,给图片添加白色底图
        ctx.fillStyle = "#ffffff";
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.drawImage(img, 0, 0, img.width, img.height)
        // 这里的图片类型,改成动态获取,即上传的图片是什么类型,就获取它的类型,传进来就好
        const handleBase64 = canvas.toDataURL("imgae/png", 1);
        const handleFile = base642File(handleBase64, "test.png");
        resolve(handleFile);
      };
    };
    reader.readAsDataURL(file);
  });
}

export const base642File = (base64, fileName) => {
    let arr = base64.split(',')
    let mime = arr[0].match(/:(.*?);/)[1]
    let bstr = atob(arr[1])
    let n = bstr.length
    let u8arr = new Uint8Array(n)
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
    }
    return new File([u8arr], fileName, { type: mime })
}

export const file2Base64 = file => {
    return new Promise((resolve) => {
        let reader = new FileReader()
        reader.readAsDataURL(file)
        reader.onload = (e) => {
            resolve(e.target.result)
        }
    })
}

重要代码!!!

ctx.fillStyle = “#ffffff”;
ctx.fillRect(0, 0, canvas.width, canvas.height);

在vue中使用

<template>
    <div>
        <van-uploader :after-read='afterRead' accept='.jpg,.jpeg,.png' />
        <div class="pic">
            <div class="pic-item">
                <p style="font-size: 16px;">压缩前的图片展示:</p>
                <div>
                    <img :src="base64Before" alt="" style="width: 400px;height: 300px;">
                </div>
            </div>
            <div class="pic-item">
                <p style="font-size: 16px;">压缩后的图片展示:</p>
                <div>
                    <img :src="base64After" alt="" style="width: 400px;height: 300px;">
                </div>
            </div>
        </div>
    </div>
</template>

<script>
import { compressImageConversion, file2Base64 } from '../utils/file.js'

export default {

    data() {
        return {
            base64Before: '',
            base64After: '',
        }
    },
    methods: {
        afterRead(file) {
            console.log('压缩前', file)
            this.base64Before = file.content
            compressImageConversion(file.file, file.content, (handleFile) => {
                console.log('压缩后', handleFile)
                file2Base64(handleFile).then(handleBase64 => {
                    this.base64After = handleBase64
                })
            })
        }
    }
}
</script>

<style>
.pic {
    display: flex;
}
.pic-item {
    margin: 10px;
}
</style>

效果:
在这里插入图片描述
封装的file.js里面的方法,可以直接复制到项目中使用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值