补充文件缓存预加载接口preLoadCache、isUrlExist,以及ImageKnifeOption属性isCacheable、onlyRetrieveFromCache
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
This commit is contained in:
parent
d152713556
commit
2126d46aa4
|
@ -1,3 +1,9 @@
|
|||
## 3.0.0-rc.1
|
||||
- 新增从内存或文件缓存获取图片数据接口isUrlExist
|
||||
- 新增图片预加载preLoadCache并会犯文件缓存路径
|
||||
- ImageKnifeOption新增writeCacheStrategy存入策略
|
||||
- ImageKnifeOption新增onlyRetrieveFromCache仅用缓存加载
|
||||
|
||||
## 3.0.0-rc.0
|
||||
使用Image组件替换Canvas组件渲染,并重构大部分的实现逻辑,提升渲染性能
|
||||
|
||||
|
|
21
README.md
21
README.md
|
@ -121,7 +121,28 @@ ImageKnifeComponent({ ImageKnifeOption:
|
|||
}
|
||||
}).width(100).height(100)
|
||||
```
|
||||
## 接口说明
|
||||
### ImageKnifeOption参数列表
|
||||
|
||||
| 参数名称 | 入参内容 | 功能简介 |
|
||||
|-----------------------|--------------------------------|---------------|
|
||||
| loadSrc | string、PixelMap、Resource | 主图展示 |
|
||||
| placeholderSrc | PixelMap、Resource | 占位图图展示(可选) |
|
||||
| errorholderSrc | PixelMap、Resource | 错误图展示(可选) |
|
||||
| objectFit | ImageFit | 图片展示样式(可选) |
|
||||
| writeCacheStrategy | WriteCacheStrategy_Type | 写入缓存策略(可选) |
|
||||
| onlyRetrieveFromCache | boolean | 仅使用缓存加载数据(可选) |
|
||||
| customGetImage | (context: Context, src: string | 自定义网络(可选) | | Resource | 错误占位图数据源 |
|
||||
| border | BorderOptions | 边框圆角(可选) |
|
||||
| priority | taskpool.Priority | 加载优先级(可选) |
|
||||
| context | common.UIAbilityContext | 上下文(可选) |
|
||||
| progressListener | (progress: number)=>void | 进度(可选) |
|
||||
|
||||
### ImageKnife接口
|
||||
| 参数名称 | 入参内容 | 功能简介 |
|
||||
|--------------|------------------------------------|---------------|
|
||||
| preLoadCache | url:string | 预加载并返回文件缓存路径 |
|
||||
| isUrlExist | url: string, cacheType: Cache_Type | 从内存或文件缓存中获取资源 |
|
||||
|
||||
## 约束与限制
|
||||
API11
|
||||
|
|
|
@ -62,7 +62,18 @@ struct Index {
|
|||
|
||||
});
|
||||
})
|
||||
Button("测试文件缓存预加载").onClick(()=>{
|
||||
router.push({
|
||||
uri: 'pages/TestPrefetchToFileCache',
|
||||
|
||||
});
|
||||
})
|
||||
Button("测试获取内存文件缓存").onClick(()=>{
|
||||
router.push({
|
||||
uri: 'pages/TestIsUrlExist',
|
||||
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
.width('100%')
|
||||
|
|
|
@ -18,20 +18,20 @@ import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/imageknife';
|
|||
@Component
|
||||
struct ListPage {
|
||||
|
||||
private datas: string[] = []
|
||||
private data: string[] = []
|
||||
@State ImageKnifeOption: ImageKnifeOption = { loadSrc: $r('app.media.startIcon')}
|
||||
|
||||
|
||||
aboutToAppear(): void {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
this.datas.push(i.toString())
|
||||
this.data.push(i.toString())
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
Row() {
|
||||
List({ space: 10 }) {
|
||||
ForEach(this.datas, (item: string) => {
|
||||
ForEach(this.data, (item: string) => {
|
||||
ImageKnifeComponent({ ImageKnifeOption: this.ImageKnifeOption }).height(200).width(200)
|
||||
}, (item: string) => item)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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,ImageKnifeOption,ImageKnifeData,Cache_Type } from '@ohos/imageknife'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TestIsUrlExist {
|
||||
@State imageKnifeOption: ImageKnifeOption = {
|
||||
loadSrc:$r('app.media.startIcon'),
|
||||
placeholderSrc:$r('app.media.loading')
|
||||
}
|
||||
@State source: PixelMap | string = ""
|
||||
@State source1: PixelMap | string = ""
|
||||
build() {
|
||||
Column() {
|
||||
Flex(){
|
||||
Button("加载gif图").onClick(()=>{
|
||||
this.imageKnifeOption = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658"
|
||||
})
|
||||
Button("内存缓存获取gif").onClick(()=>{
|
||||
ImageKnife.getInstance()
|
||||
.isUrlExist("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",Cache_Type.MemoryCache)
|
||||
.then((data)=>{
|
||||
this.source = data!.source
|
||||
})
|
||||
})
|
||||
Button("文件缓存获取gif").onClick(()=>{
|
||||
ImageKnife.getInstance()
|
||||
.isUrlExist("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",Cache_Type.FileCache)
|
||||
.then((data)=>{
|
||||
this.source1 = data!.source
|
||||
})
|
||||
})
|
||||
}
|
||||
Flex(){
|
||||
Button("加载静态图").onClick(()=>{
|
||||
this.imageKnifeOption = 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp'
|
||||
})
|
||||
Button("内存缓存获取").onClick(()=>{
|
||||
ImageKnife.getInstance()
|
||||
.isUrlExist('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',Cache_Type.MemoryCache)
|
||||
.then((data)=>{
|
||||
this.source = data!.source
|
||||
})
|
||||
})
|
||||
Button("文件缓存获取").onClick(()=>{
|
||||
ImageKnife.getInstance()
|
||||
.isUrlExist('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',Cache_Type.FileCache)
|
||||
.then((data)=>{
|
||||
this.source1 = data!.source
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
ImageKnifeComponent({
|
||||
ImageKnifeOption: this.imageKnifeOption
|
||||
}).width(200).height(200)
|
||||
Image(this.source)
|
||||
.width(200).height(200).backgroundColor(Color.Pink)
|
||||
Image(this.source1)
|
||||
.width(200).height(200).backgroundColor(Color.Pink)
|
||||
}
|
||||
.height('100%') .width('100%')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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,ImageKnifeOption } from '@ohos/imageknife'
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TestPrefetchToFileCachePage {
|
||||
@State imageKnifeOption: ImageKnifeOption = {
|
||||
loadSrc:$r('app.media.startIcon'),
|
||||
placeholderSrc:$r('app.media.loading')
|
||||
}
|
||||
async preload(url:string) {
|
||||
let fileCachePath = await ImageKnife.getInstance().preLoadCache(url)
|
||||
console.log("preload-fileCachePath=="+ fileCachePath)
|
||||
}
|
||||
build() {
|
||||
Column() {
|
||||
Button("磁盘预加载").onClick(async ()=>{
|
||||
await this.preload("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658")
|
||||
})
|
||||
Button("加载图片").onClick(()=>{
|
||||
this.imageKnifeOption.loadSrc = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658"
|
||||
})
|
||||
ImageKnifeComponent({
|
||||
ImageKnifeOption: this.imageKnifeOption
|
||||
}).width(300).height(300)
|
||||
}
|
||||
.height('100%') .width('100%')
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ export struct UserAvatar {
|
|||
imgSizes: number = 1
|
||||
@State ImageKnifeOption: ImageKnifeOption = new ImageKnifeOption()
|
||||
@StorageProp('WeLink_Mob_fontSize_multiple') @Watch('updateImgSize') WeLink_Mob_fontSize_multiple: number = 0
|
||||
scaleable: boolean = true;
|
||||
scalable: boolean = true;
|
||||
@State calcImgSize: number = 100
|
||||
|
||||
aboutToAppear(): void {
|
||||
|
@ -25,7 +25,7 @@ export struct UserAvatar {
|
|||
}
|
||||
|
||||
setImageSize() {
|
||||
if (!this.scaleable) {
|
||||
if (!this.scalable) {
|
||||
this.calcImgSize = this.imgSize
|
||||
} else if (this.WeLink_Mob_fontSize_multiple < 0.9) {
|
||||
this.calcImgSize = this.imgSize * 0.9
|
||||
|
@ -72,12 +72,12 @@ export struct UserAvatar {
|
|||
|
||||
|
||||
|
||||
// Image(this.userInfo)
|
||||
// Text((this.imageKnifeOption.loadSrc as string).split('/')[8])
|
||||
// .position({ x: 0, y: 0 })
|
||||
// .zIndex(9)
|
||||
// .fontSize(12)
|
||||
// .fontColor('#ff0000')
|
||||
// Image(this.userInfo)
|
||||
// Text((this.imageKnifeOption.loadSrc as string).split('/')[8])
|
||||
// .position({ x: 0, y: 0 })
|
||||
// .zIndex(9)
|
||||
// .fontSize(12)
|
||||
// .fontColor('#ff0000')
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,8 @@
|
|||
"pages/LongImagePage",
|
||||
"pages/TransformPage",
|
||||
"pages/UserPage",
|
||||
"pages/TestImageFlash"
|
||||
"pages/TestImageFlash",
|
||||
"pages/TestPrefetchToFileCache",
|
||||
"pages/TestIsUrlExist"
|
||||
]
|
||||
}
|
|
@ -10,3 +10,5 @@ export { FileUtils } from './src/main/ets/utils/FileUtils'
|
|||
|
||||
export { LogUtil } from './src/main/ets/utils/LogUtil'
|
||||
|
||||
export { ImageKnifeData , Cache_Type} "./src/maim/ets/model/ImageKnifeData"
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"main": "index.ets",
|
||||
"repository": "https://gitee.com/openharmony-tpc/ImageKnife",
|
||||
"type": "module",
|
||||
"version": "3.0.0-rc.0",
|
||||
"version": "3.0.0-rc.1",
|
||||
"dependencies": {
|
||||
|
||||
},
|
||||
|
|
|
@ -13,11 +13,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeRequest } from './ImageKnifeRequest';
|
||||
import { ImageKnifeData } from './model/ImageKnifeData';
|
||||
import { ImageKnifeData,Cache_Type } from './model/ImageKnifeData';
|
||||
import { MemoryLruCache } from './utils/MemoryLruCache';
|
||||
import { IMemoryCache } from './utils/IMemoryCache'
|
||||
import { FileCache } from './utils/FileCache';
|
||||
import { ImageKnifeDispatcher } from './ImageKnifeDispatcher';
|
||||
import { ImageKnifeOption } from './ImageKnifeOption';
|
||||
import { Tools } from './utils/Tools';
|
||||
import { common } from '@kit.AbilityKit';
|
||||
|
||||
|
||||
export class ImageKnife {
|
||||
|
@ -84,6 +87,86 @@ export class ImageKnife {
|
|||
saveFileCache(key: string, data: ArrayBuffer): void {
|
||||
this.fileCache?.put(key, data)
|
||||
}
|
||||
getFileCache(): FileCache{
|
||||
return this.fileCache as FileCache
|
||||
}
|
||||
// 预加载到文件缓存,并返回缓存路径
|
||||
preLoadCache(url:string): Promise<string> {
|
||||
return new Promise((resolve,reject)=>{
|
||||
let imageKnifeOption = new ImageKnifeOption()
|
||||
imageKnifeOption.loadSrc = url
|
||||
let keys = Tools.generateKey(url)
|
||||
let cachePath = ImageKnife.getInstance().getFileCache().getFileToPath(keys)
|
||||
if(cachePath == null || cachePath == "" || cachePath == undefined) {
|
||||
let request = new ImageKnifeRequest(
|
||||
imageKnifeOption,
|
||||
imageKnifeOption.context !== undefined ? imageKnifeOption.context : getContext(this) as common.UIAbilityContext,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
{
|
||||
showPixelMap(version: number, pixelMap: PixelMap | string) {
|
||||
let cachePaths = ImageKnife.getInstance().getFileCache().getFileToPath(keys)
|
||||
if(cachePaths != "") {
|
||||
resolve(cachePaths)
|
||||
} else {
|
||||
reject(undefined)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
this.execute(request)
|
||||
} else {
|
||||
resolve(cachePath)
|
||||
}
|
||||
})
|
||||
}
|
||||
// 从内存或文件缓存中获取资源
|
||||
isUrlExist(url: string, cacheType: Cache_Type):Promise<ImageKnifeData | undefined> {
|
||||
return new Promise((resolve,reject)=>{
|
||||
if(cacheType == Cache_Type.MemoryCache) {
|
||||
let keys = Tools.generateMemoryKey(url)
|
||||
let memoryCache:ImageKnifeData | undefined = ImageKnife.getInstance()
|
||||
.loadFromMemoryCache(keys)
|
||||
resolve(memoryCache)
|
||||
} else if (cacheType == Cache_Type.FileCache) {
|
||||
let keys = Tools.generateKey(url)
|
||||
let buffer = ImageKnife.getInstance().loadFromFileCache(keys)
|
||||
if(buffer != undefined) {
|
||||
let fileTypeUtil = new FileTypeUtil();
|
||||
let typeValue = fileTypeUtil.getFileType(buffer);
|
||||
if (typeValue === 'gif' || typeValue === 'webp') {
|
||||
let base64Help = new util.Base64Helper()
|
||||
|
||||
let base64str = "data:image/" + typeValue + ";base64," + base64Help.encodeToStringSync(new Uint8Array(buffer))
|
||||
resolve({
|
||||
source:base64str,
|
||||
imageWidth: 0,
|
||||
imageHeight: 0
|
||||
})
|
||||
}
|
||||
|
||||
let imageSource: image.ImageSource = image.createImageSource(buffer);
|
||||
let decodingOptions: image.DecodingOptions = {
|
||||
editable: true,
|
||||
}
|
||||
|
||||
let resPixelmap: PixelMap | undefined = undefined
|
||||
imageSource.createPixelMap(decodingOptions)
|
||||
.then((pixelmap: PixelMap) => {
|
||||
resolve({
|
||||
source:pixelmap,
|
||||
imageWidth: 0,
|
||||
imageHeight: 0
|
||||
})
|
||||
imageSource.release()
|
||||
})
|
||||
} else {
|
||||
resolve(undefined)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有文件缓存
|
||||
|
|
|
@ -33,6 +33,7 @@ import { FileTypeUtil } from './utils/FileTypeUtil';
|
|||
import util from '@ohos.util';
|
||||
import { Tools } from './utils/Tools';
|
||||
import { SparkMD5 } from './3rd_party/sparkmd5/spark-md5';
|
||||
import { WriteCacheStrategy_Type } "./ImageKnifeOption"
|
||||
|
||||
export class ImageKnifeDispatcher {
|
||||
// 最大并发
|
||||
|
@ -121,7 +122,9 @@ export class ImageKnifeDispatcher {
|
|||
context: currentRequest.context,
|
||||
src: imageSrc,
|
||||
key: key,
|
||||
customGetImage: currentRequest.ImageKnifeOption.customGetImage
|
||||
customGetImage: currentRequest.ImageKnifeOption.customGetImage,
|
||||
onlyRetrieveFromCache: currentRequest.ImageKnifeOption.onlyRetrieveFromCache,
|
||||
requestSource
|
||||
}
|
||||
// 启动线程下载和解码主图
|
||||
let task = new taskpool.Task(requestJob, request)
|
||||
|
@ -164,7 +167,9 @@ export class ImageKnifeDispatcher {
|
|||
}
|
||||
|
||||
// 保存内存缓存
|
||||
ImageKnife.getInstance().saveMemoryCache(Tools.generateMemoryKey(imageSrc), ImageKnifeData)
|
||||
if(currentRequest.ImageKnifeOption.writeCacheStrategy == WriteCacheStrategy_Type.OnlyFile) {
|
||||
ImageKnife.getInstance().saveMemoryCache(Tools.generateMemoryKey(imageSrc), ImageKnifeData)
|
||||
}
|
||||
|
||||
if (requestList !== undefined) {
|
||||
|
||||
|
@ -250,7 +255,7 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
|
|||
if (request.src.indexOf("http://") == 0 || request.src.indexOf("https://") == 0) { //从网络下载
|
||||
// 先从文件缓存获取
|
||||
resBuf = FileCache.getFileCacheByFile(request.context, request.key)
|
||||
if (resBuf === undefined) {
|
||||
if (resBuf === undefined && request.onlyRetrieveFromCache != true && request.requestSource == 0) {
|
||||
// // 模拟耗时验证
|
||||
// let start = (new Date()).getTime();
|
||||
// while ((new Date()).getTime() - start < 5000) {
|
||||
|
@ -309,7 +314,12 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
|
|||
}
|
||||
}
|
||||
} else if ((request.src as Resource).id !== undefined) { //从资源文件获取
|
||||
resBuf = request.context.resourceManager.getMediaContentSync((request.src as Resource).id).buffer as ArrayBuffer
|
||||
resBuf = FileCache.getFileCacheByFile(request.context, request.key)
|
||||
if (resBuf == undefined && request.onlyRetrieveFromCache != true && request.requestSource == 0) {
|
||||
resBuf = request.context.resourceManager.getMediaContentSync((request.src as Resource).id).buffer as ArrayBuffer
|
||||
} else if (resBuf == undefined && request.requestSource != 0) {
|
||||
resBuf = request.context.resourceManager.getMediaContentSync((request.src as Resource).id).buffer as ArrayBuffer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,5 +380,7 @@ interface RequestJobRequest {
|
|||
context: common.UIAbilityContext,
|
||||
src: string | PixelMap | Resource,
|
||||
key: string,
|
||||
customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>
|
||||
customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>,
|
||||
onlyRetrieveFromCache?: boolean
|
||||
requestSource:ImageKnifeRequestSource
|
||||
}
|
||||
|
|
|
@ -14,7 +14,10 @@
|
|||
*/
|
||||
import taskpool from '@ohos.taskpool';
|
||||
import common from '@ohos.app.ability.common'
|
||||
|
||||
export enum WriteCacheStrategy_Type {
|
||||
DEFAULT = 0,// 默认都开启
|
||||
OnlyFile = 1 // 仅缓存文件
|
||||
}
|
||||
@Observed
|
||||
export class ImageKnifeOption {
|
||||
// 主图资源
|
||||
|
@ -25,6 +28,10 @@ export class ImageKnifeOption {
|
|||
errorholderSrc?: PixelMap | Resource;
|
||||
|
||||
objectFit?: ImageFit
|
||||
// 缓存策略
|
||||
writeCacheStrategy?: WriteCacheStrategy_Type
|
||||
// 仅使用缓存加载数据
|
||||
onlyRetrieveFromCache?: boolean = false;
|
||||
|
||||
customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>
|
||||
|
||||
|
|
|
@ -18,3 +18,10 @@ export interface ImageKnifeData {
|
|||
imageHeight: number
|
||||
}
|
||||
|
||||
export enum Cache_Type {
|
||||
// 内存缓存
|
||||
MemoryCache = 0,
|
||||
// 文件缓存
|
||||
FileCache = 1
|
||||
}
|
||||
|
||||
|
|
|
@ -172,8 +172,8 @@ export class FileCache {
|
|||
|
||||
let remove: number | undefined = this.lruCache.remove(key)
|
||||
if (remove !== undefined) {
|
||||
FileUtils.getInstance().deleteFile(this.path + key)
|
||||
this.removeMemorySize(remove)
|
||||
FileUtils.getInstance().deleteFile(this.path + key)
|
||||
this.removeMemorySize(remove)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,4 +258,20 @@ export class FileCache {
|
|||
return FileUtils.getInstance()
|
||||
.readFileSync(context.cacheDir + FileUtils.SEPARATOR + FileCache.CACHE_FOLDER + FileUtils.SEPARATOR + key)
|
||||
}
|
||||
/**
|
||||
* 获取key缓存数据绝对路径
|
||||
*
|
||||
* @params key 数值
|
||||
*/
|
||||
getFileToPath(key: string): string {
|
||||
if(!!!key) {
|
||||
throw new Error("key is null,checking the parameter")
|
||||
}
|
||||
let path = this.path + key
|
||||
if(FileUtils.getInstance().exist(path)) {
|
||||
return path
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue