前端处理图片的N中方式

前言

在前端开发的世界里,图片处理和优化是至关重要的一环。本文章浅析了图片处理的多个方面,包括灰度处理、抠图去除背景、证件照一键换背景、图像编辑器以及canvas海报等。此外,还探讨了图片压缩的各种手段,并通过sharp、webpack和oss等示例演示了实际应用。对于图片格式和兼容性的了解,以及小图处理与SVG的应用,也在本文章中得到详细的讨论。无论你是新手还是经验丰富的前端开发者,这里都有你需要的技术指南,助你在图像处理的道路上更进一步。

1、图片处理

1、灰度处理

图片灰度处理的意义:

  • 简化图像、提高性能:将彩色图像转换为灰度图像可以简化图像的信息表示。灰度图像只有一个通道,每个像素的值表示亮度,因此比彩色图像更加简洁。这可以减少图像处理的复杂度,并降低存储和传输的成本。
  • 色彩失真不敏感+提取关键特征: 在某些图像处理任务中,彩色信息可能不是必要的,而只需关注图像的亮度信息。例如,人脸识别算法通常使用灰度图像进行特征提取,因为亮度信息对于人脸的结构和纹理更具有表达能。灰度图像不受彩色信息的影响,因此对色彩变化更不敏感。在某些图像处理任务中,如边缘检测、图像增强等,灰度图像可以更好地保留图像的结构和细节,而不受颜色变化的干扰, 如:医学影像领域。
  • 对于视力障碍者来说,灰度处理有利于他们更好的看世界

在线demo

JS 复制代码
// 文件输入框变化时的事件监听器
document.getElementById("imageInput").addEventListener("change", handleImage);

function handleImage(e) {
  // 获取选择的文件
  const fileInput = e.target;
  const file = fileInput.files[0];

  if (file) {
    // 创建FileReader以读取所选图像
    const reader = new FileReader();

    // 读取器完成读取时的事件处理程序
    reader.onload = function (e) {
      // 获取对原始图像和灰度画布的引用
      const originalImage = document.getElementById("originalImage");
      originalImage.src = e.target.result;

      const grayscaleCanvas = document.getElementById("grayscaleCanvas");
      const ctx = grayscaleCanvas.getContext("2d");

      // 原始图像加载完成时的事件处理程序
      originalImage.onload = function () {
        // 将灰度画布的尺寸设置为原始图像的尺寸
        grayscaleCanvas.width = originalImage.width;
        grayscaleCanvas.height = originalImage.height;

        // 在灰度画布上绘制原始图像
        ctx.drawImage(
          originalImage,
          0,
          0,
          originalImage.width,
          originalImage.height
        );

        // 获取灰度图像的图像数据
        const imageData = ctx.getImageData(
          0,
          0,
          originalImage.width,
          originalImage.height
        );
        const data = imageData.data;

        // 将每个像素的颜色值取平均,实现灰度效果
        for (let i = 0; i < data.length; i += 4) {
          const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
          data[i] = data[i + 1] = data[i + 2] = avg;
        }

        // // 最大值法
        // for (let i = 0; i < data.length; i += 4) {
        //   const maxVal = Math.max(data[i], data[i + 1], data[i + 2]);
        //   data[i] = data[i + 1] = data[i + 2] = Math.min(255, maxVal);
        // }

        // // 加权平均值法:
        // const Wr = 0.3; // Weight for red
        // const Wg = 0.59; // Weight for green
        // const Wb = 0.11; // Weight for blue

        // for (let i = 0; i < data.length; i += 4) {
        //   const weightedAvg =
        //     (data[i] * Wr + data[i + 1] * Wg + data[i + 2] * Wb) /
        //     (Wr + Wg + Wb);
        //   data[i] =
        //     data[i + 1] =
        //     data[i + 2] =
        //       Math.min(255, Math.max(0, weightedAvg));
        // }


        // 将处理后的图像数据放回灰度画布
        ctx.putImageData(imageData, 0, 0);

        // 显示原始图像和灰度画布
        originalImage.style.display = "block";
        grayscaleCanvas.style.display = "block";
      };
    };

    // 读取文件数据URL
    reader.readAsDataURL(file);
  }
}

注:关于图片灰度转换的6种算法,这里使用了平均值算法

2、扩展(抠图去除背景)

在线demo

这里借助了三方api: removebg,Cloud-Hosted Background Image Remover

js 复制代码
 // 发送POST请求到remove.bg的API
fetch("https://api.remove.bg/v1.0/removebg", {
  method: "POST",
  headers: {
    "X-Api-Key": "XXXXXX", // 替换成你自己的Remove.bg API密钥
  },
  body: formData,
})

3、扩展(证件照一键换背景)

在线demo

到这里就水到渠成,整体思路是:详细代码见上面👆demo

4、扩展(图像编辑器)

在线demo

借助:tui-image-editor

5、扩展(canvas海报)

2、图片压缩

根据 HTTP ARCHIVE 的统计,网站静态资源传输数据中位数为 2.5MB 左右,而其中图片传输数据的中位数在 1MB 左右。

1、压缩手段

2、demo演示

1、sharp:

sharp压缩服务端

sharp压缩客户端

压缩效果:

⚠️注意:sahrp存在的问题

2、wepack:

四个压缩工具

3、oss

oss阿里云图片处理

