使用Canvas API实现前端图片压缩记录

前言

最近我在工作上遇到用户上传大尺寸图片的需求,发现直接上传原始图片会消耗过多带宽和存储空间。于是在网上找了一些像 图片压缩网站 这样的工具能在浏览器里直接完成压缩,无需上传到服务器,这让我很受启发。经过研究,我找到了使用Canvas API的简单实现方案,下面是自己实现的代码和想法。

核心实现原理

Canvas图片压缩主要利用以下技术流程:

  1. 将原始图片绘制到Canvas画布上
  2. 调整Canvas尺寸以实现分辨率压缩
  3. 使用有损编码(如JPEG)和可调质量参数输出图片
  4. 将结果转换为Blob或Base64格式

关键代码实现

1. 图片加载与绘制

javascript 复制代码
function loadImage(file) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    const url = URL.createObjectURL(file);
    
    img.onload = () => {
      URL.revokeObjectURL(url);
      resolve(img);
    };
    
    img.onerror = (e) => {
      reject(e);
    };
    
    img.src = url;
  });
}

2. 核心压缩函数

javascript 复制代码
async function compressImage(file, options = {}) {
  const { 
    quality = 0.8, 
    maxWidth = 800, 
    maxHeight = 800,
    mimeType = 'image/jpeg'
  } = options;
  
  // 加载原始图片
  const img = await loadImage(file);
  
  // 计算缩放比例
  const [newWidth, newHeight] = calculateSize(img, maxWidth, maxHeight);
  
  // 创建canvas并绘制
  const canvas = document.createElement('canvas');
  canvas.width = newWidth;
  canvas.height = newHeight;
  
  const ctx = canvas.getContext('2d');
  ctx.drawImage(img, 0, 0, newWidth, newHeight);
  
  // 转换为Blob对象
  return new Promise((resolve) => {
    canvas.toBlob(
      (blob) => resolve(blob),
      mimeType,
      quality
    );
  });
}

// 辅助函数:计算新尺寸
function calculateSize(img, maxWidth, maxHeight) {
  let width = img.width;
  let height = img.height;
  
  // 计算缩放比例
  if (width > height) {
    if (width > maxWidth) {
      height = Math.round((height * maxWidth) / width);
      width = maxWidth;
    }
  } else {
    if (height > maxHeight) {
      width = Math.round((width * maxHeight) / height);
      height = maxHeight;
    }
  }
  
  return [width, height];
}

3. 使用示例

javascript 复制代码
const fileInput = document.querySelector('input[type="file"]');

fileInput.addEventListener('change', async (e) => {
  const file = e.target.files[0];
  if (!file) return;
  
  try {
    const compressedBlob = await compressImage(file, {
      quality: 0.7,
      maxWidth: 1024,
      maxHeight: 1024
    });
    
    // 使用压缩后的Blob
    console.log(`原始大小: ${file.size} bytes`);
    console.log(`压缩后: ${compressedBlob.size} bytes`);
    
    // 可以上传到服务器或提供给用户下载
  } catch (error) {
    console.error('压缩失败:', error);
  }
});

关键参数说明

  1. quality (0-1) : 控制JPEG压缩质量,数值越小压缩率越高
  2. maxWidth/maxHeight: 限制图片最大尺寸,实现分辨率压缩
  3. mimeType: 可指定为'image/jpeg'(有损)、'image/png'(无损)等

浏览器兼容性

Canvas压缩功能在现代浏览器中支持良好,包括:

  • Chrome 50+
  • Firefox 50+
  • Safari 10+
  • Edge 15+
相关推荐
mldong4 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排5 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60615 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角6 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!6 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰7 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi8 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen9 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马9 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒10 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端