diff --git a/README.md b/README.md index 1b318ab..49be84c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ - 支持内存缓存,使用LRUCache算法,对图片数据进行内存缓存。 - 支持磁盘缓存,对于下载图片会保存一份至磁盘当中。 - 支持进行图片变换: 支持图像像素源图片变换效果。 -- 支持用户配置参数使用:(例如:配置是否开启一级内存缓存,配置磁盘缓存策略,配置仅使用缓存加载数据,配置图片变换效果,配置占位图,配置加载失败占位图等)。 +- 支持用户配置参数使用:( + 例如:配置是否开启一级内存缓存,配置磁盘缓存策略,配置仅使用缓存加载数据,配置图片变换效果,配置占位图,配置加载失败占位图等)。 - 推荐使用ImageKnifeComponent组件配合ImageKnifeOption参数来实现功能。 - 支持用户自定义配置实现能力参考ImageKnifeComponent组件中对于入参ImageKnifeOption的处理。 @@ -22,9 +23,11 @@ ohpm install @ohos/imageknife ``` ## 使用说明 -### 0.依赖配置 -0.1.在项目中entry/oh-package.json5中做如下修改,然后点击Sync Now: +### 1.依赖配置 + +在项目中entry/oh-package.json5中做如下修改,然后点击Sync Now: + ```json5 { "name": "entry", @@ -39,7 +42,7 @@ ohpm install @ohos/imageknife } ``` -0.2.在entry\src\main\ets\entryability\EntryAbility.ts中做如下配置初始化全局ImageKnife实例: +在entry\src\main\ets\entryability\EntryAbility.ts中做如下配置初始化全局ImageKnife实例: ```typescript import UIAbility from '@ohos.app.ability.UIAbility'; @@ -47,22 +50,20 @@ import window from '@ohos.window'; import { ImageKnife } from '@ohos/imageknife' export default class EntryAbility extends UIAbility { - onCreate(want, launchParam) { - globalThis.ImageKnife = ImageKnife.with(this.context); - } - onWindowStageCreate(windowStage: window.WindowStage) { windowStage.loadContent('pages/Index', (err, data) => { }); + //初始化全局ImageKnife + globalThis.ImageKnife = ImageKnife.with(this.context); } } ``` -### 1.加载普通图片 +### 2.加载普通图片 接下来我们来写个简单实例看看: -```typescript +```extendtypescript import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/imageknife' @Entry @@ -73,132 +74,151 @@ struct Index { loadSrc: $r('app.media.icon') } -build() { - Row() { - Column() { - Text(this.message) - .fontSize(50) - .fontWeight(FontWeight.Bold) - ImageKnifeComponent({ imageKnifeOption: this.option }) - .width(300) - .height(300) - } -.width('100%') -} -.height('100%') -} + build() { + Row() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + ImageKnifeComponent({ imageKnifeOption: this.option }) + .width(300) + .height(300) + }.width('100%') + }.height('100%') + } } ``` 非常简单,仅需定义一个ImageKnifeOption数据对象,然后在你需要的UI位置,加入ImageKnifeComponent自定义组件就可以加载出一张图像了。 -### 2.加载SVG图片 +### 3.加载SVG图片 -加载svg其实和普通流程没有区别,只要将 `loadSrc: $r('app.media.jpgSample'),` `改成一张 loadSrc: $r('app.media.svgSample'),`svg类型图片即可。 +加载svg其实和普通流程没有区别,只要将 `loadSrc: $r('app.media.jpgSample'),` `改成一张 loadSrc: $r('app.media.svgSample'),` +svg类型图片即可。 目前加载SVG图片解析依赖了 [SVG三方库](https://gitee.com/openharmony-sig/ohos-svg),由于目前该库还无法解析mask标签,所以这里大家需要留意一下。 -### 3.加载GIF图片 +### 4.加载GIF图片 -3.1加载GIF其实和普通流程也没有区别只要将 `loadSrc: $r('app.media.jpgSample'),` `改成一张 loadSrc: $r('app.media.gifSample'),`GIF图片即可。 +加载GIF其实和普通流程也没有区别只要将 `loadSrc: $r('app.media.jpgSample'),` `改成一张 loadSrc: $r('app.media.gifSample'),` +GIF图片即可。 -但是解析gif图片属于耗时操作,所以我们需要将其放入子线程操作。 **这里我们需要在页面的创建和销毁上添加一个worker子线程操作。** +但是解析gif图片属于耗时操作,所以我们需要将其放入子线程操作。 **这里我们需要在页面的创建和销毁上添加一个worker子线程操作。 +** + +```extendtypescript +import router from '@ohos.router' + +import { ImageKnifeComponent, ImageKnifeOption, } from '@ohos/imageknife' +import worker from '@ohos.worker'; -```typescript -import router from '@system.router'; -import { - ImageKnifeComponent, - ImageKnifeOption, -} from '@ohos/imageknife' -import ArkWorker from '@ohos.worker' @Entry @Component struct IndexFunctionDemo { - private globalGifWorker:any = undefined - @State imageKnifeOption: ImageKnifeOption = - { - loadSrc: $r('app.media.gifSample'), + private globalGifWorker: any = undefined + @State imageKnifeOption1: ImageKnifeOption = { + loadSrc: $r('app.media.icon'), placeholderSrc: $r('app.media.icon_loading'), errorholderSrc: $r('app.media.icon_failed') }; - + @State imageKnifeOption2: ImageKnifeOption = { + loadSrc: $r('app.media.icon'), + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed') + }; + build() { Scroll() { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Text("简单示例:加载一张gif图片").fontSize(15) - ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption }) - .width(300) - .height(300) + Text("简单示例1:加载一张本地png图片").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("加载PNG") + .onClick(() => { + this.imageKnifeOption1 = { + loadSrc: $r('app.media.pngSample'), + + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed') + } + }).margin({ top: 5, left: 3 }) + ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(300).height(300) + }.width('100%').backgroundColor(Color.Pink) + + Text("简单示例2:加载一张网络gif图片").fontSize(15) + Text("gif解析在子线程,请在页面构建后创建worker,注入imageknife").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("加载GIF") + .onClick(() => { + this.imageKnifeOption2 = { + loadSrc: 'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658', + + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + displayProgress: true, + } + }).margin({ top: 5, left: 3 }) + ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 }).width(300).height(300) + }.width('100%').backgroundColor(Color.Pink) + + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("ImageKnife测试目录页面") + .onClick(() => { + console.log("pages/imageknifeTestCaseIndex 页面跳转") + router.pushUrl({ url: "pages/imageknifeTestCaseIndex" }); + }).margin({ top: 15 }) + }.width('100%').height(60).backgroundColor(Color.Pink) } } .width('100%') .height('100%') } - + aboutToAppear() { - // 页面初始化创建worker - this.globalGifWorker = new ArkWorker.Worker('entry/ets/pages/workers/gifParseWorker.ts', { - type: 'classic', - name: 'ImageKnifeParseGIF' - }) + this.globalGifWorker = new worker.ThreadWorker('entry/ets/workers/GifLoadWorker.ts') // gif解析在子线程,请在页面构建后创建worker,注入imageknife globalThis.ImageKnife.setGifWorker(this.globalGifWorker) } - aboutToDisappear(){ - // 页面销毁 销毁worker - if(this.globalGifWorker){ + + aboutToDisappear() { + // 页面销毁 销毁worker + if (this.globalGifWorker) { this.globalGifWorker.terminate(); } } - } ``` -#### 创建worker +#### 5.创建worker 由于使用到了worker,目前worker创建只能在entry里面,所以我这边着重讲一下worker配置的流程。 -在entry/src/main/ets/pages目录下创建文件夹workers,然后在文件夹中创建gifParseWorker.ts文件,最后填入内容: +在entry目录上:点击鼠标右键 --> New --> Worker -```typescript -import arkWorker from '@ohos.worker'; + + +在弹出窗口中填入即将创建的worker的名称GifLoadWorker,点击弹窗右下角Finish, + + + +DevEco将自动在entry/src/main/ets/workers目录下生成GifLoadWorker.ts文件,并在其中生成模板代码 + + + +同时entry模块下build-profile.json5也会自动生成新建的worker的配置信息 + + + +接下来我们在GifLoadWorker.ts中导入gif处理方法 + +```extendtypescript import { gifHandler } from '@ohos/imageknife/GifWorker' - -arkWorker.parentPort.onmessage = gifHandler; +``` +同时设置 +```extendtypescript +workerPort.onmessage = gifHandler ``` -代码处理流程已经封装在gifHanlder函数中了。 - - - -接下来我们需要在entry/build-profile.json5文件中添加配置 - -```typescript -{ - "apiType": 'stageMode', - "buildOption": { - "sourceOption": { - "workers": [ - "./src/main/ets/pages/workers/gifParseWorker.ts", - ] - } - }, - "targets": [ - { - "name": "default", - }, - { - "name": "ohosTest", - } - ] -} -``` - - - - - -经过了上面的配置,就配置好了worker, GIF图片加载就能顺利进行了。 **如果GIF加载未成功,可以检查一下worker配置是否完成**。 +经过了上面的配置,就配置好了worker,GIF图片加载就能顺利进行了。 如果GIF加载未成功,可以检查一下worker配置是否完成,或者参考entry/src/main/ets/pages/testGifLoadWithWorkerPage.ets中的gif加载写法。 ## 进阶使用 @@ -206,40 +226,41 @@ arkWorker.parentPort.onmessage = gifHandler; ### ImageKnifeOption参数列表 -| 参数名称 | 入参内容 | 功能简介 | -| ---------------------------- | ------------------------------------------------------------ | ----------------------------------- | -| loadSrc | string \| PixelMap \| Resource | 设置主图资源(必选) | -| mainScaleType | ScaleType | 设置主图展示样式(可选) | -| strategy | DiskStrategy | 设置磁盘缓存策略(可选) | -| dontAnimateFlag | boolean | gif加载展示一帧(可选) | -| placeholderSrc | PixelMap \| Resource | 设置占位图(可选) | -| placeholderScaleType | ScaleType | 设置占位图展示样式(可选) | -| errorholderSrc | PixelMap \| Resource | 设置加载失败占位图(可选) | -| errorholderSrcScaleType | ScaleType | 设置失败占位图展示样式(可选) | -| retryholderSrc | PixelMap \| Resource | 设置加载失败重试占位图(可选) | -| retryholderScaleType | ScaleType | 设置重试占位图展示样式(可选) | -| thumbSizeMultiplier | number 范围(0,1] | 设置缩略图占比(可选) | -| thumbSizeDelay | number | 设置缩略图展示时间(可选) | -| thumbSizeMultiplierScaleType | ScaleType | 设置缩略图展示样式(可选) | -| displayProgress | boolean | 设置是否展示下载进度条(可选) | -| canRetryClick | boolean | 设置重试图层是否点击重试(可选) | -| onlyRetrieveFromCache | boolean | 仅使用缓存加载数据(可选) | -| isCacheable | boolean | 是否开启一级内存缓存(可选) | -| gif | {
// 返回一周期动画gif消耗的时间
loopFinish?: (loopTime?) => void
// gif播放速率相关
speedFactory?: number
// 直接展示gif第几帧数据
seekTo?: number
} | GIF播放控制能力(可选) | -| transformation | BaseTransform | 单个变换(可选) | -| transformations | Array> | 多个变换,目前仅支持单个变换(可选) | -| allCacheInfoCallback | IAllCacheInfoCallback | 输出缓存相关内容和信息(可选) | -| **drawLifeCycle** | **IDrawLifeCycle** | **用户自定义实现绘制方案(可选)** | +| 参数名称 | 入参内容 | 功能简介 | +|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------| +| loadSrc | string \ | PixelMap \ | Resource | 设置主图资源(必选) | +| mainScaleType | ScaleType | 设置主图展示样式(可选) | +| strategy | DiskStrategy | 设置磁盘缓存策略(可选) | +| dontAnimateFlag | boolean | gif加载展示一帧(可选) | +| placeholderSrc | PixelMap \ | Resource | 设置占位图(可选) | +| placeholderScaleType | ScaleType | 设置占位图展示样式(可选) | +| errorholderSrc | PixelMap \ | Resource | 设置加载失败占位图(可选) | +| errorholderSrcScaleType | ScaleType | 设置失败占位图展示样式(可选) | +| retryholderSrc | PixelMap \ | Resource | 设置加载失败重试占位图(可选) | +| retryholderScaleType | ScaleType | 设置重试占位图展示样式(可选) | +| thumbSizeMultiplier | number 范围(0,1] | 设置缩略图占比(可选) | +| thumbSizeDelay | number | 设置缩略图展示时间(可选) | +| thumbSizeMultiplierScaleType | ScaleType | 设置缩略图展示样式(可选) | +| displayProgress | boolean | 设置是否展示下载进度条(可选) | +| canRetryClick | boolean | 设置重试图层是否点击重试(可选) | +| onlyRetrieveFromCache | boolean | 仅使用缓存加载数据(可选) | +| isCacheable | boolean | 是否开启一级内存缓存(可选) | +| gif | {
// 返回一周期动画gif消耗的时间
loopFinish?: (loopTime?) => void
// gif播放速率相关
speedFactory?: number
// 直接展示gif第几帧数据
seekTo?: number
} | GIF播放控制能力(可选) | +| transformation | BaseTransform | 单个变换(可选) | +| transformations | Array> | 多个变换,目前仅支持单个变换(可选) | +| allCacheInfoCallback | IAllCacheInfoCallback | 输出缓存相关内容和信息(可选) | +| **drawLifeCycle** | **IDrawLifeCycle** | **用户自定义实现绘制方案(可选)** | 其他参数只需要在ImageKnifeOption对象上按需添加即可。 -这里我们着重讲一下**自定义实现绘制方案**。为了增强绘制扩展能力,目前ImageKnifeComponent使用了Canvas的渲染能力作为基础。在此之上为了抽象组件绘制表达。我将图像的状态使用了**IDrawLifeCycle绘制生命周期进行表达**, +这里我们着重讲一下**自定义实现绘制方案**。为了增强绘制扩展能力,目前ImageKnifeComponent使用了Canvas的渲染能力作为基础。在此之上为了抽象组件绘制表达。我将图像的状态使用了 +**IDrawLifeCycle绘制生命周期进行表达**, -大致流程 展示占位图->展示网络加载进度->展示缩略图->展示主图->展示重试图层->展示失败占位图 +大致流程 展示占位图->展示网络加载进度->展示缩略图->展示主图->展示重试图层->展示失败占位图 -ImageKnifeComponent内部,责任链实现。 用户参数设置->全局参数设置->自定义组件内部设置 +ImageKnifeComponent内部,责任链实现。 用户参数设置->全局参数设置->自定义组件内部设置 采用责任链的好处是,用户可以通过自定义绘制,重新绘制图层。如果不想绘制也可以通过预制回调获取绘制流程信息。 @@ -250,14 +271,15 @@ ImageKnifeComponent内部,责任链实现。 用户参数设置->全局参数 代码如下: ```typescript -import {ImageKnifeComponent} from '@ohos/imageknife' -import {ImageKnifeOption} from '@ohos/imageknife' -import {ImageKnifeDrawFactory} from '@ohos/imageknife' +import { ImageKnifeComponent } from '@ohos/imageknife' +import { ImageKnifeOption } from '@ohos/imageknife' +import { ImageKnifeDrawFactory } from '@ohos/imageknife' + @Entry @Component struct Index { - @State imageKnifeOption1: ImageKnifeOption = - { // 加载一张本地的jpg资源(必选) + @State imageKnifeOption1: ImageKnifeOption = { + // 加载一张本地的jpg资源(必选) loadSrc: $r('app.media.jpgSample'), // 占位图使用本地资源icon_loading(可选) placeholderSrc: $r('app.media.icon_loading'), @@ -266,27 +288,30 @@ struct Index { // 绘制圆角30,边框5,边框"#ff00ff".用户自定义绘制(可选) drawLifeCycle:ImageKnifeDrawFactory.createRoundLifeCycle(5,"#ff00ff",30) }; - - - build() { - Scroll() { - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }) - .width(300) - .height(300) - } + + build(){ + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }) + .width(300) + .height(300) + } + } + .width('100%') + .height('100%') } - .width('100%') - .height('100%') - } } ``` -`ImageKnifeDrawFactory.createRoundLifeCycle(5,"#ff00ff",30)`我们深入查看源码可以发现,实际上是对IDrawLifeCycle接口的部分实现,这里我介绍一下IDrawLifeCycle。 +`ImageKnifeDrawFactory.createRoundLifeCycle(5,"#ff00ff",30)` +我们深入查看源码可以发现,实际上是对IDrawLifeCycle接口的部分实现,这里我介绍一下IDrawLifeCycle。 -**IDrawLifeCycle的返回值代表事件是否被消费,如果被消费接下来组件内部就不会处理,如果没被消费就会传递到下一个使用者。目前消费流程(用户自定义->全局配置定义->组件内部默认定义)** +* +*IDrawLifeCycle的返回值代表事件是否被消费,如果被消费接下来组件内部就不会处理,如果没被消费就会传递到下一个使用者。目前消费流程(用户自定义-> +全局配置定义->组件内部默认定义)** -所以我们在当数据是一张PixelMap的时候(目前jpg png bmp webp svg返回的都是PixelMap,gif返回GIFFrame数组),我们返回了true。消费了事件,代表这个绘制流程用户自定义完成。 +所以我们在当数据是一张PixelMap的时候(目前jpg png bmp webp +svg返回的都是PixelMap,gif返回GIFFrame数组),我们返回了true。消费了事件,代表这个绘制流程用户自定义完成。 @@ -298,20 +323,20 @@ struct Index { ```typescript import AbilityStage from '@ohos.application.AbilityStage' -import { ImageKnife,ImageKnifeDrawFactory} from '@ohos/imageknife' +import { ImageKnife, ImageKnifeDrawFactory } from '@ohos/imageknife' import ArkWorker from '@ohos.worker' export default class MyAbilityStage extends AbilityStage { - onCreate() { - globalThis.ImageKnife = ImageKnife.with(this.context); - // 全局配置网络加载进度条 - globalThis.ImageKnife.setDefaultLifeCycle(ImageKnifeDrawFactory.createProgressLifeCycle("#10a5ff", 0.5)) - } + onCreate() { + globalThis.ImageKnife = ImageKnife.with(this.context); + // 全局配置网络加载进度条 + globalThis.ImageKnife.setDefaultLifeCycle(ImageKnifeDrawFactory.createProgressLifeCycle("#10a5ff", 0.5)) + } } ``` -这里大家可能会问,为什么会将这个IDrawLifeCycle放在AbilityStage里面实现? +这里大家可能会问,为什么会将这个IDrawLifeCycle放在AbilityStage里面实现? 这是因为网络下载百分比进度很多时候都是全局通用,如果有需要全局配置的自定义展示方案。推荐在AbilityStage里面,往ImageKnife的setDefaultLifeCycle函数中注入,即可将ImageKnifeComponent中的默认绘制方案替换。 @@ -331,13 +356,14 @@ export default class MyAbilityStage extends AbilityStage { ### 数据加载 -#### RequestOption构建: +#### RequestOption构建: -请查阅下文接口内容:[RequestOption接口方法](#requestoption用户配置参数) +请查阅下文接口内容:[RequestOption接口方法](#requestoption用户配置参数) 了解了RequestOption的参数内容后,我们可以参考ImageKnifeComponent组件代码进行分析。 -**从`imageKnifeExecute()`函数入口,首先我们需要构建一个RequestOption对象,`let request = new RequestOption()`, 接下来就是按需配置request对象的内容,最后使用 `globalThis.ImageKnife.call(request)`发送request执行任务即可。** +**从`imageKnifeExecute()`函数入口,首先我们需要构建一个RequestOption对象,`let request = new RequestOption()`, +接下来就是按需配置request对象的内容,最后使用 `globalThis.ImageKnife.call(request)`发送request执行任务即可。** 是不是很简单,而其实最重要的内容是就是: **按需配置request对象的内容** 为了更好理解,我举例说明一下: @@ -386,86 +412,84 @@ request.skipMemoryCache(true) 这里只是简单介绍部分使用,更多的内容请参考 **按需加载** 原则,并且可以参考ImageKnifeComponent源码或者根据文档自行探索实现。 - - ## 接口说明 ### RequestOption用户配置参数 -| 方法名 | 入参 | 接口描述 | -| ------------------------------------------------------------ | ---------------------------------------------------------- | -------------------------------------------------------- | -| load(src: string \| PixelMap \| Resource) | string \| PixelMap \| Resource | 待加载图片的资源 | -| setImageViewSize(imageSize: { width: number, height: number }) | { width: number, height: number } | 传入显示图片组件的大小,变换的时候需要作为参考 | -| diskCacheStrategy(strategy: DiskStrategy) | DiskStrategy | 配置磁盘缓存策略 NONE SOURCE RESULT ALL AUTOMATIC | -| placeholder(src: PixelMap \| Resource, func?: AsyncSuccess) | src: PixelMap \| Resource, func?: AsyncSuccess | 配置占位图,其中func为数据回调函数 | -| errorholder(src: PixelMap \| Resource, func?: AsyncSuccess) | src: PixelMap \| Resource, func?: AsyncSuccess | 配置加载失败占位图,其中func为数据回调函数 | -| retryholder(src: PixelMap \| Resource, func?: AsyncSuccess) | src: PixelMap \| Resource, func?: AsyncSuccess | 配置重试占位图,如果配置则加载失败后优先展示重试占位图 | -| addListener(func: AsyncCallback) | func: AsyncCallback | 配置整个监听回调,数据正常加载返回,加载失败返回错误信息 | -| thumbnail(sizeMultiplier:number, func?: AsyncSuccess) | sizeMultiplier:number, func?: AsyncSuccess | 设置缩略图比例,缩略图返回后,加载并展示缩略图 | -| addProgressListener(func?: AsyncSuccess) | func?: AsyncSuccess | 设置网络下载百分比监听,返回数据加载百分比数值 | -| addRetryListener(func?: AsyncSuccess) | func?: AsyncSuccess | 设置重试监听 | -| addAllCacheInfoCallback(func: IAllCacheInfoCallback) | func: IAllCacheInfoCallback | 设置获取所有缓存信息监听 | -| skipMemoryCache(skip: boolean) | skip: boolean | 配置是否跳过内存缓存 | -| retrieveDataFromCache(flag: boolean) | flag: boolean | 配置仅从缓存中加载数据 | +| 方法名 | 入参 | 接口描述 | +|-----------------------------------------------------------------------|------------------------------------------------------------|----------------------------------------------| +| load(src: string \ | PixelMap \ | Resource) | string \| PixelMap \| Resource | 待加载图片的资源 | +| setImageViewSize(imageSize: { width: number, height: number }) | { width: number, height: number } | 传入显示图片组件的大小,变换的时候需要作为参考 | +| diskCacheStrategy(strategy: DiskStrategy) | DiskStrategy | 配置磁盘缓存策略 NONE SOURCE RESULT ALL AUTOMATIC | +| placeholder(src: PixelMap \ | Resource, func?: AsyncSuccess) | src: PixelMap \ | Resource, func?: AsyncSuccess | 配置占位图,其中func为数据回调函数 | +| errorholder(src: PixelMap \ | Resource, func?: AsyncSuccess) | src: PixelMap \ | Resource, func?: AsyncSuccess | 配置加载失败占位图,其中func为数据回调函数 | +| retryholder(src: PixelMap \ | Resource, func?: AsyncSuccess) | src: PixelMap \ | Resource, func?: AsyncSuccess | 配置重试占位图,如果配置则加载失败后优先展示重试占位图 | +| addListener(func: AsyncCallback) | func: AsyncCallback | 配置整个监听回调,数据正常加载返回,加载失败返回错误信息 | +| thumbnail(sizeMultiplier:number, func?: AsyncSuccess) | sizeMultiplier:number, func?: AsyncSuccess | 设置缩略图比例,缩略图返回后,加载并展示缩略图 | +| addProgressListener(func?: AsyncSuccess) | func?: AsyncSuccess | 设置网络下载百分比监听,返回数据加载百分比数值 | +| addRetryListener(func?: AsyncSuccess) | func?: AsyncSuccess | 设置重试监听 | +| addAllCacheInfoCallback(func: IAllCacheInfoCallback) | func: IAllCacheInfoCallback | 设置获取所有缓存信息监听 | +| skipMemoryCache(skip: boolean) | skip: boolean | 配置是否跳过内存缓存 | +| retrieveDataFromCache(flag: boolean) | flag: boolean | 配置仅从缓存中加载数据 | 同时支持[图片变换相关](#图片变换相关)接口。 ### ImageKnife 启动器/门面类 -| 方法名 | 入参 | 接口描述 | -| ------------------------------- | ---------------------- | ---------------------------------- | -| call(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行加载流程 | +| 方法名 | 入参 | 接口描述 | +|---------------------------------|------------------------|-------------------| +| call(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行加载流程 | | preload(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行预加载流程 | ### 缓存策略相关 -| 使用方法 | 类型 | 策略描述 | -| ------------------------------------------ | --------- | ---------------------------------------- | +| 使用方法 | 类型 | 策略描述 | +|--------------------------------------------|-----------|----------------------| | request.diskCacheStrategy(new ALL()) | ALL | 表示既缓存原始图片,也缓存转换过后的图片 | -| request.diskCacheStrategy(new AUTOMATIC()) | AUTOMATIC | 表示尝试对本地和远程图片使用适合的策略 | -| request.diskCacheStrategy(new DATA()) | DATA | 表示只缓存原始图片 | -| request.diskCacheStrategy(new NONE()) | NONE | 表示不缓存任何内容 | -| request.diskCacheStrategy(new RESOURCE()) | RESOURCE | 表示只缓存转换过后的图片 | +| request.diskCacheStrategy(new AUTOMATIC()) | AUTOMATIC | 表示尝试对本地和远程图片使用适合的策略 | +| request.diskCacheStrategy(new DATA()) | DATA | 表示只缓存原始图片 | +| request.diskCacheStrategy(new NONE()) | NONE | 表示不缓存任何内容 | +| request.diskCacheStrategy(new RESOURCE()) | RESOURCE | 表示只缓存转换过后的图片 | ### ScaleType类型展示效果 -| 使用方法 | 类型 | 策略描述 | -| ----------------------- | ---- | ---------------------------------------------------- | -| ScaleType.FIT_START | int | 图像位于用户设置组件左上角显示,图像会缩放至全部展示 | -| ScaleType.FIT_END | int | 图像位于用户设置组件右下角显示,图像会缩放至全部展示 | -| ScaleType.FIT_CENTER | int | 图像位于用户设置组件居中,图像会缩放至全部展示 | -| ScaleType.CENTER | int | 图像居中展示,不缩放 | -| ScaleType.CENTER_CROP | int | 图像的宽高长度,短的部分缩放至组件大小,超出的全部裁剪 | -| ScaleType.FIT_XY | int | 图像拉伸至组件大小 | -| ScaleType.CENTER_INSIDE | int | 如果图像大于组件则执行FIT_CENTER,小于组件则CENTER | -| ScaleType.NONE | int | 如果不想适配,直接展示原图大小 | +| 使用方法 | 类型 | 策略描述 | +|-------------------------|-----|-----------------------------------| +| ScaleType.FIT_START | int | 图像位于用户设置组件左上角显示,图像会缩放至全部展示 | +| ScaleType.FIT_END | int | 图像位于用户设置组件右下角显示,图像会缩放至全部展示 | +| ScaleType.FIT_CENTER | int | 图像位于用户设置组件居中,图像会缩放至全部展示 | +| ScaleType.CENTER | int | 图像居中展示,不缩放 | +| ScaleType.CENTER_CROP | int | 图像的宽高长度,短的部分缩放至组件大小,超出的全部裁剪 | +| ScaleType.FIT_XY | int | 图像拉伸至组件大小 | +| ScaleType.CENTER_INSIDE | int | 如果图像大于组件则执行FIT_CENTER,小于组件则CENTER | +| ScaleType.NONE | int | 如果不想适配,直接展示原图大小 | ### 图片变换相关 -| 使用方法 | 类型 | 相关描述 | -| ------------------------------ | ---------------------------------- | ---------------------------------------------------- | +| 使用方法 | 类型 | 相关描述 | +|--------------------------------|------------------------------------|----------------------------------| | request.centerCrop() | CenterCrop | 可以根据图片文件,目标显示大小,进行对应centerCrop | | request.centerInside() | CenterInside | 可以根据图片文件,目标显示大小,进行对应centerInside | | request.fitCenter() | FitCenter | 可以根据图片文件,目标显示大小,进行对应fitCenter | -| request.blur() | BlurTransformation | 模糊处理 | -| request.brightnessFilter() | BrightnessFilterTransformation | 亮度滤波器 | -| request.contrastFilter() | ContrastFilterTransformation | 对比度滤波器 | -| request.cropCircle() | CropCircleTransformation | 圆形剪裁显示 | -| request.cropCircleWithBorder() | CropCircleWithBorderTransformation | 圆环展示 | -| request.cropSquare() | CropSquareTransformation | 正方形剪裁 | -| request.crop() | CropTransformation | 自定义矩形剪裁 | -| request.grayscale() | GrayscaleTransformation | 灰度级转换 | -| request.invertFilter() | InvertFilterTransformation | 反转滤波器 | -| request.pixelationFilter() | PixelationFilterTransformation | 像素化滤波器 | -| request.rotateImage() | RotateImageTransformation | 图片旋转 | -| request.roundedCorners() | RoundedCornersTransformation | 圆角剪裁 | -| request.sepiaFilter() | SepiaFilterTransformation | 乌墨色滤波器 | -| request.sketchFilter() | SketchFilterTransformation | 素描滤波器 | -| request.mask() | MaskTransformation | 遮罩 | -| request.swirlFilter() | SwirlFilterTransformation | 扭曲滤波器 | -| request.kuwaharaFilter() | KuwaharaFilterTransform | 桑原滤波器 | -| request.toonFilter() | ToonFilterTransform | 动画滤波器 | -| request.vignetteFilter() | VignetteFilterTransform | 装饰滤波器 | +| request.blur() | BlurTransformation | 模糊处理 | +| request.brightnessFilter() | BrightnessFilterTransformation | 亮度滤波器 | +| request.contrastFilter() | ContrastFilterTransformation | 对比度滤波器 | +| request.cropCircle() | CropCircleTransformation | 圆形剪裁显示 | +| request.cropCircleWithBorder() | CropCircleWithBorderTransformation | 圆环展示 | +| request.cropSquare() | CropSquareTransformation | 正方形剪裁 | +| request.crop() | CropTransformation | 自定义矩形剪裁 | +| request.grayscale() | GrayscaleTransformation | 灰度级转换 | +| request.invertFilter() | InvertFilterTransformation | 反转滤波器 | +| request.pixelationFilter() | PixelationFilterTransformation | 像素化滤波器 | +| request.rotateImage() | RotateImageTransformation | 图片旋转 | +| request.roundedCorners() | RoundedCornersTransformation | 圆角剪裁 | +| request.sepiaFilter() | SepiaFilterTransformation | 乌墨色滤波器 | +| request.sketchFilter() | SketchFilterTransformation | 素描滤波器 | +| request.mask() | MaskTransformation | 遮罩 | +| request.swirlFilter() | SwirlFilterTransformation | 扭曲滤波器 | +| request.kuwaharaFilter() | KuwaharaFilterTransform | 桑原滤波器 | +| request.toonFilter() | ToonFilterTransform | 动画滤波器 | +| request.vignetteFilter() | VignetteFilterTransform | 装饰滤波器 | @@ -512,7 +536,10 @@ DevEco Studio 版本:4.0 Canary2(4.0.3.312), SDK: API10 (4.0.9.3) - RequestOption.ets # 用户设置参数封装 /entry/src/ -- main/ets/MainAbility +- main/ets + - entryability + - CustomEngineKeyImpl.ets + - EntryAbility.ts - pages # 测试page页面列表 - basicTestFeatureAbilityPage.ets # 测试列表加载 - basicTestFileIOPage.ets # 测试fileio @@ -539,15 +566,19 @@ DevEco Studio 版本:4.0 Canary2(4.0.3.312), SDK: API10 (4.0.9.3) - testImageKnifeOptionChangedPage4.ets # 数据切换测试,内容动画 - testImageKnifeOptionChangedPage5.ets # 数据切换测试,ImageKnifeDrawFactory封装圆角圆环边框等 - testPreloadPage.ets # 预加载测试 - - transformPixelMapPage.ets # 所有类型变换测试 - - - gifParseWorker.ts # gifworker子线程解析 - - worker1.js # worker多线程测试 + - transformPixelMapPage.ets # 所有类型变换测试 + - testSingleFrameGifPage.ets # 单帧gif加载测试 + - testGifLoadWithWorkerPage.ets # gif加载有无worker的影响测试 + -workers + - GifLoadWorkers.ts # gif子线程解析 + - MyWorker.ts # worker使用示例 + - PngLoadWorker.ts # png子线程解析 ``` ## 贡献代码 -使用过程中发现任何问题都可以提 [issue](https://gitee.com/openharmony-tpc/ImageKnife/issues) 给我们,当然,我们也非常欢迎你给我们发 [PR](https://gitee.com/openharmony-tpc/ImageKnife/issues) 。 +使用过程中发现任何问题都可以提 [issue](https://gitee.com/openharmony-tpc/ImageKnife/issues) +给我们,当然,我们也非常欢迎你给我们发 [PR](https://gitee.com/openharmony-tpc/ImageKnife/issues) 。 ## 开源协议 diff --git a/build-profile.json5 b/build-profile.json5 index 0ac1294..fe9a36b 100644 --- a/build-profile.json5 +++ b/build-profile.json5 @@ -8,7 +8,20 @@ "signingConfig": "default" } ], - "signingConfigs": [] + "signingConfigs": [ + { + "name": "default", + "material": { + "certpath": "C:\\Users\\admin\\.ohos\\config\\openharmony\\auto_ohos_default_ImageKnife_com.openharmony.imageknife.cer", + "storePassword": "0000001B3AC9BCC9FC4C1EC6B2F892BA3D039A330151A3AB9DA17BBAACE0F312E52F6D6FC0AE585B7479F8", + "keyAlias": "debugKey", + "keyPassword": "0000001BA819F9A4DDFF14F3529073770609B0607886D8D748670E7BC8A5D0A2F750613562B838B0D78F98", + "profile": "C:\\Users\\admin\\.ohos\\config\\openharmony\\auto_ohos_default_ImageKnife_com.openharmony.imageknife.p7b", + "signAlg": "SHA256withECDSA", + "storeFile": "C:\\Users\\admin\\.ohos\\config\\openharmony\\auto_ohos_default_ImageKnife_com.openharmony.imageknife.p12" + } + } + ] }, "modules": [ { diff --git a/entry/build-profile.json5 b/entry/build-profile.json5 index be49080..52767e4 100644 --- a/entry/build-profile.json5 +++ b/entry/build-profile.json5 @@ -3,8 +3,9 @@ "buildOption": { "sourceOption": { "workers": [ - "./src/main/ets/pages/workers/worker1.js", - "./src/main/ets/pages/workers/gifParseWorker.ts", + './src/main/ets/workers/GifLoadWorker.ts', + './src/main/ets/workers/PngLoadWorker.ts', + './src/main/ets/workers/MyWorker.ts' ] } }, diff --git a/entry/src/main/ets/entryability/EntryAbility.ts b/entry/src/main/ets/entryability/EntryAbility.ts index 1e69afb..af3922b 100644 --- a/entry/src/main/ets/entryability/EntryAbility.ts +++ b/entry/src/main/ets/entryability/EntryAbility.ts @@ -21,21 +21,6 @@ import abilityAccessCtrl,{Permissions} from '@ohos.abilityAccessCtrl'; export default class EntryAbility extends UIAbility { - onCreate(want, launchParam) { - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); - globalThis.ImageKnife = ImageKnife.with(this.context); - // 全局配置网络加载进度条 - globalThis.ImageKnife.setDefaultLifeCycle(ImageKnifeDrawFactory.createProgressLifeCycle("#10a5ff", 0.5)) - // 全局配置缓存key - globalThis.ImageKnife.setEngineKeyImpl(new CustomEngineKeyImpl()) - - LogUtil.mLogLevel = LogUtil.ALL - } - - onDestroy() { - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); - } - onWindowStageCreate(windowStage: window.WindowStage) { // Main window is created, set main page for this ability hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); @@ -59,20 +44,13 @@ export default class EntryAbility extends UIAbility { } hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); }); - } - onWindowStageDestroy() { - // Main window is destroyed, release UI related resources - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); - } - - onForeground() { - // Ability has brought to foreground - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); - } - - onBackground() { - // Ability has back to background - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + globalThis.ImageKnife = ImageKnife.with(this.context); + // 全局配置网络加载进度条 + globalThis.ImageKnife.setDefaultLifeCycle(ImageKnifeDrawFactory.createProgressLifeCycle("#10a5ff", 0.5)) + // 全局配置缓存key + globalThis.ImageKnife.setEngineKeyImpl(new CustomEngineKeyImpl()) + //开启ImageKnife所有级别日志开关 + LogUtil.mLogLevel = LogUtil.ALL } } diff --git a/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets b/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets index 762ff03..748aa83 100644 --- a/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets +++ b/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets @@ -224,16 +224,17 @@ struct IndexFunctionDemo { router.pushUrl({ url: "pages/testSingleFrameGifPage" }); }).margin({ top: 5, left: 3 }) }.width('100%').height(60).backgroundColor(Color.Pink) + + Text("worker测试").fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button("gif加载有无worker的区别测试") + .onClick(() => { + router.pushUrl({ url: "pages/testGifLoadWithWorkerPage" }); + }).margin({ top: 5, left: 3 }) + }.width('100%').height(60).backgroundColor(Color.Pink) } } .width('100%') .height('100%') } - - aboutToAppear() { - } - - onBackPress() { - - } } \ No newline at end of file diff --git a/entry/src/main/ets/pages/index.ets b/entry/src/main/ets/pages/index.ets index 9a3b3f5..de47d3f 100644 --- a/entry/src/main/ets/pages/index.ets +++ b/entry/src/main/ets/pages/index.ets @@ -12,31 +12,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import router from '@system.router'; -import { - ImageKnifeComponent, - ImageKnifeOption, -} from '@ohos/imageknife' -import ArkWorker from '@ohos.worker' +import router from '@ohos.router' +import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/imageknife' +import worker from '@ohos.worker'; + @Entry @Component struct IndexFunctionDemo { - private globalGifWorker:any = undefined - @State imageKnifeOption1: ImageKnifeOption = - { - loadSrc: $r('app.media.icon'), + private globalGifWorker: any = undefined + @State imageKnifeOption1: ImageKnifeOption = { + loadSrc: $r('app.media.icon'), - placeholderSrc: $r('app.media.icon_loading'), - errorholderSrc: $r('app.media.icon_failed') - }; + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed') + }; + @State imageKnifeOption2: ImageKnifeOption = { + loadSrc: $r('app.media.icon'), - @State imageKnifeOption2: ImageKnifeOption = - { - loadSrc: $r('app.media.icon'), - - placeholderSrc: $r('app.media.icon_loading'), - errorholderSrc: $r('app.media.icon_failed') - }; + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed') + }; build() { Scroll() { @@ -65,7 +60,7 @@ struct IndexFunctionDemo { placeholderSrc: $r('app.media.icon_loading'), errorholderSrc: $r('app.media.icon_failed'), - displayProgress:true, + displayProgress: true, } }).margin({ top: 5, left: 3 }) ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 }).width(300).height(300) @@ -85,20 +80,16 @@ struct IndexFunctionDemo { } aboutToAppear() { - this.globalGifWorker = new ArkWorker.Worker('entry/ets/pages/workers/gifParseWorker.ts', { - type: 'classic', - name: 'ImageKnifeParseGIF' - }) + //替代过时的ArkWorker.Worker + this.globalGifWorker = new worker.ThreadWorker('entry/ets/workers/GifLoadWorker.ts') // gif解析在子线程,请在页面构建后创建worker,注入imageknife globalThis.ImageKnife.setGifWorker(this.globalGifWorker) } - aboutToDisappear(){ - if(this.globalGifWorker){ + + aboutToDisappear() { + // 页面销毁 销毁worker + if (this.globalGifWorker) { this.globalGifWorker.terminate(); } } - - onBackPress() { - - } } \ No newline at end of file diff --git a/entry/src/main/ets/pages/pngjTestCasePage.ets b/entry/src/main/ets/pages/pngjTestCasePage.ets index 7145b43..55cea8f 100644 --- a/entry/src/main/ets/pages/pngjTestCasePage.ets +++ b/entry/src/main/ets/pages/pngjTestCasePage.ets @@ -18,6 +18,7 @@ import resourceManager from '@ohos.resourceManager'; import { FileUtils } from '@ohos/imageknife' import featureability from '@ohos.ability.featureAbility' import ArkWorker from '@ohos.worker' +import worker from '@ohos.worker'; @Entry @Component @@ -109,11 +110,8 @@ struct PngjTestCasePage { if (!this.pngdecodeRun2) { this.pngdecodeRun2 = true; let pngj = new Pngj(); - let worker = new ArkWorker.Worker('entry/ets/pages/workers/worker1.js', { - type: 'classic', - name: 'readPngImageAsync' - }) - pngj.readPngImageAsync(worker, this.pngSource1, (sender, value) => { + let png_load_worker = new worker.ThreadWorker('entry/ets/workers/PngLoadWorker.ts') + pngj.readPngImageAsync(png_load_worker, this.pngSource1, (sender, value) => { this.pngSource1 = sender this.hint2 = 'img with=' + value.width + ' img height=' + value.height + ' img depth=' + value.depth + ' img ctype=' + value.ctype @@ -154,11 +152,8 @@ struct PngjTestCasePage { if (!this.pngdecodeRun3) { this.pngdecodeRun3 = true; let pngj = new Pngj(); - let worker = new ArkWorker.Worker('entry/ets/pages/workers/worker1.js', { - type: 'classic', - name: 'writePngWithStringAsync' - }) - pngj.writePngWithStringAsync(worker, 'hello world', this.pngSource3, (sender, value) => { + let png_load_worker = new worker.ThreadWorker('entry/ets/workers/PngLoadWorker.ts') + pngj.writePngWithStringAsync(png_load_worker, 'hello world', this.pngSource3, (sender, value) => { this.pngSource3 = sender FileUtils.getInstance().createFileProcess( this.rootFolder + '/pngj', @@ -204,11 +199,8 @@ struct PngjTestCasePage { if (!this.pngdecodeRun4) { this.pngdecodeRun4 = true; let pngj = new Pngj(); - let worker = new ArkWorker.Worker('entry/ets/pages/workers/worker1.js', { - type: 'classic', - name: 'writePngAsync' - }) - pngj.writePngAsync(worker, this.pngSource4, (sender, value) => { + let png_load_worker = new worker.ThreadWorker('entry/ets/workers/PngLoadWorker.ts') + pngj.writePngAsync(png_load_worker, this.pngSource4, (sender, value) => { this.pngSource4 = sender FileUtils.getInstance().createFileProcess( this.rootFolder + '/pngj', diff --git a/entry/src/main/ets/pages/testSingleFrameGifPage.ets b/entry/src/main/ets/pages/testSingleFrameGifPage.ets index b126aed..aafb97b 100644 --- a/entry/src/main/ets/pages/testSingleFrameGifPage.ets +++ b/entry/src/main/ets/pages/testSingleFrameGifPage.ets @@ -52,8 +52,8 @@ struct TestSingleFrameGifPage { }) ImageKnifeComponent({ imageKnifeOption: this.options }) .margin(16) - .width(300) - .height(300) + .width(200) + .height(200) } .width("100%") .height("100%") diff --git a/entry/src/main/ets/pages/workers/gifParseWorker.ts b/entry/src/main/ets/pages/workers/gifParseWorker.ts deleted file mode 100644 index 427f5ab..0000000 --- a/entry/src/main/ets/pages/workers/gifParseWorker.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the 'License'); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import arkWorker from '@ohos.worker'; -import { gifHandler } from '@ohos/imageknife/GifWorker' - -arkWorker.parentPort.onmessage = gifHandler; - - - - - - diff --git a/entry/src/main/ets/pages/workers/worker1.js b/entry/src/main/ets/pages/workers/worker1.js deleted file mode 100644 index 9aff18e..0000000 --- a/entry/src/main/ets/pages/workers/worker1.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2021 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import arkWorker from '@ohos.worker'; - -import {handler} from '@ohos/imageknife/PngWork' - -arkWorker.parentPort.onmessage = handler - - - - - - - - - diff --git a/entry/src/main/ets/workers/GifLoadWorker.ts b/entry/src/main/ets/workers/GifLoadWorker.ts new file mode 100644 index 0000000..50e960f --- /dev/null +++ b/entry/src/main/ets/workers/GifLoadWorker.ts @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import worker, { ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@ohos.worker'; +import { gifHandler } from '@ohos/imageknife/GifWorker' + +var workerPort: ThreadWorkerGlobalScope = worker.workerPort; + +/** + * Defines the event handler to be called when the worker thread receives a message sent by the host thread. + * The event handler is executed in the worker thread. + * + * 代码参考自@ohos/imageknife/GifWorker中gifHandler方法 + * + * @param e message data + */ +workerPort.onmessage = gifHandler + +/** + * Defines the event handler to be called when the worker receives a message that cannot be deserialized. + * The event handler is executed in the worker thread. + * + * @param e message data + */ +workerPort.onmessageerror = function (e: MessageEvents) { + console.log("GifLoadWorker.ts workerPort.onmessageerror: " + e.data) +} + +/** + * Defines the event handler to be called when an exception occurs during worker execution. + * The event handler is executed in the worker thread. + * + * @param e error message + */ +workerPort.onerror = function (e: ErrorEvent) { + console.log("GifLoadWorker.ts workerPort.onerror: " + e.message) +} \ No newline at end of file diff --git a/entry/src/main/ets/workers/MyWorker.ts b/entry/src/main/ets/workers/MyWorker.ts new file mode 100644 index 0000000..9ba3e0f --- /dev/null +++ b/entry/src/main/ets/workers/MyWorker.ts @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import worker, { ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@ohos.worker'; + +var workerPort: ThreadWorkerGlobalScope = worker.workerPort; + +/** + * Defines the event handler to be called when the worker thread receives a message sent by the host thread. + * The event handler is executed in the worker thread. + * + * @param e message data + */ +workerPort.onmessage = function (e: MessageEvents) { + console.log("MyWorker.ts workerPort.onmessage:" + e.data) + + //子线程向主线程发送消息 + workerPort.postMessage("天天向上") +} + +/** + * Defines the event handler to be called when the worker receives a message that cannot be deserialized. + * The event handler is executed in the worker thread. + * + * @param e message data + */ +workerPort.onmessageerror = function (e: MessageEvents) { + console.log("MyWorker.ts workerPort.onmessageerror") +} + +/** + * Defines the event handler to be called when an exception occurs during worker execution. + * The event handler is executed in the worker thread. + * + * @param e error message + */ +workerPort.onerror = function (e: ErrorEvent) { + console.log("MyWorker.ts workerPort.onerror") +} \ No newline at end of file diff --git a/entry/src/main/ets/workers/PngLoadWorker.ts b/entry/src/main/ets/workers/PngLoadWorker.ts new file mode 100644 index 0000000..d9cf419 --- /dev/null +++ b/entry/src/main/ets/workers/PngLoadWorker.ts @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import worker, { ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@ohos.worker'; +import { UPNG } from '@ohos/imageknife/src/main/ets/components/3rd_party/upng/UPNG' + +var workerPort: ThreadWorkerGlobalScope = worker.workerPort; + +/** + * Defines the event handler to be called when the worker thread receives a message sent by the host thread. + * The event handler is executed in the worker thread. + * + * @param e message data + */ +workerPort.onmessage = function (e: MessageEvents) { + var data = e.data; + switch (data.type) { + case 'readPngImageAsync': + var png = UPNG.decode(data.data); + let array = png.data; + let arrayData = array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + png.data = arrayData; + let dataObj = { type: 'readPngImageAsync', data: png, receiver: data.data } + workerPort.postMessage(dataObj, [png.data, data.data]); + break; + case 'writePngWithStringAsync': + let addInfo = data.info; + let pngDecode = UPNG.decode(data.data); + let newPng = UPNG.encodeWithString(addInfo, UPNG.toRGBA8(pngDecode), pngDecode.width, pngDecode.height, 0) + let dataObj2 = { type: 'writePngWithStringAsync', data: newPng, receiver: data.data } + workerPort.postMessage(dataObj2, [newPng, data.data]); + break; + case 'writePngAsync': + let pngDecode3 = UPNG.decode(data.data); + let newPng3 = UPNG.encode(UPNG.toRGBA8(pngDecode3), pngDecode3.width, pngDecode3.height, 0) + let dataObj3 = { type: 'writePngAsync', data: newPng3, receiver: data.data } + workerPort.postMessage(dataObj3, [newPng3, data.data]); + break; + default: + break + } +} + +/** + * Defines the event handler to be called when the worker receives a message that cannot be deserialized. + * The event handler is executed in the worker thread. + * + * @param e message data + */ +workerPort.onmessageerror = function (e: MessageEvents) { + console.log("PngLoadWorker.ts workerPort.onmessageerror: " + e.data) +} + +/** + * Defines the event handler to be called when an exception occurs during worker execution. + * The event handler is executed in the worker thread. + * + * @param e error message + */ +workerPort.onerror = function (e: ErrorEvent) { + console.log("PngLoadWorker.ts workerPort.onerror: " + e.message) +} \ No newline at end of file diff --git a/entry/src/main/resources/base/media/honor.gif b/entry/src/main/resources/base/media/honor.gif new file mode 100644 index 0000000..2069a4b Binary files /dev/null and b/entry/src/main/resources/base/media/honor.gif differ diff --git a/entry/src/main/resources/base/profile/main_pages.json b/entry/src/main/resources/base/profile/main_pages.json index 63fea64..5a9b46a 100644 --- a/entry/src/main/resources/base/profile/main_pages.json +++ b/entry/src/main/resources/base/profile/main_pages.json @@ -28,6 +28,7 @@ "pages/manyPhotoShowPage", "pages/tempUrlTestPage", "pages/drawFactoryTestPage", - "pages/testSingleFrameGifPage" + "pages/testSingleFrameGifPage", + "pages/testGifLoadWithWorkerPage" ] } diff --git a/imageknife/GifWorker.ts b/imageknife/GifWorker.ts index 2a54ab1..f9d1a61 100644 --- a/imageknife/GifWorker.ts +++ b/imageknife/GifWorker.ts @@ -12,13 +12,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import arkWorker from '@ohos.worker'; +import worker, { ThreadWorkerGlobalScope } from '@ohos.worker'; import { parseBufferToFrame } from './src/main/ets/components/imageknife/utils/gif/parse/GIFParse' export enum LoadType { loadBufferByWorker = "loadBufferByWorker" } +var workerPort : ThreadWorkerGlobalScope = worker.workerPort; + // Send or Receive Format Data Such as: {type: yourResolveType, data: yourDataJson, error?: yourErrorInfo } export function gifHandler(e) { let data = e.data; @@ -56,7 +58,7 @@ export function gifHandler(e) { transparentIndex: transparentIndexs } let dataObj = { type: recType, data: frame } - arkWorker.parentPort.postMessage(dataObj, patchs); + workerPort.postMessage(dataObj, patchs) } } diff --git a/screenshot/worker1.png b/screenshot/worker1.png new file mode 100644 index 0000000..8769b21 Binary files /dev/null and b/screenshot/worker1.png differ diff --git a/screenshot/worker2.png b/screenshot/worker2.png new file mode 100644 index 0000000..db52375 Binary files /dev/null and b/screenshot/worker2.png differ diff --git a/screenshot/worker3.png b/screenshot/worker3.png new file mode 100644 index 0000000..f8cc1e0 Binary files /dev/null and b/screenshot/worker3.png differ diff --git a/screenshot/worker4.png b/screenshot/worker4.png new file mode 100644 index 0000000..f4c62d3 Binary files /dev/null and b/screenshot/worker4.png differ