實現圖片自動壓縮算法,canvas壓縮圖片方法

背景:

在使用某些支持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 } = optionsconst 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.widthlet height = img.height// 壓縮圖像像素while (width > maxSize || height > maxSize) {width *= ratioheight *= ratio}return {width,height,}
}function createCanvasContext(width: number, height: number) {const canvas = new OffscreenCanvas(width, height)canvas.width = widthcanvas.height = heightreturn {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.pswp.cn/diannao/84209.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/84209.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/84209.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

周界安全防護新突破:AI智能分析網關V4周界入侵檢測算法的技術應用

一、方案概述 在安防周界防護領域&#xff0c;傳統紅外對射、電子圍欄等防護系統弊端顯著&#xff0c;其誤報率高&#xff0c;易受飛鳥、樹枝等干擾&#xff0c;且在惡劣天氣、復雜光照下難以精準識別入侵。隨著安全需求升級&#xff0c;基于AI智能分析網關V4的周界翻越入侵檢…

解決服務器重裝之后vscode Remote-SSH無法連接的問題

在你的windows命令窗口輸入&#xff1a; ssh-keygen -R 服務器IPssh-keygen 不是內部或外部命令 .找到Git(安裝目錄)/usr/bin目錄下的ssh-keygen.exe(如果找不到&#xff0c;可以在計算機全局搜索) 2.屬性–>高級系統設置–>環境變量–>系統變量,找到Path變量&#…

leetcode 33. Search in Rotated Sorted Array

題目描述 可以發現的是&#xff0c;將數組從中間分開成左右兩部分的時候&#xff0c;一定至少有一部分的數組是有序的。左部分[left,mid-1]&#xff0c;右部分[mid1,right]。 第一種情況&#xff1a;左右兩部分都是有序的&#xff0c;說明nums[mid]就是整個數組的最大值。此時…

推薦一款滴滴團隊開源流程圖編輯框架logic-flow

LogicFlow 是一款基于 JavaScript 的流程圖編輯框架&#xff0c;提供直觀的可視化界面&#xff0c;幫助用戶輕松創建、編輯和管理復雜的工作流、業務邏輯或流程模型。其核心優勢在于低代碼化、高度可定制和強交互性&#xff0c;適用于業務系統開發、BPMN 流程設計、決策樹建模等…

java 進階 1.0.3

Thread API說明 自己滾去看文檔 CPU線程調度 每一個線程的優先使用權都是系統隨機分配的&#xff0c;人人平等 誰先分配到就誰先用 也可以耍賴&#xff0c;就是賦予某一個線程擁有之高使用權&#xff1a;優先級 這樣的操作就叫做線程調度 最基本的是系統輪流獲得 java的做法是搶…

匯川EasyPLC MODBUS-RTU通信配置和編程實現

累積流量計算(MODBUS RTU通信數據處理)數據處理相關內容。 累積流量計算(MODBUS RTU通信數據處理)_流量積算儀modbus rtu通訊-CSDN博客文章瀏覽閱讀219次。1、常用通信數據處理MODBUS通信系列之數據處理_modbus模擬的數據變化后會在原來的基礎上累加是為什么-CSDN博客MODBUS通…

【機械視覺】Halcon—【二、Halcon算子全面介紹(超詳細版)】

介紹 Halcon 的算子&#xff08;operators&#xff09;按照功能被系統性地劃分為多個類別&#xff0c;官方文檔中目前&#xff08;Halcon 22.11 版本&#xff09;共有 19 個主分類&#xff0c;每個主分類下還有若干子分類。 本人在此對這19個分類的常用核心算子進行了一系列的…

Https流式輸出一次輸出一大段,一卡一卡的-解決方案

【背景】 最近遇到一個奇怪的現象&#xff0c;前端vue&#xff0c;后端python&#xff0c;服務部署在服務器上面后&#xff0c;本來一切正常&#xff0c;但公司說要使用https訪問&#xff0c;想著也沒什么問題&#xff0c;切過去發現在沒有更改任何代碼的情況下&#xff0c;ht…

Vue常用自定義指令-積累的魅力【VUE】

前言 在【自定義指令—v2與v3之間的區別【VUE基礎】一文中&#xff0c;整理了自定義指令部分vue2和vue3 兩個版本的區別&#xff0c;有興趣的伙伴或者針對自定義部分比較迷茫的伙伴可以跳轉看一下。此次主要介紹一些自己積累的一些自定義指令的代碼&#xff0c;與大家一起分享。…

【mysql】mysql的高級函數、高級用法

mysql是最常用的數據庫之一&#xff0c;常見的函數用法大家應該都很熟悉&#xff0c;本文主要例舉一些相對出現頻率比較少的高級用法 (注&#xff1a;需注意mysql版本&#xff0c;大部分高級特性都是mysql8才有的) 多值索引與虛擬列 主要是解決字符串索引問題&#xff0c;光說…

C#日期和時間:DateTime轉字符串全面指南

C#日期和時間&#xff1a;DateTime轉字符串全面指南 在 C# 開發中&#xff0c;DateTime類型的時間格式化是高頻操作場景。無論是日志記錄、數據持久化&#xff0c;還是接口數據交互&#xff0c;合理的時間字符串格式都能顯著提升系統的可讀性和兼容性。本文將通過 20 實戰示例…

Canvas設計圖片編輯器全講解(一)Canvas基礎(萬字圖文講解)

一、前序 近兩年AI發展太過迅速&#xff0c;各類AI產品層出不窮&#xff0c;AI繪圖/AI工作流/AI視頻等平臺的蓬勃發展&#xff0c;促使圖片/視頻等復雜內容的創作更加簡單&#xff0c;讓更多普通人有了圖片和視頻創作的機會。另一方面用戶內容消費也逐漸向圖片和視頻傾斜。在“…

Javase易混點專項復習02_static關鍵字

1. static關鍵字1.1概述1.2修飾一個成員變量例&#xff1a;1.2.1靜態屬性與非靜態屬性示例及內存圖對比 1.3修飾一個方法&#xff08;靜態方法&#xff09;1.4.static修飾成員的訪問特點總結1.5動態代碼塊和靜態代碼塊1.5.1動態代碼塊1.5.2 靜態代碼塊 1.6帶有繼承的對象創建過…

C++滑動門問題(附兩種方法)

題目如下&#xff1a; 滑動窗口 - 題目 - Liusers OJ ——引用自OJ網站 方法如下&#xff1a; 1.常規思想 #include<bits/stdc.h> using namespace std; int main() {int n,k;int a[110];cin>>n>>k;for(int i0;i<n;i){cin>>a[i];}for(int i0;i…

mysql連接池druid監控配置

文章目錄 前置依賴啟用配置訪問監控一些問題 前置 連接池有很多類型&#xff0c;比如 c3p0&#xff0c;比如 hikariCP&#xff0c;比如 druid。c3p0 一些歷史項目可能用的比較多&#xff0c;hikariCP 需要高性能的項目比較多&#xff0c;druid 性能也很好&#xff0c;而且還提…

Jetson系統燒錄與環境配置全流程詳解(含驅動、GCC、.Net設置)

Jetson系統燒錄與環境配置全流程詳解&#xff08;含驅動、GCC、.Net設置&#xff09; 目錄1. 準備工作與工具安裝1.1 主機系統要求1.2 安裝 SDK Manager 2. JetPack 系統燒錄流程2.1 Jetson 進入恢復模式2.2 使用 SDK Manager 燒錄 JetPack 3. Jetson 系統基礎設置4. 配置 .Net…

分布式緩存:緩存的三種讀寫模式及分類

文章目錄 緩存全景圖Pre緩存讀寫模式概述1. Cache Aside&#xff08;旁路緩存&#xff09;工作流程優缺點 2. Read/Write Through&#xff08;讀寫穿透&#xff09;工作流程優缺點典型場景 3. Write Behind Caching&#xff08;異步寫回&#xff09;工作流程優缺點典型場景 緩存…

Ntfs!FindFirstIndexEntry函數中ReadIndexBuffer函數的作用是新建一個Ntfs!_INDEX_LOOKUP_STACK結構

第一部分&#xff1a; 0: kd> kc # 00 Ntfs!FindFirstIndexEntry 01 Ntfs!NtfsRestartIndexEnumeration 02 Ntfs!NtfsQueryDirectory 03 Ntfs!NtfsCommonDirectoryControl 04 Ntfs!NtfsFsdDirectoryControl 05 nt!IofCallDriver 06 nt!IopSynchronousServiceTail 07 nt!Nt…

5.24 note

笛卡爾積(?選擇條件 select a.student_name as member_A, b.student_name as member_B, c.student_name as member_C from schoola as a join schoolb as b join schoolc as c where a.student_name ! b.student_name and a.student_name !…

為什么需要在循環里fetch?

假設有多個設備連接在后端,數量不定,需要按個讀回狀態,那么就要在循環里fetch了. 此函數非常好用,來自于國內一個作者,時間久了,忘記了來源,抱歉. export default async function fetchWithTimeout(resource, options {}) {const { timeout 1000 } options;const controll…