利用 Canvas 将白色背景的 JPEG 图片转成透明的 PNG 图片

本文介绍了一个使用HTML5和Node.js编写的脚本,用于将JPEG图片中的白色背景转换为透明,并保存为PNG格式。通过利用canvas API操作图片像素,实现了简单高效的图片格式转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者 @zwhu
源码 @raw
原文章 @github

使用场景

老板让我这个不会P图的伪前端把公司的Logo放到公司网站上,结果给了我一张 JPEG 格式的图片,作为一个有追求的码农,怎么能现学 ps,于是利用一点HTML5+NODE的知识写了个转换的脚本。

此脚本的功能是将 JPEG 格式的图片中的白色背景转成透明,然后再保存成PNG格式的图片;如果图片本身有不想被转换的白色区域,使用其他方法吧。

实现原理

原理很简单,只有两点:

RGBA

RGBA的解释 我们知道图片由很多个像素点组成的,每个像素点都有颜色,而颜色是由三基色RGB构成。而A是Alpha通道,用作不透明度参数,0%为完全透明,100%是完全不透明。所以说如果我们想实现白色背景的JPEG 图片转成透明的 PNG 图片,只需要将白色背景对应的像素点得Alpha值变成0就好了。

canvas

HTML5新增加了canvas,可以用来绘制图形,也可以对图片的像素进行操作。通过 getImageData() 方法可以返回原始的像素信息 ImageData 对象。ImageData 对象中的像素是可写的(由 RGBA 组成),因此我们可以修改像素的Alpha通道值,然后再通过 putImageData() 方法将这些像素复制到画布中。

部分代码

有了上面的知识,我们可以很轻松的通过查 canvas 的 API 来写出转换的代码(ES6),代码在下面,代码不难,也写了很详细的注释,虽然我是用 node-canvas 实现的,但是改成浏览器版本的话,也不需要几行代码,原理是想通的:

import Canvas  from 'canvas'
import fs from 'fs'

const Image = Canvas.Image

// 初始化 img 和 start time
// 获取命令行输入的源图片和保存的图片地址
let img = new Image
  , start = new Date()
  , rawPath =  process.argv[2]
  , savePath = process.argv[3]

// 在命令行中没有输入图片地址,抛错
if(!rawPath)
  throw new Error('input raw image path')

if(!savePath)
  throw new Error('input save image path')

img.onerror = function(err){
  throw err
}

// 图片加载完成
img.onload = function(){
    //    获取图片的width和height
  let width = img.width
    , height = img.height
    , canvas = new Canvas(width, height)
    , ctx = canvas.getContext('2d')

  // 将源图片复制到画布上
  // canvas 所有的操作都是在 context 上,所以要先将图片放到画布上才能操作
  ctx.drawImage(img, 0, 0, width, height)

  let imageData = ctx.getImageData(0, 0, width, height)
  
  // 获取画布的像素信息
  // 是一个一维数组,包含以 RGBA 顺序的数据,数据使用  0 至 255(包含)的整数表示
  // 如:图片由两个像素构成,一个像素是白色,一个像素是黑色,那么 data 为
  // [255,255,255,255,0,0,0,255] 
  // 这个一维数组可以看成是两个像素中RBGA通道的数组的集合即:
  // [R,G,B,A].concat([R,G,B,A])
    , data = imageData.data

 // 对像素集合中的单个像素进行循环,每个像素是由4个通道组成,所以 i=i+4
  for(let i = 0; i < data.length; i+=4) {
      // 得到 RGBA 通道的值
    let r = data[i]
      , g = data[i+1]
      , b = data[i+2]

    // 我们从最下面那张颜色生成器中可以看到在图片的右上角区域,有一小块在
    // 肉眼的观察下基本都是白色的,所以我在这里把 RGB 值都在 245 以上的
    // 的定义为白色
    // 大家也可以自己定义的更精确,或者更宽泛一些
    if([r,g,b].every(v => v < 256 && v > 245)) data[i+3] = 0
  }
  
  // 将修改后的代码复制回画布中
  ctx.putImageData(imageData, 0, 0)

  // 将修改后的图片保存
  let out = fs.createWriteStream(`${__dirname}/${savePath}`)
    , stream = canvas.pngStream()

  stream.on('data', function (chunk) {
    out.write(chunk)
  })

  stream.on('end', function () {
    console.log(`保存到 ${__dirname}/${savePath}`)
    console.log(`耗时: ${new Date()-start}ms`)
  })
}

img.src = `${__dirname}/${rawpath}`

src

### 如何在 Canvas 中保存带有透明背景图片 Canvas 默认情况下支持透明背景,因此如果未显式设置背景颜色,则生成的图片通常具有透明背景。然而,在某些场景下(如手机相册中),透明区域可能会被渲染为黑色或其他默认颜色[^1]。 #### 使用 `toDataURL` 方法保存带透明背景图片 Canvas 提供了一个内置方法 `toDataURL()`,可以将画布内容转换为 Base64 编码的数据 URI。通过指定 `'image/png'` 类型作为参数,能够确保生成的图片保留透明背景。这是因为 PNG 格式的图片天然支持 alpha 通道,而 JPEG 不支持透明度[^2]。 以下是实现代码示例: ```javascript function saveTransparentImage(canvas) { const dataURL = canvas.toDataURL('image/png'); // 使用 'image/png' 确保透明背景 const link = document.createElement('a'); link.href = dataURL; link.download = 'transparent_image.png'; // 下载文件名 link.click(); } ``` #### 如果需要更改背景颜色后再保存 有时为了适应特定需求,可能希望先将透明背景替换为其他颜色再保存图片。可以通过创建一个新的 Canvas 对象,为其填充所需的颜色,并将原始 Canvas 的内容绘制到新的 Canvas 上完成此操作[^3]。 下面是一个具体例子: ```javascript function saveWithBackgroundColor(originalCanvas, backgroundColor) { const tempCanvas = document.createElement('canvas'); tempCanvas.width = originalCanvas.width; tempCanvas.height = originalCanvas.height; const ctx = tempCanvas.getContext('2d'); ctx.fillStyle = backgroundColor; // 设置背景颜色 ctx.fillRect(0, 0, tempCanvas.width, tempCanvas.height); // 填充整个画布 ctx.drawImage(originalCanvas, 0, 0); // 绘制原有内容 const dataURL = tempCanvas.toDataURL('image/png'); const link = document.createElement('a'); link.href = dataURL; link.download = 'colored_background_image.png'; link.click(); } // 调用方式 saveWithBackgroundColor(myOriginalCanvas, '#ffffff'); // 白色背景 ``` #### Vue3 和 html2canvas 截图中的注意事项 在基于 Vue3 或 React 等框架的应用程序中,使用第三方库如 html2canvas 进行页面截图时,可能出现部分 DOM 元素丢失的情况。这通常是由于 CSS 属性(例如 visibility、opacity)、字体加载延迟或 SVG 渲染问题引起的[^4]。为了避免这些问题,建议调整配置选项如下: ```javascript import html2canvas from 'html2canvas'; async function captureAndSave(elementId) { const element = document.getElementById(elementId); const canvas = await html2canvas(element, { useCORS: true, allowTaint: false, logging: true, scale: window.devicePixelRatio || 1, }); const imgData = canvas.toDataURL('image/png'); const a = document.createElement('a'); a.href = imgData; a.download = `${elementId}_screenshot.png`; a.click(); } ``` 上述代码片段展示了如何利用 html2canvas 库捕获目标元素并将其导出为包含透明背景PNG 图片。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值