Android及Harmonyos實現圖片進度顯示效果

鴻蒙Harmonyos實現,使用ImageKnife自定義transform來實現圖片進度效果

import { Context } from '@ohos.abilityAccessCtrl';
import { image } from '@kit.ImageKit';
import { drawing } from '@kit.ArkGraphics2D';
import { GrayScaleTransformation, PixelMapTransformation } from '@ohos/imageknife';/*** 垂直進度灰度變換:頂部灰度,底部彩色,帶波浪邊界* @param grayRatio 頂部灰度區域占比 [0-1]* @param enableWave 是否啟用波浪邊界效果,false為直線分割(性能更佳)*/
@Sendable
export class VerticalProgressGrayscaleTransformation extends PixelMapTransformation {private readonly grayRatio: number;private readonly enableWave: boolean;private static readonly WAVE_AMPLITUDE_RATIO: number = 0.08; // 波浪振幅比例private static readonly WAVE_FREQUENCY: number = 2.5; // 波浪頻率private static readonly WAVE_STEPS: number = 40; // 波浪平滑度(降低提升性能)constructor(grayRatio: number, enableWave: boolean = true) {super();this.grayRatio = Math.max(0, Math.min(1, grayRatio));this.enableWave = enableWave;}override async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {try {// 邊界情況快速處理if (this.grayRatio <= 0.001) {return toTransform;}if (this.grayRatio >= 0.999) {return new GrayScaleTransformation().transform(context, toTransform, width, height);}// 獲取實際圖片尺寸const imageInfo = await toTransform.getImageInfo();if (!imageInfo.size) {return toTransform;}const actualWidth = imageInfo.size.width;const actualHeight = imageInfo.size.height;const grayHeight = Math.floor(actualHeight * this.grayRatio);// 如果灰度區域太小,直接返回原圖if (grayHeight < 5) {return toTransform;}return this.applyVerticalGrayEffect(context, toTransform, actualWidth, actualHeight, grayHeight);} catch (err) {console.error('[VerticalProgressGrayscaleTransformation] Error:', err);return toTransform;}}/*** 應用垂直灰度效果(性能優化版)*/private async applyVerticalGrayEffect(context: Context,original: PixelMap,width: number,height: number,grayHeight: number): Promise<PixelMap> {try {// 創建結果PixelMap并復制原圖const result = await this.createClonedPixelMap(original, width, height);// 創建灰度圖const grayPixelMap = await new GrayScaleTransformation().transform(context, original, width, height);// 一次性完成Canvas操作const canvas = new drawing.Canvas(result);canvas.save();// 設置裁剪路徑并繪制灰度區域canvas.clipPath(this.createOptimizedClipPath(width, grayHeight));canvas.drawImage(grayPixelMap, 0, 0, new drawing.SamplingOptions(drawing.FilterMode.FILTER_MODE_LINEAR));canvas.restore();return result;} catch (error) {console.error('[VerticalProgressGrayscaleTransformation] Apply effect error:', error);return original;}}/*** 創建克隆PixelMap(優化版)*/private async createClonedPixelMap(original: PixelMap, width: number, height: number): Promise<PixelMap> {const opts: image.InitializationOptions = {size: { width, height },pixelFormat: image.PixelMapFormat.RGBA_8888,editable: true,alphaType: image.AlphaType.PREMUL};const cloned = await image.createPixelMap(new ArrayBuffer(width * height * 4), opts);new drawing.Canvas(cloned).drawImage(original, 0, 0);return cloned;}/*** 創建優化的分割路徑(波浪或直線)*/private createOptimizedClipPath(width: number, grayHeight: number): drawing.Path {const path = new drawing.Path();// 直線分割模式(高性能)if (!this.enableWave) {path.addRect({left: 0,top: 0,right: width,bottom: grayHeight});return path;}// 波浪分割模式const amplitude = Math.min(25, grayHeight * VerticalProgressGrayscaleTransformation.WAVE_AMPLITUDE_RATIO);// 波浪太小時使用直線if (amplitude < 2) {path.addRect({left: 0,top: 0,right: width,bottom: grayHeight});return path;}// 構建波浪路徑path.moveTo(0, 0);path.lineTo(width, 0);path.lineTo(width, grayHeight);// 優化的波浪計算const steps = VerticalProgressGrayscaleTransformation.WAVE_STEPS;const stepWidth = width / steps;const waveFreq = VerticalProgressGrayscaleTransformation.WAVE_FREQUENCY;let prevX = width;let prevY = grayHeight;for (let i = 1; i <= steps; i++) {const x = width - i * stepWidth;const wavePhase = (i / steps) * Math.PI * 2 * waveFreq;const y = grayHeight + amplitude * Math.sin(wavePhase);// 使用二次貝塞爾曲線優化連接const controlX = (prevX + x) * 0.5;const controlY = (prevY + y) * 0.5;path.quadTo(controlX, controlY, x, y);prevX = x;prevY = y;}path.lineTo(0, 0);path.close();return path;}getKey(): string {return `VerticalProgressGray_${this.grayRatio}_${this.enableWave ? 'wave' : 'line'}`;}
}

