子线程网络请求和自定义网络改为异步请求、复用场景清空组件内容
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
This commit is contained in:
parent
7f51e9164e
commit
a34e20acfa
|
@ -1,3 +1,12 @@
|
|||
## 3.2.0-rc.0
|
||||
- Rollback the old version V1 decorator. V2 decorator will be provided in version 4.x
|
||||
- The sub-thread network request is changed to asynchronous, thereby increasing the number of concurrent sub-thread network requests
|
||||
- Set the concurrency through the setMaxRequests interface under the ImageKnife class
|
||||
- aboutToRecycle life cycle clear image content
|
||||
|
||||
## 3.0.3
|
||||
- Released version 3.0.3
|
||||
|
||||
## 3.0.3-rc.0
|
||||
- Custom network method to add request header parameters
|
||||
|
||||
|
|
62
README.md
62
README.md
|
@ -56,12 +56,12 @@ await ImageKnife.getInstance().initFileCache(context, 256, 256 * 1024 * 1024)
|
|||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
ImageKnifeOption: new ImageKnifeOption({
|
||||
ImageKnifeOption:{
|
||||
loadSrc: $r("app.media.app_icon"),
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Auto
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
|
||||
|
@ -69,12 +69,12 @@ ImageKnifeComponent({
|
|||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
ImageKnifeOption: new ImageKnifeOption({
|
||||
ImageKnifeOption: {
|
||||
loadSrc: this.localFile,
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Auto
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
|
||||
|
@ -82,12 +82,12 @@ ImageKnifeComponent({
|
|||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
ImageKnifeOption: new ImageKnifeOption({
|
||||
ImageKnifeOption: {
|
||||
loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Auto
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
|
||||
|
@ -95,13 +95,13 @@ ImageKnifeComponent({
|
|||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
ImageKnifeOption: new ImageKnifeOption({
|
||||
ImageKnifeOption: {
|
||||
loadSrc: "https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg",
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Auto,
|
||||
customGetImage: custom
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
|
||||
// Custom implementation of the image acquisition method, such as custom network download。
|
||||
|
@ -117,33 +117,33 @@ async function custom(context: Context, src: string | PixelMap | Resource): Prom
|
|||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
ImageKnifeOption: new ImageKnifeOption({
|
||||
ImageKnifeOption: {
|
||||
loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
|
||||
progressListener:(progress:number)=>{console.info("ImageKinfe:: call back progress = " + progress)}
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
|
||||
#### 6. Setting Border Options
|
||||
|
||||
```
|
||||
ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption(
|
||||
ImageKnifeComponent({ ImageKnifeOption:
|
||||
{
|
||||
loadSrc: $r("app.media.rabbit"),
|
||||
border: {radius:50}
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
|
||||
#### 7. Setting Image Transformation Options
|
||||
|
||||
```
|
||||
ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption(
|
||||
ImageKnifeComponent({ ImageKnifeOption:
|
||||
{
|
||||
loadSrc: $r("app.media.rabbit"),
|
||||
border: {radius:50},
|
||||
transformation: new BlurTransformation(3)
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
Multiple combined transformation usages:
|
||||
|
@ -153,14 +153,14 @@ let transformations: collections.Array<PixelMapTransformation> = new collections
|
|||
transformations.push(new BlurTransformation(5));
|
||||
transformations.push(new BrightnessTransformation(0.2));
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: new ImageKnifeOption({
|
||||
imageKnifeOption: {
|
||||
loadSrc: $r('app.media.pngSample'),
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Contain,
|
||||
border: { radius: { topLeft: 50, bottomRight: 50 } }, // Rounded corner settings
|
||||
transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined // Graphic transformation group
|
||||
})
|
||||
}
|
||||
}).width(300)
|
||||
.height(300)
|
||||
.rotate ({angle: 90}) // Rotate by 90 degrees.
|
||||
|
@ -171,12 +171,12 @@ Other transformation-related properties can be stacked to achieve combined trans
|
|||
Example of circular cropping transformation:
|
||||
|
||||
```
|
||||
ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption(
|
||||
ImageKnifeComponent({ ImageKnifeOption:
|
||||
{
|
||||
loadSrc: $r('app.media.pngSample'),
|
||||
objectFit: ImageFit.Cover,
|
||||
border: { radius: 150 }
|
||||
})
|
||||
}
|
||||
}).width(300)
|
||||
.height(300)
|
||||
```
|
||||
|
@ -184,12 +184,12 @@ ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption(
|
|||
Example of Circular cropping with border transformation:
|
||||
|
||||
```
|
||||
ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption(
|
||||
ImageKnifeComponent({ ImageKnifeOption:
|
||||
{
|
||||
loadSrc: $r('app.media.pngSample'),
|
||||
objectFit: ImageFit.Cover,
|
||||
border: { radius: 150, color: Color.Red, width: 5 }
|
||||
})
|
||||
}
|
||||
}).width(300)
|
||||
.height(300)
|
||||
```
|
||||
|
@ -198,9 +198,9 @@ Example of contrast filtering transformation:
|
|||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: new ImageKnifeOption({
|
||||
imageKnifeOption: {
|
||||
loadSrc: $r('app.media.pngSample')
|
||||
})
|
||||
}
|
||||
}).width(300)
|
||||
.height(300)
|
||||
.contrast(12)
|
||||
|
@ -210,9 +210,9 @@ Example of rotation transformation:
|
|||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: new ImageKnifeOption({
|
||||
imageKnifeOption:({
|
||||
loadSrc: $r('app.media.pngSample')
|
||||
})
|
||||
}
|
||||
}).width(300)
|
||||
.height(300)
|
||||
.rotate({angle:90})
|
||||
|
@ -222,7 +222,7 @@ ImageKnifeComponent({
|
|||
#### 8. Listening for Image Loading Success and Failure
|
||||
|
||||
```
|
||||
ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption(
|
||||
ImageKnifeComponent({ ImageKnifeOption:
|
||||
{
|
||||
loadSrc: $r("app.media.rabbit"),
|
||||
onLoadListener:{
|
||||
|
@ -241,27 +241,27 @@ ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption(
|
|||
console.info(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
#### 9. Use of syncLoad
|
||||
**syncLoad** sets whether to load the image synchronously. By default, the image is loaded asynchronously. When loading a small image, you are advised to set **syncLoad** to **true** so that the image loading can be quickly completed on the main thread.
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption:new ImageKnifeOption({
|
||||
imageKnifeOption:{
|
||||
loadSrc:$r("app.media.pngSample"),
|
||||
placeholderSrc:$r("app.media.loading")
|
||||
}),syncLoad:true
|
||||
},syncLoad:true
|
||||
})
|
||||
```
|
||||
#### 10. Use of ImageKnifeAnimatorComponent
|
||||
```
|
||||
ImageKnifeAnimatorComponent({
|
||||
imageKnifeOption:new ImageKnifeOption({
|
||||
imageKnifeOption:{
|
||||
loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
|
||||
placeholderSrc:$r('app.media.loading'),
|
||||
errorholderSrc:$r('app.media.failed')
|
||||
}),animatorOption:this.animatorOption
|
||||
},animatorOption:this.animatorOption
|
||||
}).width(300).height(300).backgroundColor(Color.Orange).margin({top:30})
|
||||
```
|
||||
#### Reuse Scenario
|
||||
|
@ -359,7 +359,7 @@ Method 2: Set the third-party HAR as a dependency in the **oh-package.json5** fi
|
|||
|
||||
This project has been verified in the following version:
|
||||
|
||||
DevEco Studio: 5.0 Canary3 (5.0.3.502), SDK: API 12 (5.0.0.31)
|
||||
DevEco Studio: NEXT Beta1-5.0.3.806, SDK: API12 Release(5.0.0.66)
|
||||
|
||||
## How to Contribute
|
||||
|
||||
|
|
62
README_zh.md
62
README_zh.md
|
@ -56,12 +56,12 @@ await ImageKnife.getInstance().initFileCache(context, 256, 256 * 1024 * 1024)
|
|||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
ImageKnifeOption: new ImageKnifeOption({
|
||||
ImageKnifeOption: {
|
||||
loadSrc: $r("app.media.app_icon"),
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Auto
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
|
||||
|
@ -69,12 +69,12 @@ ImageKnifeComponent({
|
|||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
ImageKnifeOption: new ImageKnifeOption({
|
||||
ImageKnifeOption: {
|
||||
loadSrc: this.localFile,
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Auto
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
|
||||
|
@ -82,12 +82,12 @@ ImageKnifeComponent({
|
|||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
ImageKnifeOption: new ImageKnifeOption({
|
||||
ImageKnifeOption: {
|
||||
loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Auto
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
|
||||
|
@ -95,13 +95,13 @@ ImageKnifeComponent({
|
|||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
ImageKnifeOption: new ImageKnifeOption({
|
||||
ImageKnifeOption: {
|
||||
loadSrc: "https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg",
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Auto,
|
||||
customGetImage: custom
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
|
||||
// 自定义实现图片获取方法,如自定义网络下载
|
||||
|
@ -117,33 +117,33 @@ async function custom(context: Context, src: string | PixelMap | Resource): Prom
|
|||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
ImageKnifeOption: new ImageKnifeOption({
|
||||
ImageKnifeOption: {
|
||||
loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
|
||||
progressListener:(progress:number)=>{console.info("ImageKinfe:: call back progress = " + progress)}
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
|
||||
#### 6.支持option传入border,设置边框,圆角
|
||||
|
||||
```
|
||||
ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption(
|
||||
ImageKnifeComponent({ ImageKnifeOption:
|
||||
{
|
||||
loadSrc: $r("app.media.rabbit"),
|
||||
border: {radius:50}
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
|
||||
#### 7.支持option图片变换
|
||||
|
||||
```
|
||||
ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption(
|
||||
ImageKnifeComponent({ ImageKnifeOption:
|
||||
{
|
||||
loadSrc: $r("app.media.rabbit"),
|
||||
border: {radius:50},
|
||||
transformation: new BlurTransformation(3)
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
多种组合变换用法
|
||||
|
@ -153,14 +153,14 @@ let transformations: collections.Array<PixelMapTransformation> = new collections
|
|||
transformations.push(new BlurTransformation(5));
|
||||
transformations.push(new BrightnessTransformation(0.2));
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: new ImageKnifeOption({
|
||||
imageKnifeOption: {
|
||||
loadSrc: $r('app.media.pngSample'),
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.app_icon"),
|
||||
objectFit: ImageFit.Contain,
|
||||
border: { radius: { topLeft: 50, bottomRight: 50 } }, // 圆角设置
|
||||
transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined // 图形变换组
|
||||
})
|
||||
}
|
||||
}).width(300)
|
||||
.height(300)
|
||||
.rotate({ angle: 90 }) // 旋转90度
|
||||
|
@ -171,12 +171,12 @@ ImageKnifeComponent({
|
|||
圆形裁剪变换示例
|
||||
|
||||
```
|
||||
ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption(
|
||||
ImageKnifeComponent({ ImageKnifeOption:
|
||||
{
|
||||
loadSrc: $r('app.media.pngSample'),
|
||||
objectFit: ImageFit.Cover,
|
||||
border: { radius: 150 }
|
||||
})
|
||||
}
|
||||
}).width(300)
|
||||
.height(300)
|
||||
```
|
||||
|
@ -184,12 +184,12 @@ ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption(
|
|||
圆形裁剪带边框变换示例
|
||||
|
||||
```
|
||||
ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption(
|
||||
ImageKnifeComponent({ ImageKnifeOption:
|
||||
{
|
||||
loadSrc: $r('app.media.pngSample'),
|
||||
objectFit: ImageFit.Cover,
|
||||
border: { radius: 150, color: Color.Red, width: 5 }
|
||||
})
|
||||
}
|
||||
}).width(300)
|
||||
.height(300)
|
||||
```
|
||||
|
@ -198,9 +198,9 @@ ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption(
|
|||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: new ImageKnifeOption({
|
||||
imageKnifeOption: {
|
||||
loadSrc: $r('app.media.pngSample')
|
||||
})
|
||||
}
|
||||
}).width(300)
|
||||
.height(300)
|
||||
.contrast(12)
|
||||
|
@ -210,9 +210,9 @@ ImageKnifeComponent({
|
|||
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: new ImageKnifeOption({
|
||||
imageKnifeOption: {
|
||||
loadSrc: $r('app.media.pngSample')
|
||||
})
|
||||
}
|
||||
}).width(300)
|
||||
.height(300)
|
||||
.rotate({angle:90})
|
||||
|
@ -222,7 +222,7 @@ ImageKnifeComponent({
|
|||
#### 8.监听图片加载成功与失败
|
||||
|
||||
```
|
||||
ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption(
|
||||
ImageKnifeComponent({ ImageKnifeOption:
|
||||
{
|
||||
loadSrc: $r("app.media.rabbit"),
|
||||
onLoadListener:{
|
||||
|
@ -241,27 +241,27 @@ ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption(
|
|||
console.info(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
#### 9.ImageKnifeComponent - syncLoad
|
||||
设置是否同步加载图片,默认是异步加载。建议加载尺寸较小的Resource图片时将syncLoad设为true,因为耗时较短,在主线程上执行即可
|
||||
```
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption:new ImageKnifeOption({
|
||||
imageKnifeOption:{
|
||||
loadSrc:$r("app.media.pngSample"),
|
||||
placeholderSrc:$r("app.media.loading")
|
||||
}),syncLoad:true
|
||||
},syncLoad:true
|
||||
})
|
||||
```
|
||||
#### 10.ImageKnifeAnimatorComponent 示例
|
||||
```
|
||||
ImageKnifeAnimatorComponent({
|
||||
imageKnifeOption:new ImageKnifeOption({
|
||||
imageKnifeOption: {
|
||||
loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
|
||||
placeholderSrc:$r('app.media.loading'),
|
||||
errorholderSrc:$r('app.media.failed')
|
||||
}),animatorOption:this.animatorOption
|
||||
},animatorOption:this.animatorOption
|
||||
}).width(300).height(300).backgroundColor(Color.Orange).margin({top:30})
|
||||
```
|
||||
#### 复用场景
|
||||
|
@ -361,7 +361,7 @@ ImageKnifeAnimatorComponent({
|
|||
## 约束与限制
|
||||
|
||||
在下述版本验证通过:
|
||||
DevEco Studio 5.0 Canary3(5.0.3.502)--SDK:API12 (5.0.0.31)
|
||||
DevEco Studio: NEXT Beta1-5.0.3.806, SDK: API12 Release(5.0.0.66)
|
||||
|
||||
## 贡献代码
|
||||
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (C) 2024 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 { InfoItem } from './model/DataSourcePrefetching';
|
||||
import { PageViewModel } from './model/PageViewModel';
|
||||
import { ImageKnifeComponent, ImageKnife } from '@ohos/libraryimageknife';
|
||||
import { CommonDataSource, GetSession } from './model/CommonDataSource';
|
||||
import { rcp } from '@kit.RemoteCommunicationKit';
|
||||
import { BusinessError } from '@kit.BasicServicesKit';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
export struct CustomNetImagePage {
|
||||
@State hotCommendList:CommonDataSource<InfoItem> = new CommonDataSource<InfoItem>([])
|
||||
aboutToAppear(): void {
|
||||
ImageKnife.getInstance().setMaxRequests(32)
|
||||
this.hotCommendList.addData(this.hotCommendList.totalCount(),PageViewModel.getItems())
|
||||
}
|
||||
aboutToDisappear(): void {
|
||||
ImageKnife.getInstance().setMaxRequests(8)
|
||||
}
|
||||
build() {
|
||||
Column() {
|
||||
WaterFlow() {
|
||||
LazyForEach(this.hotCommendList,(item: InfoItem)=>{
|
||||
FlowItem() {
|
||||
Column(){
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: item.albumUrl,
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.failed"),
|
||||
customGetImage:custom
|
||||
}
|
||||
}).width("50%").height(200)
|
||||
}
|
||||
}.height(200)
|
||||
.backgroundColor("#95efd2")
|
||||
},(item: string) => item)
|
||||
}.columnsTemplate("1fr 1fr")
|
||||
.columnsGap(10)
|
||||
.rowsGap(5)
|
||||
.backgroundColor(0xFAEEE0)
|
||||
.width("100%").height("100%")
|
||||
}
|
||||
}
|
||||
}
|
||||
// 自定义下载方法
|
||||
@Concurrent
|
||||
async function custom(context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>): Promise<ArrayBuffer | undefined> {
|
||||
return new Promise((resolve,reject)=>{
|
||||
if (typeof src == "string") {
|
||||
let session = GetSession.session
|
||||
let req = new rcp.Request(src,"GET");
|
||||
session.fetch(req).then((response)=>{
|
||||
if(response.statusCode == 200) {
|
||||
let buffer = response.body
|
||||
resolve(buffer)
|
||||
} else {
|
||||
reject("rcp code:"+response.statusCode)
|
||||
}
|
||||
}).catch((err:BusinessError)=>{
|
||||
reject("error rcp src:"+src+",err:"+JSON.stringify(err))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
|
@ -45,11 +45,21 @@ struct Index {
|
|||
uri: 'pages/PrefetchAndCacheCount',
|
||||
});
|
||||
})
|
||||
Button($r('app.string.request_concurrency')).margin({top:10}).onClick(()=>{
|
||||
router.push({
|
||||
uri: 'pages/SetMaxRequestPage',
|
||||
});
|
||||
})
|
||||
Button($r('app.string.Test_multiple_images')).margin({top:10}).onClick(()=>{
|
||||
router.push({
|
||||
uri: 'pages/TestCommonImage',
|
||||
});
|
||||
})
|
||||
Button($r('app.string.Customize_RCP_network')).margin({top:10}).onClick(()=>{
|
||||
router.push({
|
||||
uri: 'pages/CustomNetImagePage',
|
||||
});
|
||||
})
|
||||
Button($r('app.string.Test_Task_error')).margin({top:10}).onClick(()=>{
|
||||
router.push({
|
||||
uri: 'pages/TestTaskResourcePage',
|
||||
|
|
|
@ -109,7 +109,7 @@ struct LoadStatePage {
|
|||
}
|
||||
// 自定义下载方法
|
||||
@Concurrent
|
||||
async function custom(context: Context, src: string | PixelMap | Resource): Promise<ArrayBuffer | undefined> {
|
||||
async function custom(context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>): Promise<ArrayBuffer | undefined> {
|
||||
console.info("ImageKnife:: custom download:" + src)
|
||||
// 举例写死从本地文件读取,也可以自己请求网络图片
|
||||
return undefined
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (C) 2024 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 { ImageKnifeComponent,ImageKnife } from '@ohos/libraryimageknife';
|
||||
import { CommonDataSource } from './model/CommonDataSource';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct MaxRequest1 {
|
||||
@State hotCommendList:CommonDataSource<string> = new CommonDataSource<string>([])
|
||||
private data: Array<string> = []
|
||||
aboutToAppear(): void {
|
||||
ImageKnife.getInstance().setMaxRequests(8)
|
||||
for (let index = 0; index < 200; index++) {
|
||||
this.data.push(`https://img-blog.csdn.net/20140514114029140?${index}`)
|
||||
}
|
||||
this.hotCommendList.addData(this.hotCommendList.totalCount(),this.data)
|
||||
}
|
||||
build() {
|
||||
Column() {
|
||||
WaterFlow() {
|
||||
LazyForEach(this.hotCommendList,(item: string)=>{
|
||||
FlowItem() {
|
||||
Column(){
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: item,
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.failed"),
|
||||
}
|
||||
}).width("50%").height(160)
|
||||
}
|
||||
}.height(200)
|
||||
.backgroundColor("#95efd2")
|
||||
},(item: string) => item)
|
||||
}.columnsTemplate("1fr 1fr")
|
||||
.cachedCount(8)
|
||||
.columnsGap(10)
|
||||
.rowsGap(5)
|
||||
.backgroundColor(0xFAEEE0)
|
||||
.width("100%").height("100%")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (C) 2024 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 { ImageKnifeComponent,ImageKnife } from '@ohos/libraryimageknife';
|
||||
import { CommonDataSource } from './model/CommonDataSource';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct MaxRequest2 {
|
||||
@State hotCommendList:CommonDataSource<string> = new CommonDataSource<string>([])
|
||||
private data: Array<string> = []
|
||||
aboutToAppear(): void {
|
||||
ImageKnife.getInstance().setMaxRequests(20)
|
||||
for (let index = 200; index < 400; index++) {
|
||||
this.data.push(`https://img-blog.csdn.net/20140514114029140?${index}`)
|
||||
}
|
||||
this.hotCommendList.addData(this.hotCommendList.totalCount(),this.data)
|
||||
}
|
||||
build() {
|
||||
Column() {
|
||||
WaterFlow() {
|
||||
LazyForEach(this.hotCommendList,(item: string)=>{
|
||||
FlowItem() {
|
||||
Column(){
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: item,
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.failed"),
|
||||
}
|
||||
}).width("50%").height(160)
|
||||
}
|
||||
}.height(200)
|
||||
.backgroundColor("#95efd2")
|
||||
},(item: string) => item)
|
||||
}.columnsTemplate("1fr 1fr")
|
||||
.cachedCount(20)
|
||||
.columnsGap(10)
|
||||
.rowsGap(5)
|
||||
.backgroundColor(0xFAEEE0)
|
||||
.width("100%").height("100%")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (C) 2024 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 { ImageKnifeComponent,ImageKnife } from '@ohos/libraryimageknife';
|
||||
import { CommonDataSource } from './model/CommonDataSource';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct MaxRequest3 {
|
||||
@State hotCommendList:CommonDataSource<string> = new CommonDataSource<string>([])
|
||||
private data: Array<string> = []
|
||||
aboutToAppear(): void {
|
||||
ImageKnife.getInstance().setMaxRequests(32)
|
||||
for (let index = 400; index < 600; index++) {
|
||||
this.data.push(`https://img-blog.csdn.net/20140514114029140?${index}`)
|
||||
}
|
||||
this.hotCommendList.addData(this.hotCommendList.totalCount(),this.data)
|
||||
}
|
||||
build() {
|
||||
Column() {
|
||||
WaterFlow() {
|
||||
LazyForEach(this.hotCommendList,(item: string)=>{
|
||||
FlowItem() {
|
||||
Column(){
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: item,
|
||||
placeholderSrc: $r("app.media.loading"),
|
||||
errorholderSrc: $r("app.media.failed"),
|
||||
}
|
||||
}).width("50%").height(160)
|
||||
}
|
||||
}.height(200)
|
||||
.backgroundColor("#95efd2")
|
||||
},(item: string) => item)
|
||||
}.columnsTemplate("1fr 1fr")
|
||||
.cachedCount(40)
|
||||
.columnsGap(10)
|
||||
.rowsGap(5)
|
||||
.backgroundColor(0xFAEEE0)
|
||||
.width("100%").height("100%")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import { router } from '@kit.ArkUI'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct SetMaxRequestPage {
|
||||
build() {
|
||||
Column() {
|
||||
Button("maxRequest = 8")
|
||||
.onClick(()=>{
|
||||
router.pushUrl({url:"pages/MaxRequest1"})
|
||||
})
|
||||
Button("maxRequest = 20")
|
||||
.onClick(()=>{
|
||||
router.pushUrl({url:"pages/MaxRequest2"})
|
||||
}).margin({top:20})
|
||||
Button("maxRequest = 32")
|
||||
.onClick(()=>{
|
||||
router.pushUrl({url:"pages/MaxRequest2"})
|
||||
}).margin({top:20})
|
||||
}.width("100%")
|
||||
.height("100%")
|
||||
}
|
||||
}
|
|
@ -128,10 +128,11 @@ struct SingleImage {
|
|||
|
||||
// 自定义下载方法
|
||||
@Concurrent
|
||||
async function custom(context: Context, src: string | PixelMap | Resource,headers?: Record<string, Object>): Promise<ArrayBuffer | undefined> {
|
||||
async function custom(context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>): Promise<ArrayBuffer | undefined> {
|
||||
let refer = headers!["refer"] as string
|
||||
console.info("ImageKnife:: custom download:" + src,"refer:"+refer)
|
||||
// 举例写死从本地文件读取,也可以自己请求网络图片
|
||||
return context.resourceManager.getMediaContentSync($r("app.media.startIcon").id).buffer as ArrayBuffer
|
||||
let buffer = context.resourceManager.getMediaContentSync($r("app.media.startIcon").id).buffer as ArrayBuffer
|
||||
return buffer
|
||||
}
|
||||
|
||||
|
|
|
@ -60,8 +60,9 @@ struct TestSetCustomImagePage {
|
|||
}
|
||||
}
|
||||
@Concurrent
|
||||
async function custom(context: Context, src: string | PixelMap | Resource): Promise<ArrayBuffer | undefined> {
|
||||
async function custom(context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>): Promise<ArrayBuffer | undefined> {
|
||||
console.info("ImageKnife:: custom download:" + src)
|
||||
// 举例写死从本地文件读取,也可以自己请求网络图片
|
||||
return context.resourceManager.getMediaContentSync($r("app.media.pngSample").id).buffer as ArrayBuffer
|
||||
let buffer = context.resourceManager.getMediaContentSync($r("app.media.pngSample").id).buffer as ArrayBuffer
|
||||
return buffer
|
||||
}
|
|
@ -12,6 +12,9 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { statfs } from '@kit.CoreFileKit'
|
||||
import { rcp } from '@kit.RemoteCommunicationKit'
|
||||
|
||||
export class CommonDataSource <T> implements IDataSource {
|
||||
private dataArray: T[] = []
|
||||
private listeners: DataChangeListener[] = []
|
||||
|
@ -51,4 +54,7 @@ export class CommonDataSource <T> implements IDataSource {
|
|||
listener.onDataAdd(index)
|
||||
})
|
||||
}
|
||||
}
|
||||
export class GetSession {
|
||||
static session:rcp.Session = rcp.createSession()
|
||||
}
|
|
@ -503,6 +503,14 @@
|
|||
{
|
||||
"name": "disk",
|
||||
"value": "Disk"
|
||||
},
|
||||
{
|
||||
"name": "Customize_RCP_network",
|
||||
"value": "Customize RCP network request"
|
||||
},
|
||||
{
|
||||
"name": "request_concurrency",
|
||||
"value": "Set request concurrency"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -31,6 +31,11 @@
|
|||
"pages/PrefetchAndPreload",
|
||||
"pages/TestCacheDataPage",
|
||||
"pages/TestChangeColorPage",
|
||||
"pages/TestLoadCancelListenerPage"
|
||||
"pages/TestLoadCancelListenerPage",
|
||||
"pages/CustomNetImagePage",
|
||||
"pages/SetMaxRequestPage",
|
||||
"pages/MaxRequest1",
|
||||
"pages/MaxRequest2",
|
||||
"pages/MaxRequest3"
|
||||
]
|
||||
}
|
|
@ -499,6 +499,14 @@
|
|||
{
|
||||
"name": "disk",
|
||||
"value": "磁盘"
|
||||
},
|
||||
{
|
||||
"name": "Customize_RCP_network",
|
||||
"value": "自定义rcp网络请求"
|
||||
},
|
||||
{
|
||||
"name": "request_concurrency",
|
||||
"value": "设置请求并发度"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
"main": "index.ets",
|
||||
"repository": "https://gitee.com/openharmony-tpc/ImageKnife",
|
||||
"type": "module",
|
||||
"version": "3.0.3-rc.0",
|
||||
"version": "3.2.0-rc.0",
|
||||
"dependencies": {
|
||||
"@ohos/gpu_transform": "^1.0.2"
|
||||
},
|
||||
|
|
|
@ -38,7 +38,7 @@ export class ImageKnife {
|
|||
private _isRequestInSubThread: boolean = true;
|
||||
//定义全局网络请求header map
|
||||
headerMap: Map<string, Object> = new Map<string, Object>();
|
||||
customGetImage: ((context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>) | undefined = undefined
|
||||
customGetImage: ((context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>) => Promise<ArrayBuffer | undefined>) | undefined = undefined
|
||||
public static getInstance(): ImageKnife {
|
||||
if (!ImageKnife.instance) {
|
||||
ImageKnife.instance = new ImageKnife();
|
||||
|
@ -482,10 +482,10 @@ export class ImageKnife {
|
|||
* 全局设置自定义下载
|
||||
* @param customGetImage 自定义请求函数
|
||||
*/
|
||||
setCustomGetImage(customGetImage?: (context: Context, src: string | PixelMap | Resource,headers?: Record<string, Object>) => Promise<ArrayBuffer | undefined>) {
|
||||
setCustomGetImage(customGetImage?: (context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>) => Promise<ArrayBuffer | undefined>) {
|
||||
this.customGetImage = customGetImage
|
||||
}
|
||||
getCustomGetImage(): undefined | ((context: Context, src: string | PixelMap | Resource,headers?: Record<string, Object>) => Promise<ArrayBuffer | undefined>){
|
||||
getCustomGetImage(): undefined | ((context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>) => Promise<ArrayBuffer | undefined>){
|
||||
return this.customGetImage
|
||||
}
|
||||
}
|
|
@ -189,6 +189,16 @@ export class ImageKnifeDispatcher {
|
|||
if(request.customGetImage == undefined) {
|
||||
request.customGetImage = ImageKnife.getInstance().getCustomGetImage()
|
||||
}
|
||||
emitter.on(Constants.CALLBACK_EMITTER + memoryKey,(data)=>{
|
||||
emitter.off(Constants.CALLBACK_EMITTER + memoryKey)
|
||||
let res = data?.data?.value as RequestJobResult | undefined
|
||||
this.doTaskCallback(res, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator);
|
||||
if (isWatchProgress){
|
||||
emitter.off(Constants.PROGRESS_EMITTER + memoryKey)
|
||||
}
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
})
|
||||
if (ImageKnife.getInstance().isRequestInSubThread){
|
||||
// 启动线程下载和解码主图
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_Task.start:" + currentRequest.imageKnifeOption.loadSrc)
|
||||
|
@ -202,13 +212,14 @@ export class ImageKnifeDispatcher {
|
|||
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(subthread):" + currentRequest.imageKnifeOption.loadSrc)
|
||||
taskpool.execute(task).then((res: Object) => {
|
||||
this.doTaskCallback(res as RequestJobResult | undefined, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator);
|
||||
if (isWatchProgress){
|
||||
emitter.off(Constants.PROGRESS_EMITTER + memoryKey)
|
||||
}
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
// this.doTaskCallback(res as RequestJobResult | undefined, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator);
|
||||
// if (isWatchProgress){
|
||||
// emitter.off(Constants.PROGRESS_EMITTER + memoryKey)
|
||||
// }
|
||||
// LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
// LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
}).catch((err: BusinessError) => {
|
||||
emitter.off(Constants.CALLBACK_EMITTER + memoryKey)
|
||||
LogUtil.error("Fail to requestJob in sub thread src=" + imageSrc + " err=" + err)
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc)
|
||||
if (isWatchProgress){
|
||||
|
@ -219,11 +230,12 @@ export class ImageKnifeDispatcher {
|
|||
})
|
||||
} else { //主线程请求
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(mainthread):" + currentRequest.imageKnifeOption.loadSrc)
|
||||
requestJob(request, requestList).then((res: RequestJobResult | undefined) => {
|
||||
this.doTaskCallback(res, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator);
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
requestJob(request, requestList).then(() => {
|
||||
// this.doTaskCallback(res, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator);
|
||||
// LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
// LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc)
|
||||
}).catch((err: BusinessError) => {
|
||||
emitter.off(Constants.CALLBACK_EMITTER + memoryKey)
|
||||
LogUtil.error("Fail to requestJob in main thread src=" + imageSrc + " err=" + err)
|
||||
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc)
|
||||
this.executingJobMap.remove(memoryKey);
|
||||
|
@ -392,44 +404,15 @@ export class ImageKnifeDispatcher {
|
|||
* @returns
|
||||
*/
|
||||
@Concurrent
|
||||
async function requestJob(request: RequestJobRequest, requestList?: List<ImageKnifeRequestWithSource>): Promise<RequestJobResult | undefined> {
|
||||
async function requestJob(request: RequestJobRequest, requestList?: List<ImageKnifeRequestWithSource>) {
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob.start:" + request.src + " requestSource=" + request.requestSource)
|
||||
let src = typeof request.src == "number" ? request.resName != undefined ? request.resName : request.src + "" : request.src
|
||||
// 生成文件缓存key
|
||||
let fileKey = request.engineKey.generateFileKey(src, request.signature, request.isAnimator)
|
||||
|
||||
//获取图片资源
|
||||
let resBuf: ArrayBuffer
|
||||
try {
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob.getImageArrayBuffer.start:" + request.src)
|
||||
resBuf = await ImageKnifeLoader.getImageArrayBuffer(request, requestList, fileKey)
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob.getImageArrayBuffer.end:" + request.src)
|
||||
} catch (error) {
|
||||
LogUtil.error("ImageKnife_DataTime_requestJob.end: getImageArrayBuffer error " + request.src + " err=" + error)
|
||||
return ImageKnifeLoader.makeEmptyResult(error)
|
||||
}
|
||||
ImageKnifeLoader.execute(request,requestList,fileKey)
|
||||
|
||||
// 获取图片类型
|
||||
let typeValue = new FileTypeUtil().getFileType(resBuf);
|
||||
if(typeValue == null) {
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob.end: getFileType is null " + request.src)
|
||||
return ImageKnifeLoader.makeEmptyResult("request is not a valid image source")
|
||||
}
|
||||
|
||||
// 解析图片
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob.parseImage.start:" + request.src)
|
||||
let result: RequestJobResult = await ImageKnifeLoader.parseImage(resBuf, typeValue, fileKey, request)
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob.parseImage.end:" + request.src)
|
||||
|
||||
// 图形变化
|
||||
if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined && result?.pixelMap !== undefined && typeof result.pixelMap !== 'string') {
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob.transform.start:" + request.src)
|
||||
result.pixelMap = await request.transformation?.transform(request.context, result.pixelMap, request.componentWidth, request.componentHeight);
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob.transform.end:" + request.src)
|
||||
}
|
||||
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob.end:" + request.src)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import emitter from '@ohos.events.emitter';
|
|||
import image from '@ohos.multimedia.image';
|
||||
import { RequestJobResult } from './model/ImageKnifeData'
|
||||
import util from '@ohos.util';
|
||||
import { FileTypeUtil } from './utils/FileTypeUtil';
|
||||
|
||||
class RequestData {
|
||||
receiveSize: number = 2000
|
||||
|
@ -38,38 +39,52 @@ class RequestData {
|
|||
* ImageKnifeDispatcher 抽取出来的方法,因@Concurrent只能import方法,故抽取到另一个类
|
||||
*/
|
||||
export class ImageKnifeLoader {
|
||||
static async parseImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string,
|
||||
request: RequestJobRequest): Promise<RequestJobResult> {
|
||||
static execute(request: RequestJobRequest, requestList: List<ImageKnifeRequestWithSource> | undefined, fileKey: string){
|
||||
ImageKnifeLoader.getImageArrayBuffer(request,requestList,fileKey)
|
||||
}
|
||||
static async parseImage(resBuf: ArrayBuffer, fileKey: string,
|
||||
request: RequestJobRequest) {
|
||||
let typeValue = new FileTypeUtil().getFileType(resBuf);
|
||||
if(typeValue == null) {
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob.end: getFileType is null " + request.src)
|
||||
ImageKnifeLoader.makeEmptyResult(request,"request is not a valid image source")
|
||||
return
|
||||
}
|
||||
if(request.isAnimator) {
|
||||
return ImageKnifeLoader.parseForAnimatorComponent(resBuf ,typeValue ,fileKey, request)
|
||||
ImageKnifeLoader.parseForAnimatorComponent(resBuf ,typeValue ,fileKey, request)
|
||||
return
|
||||
}
|
||||
|
||||
if (typeValue === 'gif' || typeValue === 'webp') {
|
||||
return ImageKnifeLoader.parseAnimatorImage(resBuf ,typeValue ,fileKey , request)
|
||||
ImageKnifeLoader.parseAnimatorImage(resBuf ,typeValue ,fileKey , request)
|
||||
return
|
||||
} else if(typeValue == "svg") {
|
||||
return ImageKnifeLoader.parseSvgImage(resBuf ,typeValue ,fileKey , request)
|
||||
ImageKnifeLoader.parseSvgImage(resBuf ,typeValue ,fileKey , request)
|
||||
return
|
||||
}
|
||||
|
||||
return ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request)
|
||||
ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request)
|
||||
}
|
||||
|
||||
static makeEmptyResult(error: string): RequestJobResult{
|
||||
return {
|
||||
static makeEmptyResult(request:RequestJobRequest,error: string){
|
||||
let res: RequestJobResult = {
|
||||
pixelMap: undefined,
|
||||
bufferSize: 0,
|
||||
fileKey: '',
|
||||
loadFail: error,
|
||||
}
|
||||
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { "value": res } })
|
||||
}
|
||||
|
||||
static async parseNormalImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, request: RequestJobRequest):Promise<RequestJobResult> {
|
||||
static async parseNormalImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, request: RequestJobRequest) {
|
||||
let resPixelmap: PixelMap | undefined = undefined
|
||||
let decodingOptions: image.DecodingOptions = {
|
||||
editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false,
|
||||
}
|
||||
let imageSource: image.ImageSource = image.createImageSource(resBuf)
|
||||
if (imageSource === undefined){
|
||||
return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed")
|
||||
ImageKnifeLoader.makeEmptyResult(request,"image.createImageSource failed")
|
||||
return
|
||||
}
|
||||
|
||||
let size = (await imageSource.getImageInfo()).size
|
||||
|
@ -79,23 +94,35 @@ export class ImageKnifeLoader {
|
|||
imageSource.release()
|
||||
}).catch((error: BusinessError) => {
|
||||
imageSource.release()
|
||||
return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error))
|
||||
ImageKnifeLoader.makeEmptyResult(request,JSON.stringify(error))
|
||||
return
|
||||
})
|
||||
|
||||
return {
|
||||
if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined && resPixelmap !== undefined) {
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob.transform.start:" + request.src)
|
||||
resPixelmap = await request.transformation?.transform(request.context, resPixelmap, request.componentWidth, request.componentHeight);
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob.transform.end:" + request.src)
|
||||
}
|
||||
try {
|
||||
resPixelmap?.setTransferDetached(true)
|
||||
} catch (e) {
|
||||
LogUtil.error("PixelMap setTransferDetached err:"+JSON.stringify(e))
|
||||
}
|
||||
let res: RequestJobResult = {
|
||||
pixelMap: resPixelmap,
|
||||
bufferSize: resBuf.byteLength,
|
||||
fileKey: fileKey,
|
||||
size:size,
|
||||
type:typeValue
|
||||
};
|
||||
}
|
||||
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { "value": res } })
|
||||
}
|
||||
static async parseSvgImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string,
|
||||
request: RequestJobRequest): Promise<RequestJobResult> {
|
||||
request: RequestJobRequest) {
|
||||
let resPixelmap: PixelMap | undefined = undefined
|
||||
let imageSource: image.ImageSource = image.createImageSource(resBuf)
|
||||
if (imageSource === undefined){
|
||||
return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed")
|
||||
ImageKnifeLoader.makeEmptyResult(request,"image.createImageSource failed")
|
||||
return
|
||||
}
|
||||
|
||||
let size = (await imageSource.getImageInfo()).size
|
||||
|
@ -114,23 +141,30 @@ export class ImageKnifeLoader {
|
|||
.then((pixelmap: PixelMap) => {
|
||||
resPixelmap = pixelmap
|
||||
imageSource.release()
|
||||
try {
|
||||
resPixelmap.setTransferDetached(true)
|
||||
} catch (e) {
|
||||
LogUtil.error("PixelMap setTransferDetached err:"+JSON.stringify(e))
|
||||
}
|
||||
}).catch((error: BusinessError) => {
|
||||
imageSource.release()
|
||||
return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error))
|
||||
ImageKnifeLoader.makeEmptyResult(request,JSON.stringify(error))
|
||||
return
|
||||
})
|
||||
|
||||
return {
|
||||
let res: RequestJobResult = {
|
||||
pixelMap: resPixelmap,
|
||||
bufferSize: resBuf.byteLength,
|
||||
fileKey: fileKey,
|
||||
type:typeValue
|
||||
};
|
||||
}
|
||||
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { "value": res } })
|
||||
}
|
||||
static async parseAnimatorImage(resBuf: ArrayBuffer, typeValue: string,
|
||||
fileKey: string,request: RequestJobRequest): Promise<RequestJobResult> {
|
||||
fileKey: string,request: RequestJobRequest) {
|
||||
let imageSource: image.ImageSource = image.createImageSource(resBuf)
|
||||
if (imageSource === undefined){
|
||||
return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed")
|
||||
ImageKnifeLoader.makeEmptyResult(request,"image.createImageSource failed")
|
||||
return
|
||||
}
|
||||
|
||||
let frameCount = await imageSource.getFrameCount()
|
||||
|
@ -140,22 +174,25 @@ export class ImageKnifeLoader {
|
|||
if(frameCount == undefined || frameCount == 1) {
|
||||
} else {
|
||||
let base64str = "data:image/" + typeValue + ";base64," + new util.Base64Helper().encodeToStringSync(new Uint8Array(resBuf))
|
||||
return {
|
||||
let res: RequestJobResult = {
|
||||
pixelMap: base64str,
|
||||
bufferSize: resBuf.byteLength,
|
||||
fileKey: fileKey,
|
||||
size:size,
|
||||
type:typeValue
|
||||
};
|
||||
}
|
||||
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { "value": res } })
|
||||
return
|
||||
}
|
||||
return ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request)
|
||||
ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request)
|
||||
}
|
||||
// 为AnimatorComponent解析动图
|
||||
static async parseForAnimatorComponent(resBuf: ArrayBuffer, typeValue: string, fileKey: string,request: RequestJobRequest): Promise<RequestJobResult> {
|
||||
static async parseForAnimatorComponent(resBuf: ArrayBuffer, typeValue: string, fileKey: string,request: RequestJobRequest) {
|
||||
if (typeValue === 'gif' || typeValue === 'webp') {
|
||||
let imageSource: image.ImageSource = image.createImageSource(resBuf);
|
||||
if (imageSource === undefined){
|
||||
return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed")
|
||||
ImageKnifeLoader.makeEmptyResult(request,"image.createImageSource failed")
|
||||
return
|
||||
}
|
||||
let decodingOptions: image.DecodingOptions = {
|
||||
editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false,
|
||||
|
@ -179,9 +216,10 @@ export class ImageKnifeLoader {
|
|||
})
|
||||
}).catch((error: BusinessError) => {
|
||||
imageSource.release()
|
||||
return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error))
|
||||
ImageKnifeLoader.makeEmptyResult(request,JSON.stringify(error))
|
||||
return
|
||||
})
|
||||
return {
|
||||
let res: RequestJobResult = {
|
||||
pixelMap: "",
|
||||
bufferSize: resBuf.byteLength,
|
||||
fileKey: fileKey,
|
||||
|
@ -189,8 +227,9 @@ export class ImageKnifeLoader {
|
|||
pixelMapList,
|
||||
delayList
|
||||
}
|
||||
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { "value": res } })
|
||||
} else {
|
||||
return ImageKnifeLoader.makeEmptyResult("ImageKnifeAnimatorComponent组件仅支持动态图")
|
||||
ImageKnifeLoader.makeEmptyResult(request,"ImageKnifeAnimatorComponent组件仅支持动态图")
|
||||
}
|
||||
}
|
||||
static getHeaderObj(request:RequestJobRequest){
|
||||
|
@ -206,32 +245,44 @@ export class ImageKnifeLoader {
|
|||
}
|
||||
return headerObj
|
||||
}
|
||||
static FileCacheParseImage(request:RequestJobRequest,resBuf:ArrayBuffer,fileKey:string){
|
||||
// 保存文件缓存
|
||||
if (resBuf !== undefined && request.writeCacheStrategy !== CacheStrategy.Memory) {
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:"+request.src)
|
||||
FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf , request.fileCacheFolder)
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:"+request.src)
|
||||
}
|
||||
ImageKnifeLoader.parseImage(resBuf,fileKey,request)
|
||||
}
|
||||
// 获取图片资源
|
||||
static async getImageArrayBuffer(request: RequestJobRequest, requestList: List<ImageKnifeRequestWithSource> | undefined,fileKey:string): Promise<ArrayBuffer> {
|
||||
static async getImageArrayBuffer(request: RequestJobRequest, requestList: List<ImageKnifeRequestWithSource> | undefined,fileKey:string) {
|
||||
let resBuf: ArrayBuffer | undefined
|
||||
|
||||
let loadError: string = ""
|
||||
// 判断自定义下载
|
||||
if (request.customGetImage !== undefined && request.requestSource == ImageKnifeRequestSource.SRC && typeof request.src == "string") {
|
||||
// 先从文件缓存获取
|
||||
resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder)
|
||||
if (resBuf === undefined) {
|
||||
LogUtil.log("start customGetImage src=" + request.src)
|
||||
const headerObj: Record<string, Object> = ImageKnifeLoader.getHeaderObj(request)
|
||||
try {
|
||||
const headerObj: Record<string, Object> = ImageKnifeLoader.getHeaderObj(request)
|
||||
resBuf = await request.customGetImage(request.context, request.src,headerObj)
|
||||
LogUtil.log("end customGetImage src=" + request.src)
|
||||
} catch (err) {
|
||||
throw new Error('customGetImage loadFile failed! err = ' + err)
|
||||
}
|
||||
if (resBuf === undefined) {
|
||||
throw new Error('customGetImage loadFile failed!')
|
||||
}
|
||||
// 保存文件缓存
|
||||
if (request.writeCacheStrategy !== CacheStrategy.Memory) {
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:" + request.src)
|
||||
FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf, request.fileCacheFolder)
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:" + request.src)
|
||||
request.customGetImage(request.context, request.src, headerObj)
|
||||
.then((buffer)=>{
|
||||
if(buffer != undefined) {
|
||||
ImageKnifeLoader.FileCacheParseImage(request,buffer,fileKey)
|
||||
} else {
|
||||
loadError = "customGetImage loadFail undefined"
|
||||
ImageKnifeLoader.makeEmptyResult(request,loadError)
|
||||
}
|
||||
}).catch((err:string)=>{
|
||||
ImageKnifeLoader.makeEmptyResult(request,err)
|
||||
})
|
||||
} catch (e) {
|
||||
loadError = "customGetImage loadFail failed"
|
||||
ImageKnifeLoader.makeEmptyResult(request,loadError + e)
|
||||
}
|
||||
LogUtil.log("end customGetImage src=" + request.src)
|
||||
return
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -284,25 +335,23 @@ export class ImageKnifeLoader {
|
|||
// header: new Header('application/json')
|
||||
});
|
||||
|
||||
await promise.then((data: number) => {
|
||||
promise.then((data: number) => {
|
||||
if (data == 200 || data == 206 || data == 204) {
|
||||
resBuf = combineArrayBuffers(arrayBuffers)
|
||||
ImageKnifeLoader.FileCacheParseImage(request,resBuf,fileKey)
|
||||
} else {
|
||||
throw new Error("HttpDownloadClient has error, http code =" + JSON.stringify(data))
|
||||
loadError = "HttpDownloadClient has error, http code =" + JSON.stringify(data)
|
||||
ImageKnifeLoader.makeEmptyResult(request,loadError)
|
||||
}
|
||||
}).catch((err: Error) => {
|
||||
throw new Error("HttpDownloadClient download ERROR : err = " + JSON.stringify(err))
|
||||
loadError = "HttpDownloadClient download ERROR : err = " + JSON.stringify(err)
|
||||
ImageKnifeLoader.makeEmptyResult(request,loadError)
|
||||
});
|
||||
LogUtil.log("HttpDownloadClient.end:" + request.src)
|
||||
// 保存文件缓存
|
||||
if (resBuf !== undefined && request.writeCacheStrategy !== CacheStrategy.Memory) {
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:"+request.src)
|
||||
FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf , request.fileCacheFolder)
|
||||
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:"+request.src)
|
||||
}
|
||||
return
|
||||
}
|
||||
else {
|
||||
throw new Error('onlyRetrieveFromCache,do not fetch image src = ' + request.src)
|
||||
loadError = 'onlyRetrieveFromCache,do not fetch image src = ' + request.src
|
||||
}
|
||||
} else if (request.src.startsWith('datashare://') || request.src.startsWith('file://')) {
|
||||
await fs.open(request.src, fs.OpenMode.READ_ONLY).then(async (file) => {
|
||||
|
@ -312,13 +361,13 @@ export class ImageKnifeLoader {
|
|||
resBuf = buf;
|
||||
fs.closeSync(file.fd);
|
||||
}).catch((err:BusinessError) => {
|
||||
throw new Error('LoadDataShareFileClient fs.read err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code)
|
||||
loadError = 'LoadDataShareFileClient fs.read err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code
|
||||
})
|
||||
}).catch((err:BusinessError) => {
|
||||
throw new Error('LoadDataShareFileClient fs.stat err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code)
|
||||
loadError = 'LoadDataShareFileClient fs.stat err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code
|
||||
})
|
||||
}).catch((err:BusinessError) => {
|
||||
throw new Error('LoadDataShareFileClient fs.open err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code)
|
||||
loadError = 'LoadDataShareFileClient fs.open err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code
|
||||
})
|
||||
} else { //从本地文件获取
|
||||
try {
|
||||
|
@ -330,7 +379,7 @@ export class ImageKnifeLoader {
|
|||
fs.closeSync(file);
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error(err)
|
||||
loadError = err
|
||||
}
|
||||
}
|
||||
} else if (typeof request.src == "number") { //从资源文件获取
|
||||
|
@ -354,8 +403,9 @@ export class ImageKnifeLoader {
|
|||
}
|
||||
|
||||
if (resBuf === undefined){
|
||||
throw new Error('getImageArrayBuffer undefined')
|
||||
ImageKnifeLoader.makeEmptyResult(request,loadError)
|
||||
return
|
||||
}
|
||||
return resBuf
|
||||
ImageKnifeLoader.parseImage(resBuf,fileKey,request)
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@ import { DefaultEngineKey } from '../key/DefaultEngineKey';
|
|||
@Component
|
||||
export struct ImageKnifeComponent {
|
||||
@Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption;
|
||||
@State pixelMap: PixelMap | string | undefined = undefined
|
||||
@State pixelMap: PixelMap | string | ImageContent | undefined = undefined
|
||||
@State syncLoad: boolean = false
|
||||
@State adaptiveWidth: Length = '100%'
|
||||
@State adaptiveHeight: Length = '100%'
|
||||
|
@ -68,6 +68,7 @@ export struct ImageKnifeComponent {
|
|||
}
|
||||
|
||||
aboutToRecycle() {
|
||||
this.pixelMap = ImageContent.EMPTY
|
||||
this.clearLastRequest()
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -91,7 +91,7 @@ export interface RequestJobRequest {
|
|||
allHeaders: Map<string, Object>,
|
||||
componentWidth: number,
|
||||
componentHeight: number,
|
||||
customGetImage?: (context: Context, src: string | PixelMap | Resource ,headers?: Record<string, Object>) => Promise<ArrayBuffer | undefined>,
|
||||
customGetImage?: (context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>) => Promise<ArrayBuffer | undefined>,
|
||||
onlyRetrieveFromCache?: boolean
|
||||
requestSource: ImageKnifeRequestSource
|
||||
transformation?: PixelMapTransformation
|
||||
|
|
|
@ -61,7 +61,7 @@ export class ImageKnifeOption {
|
|||
placeholderObjectFit?: ImageFit
|
||||
// 错误图填充效果
|
||||
errorholderObjectFit?: ImageFit
|
||||
customGetImage?: (context: Context, src: string | PixelMap | Resource,headers?: Record<string, Object>) => Promise<ArrayBuffer | undefined>
|
||||
customGetImage?: (context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>) => Promise<ArrayBuffer | undefined>
|
||||
border?: BorderOptions
|
||||
// 缓存策略
|
||||
writeCacheStrategy?: CacheStrategy
|
||||
|
|
|
@ -14,4 +14,5 @@
|
|||
*/
|
||||
export class Constants {
|
||||
public static PROGRESS_EMITTER: string = "progressEmitter"
|
||||
public static CALLBACK_EMITTER: string = "callBackEmitter"
|
||||
}
|
Loading…
Reference in New Issue