实现图片自动压缩算法,canvas压缩图片方法

news2025/5/24 21:40:25

背景:

在使用某些支持webgl的图形库(eg:PIXI.js,fabric.js)场景中,如果加载的纹理超过webgl可处理的最大纹理限制,会导致渲染的纹理缺失,甚至无法显示。

方案

实现图片自动压缩算法,自动获取 webgl 支持的最大纹理大小,设置一个压缩比率,循环压缩图片的像素,直到小于最大纹理限制。
返回 canvas,方便第三方库继续处理,如果需要 image,可自行调用canvas方法转换成image。

注意:如果不需要像素处理,删除处理像素相关的代码即可。

vim imageHelp.ts

/**
 *
 * @param imgStr image base64 | url
 * @param ratio 压缩比率
 * @returns 压缩后的canvas对象,获取image 使用 canvas.convertToBlob()
 */
export async function compressImage(options: { imgStr: string; ratio?: number; negate?: 0 | 1 }) {
  const { imgStr, ratio = 0.5, negate = 0 } = options
  const isInverted = negate == 1 // 底色是否反黑色
  // 2. 添加错误处理
  if (!imgStr) throw new Error('Invalid image source')
  if (ratio <= 0 || ratio > 1) throw new Error('Invalid compression ratio')

  try {
    const img = await loadImage(imgStr)
    const maxTextureSize = getMaxTextureSize()
    // 5. 优化尺寸计算逻辑
    const { width, height } = calculateTargetSize(img, ratio, maxTextureSize)

    // 6. 使用 OffscreenCanvas 提升性能
    const { canvas, ctx } = createCanvasContext(width, height)
    ctx.drawImage(img, 0, 0, width, height)

    // 7. 添加 Worker 终止逻辑防止内存泄漏
    const worker = new CanvasWorker()
    const cleanup = () => worker.terminate()

    return await new Promise<{ canvas: OffscreenCanvas; width: number; height: number }>(
      (resolve, reject) => {
        worker.onmessage = (e) => {
          try {
            // imageData.data.buffer 所有权已转移,无法更新数据 imageData.data.buffer
            //  重新构建 ImageData 对象
            const updatedImageData = new ImageData(
              new Uint8ClampedArray(e.data.buffer),
              canvas.width,
              canvas.height
            )
            // 将修改后的图像数据放回画布
            ctx.putImageData(updatedImageData, 0, 0)
            cleanup()
            if (width > maxTextureSize || height > maxTextureSize) {
              // 压缩后的图像需要缩放,保持原图像的视觉大小
              ctx.scale(1 / ratio, 1 / ratio)
            }
            resolve({
              canvas,
              width,
              height,
            })
          } catch (error) {
            cleanup()
            reject(error)
          }
        }
        worker.onerror = (error) => {
          cleanup()
          reject(error)
        }

        // 8. 优化数据传输
        const imageData = ctx.getImageData(0, 0, width, height)
        // 传递图像数据给worker,第二个参数是一个Transferable对象,可以将数据从一个线程传递到另一个线程,而不是复制
        worker.postMessage(
          {
            buffer: imageData.data.buffer,
            targetColor: isInverted ? [0, 0, 0, 255] : [255, 255, 255, 255],
            tolerance: 50, // 添加颜色容差参数
          },
          [imageData.data.buffer]
        )
      }
    )
  } catch (error) {
    throw new Error(`Image processing failed: ${error?.message}`)
  }
}
function getMaxTextureSize(): number {
  const gl = document.createElement('canvas').getContext('webgl')
  return gl ? gl.getParameter(gl.MAX_TEXTURE_SIZE) : 4096 // 默认值
}

function calculateTargetSize(
  img: { width: number; height: number },
  ratio: number,
  maxSize: number
) {
  let width = img.width
  let height = img.height
  // 压缩图像像素
  while (width > maxSize || height > maxSize) {
    width *= ratio
    height *= ratio
  }

  return {
    width,
    height,
  }
}

function createCanvasContext(width: number, height: number) {
  const canvas = new OffscreenCanvas(width, height)
  canvas.width = width
  canvas.height = height
  return {
    canvas,
    ctx: canvas.getContext('2d')!,
  }
}

vim canvas.worker.ts