js 复制代码
// 伪代码展示
// 定义一个支持图片处理的 React Component
function CDNImage(path, width, height) {
 // 如果是 DataURL,则直接返回图片
 if (path.startsWith("data")) {
   return <img src={path} />;
 }
 // 这里的xxxx为域名
 const avifSrc = `https://xxxx/${path}?x-oss-process=image/format,avif/quality,Q_75/resize,w_${width},h_${height}`;
 const webPSrc = `https://xxxx/${path}?x-oss-process=image/format,webp/quality,Q_75/resize,w_${width},h_${height}`;
 const src = `https://xxxx/${path}`;
 return (
   <picture>
     <source srcSet={avifSrc} type="image/avif" />
     <source srcSet={webpSrc} type="image/webp" />
     <img src={src} width={width} height={height} loading="lazy" />
   </picture>
 );
}

// 使用它
import hello from "./hello.png";
<CDNImage path={hello} width={100} height={100} />;

3、图片格式+兼容性

从存储和表示图像的方式来划分,主要为两类:

  • 矢量图: 使用数学公式来描述图像。图像由一系列的点、线、曲线等数学对象组成,因此无论放大还是缩小,图像都能保持较高的质量。
  • 位图:由像素阵列组成的图像。每个像素都有自己的颜色信息,因此在缩放时可能会失去一些图像质量。

矢量图典型: SVG(Scalable Vector Graphics)

位图(bitmap):常见的图片格式 GIF、JPEG、PNG、WEBP 和 AVIF 都属于位图

位图格式的图片相同质量的情况下,他们的体积大小不同,一般来说: jpeg,png,webp,avif 依次减小

根据 webp and avif comparison 文章,针对相同质量的 jpeg,webp 减少了 30% 的体积(中位数),而 avif 减少了 50% 的体积。

综上,avif 拥有更小的体积,但为什么没大量使用呢?在于它的浏览器的兼容性,目前只有86%的支持率:

处理兼容性 : 在前端项目中,我们一般通过 img 标签来表示图片,但基于兼容性影响,可以考试使用picture,它可以根据浏览器对图片格式的支持情况,来降级处理。如此一来,它即使不支持 avif 图片格式,也可以优雅地降级到 webp 甚至 jpeg

html 复制代码
<picture>
  <source srcset="shanyue-hello.avif" type="image/avif">
  <source srcset="shanyue-hello.webp" type="image/webp">
  <img src="shanyue-hello.jpeg">
</picture>

4、小图处理与svg

在前端性能优化中,常有一项是将小图片转化为 DataURL,转化为 DataURL 虽然无法使得图片体积减小,但是可以使得图片地址内联,减少了 HTTP 请求次数

DataUrl组成规范

从上可知:

  • DataURL 并不仅可代表图片,他同样也可代表其它所有文件类型,比如音视频,Markdown,HTML 等,只要你给出了对应的 MIME Type。
  • DataURL 并不仅可由 base64 表示,它也可以使用纯文本表示,比如 HTML。只有二进制的资源,如 jpeg/avif 等二进制资源必须使用 base64 表示。
html 复制代码
data:text/html,lots of text...<p><a name%3D"bottom">bottom</a>?arg=val</p>

// 转换前:
lots of text...
<p><a name="bottom">bottom</a>?arg=val</p>

webpack处理小图:

在 webpack 5 中,可使用 asset 模块对小图片进行处理。

json 复制代码
{
 module: {
    rules: [
      {
        test: /.(jpg|png|avif)/,
        type: 'asset',
        parser: {
          // 对小于 4kb 的图片进行 DataURL 处理
          dataUrlCondition: {
            maxSize: 4 * 1024
          }
        }
      }
    ]
  },
};

注意,以上 asset 仅对二进制图片进行了处理,而无对 svg 这种文本图片进行处理。因为 SVG 为文本格式,使用 base64 编码反而使其体积增大了 30%,而文本格式并不必使用 base64 编码。

处理SVG:

在官方示例中,对 svg 生成 DataURL 时进行了额外的处理。使用了 mini-svg-data-uri,而 源码 也极其简单,仅有几十行,核心功能是 URLEncode 以及字符串,引号等的处理

javascript 复制代码
// mini-svg-data-uri demo
const path = require('path');
const svgToMiniDataURI = require('mini-svg-data-uri');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /.svg/,
        type: 'asset/inline',
        generator: {
          dataUrl: content => {
            content = content.toString();
            return svgToMiniDataURI(content);
          }
        }
      }
    ]
  },
};

end❤️

相关推荐
时清云26 分钟前
【算法】合并两个有序链表
前端·算法·面试
小爱丨同学34 分钟前
宏队列和微队列
前端·javascript
持久的棒棒君1 小时前
ElementUI 2.x 输入框回车后在调用接口进行远程搜索功能
前端·javascript·elementui
2401_857297911 小时前
秋招内推2025-招联金融
java·前端·算法·金融·求职招聘
undefined&&懒洋洋2 小时前
Web和UE5像素流送、通信教程
前端·ue5
大前端爱好者4 小时前
React 19 新特性详解
前端
小程xy4 小时前
react 知识点汇总(非常全面)
前端·javascript·react.js
随云6324 小时前
WebGL编程指南之着色器语言GLSL ES(入门GLSL ES这篇就够了)
前端·webgl
随云6324 小时前
WebGL编程指南之进入三维世界
前端·webgl
寻找09之夏5 小时前
【Vue3实战】:用导航守卫拦截未保存的编辑,提升用户体验
前端·vue.js