Android實現,使用Glide自定義transform實現

public class VerticalProgressGrayscaleTransformation extends BitmapTransformation {private final float grayRatio; // 灰度區域高度占比,取值范圍 [0, 1]public VerticalProgressGrayscaleTransformation(float grayRatio) {this.grayRatio = grayRatio;}@Overrideprotected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {int width = toTransform.getWidth();int height = toTransform.getHeight();Bitmap.Config config = toTransform.getConfig() != null ? toTransform.getConfig() : Bitmap.Config.ARGB_8888;Bitmap bitmap = pool.get(width, height, config);Canvas canvas = new Canvas(bitmap);// 1. 首先繪制完整的原始彩色圖像作為底層canvas.drawBitmap(toTransform, 0, 0, null);// 對 grayRatio 進行邊界處理,確保在 [0, 1] 范圍內float clampedGrayRatio = Math.max(0f, Math.min(1f, this.grayRatio));// 只有當灰度占比大于一個極小值時才應用灰度效果if (clampedGrayRatio > 0.001f) {Paint grayPaint = new Paint(Paint.ANTI_ALIAS_FLAG); // 添加抗鋸齒ColorMatrix matrix = new ColorMatrix(new float[]{0.299f, 0.587f, 0.114f, 0, 0,0.299f, 0.587f, 0.114f, 0, 0,0.299f, 0.587f, 0.114f, 0, 0,0, 0, 0, 1, 0,});grayPaint.setColorFilter(new ColorMatrixColorFilter(matrix));// 波浪的基準Y坐標,即灰色區域的平均下邊界int waveBaseY = (int) (height * clampedGrayRatio);Path grayRegionPath = new Path();grayRegionPath.moveTo(0, 0);      // 移動到左上角grayRegionPath.lineTo(width, 0);  // 畫到右上角// 定義波浪的振幅float amplitude;if (clampedGrayRatio <= 0.001f || clampedGrayRatio >= 0.999f) {amplitude = 0f; // 如果完全著色或完全灰色,則沒有波浪} else {float baseAmplitude = height * 0.03f; // 基礎振幅為圖片高度的3%// 確保振幅不會使波浪超出圖片頂部或底部amplitude = Math.min(baseAmplitude, waveBaseY);amplitude = Math.min(amplitude, height - waveBaseY);}// 從右向左繪制波浪線作為灰色區域的下邊界grayRegionPath.lineTo(width, waveBaseY); // 連接到右側波浪基準點int numCycles = 3; // 波浪周期數float waveLength = (float) width / numCycles; // 每個周期的長度float currentX = width;for (int i = 0; i < numCycles * 2; i++) { // 每個周期包含一個波峰和波谷,共 numCycles * 2段float nextX = Math.max(0, currentX - waveLength / 2); // 下一個X點float controlX = (currentX + nextX) / 2; // 控制點X坐標// 控制點Y坐標,交替形成波峰和波谷// 從右往左畫,i為偶數時是波峰(相對基準線向上,Y值減小),奇數時是波谷(Y值增大)float controlY = waveBaseY + ((i % 2 == 0) ? -amplitude : amplitude);grayRegionPath.quadTo(controlX, controlY, nextX, waveBaseY); // 二階貝塞爾曲線currentX = nextX;if (currentX == 0) {break; // 到達左邊界}}grayRegionPath.lineTo(0, waveBaseY); // 確保連接到左側波浪基準點grayRegionPath.close(); // 閉合路徑,連接回 (0,0)// 保存畫布狀態canvas.save();// 將畫布裁剪為波浪路徑定義的區域canvas.clipPath(grayRegionPath);//在裁剪區域內,使用灰度畫筆再次繪制原始圖像canvas.drawBitmap(toTransform, 0, 0, grayPaint);// 恢復畫布狀態canvas.restore();}return bitmap;}@Overridepublic void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {messageDigest.update(("VerticalProgressGrayscaleTransformation" + grayRatio).getBytes());}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/85013.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/85013.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/85013.shtml

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

相關文章

linux 中的自動化之systemd

linux | 自動化之systemd linux 中的自動化之systemd 學習總是循序漸進的。 linux 中程序的自動化&#xff0c;包括早期手動啟動&#xff0c;查看啟動后的日志、分析啟動情況&#xff0c;再到后面封裝腳本(大致要求啟動后檢查是否掛了&#xff0c;掛了拉起&#xff0c;沒掛跳過…

【編譯工具】CodeRider 2.0:馭碼 CodeRider 2.0 全流程智能研發協作平臺深度技術測評報告

目錄 前言&#xff1a;CodeRider 2.0 簡介 &#xff08;1&#xff09;核心功能 &#xff08;2&#xff09;適用場景 &#xff08;3&#xff09;優勢 一、產品概述與技術架構 &#xff08;1&#xff09;產品定位與核心價值 &#xff08;2&#xff09;技術架構解析 &…

抓包 TCP 四次揮手報文

文章目錄 抓包 TCP 三次握手報文一、第一次揮手二、第二次揮手三、第三次揮手四、第四次揮手 抓包 TCP 三次握手報文 抓包 TCP 三次握手報文 一、第一次揮手 二、第二次揮手 三、第三次揮手 四、第四次揮手

KMP(Kotlin Multiplatform)發布Web版本亂碼

一、背景 最近用KMP嘗試運行在Android、iOS、desktop都成功了&#xff0c;網絡數據訪問也正常。 可是當運行wasmJs的時候遇到了2個較大的問題。 中文字體出現亂碼。 出現了跨域問題。 首先貼一下每個平臺的運行截圖&#xff1a; Android iOS Desktop 二、問題 當web跑起…

一個應用程序或移動網站項目提供最佳UI解決方案

一個應用程序或移動網站項目提供最佳UI解決方案 此套件是用大量的愛和辛勤工作制作的&#xff0c;為您的下一個應用程序或移動網站項目提供最佳解決方案。120個完全可編輯的界面&#xff0c;分為10個類別和2種文件格式&#xff0c;Photoshop和AI。簡單易用的結構將允許您以所…

Android studio打包生成jar包文件

Android studio打包生成jar包文件 一 項目配置1.修改 app/build.gradle2.修改 AndroidManifest.xml 二 打 Jar 包1.修改 app/build.gradle2.編譯生成 Jar 包 一 項目配置 1.修改 app/build.gradle 將com.android.application改成com.android.library注釋掉applicationId 2.…

JAVA類加載機制(jdk8)

三句話總結JDK8的類加載機制&#xff1a; 類緩存&#xff1a;每個類加載器對他加載過的類都有一個緩存。雙親委派&#xff1a;向上委托查找&#xff0c;向下委托加載。沙箱保護機制&#xff1a;不允許應用程序加載JDK內部的系統類。 JDK8的類加載體系 類加載器的核心方法 //…

更進一步深入的研究ObRegisterCallBack

引入 我們如果想hook對象的回調,在上篇文章里我們已經知道了對象回調函數存在一個列表里面&#xff0c;我們通過dt可以看見&#xff0c;這里他是一個LIST_ENTRY結構&#xff0c;但是實際調用的時候&#xff0c;這樣是行不通的&#xff0c;說明它結構不對 0: kd> dt _OBJEC…

Nginx-3 Nginx 的負載均衡策略

Nginx-3 Nginx 的負載均衡策略 Nginx 的負載均衡其實就是指將請求按照一定的策略轉發給服務集群中的一臺&#xff0c;提高了服務集群的可用性&#xff0c;解決數據流量過大、網絡負荷過重的問題。 AKF 擴展立方體 分為 3 個方向負載&#xff1a; x 軸&#xff1a;增加實例數…

Wiiu平臺RetroArch全能模擬器美化整合包v1.18

這款WiiU平臺RetroArch全能模擬器美化整合包v1.18的亮點包括&#xff1a; 1. 18款平臺完美兼容&#xff1a;無論你是喜歡NES時代的經典游戲&#xff0c;還是鐘愛SNES、GBA等平臺的大作&#xff0c;這款整合包都能滿足你的需求&#xff0c;讓你盡情暢玩游戲。 2. 三款自制主題&a…

MyBatis原理

Mybatis執行過程為&#xff1a;接口代理->sqlSession會話->executor執行器->JDBC操作 一、接口代理 Mybatis根據Mapper接口&#xff0c;動態生成相應實現類 二、SqlSession介紹 MyBatis核心對象SqlSession介紹 - MyBatis中文官網 三、Executor執行器介紹 精通My…

升級內核4.19-腳本

#bash cd /root yum remove -y kernel-tools-3.10.0-1160.el7.x86_64 yum remove -y kernel-tools-libs-3.10.0-1160.el7.x86_64tar -xvf rhel-7-amd64-rpms.tar.gz cd /root/rhel-7-amd64-rpms #安裝依賴、包括socat&conntrack yum localinstall -y *.rpm --skip-broken#升…

全面理解 JVM 垃圾回收(GC)機制:原理、流程與實踐

JVM 的 GC&#xff08;Garbage Collection&#xff09;機制是 Java 程序性能的關鍵支柱。本文將從堆內存布局、回收原理、GC 算法、流程細節、并發收集器機制等維度&#xff0c;系統講清楚 GC 的底層運作原理和優化思路。 一、JVM 堆內存結構 Java 堆是 GC 管理的主要區域&am…

runas命令讓其他用戶以管理員權限運行程序

RUNAS 用法: RUNAS使用示例&#xff1a; runas /noprofile /user:mymachine\administrator cmd #本機Administrator管理員身份執行CMD&#xff0c;/noprofile為不加載該用戶的配置信息。runas /profile /env /user:mydomain\admin “mmc %windir%\system32\dsa.msc” #本機上…

實戰指南:部署MinerU多模態文檔解析API與Dify深度集成(實現解析PDF/JPG/PNG)

MinerU web api部署 MinerU 能夠將包含圖片、公式、表格等元素的多模態 PDF、PPT、DOCX 等文檔轉化為易于分析的 Markdown 格式。 克隆 MinerU 的倉庫 git clone https://github.com/opendatalab/MinerU.gitcd 到 projects/web-api cd projects/web-api在可以科學上網的情況下…

向量外積與秩1矩陣的關系

向量外積與秩1矩陣的關系 flyfish 向量外積是構造秩1矩陣的基本工具&#xff0c;其本質是用兩組向量的線性組合刻畫矩陣的行和列相關性&#xff1b;任意秩1矩陣必可表示為外積&#xff0c;而低秩矩陣&#xff08;秩 k k k&#xff09;可分解為 k k k 個外積矩陣的和&#x…

設計模式-創建型模式(詳解)

創建型模式 單例模式 一個類只允許創建一個對象&#xff0c;稱為單例。 單例體現&#xff1a;配置類、連接池、全局計數器、id生成器、日志對象。 懶漢式 (線程不安全) 單例&#xff1a;【不可用】 用到該單例對象的時候再創建。但存在很大問題&#xff0c;單線程下這段代…

什么是BI?有哪些應用場景

BI&#xff08;Business Intelligence&#xff0c;商業智能&#xff09;是通過技術手段對海量業務數據進行采集、整合、分析和可視化的過程&#xff0c;旨在幫助企業從數據中獲取洞察&#xff0c;支持決策。其核心是通過工具&#xff08;如Quick BI&#xff09;將原始數據轉化為…

從零開始:使用Vite和Vue.js搭建一個空項目

進入node.js官網 https://nodejs.org/zh-cn 下載node.js 點擊進行安裝&#xff0c; 完成之后&#xff0c;按住shift鼠標右鍵&#xff0c;打開powershell窗口 輸入node -v &#xff0c;出現版本號就是成功了 node -v 接下來&#xff0c;打開設置&#xff0c;搜索開發者設置&…