self.onmessage = (event) => {
  const { buffer, targetColor, isInverted } = event.data
  // 转换为 Uint8ClampedArray 进行像素级别的处理
  const data = new Uint8ClampedArray(buffer);
  // 遍历每个像素
  for(let i = 0; i < data.length; i += 4) {
    const r = data[i];     // 红色通道
    const g = data[i + 1]; // 绿色通道
    const b = data[i + 2]; // 蓝色通道

    // 检查该像素是否为需要删除的颜色
    if(r === targetColor[0] && g === targetColor[1] && b === targetColor[2]) {
      // 将黑色像素设置为透明
      data[i + 3] = 0; // Alpha通道设置为0
    }
    // 反转颜色
    if(isInverted) {
      data[i] = 255 - data[i]
      data[i + 1] = 255 - data[i + 1]
      data[i + 2] = 255 - data[i + 2]
    }
  }
  self.postMessage(data)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2384891.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2025电工杯数学建模A题思路数模AI提示词工程

我发布的智能体链接&#xff1a;数模AI扣子是新一代 AI 大模型智能体开发平台。整合了插件、长短期记忆、工作流、卡片等丰富能力&#xff0c;扣子能帮你低门槛、快速搭建个性化或具备商业价值的智能体&#xff0c;并发布到豆包、飞书等各个平台。https://www.coze.cn/search/n…

LLM | 论文精读 | NAACL 2025 | Clarify When Necessary:教语言模型何时该“问一句”再答!

&#x1f50d; 解读 NAACL 2025 重磅论文《Clarify When Necessary》&#xff1a;教语言模型何时该“问一句”再答&#xff01; &#x1f9e9; 一、现实问题&#xff1a;大模型“看不懂装懂”有多危险&#xff1f; 我们每天用的 ChatGPT、Claude 等大型语言模型&#xff08;LL…

嵌入式鸿蒙openharmony应用开发环境搭建与工程创建实现

各位小伙伴大家好,本周开始分享鸿蒙开发相关的内容,从基础的配置方法到各种功能的实现,探索国产操作系统的奥秘。 第一:观察结果 第二:开源语言 ArkTS是鸿蒙应用开发中使用的TypeScript超集,提供了一套丰富的API来构建应用界面和逻辑。 第三:环境搭建 步骤 1 通过如…

MDK的编译过程及文件类型全解

本章参考资料&#xff1a;MDK的帮助手册《ARM Development Tools》&#xff0c;点击MDK界面的“help->uVision Help”菜单可打开该文件。 关于ELF文件格式&#xff0c;参考配套资料里的《ELF文件格式》文件。 在本章中讲解了非常多的文件类型&#xff0c;学习时请跟着教程的…

Linux Shell编程(八)

目录 Case语句 1--case格式 2--case使用案例&#xff1a;输入不容的数字&#xff0c;给出不同的结果 跳出循环 1--break 案例&#xff1a;执行十次时&#xff0c;跳出当前循环 完整流程 2--continue 案例&#xff1a;跳过2&#xff0c;4 输出 完整流程 Case语句 1--case格式 c…

AI筑基,新质跃升|英码科技亮相华为广东新质生产力创新峰会,发布大模型一体机新品,助力产业智能化转型

5月15日&#xff0c;以“AI筑基&#xff0c;新质跃升”为主题的华为中国行2025广东新质生产力创新峰会在惠州圆满召开。本次峰会聚焦人工智能、算力基础设施等新ICT技术如何驱动“新质生产力”&#xff0c;共探广东高质量发展新路径。英码科技受邀出席本次峰会&#xff0c;并携…

手机打电话时由对方DTMF响应切换多级IVR语音菜单(话术脚本与实战)

手机打电话时由对方DTMF响应切换多级IVR语音菜单 &#xff08;话术脚本与实战&#xff09; --本地AI电话机器人 上一篇&#xff1a;手机打电话时由对方DTMF响应切换多级IVR语音应答&#xff08;二&#xff09; 下一篇&#xff1a;手机打电话时由对方DTMF响应切换多级IVR语音…

面试题——JDBC|Maven|Spring的IOC思想|DI思想|SpringMVC

目录 一、JDBC 1、jdbc连接数据库的基本步骤&#xff08;掌握**&#xff09; 2、Statement和PreparedStatement的区别 &#xff08;掌握***&#xff09; 二、Maven 1、maven的作用 2、maven 如何排除依赖 3、maven scope作用域有哪些&#xff1f; 三、Spring的IOC思想 …

DETR3D- 3D Object Detection from Multi-view Images via 3D-to-2D Queries

MIT CORL 2021 纯视觉BEV方案transformer网络3D检测 paper&#xff1a;[2110.06922] DETR3D: 3D Object Detection from Multi-view Images via 3D-to-2D Queries code&#xff1a;GitHub - WangYueFt/detr3d DNN提图像特征&#xff0c;FPN提多尺度特征 pts_bbox_head Detr3…

SpringBoot3整合WebSocket

一、WebSocket简介 WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信&#xff0c;允许服务器主动向客户端推送数据。 与传统的 HTTP 请求-响应模式不同&#xff0c;WebSocket 在建立连接后&#xff0c;允许服务器和客户端之间进行双向…

鸿蒙进阶——驱动框架UHDF 机制核心源码解读(一)

文章大纲 引言一、uhdf 概述二、uhdf 的核心参与角色1、drivers/hdf_core/adapter/uhdf2/manager/device_manager.c1.1、drivers/hdf_core/framework/core/manager/src/devmgr_service.c#DevmgrServiceGetInstance通过objectId获取IDevmgrService实例1.2、drivers/hdf_core/fra…

Idea 配合 devtools 依赖 实现热部署

核心依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency> yaml配置 spring: #…

从逻辑学视角严谨证明数据加密的数学方法与实践

文章目录 一、加密数据的数学指纹&#xff1a;信息论基础1.1 加密检测的核心原理1.2 香农熵&#xff1a;量化信息的不确定性 二、统计检验方法&#xff1a;从随机性到加密性2.1 卡方检验的数学原理2.2 游程检验与序列相关性2.3 NIST统计测试套件 三、加密算法的特征识别3.1 对称…

敦煌网测评从环境搭建到风控应对,精细化运营打造安全测评体系

自养号测评&#xff0c;抢占流量为快速提升产品权重和销量&#xff0c;很多卖家常采用自己养号补单测评的方式&#xff0c;技术搭建需要很多要素 一、硬件参数的关联性 在我们使用设备进行注册或操作账号的过程中&#xff0c;系统会记录下大量的系统与网络参数&#xff0c;其中…

本地分支git push 报错 fatal: The current branch XXXX has no upstream branch.

背景&#xff1a; 我新建了一个本地分支叫做 “新增Saas修改需求”&#xff0c;然后当我提交代码执行 git push时报错如下&#xff0c;并且代码仓库中没有我新建的“新增Saas修改需求”这个分支。 报错信息&#xff1a; 解决方法&#xff1a; 直接采用方法2 ”git push -u orig…

Python----循环神经网络(WordEmbedding词嵌入)

一、编码 当我们用数字来让电脑“认识”字符或单词时&#xff0c;最简单的方法是为每个字符或单词分配一个唯一的编号&#xff0c;然后用一个长长的向量来表示它。比如&#xff0c;假设“我”这个字在字典中的编号是第10个&#xff0c;那么它的表示就是一个很多0组成的向量&…

CUDA的设备,流处理器(Streams),核,线程块(threadblock),线程,网格(‌gridDim),块(block)和多gpu设备同步数据概念

CUDA的设备,流处理器&#xff0c;核&#xff0c;线程块&#xff08;threadblock&#xff09;&#xff0c;线程&#xff0c;网格&#xff08;‌gridDim&#xff09;&#xff0c;块&#xff08;block&#xff09;和多gpu设备同步数据概念 CUDA的设备,流处理器&#xff0c;核&…

LeetCode 1340. 跳跃游戏 V(困难)

题目描述 给你一个整数数组 arr 和一个整数 d 。每一步你可以从下标 i 跳到&#xff1a; i x &#xff0c;其中 i x < arr.length 且 0 < x < d 。i - x &#xff0c;其中 i - x > 0 且 0 < x < d 。 除此以外&#xff0c;你从下标 i 跳到下标 j 需要满…

x-cmd install | cargo-selector:优雅管理 Rust 项目二进制与示例,开发体验升级

目录 功能亮点安装优势特点适用场景总结 还在为 Rust 项目中众多的二进制文件和示例而烦恼吗&#xff1f;cargo-selector 让你告别繁琐的命令行&#xff0c;轻松选择并运行目标程序&#xff01; 功能亮点 交互式选择&#xff1a; 在终端中以交互方式浏览你的二进制文件和示例&…

大模型「瘦身」指南:从LLaMA到MobileBERT的轻量化部署实战

大模型「瘦身」指南&#xff1a;从LLaMA到MobileBERT的轻量化部署实战 系统化学习人工智能网站&#xff08;收藏&#xff09;&#xff1a;https://www.captainbed.cn/flu 文章目录 大模型「瘦身」指南&#xff1a;从LLaMA到MobileBERT的轻量化部署实战摘要引言一、轻量化技术…