使用taskpool实现多线程加载图片资源

Signed-off-by: baofeng <baofeng6@h-partners.com>
This commit is contained in:
baofeng 2024-03-06 18:37:10 +08:00 committed by Madi
parent 69f6d68b38
commit ff7a9987ef
48 changed files with 2034 additions and 591 deletions

View File

@ -290,6 +290,10 @@ struct IndexFunctionDemo {
.onClick(() => {
router.pushUrl({ url: "pages/testManyNetImageLoadWithPage" });
}).margin({ top: 5, left: 3 })
Button("多线程加载大量网络图片加载速度")
.onClick(() => {
router.pushUrl({ url: "pages/testManyNetImageLoadWithPage2" });
}).margin({ top: 5, left: 3 })
Button("测试多张gif加载位置")
.onClick(() => {
router.pushUrl({ url: "pages/testManyGifLoadWithPage" });

View File

@ -18,9 +18,8 @@ import {ImageKnifeGlobal} from '@ohos/libraryimageknife'
import {RotateImageTransformation} from '@ohos/libraryimageknife'
import {Material} from './model/Material'
import {TestDataSource} from './model/TestDataSource'
import {DiskLruCache} from '@ohos/disklrucache'
import ArkWorker from '@ohos.worker'
import Prompt from '@system.prompt'
@Entry
@Component
struct photosPausedResumedPage {

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2023 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 { ScaleType, ImageKnifeComponent, NONE, DiskStrategy } from "@ohos/libraryimageknife"
import { Material } from './model/Material';
import { TestDataSource } from './model/TestDataSource';
@Entry
@Component
struct TestManyNetImageLoadWithPage2 {
private data: TestDataSource = new TestDataSource();
private setting: DiskStrategy = new NONE();
build() {
Scroll() {
Column() {
Grid() {
LazyForEach(this.data, (item: Material, index) => {
GridItem() {
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: item.thumbnail,
placeholderSrc: $r('app.media.icon_loading'),
mainScaleType: ScaleType.CENTER_CROP,
placeholderScaleType: ScaleType.CENTER_CROP,
isCacheable: false,
// strategy: this.setting
}
}).width('100%').height('100%')
}.width('45%').height(200)
}, (item: string) => JSON.stringify(item))
}
.columnsTemplate('1fr 1fr')
.columnsGap(8)
.rowsGap(10)
.width('100%')
.hitTestBehavior(HitTestMode.None)
.maxCount(10)
.cachedCount(5)
}.margin({ top: 5 })
}
}
}

View File

@ -34,6 +34,7 @@
"pages/hspCacheTestPage",
"pages/multiHspTestPage",
"pages/testManyNetImageLoadWithPage",
"pages/testManyNetImageLoadWithPage2",
"pages/testManyGifLoadWithPage",
"pages/testImageAntiAliasingWithPage",
"pages/testImageKnifeRouter1",

View File

@ -18,10 +18,12 @@ import LogUtilTest from './logutil.test'
import Transform from './transfrom.test'
import RequestOptionTest from './requestoption.test'
import ImageKnifeTest from './imageknife.test'
import DiskLruCacheTest from './diskLruCache.test'
export default function testsuite() {
abilityTest()
lruCacheTest()
DiskLruCacheTest()
LogUtilTest()
Transform()
RequestOptionTest()

View File

@ -0,0 +1,177 @@
/*
* Copyright (C) 2023 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 hilog from '@ohos.hilog';
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Hypium } from '@ohos/hypium'
import { DiskLruCache, ImageKnifeGlobal, ImageKnife, DiskCacheEntry } from '@ohos/imageknife'
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import { AbilityConstant, common, UIAbility, Want } from '@kit.AbilityKit';
import fs from '@ohos.file.fs';
const BASE_COUNT: number = 2000;
export default function DiskLruCacheTest() {
describe('DiskLruCacheTest', () => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
})
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
})
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
})
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
})
it('testSetCahe', 0, () => {
let context: Object | undefined = ImageKnifeGlobal.getInstance().getHapContext();
if (context != undefined) {
let disLruCache: DiskLruCache = DiskLruCache.create(context as common.UIAbilityContext, 1024);
let startTime = new Date().getTime();
disLruCache.set('test', "Hello World Simple Example.");
disLruCache.set('testABC', "Hello World ABC");
disLruCache.set('testDE', "Hello World Simple DE");
expect(String.fromCharCode(...new Uint8Array(disLruCache.get('test') as ArrayBufferLike)) == "Hello World Simple Example.")
.assertTrue()
expect(String.fromCharCode(...new Uint8Array(disLruCache.get('testABC') as ArrayBufferLike)) == "Hello World ABC")
.assertTrue()
expect(String.fromCharCode(...new Uint8Array(disLruCache.get('testDE') as ArrayBufferLike)) == "Hello World Simple DE")
.assertTrue()
let str: string = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
for (let index = 0; index < 100; index++) {
str += index;
disLruCache.set('test' + index, str);
}
expect(disLruCache.getSize() <= 1024).assertTrue()
endTime(startTime, 'testSetCahe');
disLruCache.cleanCacheData();
}
})
it('testGetCacheAsync', 1, () => {
let context: common.UIAbilityContext = ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext;
if (context != undefined) {
let data = context.filesDir
let cache: DiskLruCache = DiskLruCache.create(context);
let startTime = new Date().getTime();
let path = data + '/testFile.txt';
let file = fs.openSync(path, 0o102);
fs.writeSync(file.fd, "hello, world!");
let length = fs.statSync(path).size;
let dataArr = new ArrayBuffer(length);
fs.readSync(file.fd, dataArr);
cache.set('testFile', dataArr);
expect(cache.get('testFile')?.byteLength == 13).assertTrue()
endTime(startTime, 'testGetCacheAsync');
cache.cleanCacheData();
}
})
it('testDeleteCacheDataByKey', 2, () => {
let context: common.UIAbilityContext = ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext;
if (context != undefined) {
let cache: DiskLruCache = DiskLruCache.create(context);
let startTime = new Date().getTime();
cache.set('test', "Hello World Simple Example.");
cache.set('testABC', "Hello World ABC");
expect(String.fromCharCode(...new Uint8Array(cache.get('test') as ArrayBufferLike)))
.assertEqual("Hello World Simple Example.");
expect(String.fromCharCode(...new Uint8Array(cache.get('testABC') as ArrayBufferLike)))
.assertEqual("Hello World ABC");
cache.deleteCacheDataByKey('test');
cache.deleteCacheDataByKey('testABC');
expect(String.fromCharCode(...new Uint8Array(cache.get('test') as ArrayBufferLike))).assertEqual('');
expect(String.fromCharCode(...new Uint8Array(cache.get('testABC') as ArrayBufferLike))).assertEqual('');
endTime(startTime, 'testDeleteCacheDataByKey');
cache.cleanCacheData();
}
})
it('testGetPath', 3, async () => {
let context: common.UIAbilityContext = ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext;
if (context != undefined) {
let cache: DiskLruCache = DiskLruCache.create(context);
let startTime = new Date().getTime();
cache.set('test', "Hello World Simple Example.");
let path: string = ''
await cache.getFileToPathAsync('test').then((data) => {
path = data
})
expect(String.fromCharCode(...new Uint8Array(cache.get('test') as ArrayBufferLike)) == "Hello World Simple Example.")
.assertTrue()
expect(cache.getFileToPath('test') == path).assertTrue()
expect(cache.getPath() + cache.getCacheMap().getFirstKey() == path).assertTrue()
endTime(startTime, 'testGetPath');
cache.cleanCacheData();
}
})
it('testGetCacheMap', 6, async () => {
let context: common.UIAbilityContext = ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext;
if (context != undefined) {
let cache: DiskLruCache = DiskLruCache.create(context);
let startTime = new Date().getTime();
cache.set('test', "Hello World Simple Example.");
expect(cache.getCacheMap().getFirstKey() == '098f6bcd4621d373cade4e832627b4f6').assertTrue()
expect(cache.getCacheMap().hasKey('098f6bcd4621d373cade4e832627b4f6') == true).assertTrue()
endTime(startTime, 'testGetCacheMap');
cache.cleanCacheData();
}
})
it('testGetSize', 7, async () => {
let context: common.UIAbilityContext = ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext;
if (context != undefined) {
let cache: DiskLruCache = DiskLruCache.create(context);
let startTime = new Date().getTime();
cache.set('test', "Hello World Simple Example.");
expect(String.fromCharCode(...new Uint8Array(cache.get('test') as ArrayBufferLike)) == "Hello World Simple Example.")
.assertTrue()
expect(cache.getSize() == 27).assertTrue()
endTime(startTime, 'testGetSize');
cache.cleanCacheData();
}
})
it('testDiskCacheEntry', 8, async () => {
let startTime = new Date().getTime();
let dentry = new DiskCacheEntry('test', 30 * 1024 * 1024)
expect(dentry.getKey() == 'test').assertTrue()
dentry.setKey('newtest')
expect(dentry.getKey() == 'newtest').assertTrue()
expect(dentry.getLength() == 30 * 1024 * 1024).assertTrue()
dentry.setLength(12 * 1024 * 1024)
expect(dentry.getLength() == 12 * 1024 * 1024).assertTrue()
expect(dentry.toString() == dentry.getKey() + ' - ' + dentry.getLength()).assertTrue()
endTime(startTime, 'testDiskCacheEntry');
})
})
}
function endTime(startTime: number, tag: string) {
let endTime: number = new Date().getTime();
let averageTime = ((endTime - startTime) * 1000 / BASE_COUNT)
console.info(tag + " startTime: " + endTime)
console.info(tag + " endTime: " + endTime)
console.log(tag + " averageTime: " + averageTime + "μs");
}

View File

@ -21,6 +21,8 @@
export { FileUtils } from './src/main/ets/components/cache/FileUtils'
export { Base64 } from './src/main/ets/components/cache/Base64'
export { LruCache } from './src/main/ets/components/cache/LruCache'
export { DiskLruCache } from './src/main/ets/components/cache/DiskLruCache'
export { DiskCacheEntry } from './src/main/ets/components/cache/DiskCacheEntry'
export { DiskStrategy } from './src/main/ets/components/cache/diskstrategy/DiskStrategy'
export { ALL } from './src/main/ets/components/cache/diskstrategy/enum/ALL'
export { AUTOMATIC } from './src/main/ets/components/cache/diskstrategy/enum/AUTOMATIC'

View File

@ -17,7 +17,6 @@
"version": "2.1.2-rc.8",
"dependencies": {
"pako": "^2.1.0",
"@ohos/disklrucache": "^2.0.2-rc.0",
"@ohos/gpu_transform": "^1.0.0"
},
"tags": [

View File

@ -0,0 +1,46 @@
/*
* 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.
*/
export class DiskCacheEntry {
// 缓存的key
key: string = ''
// 缓存文件大小
length: number = 0
constructor(key: string, length?: number) {
this.key = key
this.length = length as number
}
setKey(key: string) {
this.key = key
}
getKey(): string {
return this.key
}
setLength(length: number) {
this.length = length
}
getLength(): number {
return this.length
}
toString(): string {
return this.key + ' - ' + this.length
}
}

View File

@ -0,0 +1,496 @@
/*
* 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 fileio from '@ohos.fileio'
import { CustomMap } from './CustomMap'
import { FileUtils } from './FileUtils'
import { FileReader } from './FileReader'
import { DiskCacheEntry } from './DiskCacheEntry'
import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5'
import { Context } from '@ohos.abilityAccessCtrl'
import { common } from '@kit.AbilityKit'
export class DiskLruCache {
// 默认缓存数据最大值
private static readonly DEFAULT_MAX_SIZE: number = 300 * 1024 * 1024
// 默认缓存文件名
private static readonly DEFAULT_NAME: string = 'diskLruCache'
// 缓存journal文件名称
private static readonly journal: string = 'journal'
// 缓存journal备份文件名称
private static readonly journalTemp: string = 'journal_temp'
// 备份文件save标识符
private static readonly SAVE: string = 'save'
// 备份文件read标识符
private static readonly READ: string = 'read'
// 备份文件remove标识符
private static readonly REMOVE: string = 'remove'
// 缓存文件路径地址
private path: string = ''
// 缓存journal文件路径
private journalPath: string = ''
// 缓存journal备份文件路径
private journalPathTemp: string = ''
// 缓存数据最大值
private maxSize: number = DiskLruCache.DEFAULT_MAX_SIZE
// 当前缓存数据值
private size: number = 0
// 缓存数据集合
private cacheMap: CustomMap<string, DiskCacheEntry> = new CustomMap<string, DiskCacheEntry>()
constructor(path: string, maxSize: number) {
this.path = path
this.maxSize = maxSize
this.journalPath = path + DiskLruCache.journal
this.journalPathTemp = path + DiskLruCache.journalTemp
}
/**
* 打开context获取的cache路径中的缓存如果不存在缓存则创建新缓存
*
* @param context 上下文
* @param maxSize 缓存数据最大值默认值为300M
*/
public static create(context: common.UIAbilityContext, maxSize?: number): DiskLruCache {
if (!!!context) {
throw new Error('DiskLruCache create context is empty, checking the parameter');
}
if (!!!maxSize) {
maxSize = DiskLruCache.DEFAULT_MAX_SIZE
}
if (maxSize <= 0) {
throw new Error("DiskLruCache create maxSize <= 0, checking the parameter");
}
// 使用默认应用在内部存储上的缓存路径,作为存储地址
let path = context.cacheDir + FileUtils.SEPARATOR + DiskLruCache.DEFAULT_NAME
if (!FileUtils.getInstance().existFolder(path)) {
FileUtils.getInstance().createFolder(path)
}
if (path.endsWith(FileUtils.SEPARATOR)) {
path = path
} else {
path = path + FileUtils.SEPARATOR
}
let journalPath = path + DiskLruCache.journal
let journalPathTemp = path + DiskLruCache.journalTemp
// 判断日志文件是否存在,如果没有初始化创建
if (FileUtils.getInstance().exist(journalPath)) {
let stat = fileio.statSync(journalPath)
if (stat.size > 0) {
FileUtils.getInstance().createFile(journalPathTemp)
FileUtils.getInstance().copyFile(journalPath, journalPathTemp)
let diskLruCache: DiskLruCache = new DiskLruCache(path, maxSize)
diskLruCache.readJournal(journalPathTemp)
diskLruCache.resetJournalFile()
return diskLruCache
} else {
return new DiskLruCache(path, maxSize)
}
} else {
FileUtils.getInstance().createFile(journalPath)
return new DiskLruCache(path, maxSize)
}
}
/**
* 设置disk缓存最大数据值
*
* @param max 缓存数据最大值
*/
setMaxSize(max: number) {
if (max <= 0 || max > DiskLruCache.DEFAULT_MAX_SIZE) {
throw new Error('setMaxSize error, checking the parameter');
}
this.maxSize = max
this.trimToSize()
}
/**
* 存储disk缓存数据
*
* @param key 键值
* @param content 文件内容
*/
set(key: string, content: ArrayBuffer | string) {
if (!!!key) {
throw new Error('key is null, checking the parameter')
}
let fileSize = 0;
if (content instanceof ArrayBuffer) {
if (content == null || content.byteLength == 0) {
throw new Error('content is null. checking the parameter')
}
fileSize = content.byteLength
} else {
if (!!!content) {
throw new Error('content is null, checking the parameter')
}
fileSize = content.length;
}
if (this.fileSizeMoreThenMaxSize(fileSize)) {
throw new Error('content must be less then DiskLruCache Size, checking the parameter')
return
}
key = SparkMD5.hashBinary(key)
this.size = this.size + fileSize
this.putCacheMap(key, fileSize)
FileUtils.getInstance().writeData(this.journalPath, DiskLruCache.SAVE + ' ' + key + FileReader.LF)
this.trimToSize()
let tempPath = this.path + key
FileUtils.getInstance().writeNewFile(tempPath, content)
}
/**
* 异步存储disk缓存数据
*
* @param key 键值
* @param content 文件内容
*/
async setAsync(key: string, content: ArrayBuffer | string): Promise<void> {
if (!!!key) {
throw new Error('key is null, checking the parameter')
}
let fileSize = 0;
if (content instanceof ArrayBuffer) {
if (content == null || content.byteLength == 0) {
throw new Error('content is null. checking the parameter')
}
fileSize = content.byteLength
} else {
if (!!!content) {
throw new Error('content is null, checking the parameter')
}
fileSize = content.length;
}
if (this.fileSizeMoreThenMaxSize(fileSize)) {
throw new Error('content must be less then DiskLruCache Size, checking the parameter')
return
}
key = SparkMD5.hashBinary(key)
this.size = this.size + fileSize
this.putCacheMap(key, fileSize)
await FileUtils.getInstance().writeDataAsync(this.journalPath, DiskLruCache.SAVE + ' ' + key + FileReader.LF)
this.trimToSize()
let tempPath = this.path + key
await FileUtils.getInstance().writeNewFileAsync(tempPath, content)
}
/**
* 获取key缓存数据
*
* @param key key 键值
*/
get(key: string): ArrayBuffer | undefined {
if (!!!key) {
throw new Error('key is null,checking the parameter');
}
key = SparkMD5.hashBinary(key)
let path = this.path + key;
if (FileUtils.getInstance().exist(path)) {
let ab: ArrayBuffer = FileUtils.getInstance().readFile(path)
this.putCacheMap(key, ab.byteLength)
FileUtils.getInstance().writeData(this.journalPath, DiskLruCache.READ + ' ' + key + FileReader.LF)
return ab
} else {
return undefined;
}
}
/**
* 异步获取key缓存数据
*
* @param key 键值
*/
async getAsync(key: string): Promise<ArrayBuffer | undefined> {
if (!!!key) {
throw new Error('key is null,checking the parameter');
}
key = SparkMD5.hashBinary(key)
let path = this.path + key;
if (FileUtils.getInstance().exist(path)) {
let ab: ArrayBuffer = await FileUtils.getInstance().readFileAsync(path)
this.putCacheMap(key, ab.byteLength)
await FileUtils.getInstance().writeDataAsync(this.journalPath, DiskLruCache.READ + ' ' + key + FileReader.LF)
return ab
} else {
return undefined;
}
}
/**
* 获取key缓存数据绝对路径
*
* @param key 键值
*/
getFileToPath(key: string): string {
if (!!!key) {
throw new Error('key is null,checking the parameter');
}
key = SparkMD5.hashBinary(key);
let path = this.path + key;
if (FileUtils.getInstance().exist(path)) {
FileUtils.getInstance().writeData(this.journalPath, DiskLruCache.READ + ' ' + key + FileReader.LF);
return path
} else {
return "";
}
}
/**
* 异步获取key缓存数据绝对路径
*
* @param key 键值
*/
async getFileToPathAsync(key: string): Promise<string> {
if (!!!key) {
throw new Error('key is null,checking the parameter');
}
key = SparkMD5.hashBinary(key);
let path = this.path + key;
if (FileUtils.getInstance().exist(path)) {
await FileUtils.getInstance().writeDataAsync(this.journalPath, DiskLruCache.READ + ' ' + key + FileReader.LF);
return path
} else {
return ""
}
}
/**
* 获取缓存路径
*/
getPath(): string {
return this.path;
}
/**
* 删除key缓存数据
*
* @param key 键值
*/
deleteCacheDataByKey(key: string): DiskCacheEntry {
if (!!!key) {
throw new Error('key is null,checking the parameter');
}
key = SparkMD5.hashBinary(key)
let path = this.path + key;
if (FileUtils.getInstance().exist(path)) {
let ab = FileUtils.getInstance().readFile(path)
this.size = this.size - ab.byteLength
this.cacheMap.remove(key)
FileUtils.getInstance().writeData(this.journalPath, DiskLruCache.REMOVE + ' ' + key + FileReader.LF)
FileUtils.getInstance().deleteFile(path)
}
return this.cacheMap.get(key) as DiskCacheEntry;
}
/**
*遍历当前的磁盘缓存数据
*
* @param fn 遍历后方法回调
*/
foreachDiskLruCache(fn: Function) {
this.cacheMap.each(fn())
}
/**
* 清除所有disk缓存数据
*/
cleanCacheData() {
this.cacheMap.each((value, key) => {
FileUtils.getInstance().deleteFile(this.path + key)
})
FileUtils.getInstance().deleteFile(this.journalPath)
this.cacheMap.clear()
this.size = 0
}
getCacheMap() {
return this.cacheMap;
}
/**
* 返回当前DiskLruCache的size大小
*/
getSize() {
return this.size;
}
/**
* 处理journal文件数据
*
* @param line 日志行字符串
*/
private dealWithJournal(line: string) {
let filePath = ''
try {
let lineData = line.split(' ')
if (lineData.length > 1) {
if (lineData[0] != DiskLruCache.REMOVE) {
filePath = this.path + lineData[1]
let fileStat = fileio.statSync(filePath)
if (fileStat.isFile() && fileStat.size > 0) {
this.size = this.size + fileStat.size
FileUtils.getInstance().writeData(this.journalPath, line + FileReader.LF)
this.putCacheMap(lineData[1], fileStat.size)
}
} else {
if (this.cacheMap.hasKey(lineData[1])) {
let cacheEntry: DiskCacheEntry = this.cacheMap.get(lineData[1]) as DiskCacheEntry;
this.size = this.size - cacheEntry.getLength()
this.cacheMap.remove(lineData[1])
}
}
}
} catch (e) {
console.error('DiskLruCache - dealWithJournal e ' + e)
}
}
/**
* 重置journal文件数据
*/
private resetJournalFile() {
FileUtils.getInstance().clearFile(this.journalPath)
for (let key of this.cacheMap.keys()) {
FileUtils.getInstance().writeData(this.journalPath, DiskLruCache.SAVE + ' ' + key + FileReader.LF)
}
}
/**
* 读取journal文件的缓存数据
*
* @param path 日志缓存文件路径地址
*/
private readJournal(path: string) {
let fileReader = new FileReader(path)
let line: string = ''
while (!fileReader.isEnd()) {
line = fileReader.readLine()
line = line.replace(FileReader.LF, '').replace(FileReader.CR, '')
this.dealWithJournal(line)
}
fileReader.close()
FileUtils.getInstance().deleteFile(this.journalPathTemp)
this.trimToSize()
}
/**
* 缓存数据map集合
*
* @param key 键值
* @param length 缓存文件大小
*/
private putCacheMap(key: string, length?: number) {
if (length && length > 0) {
this.cacheMap.put(key, new DiskCacheEntry(key, length))
} else {
this.cacheMap.put(key, new DiskCacheEntry(key))
}
}
/**
* 根据LRU算法删除多余缓存数据
*/
private trimToSize() {
while (this.size > this.maxSize) {
let tempKey: string = this.cacheMap.getFirstKey()
let fileSize = FileUtils.getInstance().getFileSize(this.path + tempKey)
if (fileSize > 0) {
this.size = this.size - fileSize
}
FileUtils.getInstance().deleteFile(this.path + tempKey)
this.cacheMap.remove(tempKey)
FileUtils.getInstance().writeData(this.journalPath, DiskLruCache.REMOVE + ' ' + tempKey + FileReader.LF)
}
}
/**
* 图片文件过大 直接超过DiskLruCache上限
*/
private fileSizeMoreThenMaxSize(fileSize: number): boolean {
if (fileSize > this.maxSize) {
return true;
}
return false;
}
/**
* 子线程里只写入缓存文件
* @param context
* @param key
* @param value
*/
static saveFileCacheOnlyFile(path: string, key: string, value: ArrayBuffer): boolean {
// 写文件
if (!!!key) {
throw new Error('key is null, checking the parameter')
}
key = SparkMD5.hashBinary(key);
FileUtils.getInstance()
.writeData(path + DiskLruCache.journal, DiskLruCache.SAVE + ' ' + key + FileReader.LF);
FileUtils.getInstance().writeNewFile(path + key, value);
return true
}
/**
* 子线程中,通过文件名,直接查找是否有文件缓存
* @param context
* @param key
* @returns
*/
static getFileCacheByFile(path: string, key: string): ArrayBuffer | undefined {
// 从文件获取查看是否有缓存
if (!!!key) {
throw new Error('key is null,checking the parameter');
}
key = SparkMD5.hashBinary(key)
let filepath = path + key;
if (FileUtils.getInstance().exist(filepath)) {
let ab: ArrayBuffer = FileUtils.getInstance().readFile(filepath)
FileUtils.getInstance().writeData(path + DiskLruCache.journal, DiskLruCache.READ + ' ' + key + FileReader.LF)
return ab
} else {
return undefined;
}
}
// 添加缓存键值对,但不写文件(用于子线程已经写文件的场景)
setCacheMapAndSize(key: string, content: ArrayBuffer | string): void {
if (!!!key) {
throw new Error('key is null, checking the parameter')
}
let fileSize = 0;
if (content instanceof ArrayBuffer) {
if (content == null || content.byteLength == 0) {
throw new Error('content is null. checking the parameter')
}
fileSize = content.byteLength
} else {
if (!!!content) {
throw new Error('content is null, checking the parameter')
}
fileSize = content.length;
}
if (this.fileSizeMoreThenMaxSize(fileSize)) {
throw new Error('content must be less then DiskLruCache Size, checking the parameter')
return
}
key = SparkMD5.hashBinary(key);
this.size = this.size + fileSize;
this.putCacheMap(key, fileSize);
this.trimToSize();
}
}

View File

@ -0,0 +1,99 @@
/*
* 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 fs, { ReadOptions } from '@ohos.file.fs';
import { RequestOption } from '../imageknife/RequestOption';
export class FileReader {
// 换行符
static readonly LF: string = '\n'
// CR符
static readonly CR: string = '\r'
// 文件大小
fileLength: number = 0
// 读取的长度
length: number = 0
// 读写stream
stream: fs.Stream | null = null
// 缓存buf
buf: ArrayBuffer = new ArrayBuffer(1)
/**
* 读取文件行
*
* @param path 文件路径
*/
constructor(path: string) {
if (!!!path) {
throw new Error('FileReader constructor path is null, checking the parameter')
return;
}
try {
this.stream = fs.createStreamSync(path, 'r+');
let stat = fs.statSync(path)
this.fileLength = stat.size
} catch (e) {
console.log(path);
console.log(e.toString());
}
}
/**
* 循环读取文件数据
*/
readLine(): string {
let line = ''
while (this.length < this.fileLength) {
this.stream?.readSync(this.buf, { length: this.length })
this.length++
let temp = String.fromCharCode(...new Uint8Array(this.buf));
line = line + temp
// check CRLF
if (temp == FileReader.CR) {
// 边界判断 首先拿到下一个字符判断是否是LF 如果是CRLF需要再向后挪一位
if (this.length < this.fileLength) {
let nextBuf = new ArrayBuffer(1)
this.stream?.readSync(nextBuf, { length: this.length })
let nextTemp = String.fromCharCode(...new Uint8Array(nextBuf));
// 如果是CRLF 需要给当前length+1 向后挪一位
if (nextTemp == FileReader.LF) {
this.length++
}
}
// 如果不是CRLF 只有一个CR结尾length不用变
return line;
} else {
// 判断LF情况
if (temp == FileReader.LF) {
return line
}
}
}
return line
}
/**
* 判断文件是否结束
*/
isEnd() {
return this.fileLength <= 0 || this.length == this.fileLength
}
/**
* 关闭stream
*/
close() {
this.stream?.closeSync()
}
}

View File

@ -16,6 +16,7 @@
import fs from '@ohos.file.fs';
import { BusinessError } from '@ohos.base'
export class FileUtils {
static readonly SEPARATOR: string = '/'
base64Str: string = ''
private static sInstance: FileUtils;
@ -32,12 +33,20 @@ export class FileUtils {
/**
* 新建文件
*
* @param path 文件绝对路径及文件名
* @return number 文件句柄id
*/
createFile(path: string): number {
return fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE).fd
let num = -1;
try {
num = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE).fd
} catch (e) {
console.log("createFile err :" + e)
}
return num;
}
/**
* 删除文件
@ -143,16 +152,20 @@ export class FileUtils {
/**
* 判断path文件是否存在
*
* @param path 文件绝对路径
*/
exist(path: string): boolean {
try {
if (fs.accessSync(path)) {
let stat = fs.statSync(path)
return stat.isFile()
} catch (e) {
console.debug("FileUtils - fileutils exsit e" + e)
console.log("path=>" + path)
return false
}
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error("accessSync failed with error message: " + err.message + ", error code: " + err.code);
}
return false
}
/**
@ -318,9 +331,84 @@ export class FileUtils {
return tmpUint8Array
}
/**
* 异步向path写入数据
*
* @param path 文件绝对路径
* @param content 文件内容
*/
async writeDataAsync(path: string, content: ArrayBuffer | string): Promise<void> {
let fd = (await fs.open(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)).fd
let stat = await fs.stat(path)
await fs.write(fd, content, { offset: stat.size })
await fs.close(fd)
}
/**
* 异步拷贝文件
*
* @param src 文件绝对路径及文件名
* @param dest 拷贝到对应的路径
*/
async copyFileAsync(src: string, dest: string): Promise<void> {
await fs.copyFile(src, dest);
}
/**
* 读取路径path的文件
*
* @param path 文件绝对路径
*/
async readFileAsync(path: string): Promise<ArrayBuffer> {
let stat = await fs.stat(path);
let fd = (await fs.open(path, fs.OpenMode.READ_WRITE)).fd;
let length = stat.size;
let buf = new ArrayBuffer(length);
await fs.read(fd, buf);
return buf
}
/**
* 向path写入数据
*
* @param path 文件绝对路径
* @param data 文件内容
*/
async writeNewFileAsync(path: string, data: ArrayBuffer | string): Promise<void> {
let fd = (await fs.open(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)).fd
await fs.truncate(fd)
await fs.write(fd, data)
await fs.fsync(fd)
await fs.close(fd)
}
uint8ArrayToBuffer(array: Uint8Array): ArrayBuffer {
return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset)
}
/**
* 向path写入数据
*
* @param path 文件绝对路径
* @param data 文件内容
*/
writeNewFile(path: string, data: ArrayBuffer | string) {
this.createFile(path)
this.writeFile(path, data)
}
/**
* 读取路径path的文件
*
* @param path 文件绝对路径
*/
readFile(path: string): ArrayBuffer {
let fd = fs.openSync(path, fs.OpenMode.READ_WRITE).fd;
let length = fs.statSync(path).size
let buf = new ArrayBuffer(length);
fs.readSync(fd, buf)
return buf
}
}

View File

@ -13,7 +13,7 @@
* limitations under the License.
*/
import { DiskLruCache } from "@ohos/disklrucache"
import { DiskLruCache } from "../cache/DiskLruCache"
import { EngineKeyFactories } from "../cache/key/EngineKeyFactories"
import { EngineKeyInterface } from "../cache/key/EngineKeyInterface"
import { RequestOption } from "../imageknife/RequestOption"
@ -38,18 +38,30 @@ import { EasyLinkedHashMap } from './utils/base/EasyLinkedHashMap'
import { MethodMutex } from './utils/base/MethodMutex'
import worker from '@ohos.worker'
import common from '@ohos.app.ability.common'
import HashMap from '@ohos.util.HashMap'
import LinkedList from '@ohos.util.LinkedList'
import { MemoryLruCache } from '../cache/MemoryLruCache'
import { BusinessError } from '@kit.BasicServicesKit'
import { taskpool } from '@kit.ArkTS'
import { GIFFrame } from './utils/gif/GIFFrame'
import { MemoryCacheProxy } from './requestmanage/MemoryCacheProxy'
import { ObjectKey } from './ObjectKey'
export enum ResourceUsage {
PLACEHOLDER = 'placeholder',
RETRYHODLER = 'retryholder',
ERRORHOLDER = 'errorholder',
MAIN = 'main'
}
export class ImageKnife {
static readonly SEPARATOR: string = '/'
memoryCache: MemoryLruCache;
diskMemoryCache: DiskLruCache;
dataFetch: IDataFetch;
resourceFetch: IResourceFetch<ArrayBuffer>;
filesPath: string = ""; // data/data/包名/files目录
diskMemoryCache: DiskLruCache;
memoryCacheProxy: MemoryCacheProxy<string, ImageKnifeData> = new MemoryCacheProxy(new MemoryLruCache(100, 100 * 1024 * 1024));
headerMap: Map<string, Object> = new Map<string, Object>(); //定义全局map
placeholderCache: string = "placeholderCache"
runningMaps: EasyLinkedHashMap<string, RequestOption>;
@ -80,9 +92,6 @@ export class ImageKnife {
// 构造方法传入size 为保存文件个数
this.memoryCache = new MemoryLruCache(100, 100 * 1024 * 1024);
// 创建disk缓存 传入的size 为多少比特 比如20KB 传入20*1024
this.diskMemoryCache = DiskLruCache.create(ImageKnifeGlobal.getInstance().getHapContext());
// 创建网络下载能力
this.dataFetch = new DownloadClient();
@ -92,13 +101,16 @@ export class ImageKnife {
// 初始化本地 文件保存
this.filesPath = (ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext).filesDir as string;
this.diskMemoryCache = DiskLruCache.create(ImageKnifeGlobal.getInstance()
.getHapContext() as common.UIAbilityContext);
// 通用文件格式识别初始化
this.fileTypeUtil = new FileTypeUtil();
this.engineKeyImpl = new EngineKeyFactories();
}
//全局设置请求头调用方法
addHeader(key: string, value: Object) {
this.headerMap.set(key, value);
@ -112,6 +124,10 @@ export class ImageKnife {
return this.memoryCache;
}
getMemoryCacheProxy(): MemoryCacheProxy<string, ImageKnifeData> {
return this.memoryCacheProxy;
}
public static with(context: Object): ImageKnifeGlobal {
// 存入hapContext;
let global: ImageKnifeGlobal = ImageKnifeGlobal.getInstance();
@ -200,12 +216,15 @@ export class ImageKnife {
this.dataFetch = fetch;
}
// 替代原来的DiskLruCache
public replaceDiskLruCache(size: number) {
if (this.diskMemoryCache.getCacheMap().size() <= 0) {
this.diskMemoryCache = DiskLruCache.create(ImageKnifeGlobal.getInstance().getHapContext(), size);
this.diskMemoryCache = DiskLruCache.create(ImageKnifeGlobal.getInstance()
.getHapContext() as common.UIAbilityContext, size);
} else {
let newDiskLruCache = DiskLruCache.create(ImageKnifeGlobal.getInstance().getHapContext(), size);
let newDiskLruCache = DiskLruCache.create(ImageKnifeGlobal.getInstance()
.getHapContext() as common.UIAbilityContext, size);
this.diskMemoryCache.foreachDiskLruCache((value: string | ArrayBuffer, key: string, map: Object) => {
newDiskLruCache.set(key, value);
})
@ -293,16 +312,40 @@ export class ImageKnife {
// 首先执行占位图 解析任务
if (request.placeholderSrc) {
PlaceHolderManager.execute(request)
let loadKey = '';
if (typeof request.placeholderSrc == 'string') {
loadKey = request.placeholderSrc;
} else {
loadKey = JSON.stringify(request.placeholderSrc);
}
let size = JSON.stringify(request.size);
request.placeholderCacheKey = this.generateCacheKey(loadKey, size, request.dontAnimateFlag, request.signature)
this.taskpoolLoadResource(request, ResourceUsage.PLACEHOLDER);
}
// 其次执行重试占位图 解析任务
if (request.retryholderSrc) {
RetryHolderManager.execute(request)
let loadKey = '';
if (typeof request.retryholderSrc == 'string') {
loadKey = request.retryholderSrc;
} else {
loadKey = JSON.stringify(request.retryholderSrc);
}
let size = JSON.stringify(request.size);
request.retryholderCacheKey = this.generateCacheKey(loadKey, size, request.dontAnimateFlag, request.signature)
this.taskpoolLoadResource(request, ResourceUsage.RETRYHODLER);
}
// 最后解析错误占位图
if (request.errorholderSrc) {
ErrorHolderManager.execute(request)
let loadKey = '';
if (typeof request.errorholderSrc == 'string') {
loadKey = request.errorholderSrc;
} else {
loadKey = JSON.stringify(request.errorholderSrc);
}
let size = JSON.stringify(request.size);
request.errorholderCacheKey = this.generateCacheKey(loadKey, size, request.dontAnimateFlag, request.signature)
this.taskpoolLoadResource(request, ResourceUsage.ERRORHOLDER);
}
return this.parseSource(request);
}
@ -312,6 +355,7 @@ export class ImageKnife {
let cacheKey: string;
let transferKey: string;
let dataKey: string;
//设置全局缓存key
if (this.engineKeyImpl) {
factories = this.engineKeyImpl;
} else {
@ -358,6 +402,18 @@ export class ImageKnife {
this.loadCacheManager(request);
}
private generateCacheKey(loadkey: string, size: string, dontAnimateFlag: boolean, signature?: ObjectKey) {
let factories: EngineKeyInterface;
//设置全局缓存key
if (this.engineKeyImpl) {
factories = this.engineKeyImpl;
} else {
factories = new EngineKeyFactories();
}
return factories.generateMemoryCacheKey(loadkey, size, '', dontAnimateFlag, signature);
}
// 删除执行结束的running
removeRunning(request: RequestOption) {
if (this.isPaused) {
@ -374,12 +430,11 @@ export class ImageKnife {
private keyEqualPendingToRun(nextPending: RequestOption) {
this.pendingMaps.remove(nextPending.uuid)
this.runningMaps.put(nextPending.uuid, nextPending);
RequestManager.execute((nextPending as RequestOption), this.memoryCache, this.diskMemoryCache, this.dataFetch, this.resourceFetch)
// RequestManager.execute((nextPending as RequestOption), this.memoryCache, this.diskMemoryCache, this.dataFetch, this.resourceFetch)
this.taskpoolLoadResource(nextPending, ResourceUsage.MAIN);
}
@ -409,7 +464,8 @@ export class ImageKnife {
let nextPending = pendingTailNode.value;
this.runningMaps.put(nextPending.uuid, nextPending)
this.pendingMaps.remove(nextPending.uuid)
RequestManager.execute((nextPending as RequestOption), this.memoryCache, this.diskMemoryCache, this.dataFetch, this.resourceFetch)
//RequestManager.execute((nextPending as RequestOption), this.memoryCache, this.diskMemoryCache, this.dataFetch, this.resourceFetch)
this.taskpoolLoadResource(nextPending, ResourceUsage.MAIN);
}
}
@ -461,9 +517,7 @@ export class ImageKnife {
} else {
this.runningMaps.put(request.uuid, request)
// 不存在相同key的 任务可以并行
RequestManager.execute(request, this.memoryCache, this.diskMemoryCache, this.dataFetch, this.resourceFetch)
this.taskpoolLoadResource(request, ResourceUsage.MAIN);
}
}
else {
@ -472,6 +526,99 @@ export class ImageKnife {
}
}
//多线程请求加载资源
private taskpoolLoadResource(request: RequestOption, usageType: ResourceUsage) {
if (usageType == "placeholder") {
// 先从内存中取值
let cache = this.memoryCacheProxy.loadMemoryCache(request.placeholderCacheKey, true);
if (cache) {
LogUtil.info("imageknife load placeholder from MemoryCache")
request.placeholderOnComplete(cache);
return;
}
} else if (usageType == "retryholder") {
// 先从内存中取值
let cache = this.memoryCacheProxy.loadMemoryCache(request.retryholderCacheKey, true);
if (cache) {
LogUtil.info("imageknife load retryholder from MemoryCache")
request.retryholderOnComplete(cache);
return;
}
} else if (usageType == "errorholder") {
let cache = this.memoryCacheProxy.loadMemoryCache(request.errorholderCacheKey, true);
if (cache) {
LogUtil.info("imageknife load errorholder from MemoryCache")
request.errorholderOnComplete(cache);
return;
}
} else {
// 先从内存中取值
let cache = this.memoryCacheProxy.loadMemoryCache(request.generateCacheKey, request.isCacheable);
if (cache) {
LogUtil.info("imageknife load resource from MemoryCache")
cache.waitSaveDisk = false;
request.loadComplete(cache);
return;
}
}
//图片变换方法无法直接传递到子线程,这里先把对象名和构造参数传递到子线程,然后在子线程中实例化变换方法
let transformations: string [][] = [];
if (usageType == ResourceUsage.MAIN) {
for (let i = 0; i < request.transformations.length; i++) {
transformations.push([request.transformations[i].getClassName(), request.transformations[i].getConstructorParams()])
}
}
//將要传递到子线程的参数放在一个json对象上避免方法参数过多
let taskParams = JSON.stringify({
transformations: transformations,
request: request,
usageType: usageType
})
//使用taskpool多线程执行资源下载
let task = new taskpool.Task(taskExecute, taskParams, request.headers, request.moduleContext as common.UIAbilityContext)
task.setTransferList([])
taskpool.execute(task).then((data) => {
if (usageType == "placeholder") {
if ((typeof (data as PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, data as PixelMap);
request.placeholderOnComplete(imageKnifeData)
} else {
request.placeholderOnError("request placeholder error")
}
} else if (usageType == "retryholder") {
if ((typeof (data as PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, data as PixelMap);
request.retryholderOnComplete(imageKnifeData)
} else {
request.retryholderOnError("request retryholder error")
}
} else if (usageType == "errorholder") {
if ((typeof (data as PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, data as PixelMap);
request.errorholderOnComplete(imageKnifeData)
} else {
request.errorholderOnError("request errorholder error")
}
} else {
if ((typeof (data as PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, data as PixelMap);
request.loadComplete(imageKnifeData)
} else if ((data as GIFFrame[]).length > 0) {
let imageKnifeData = ImageKnifeData.createImageGIFFrame(ImageKnifeType.GIFFRAME, data as GIFFrame[]);
request.loadComplete(imageKnifeData)
} else {
request.loadError("request resources error")
}
}
}).catch((err: BusinessError | string) => {
request.loadError(err)
})
}
private keyNotEmpty(request: RequestOption): boolean {
if (
request.generateCacheKey != null && request.generateCacheKey.length > 0 &&
@ -521,8 +668,7 @@ export class ImageKnife {
if ((typeof (request.loadSrc as image.PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, request.loadSrc as PixelMap)
request.loadComplete(imageKnifeData);
} else
if (typeof request.loadSrc == 'string') {
} else if (typeof request.loadSrc == 'string') {
// 进入三级缓存模型
return this.loadResources(request);
} else {
@ -539,5 +685,77 @@ export class ImageKnife {
}
}
/**
* 加载资源子线程包含流程:网络请求资源->下载资源到本地->解码成ixelMap | GIFFrame[]->缓存到内存和磁盘
* @param taskParams:任务参数JSON字符串类型
* @param headers请求头
* @param moduleContext模块上下文
* @returns
*/
@Concurrent
async function taskExecute(taskParams: string, headers: Map<string, Object>, moduleContext: common.UIAbilityContext): Promise<PixelMap | GIFFrame[]> {
// try {
let params: object = JSON.parse(taskParams);
let option = params["request"] as RequestOption;
let transformations = params["transformations"] as string [][];
let usageType = params["usageType"] as string;
//子线程构造RequestOption对象
let newRequestOption = new RequestOption();
newRequestOption.uuid = option.uuid;
newRequestOption.loadSrc = option.loadSrc;
newRequestOption.dontAnimateFlag = option.dontAnimateFlag;
newRequestOption.generateCacheKey = option.generateCacheKey;
newRequestOption.generateResourceKey = option.generateResourceKey;
newRequestOption.generateDataKey = option.generateDataKey;
newRequestOption.thumbSizeMultiplier = option.thumbSizeMultiplier;
newRequestOption.thumbDelayTime = option.thumbDelayTime;
newRequestOption.size = option.size;
newRequestOption.placeholderSrc = option.placeholderSrc;
newRequestOption.errorholderSrc = option.errorholderSrc;
newRequestOption.retryholderSrc = option.retryholderSrc;
newRequestOption.onlyRetrieveFromCache = option.onlyRetrieveFromCache;
newRequestOption.gpuEnabled = option.gpuEnabled;
newRequestOption.headers = headers;
newRequestOption.signature = option.signature;
ImageKnifeGlobal.getInstance().setHapContext(moduleContext);
newRequestOption.moduleContext = moduleContext;
if (option.isCacheable != null && option.isCacheable != undefined) {
newRequestOption.isCacheable = option.isCacheable;
}
//如果是本地图片不作磁盘缓存
if (typeof option.loadSrc !== 'string') {
let none = new NONE();
newRequestOption.diskCacheStrategy(none);
}
if (usageType == "placeholder") {
let manager = new PlaceHolderManager<PixelMap>(newRequestOption);
return await new Promise<PixelMap>(manager.process);
} else if (usageType == "retryholder") {
let manager = new RetryHolderManager<PixelMap>(newRequestOption);
return await new Promise<PixelMap>(manager.process);
} else if (usageType == "errorholder") {
let manager = new ErrorHolderManager<PixelMap>(newRequestOption);
return await new Promise<PixelMap>(manager.process);
} else {
if (transformations) {
for (let i = 0; i < transformations.length; i++) {
let className = transformations[i][0] as string;
let params = transformations[i][1] as string;
newRequestOption.addTransformations(className, params);
}
}
let newDataFetch = new DownloadClient();
let newResourceFetch = new ParseResClient();
let manager = new RequestManager(newRequestOption, newDataFetch, newResourceFetch);
return await new Promise<PixelMap | GIFFrame[]>(manager.process);
}
// } catch (e) {
// console.log(e)
// return await new Promise<PixelMap | GIFFrame[]>(() => {
// });
// }
}

View File

@ -241,20 +241,20 @@ export struct ImageKnifeComponent {
}
if (this.imageKnifeOption.placeholderSrc) {
request.placeholder(this.imageKnifeOption.placeholderSrc, {asyncSuccess:(data:ImageKnifeData) => {
LogUtil.log('ImageKnifeComponent request.placeholder callback')
LogUtil.log('ImageKnife ImageKnifeComponent request.placeholder callback')
this.runNextFunction(this.displayPlaceholder,data)
}
})
}
if (this.imageKnifeOption.thumbSizeMultiplier) {
request.thumbnail(this.imageKnifeOption.thumbSizeMultiplier, {asyncSuccess:(data:ImageKnifeData) => {
LogUtil.log('ImageKnifeComponent request.thumbnail callback')
LogUtil.log('ImageKnife ImageKnifeComponent request.thumbnail callback')
this.runNextFunction(this.displayThumbSizeMultiplier,data)
}}, this.imageKnifeOption.thumbSizeDelay)
}
if (this.imageKnifeOption.errorholderSrc) {
request.errorholder(this.imageKnifeOption.errorholderSrc, {asyncSuccess:(data:ImageKnifeData) => {
LogUtil.log('ImageKnifeComponent request.errorholder callback')
LogUtil.log('ImageKnife ImageKnifeComponent request.errorholder callback')
this.runNextFunction(this.displayErrorholder,data)
}})
}
@ -276,14 +276,14 @@ export struct ImageKnifeComponent {
if (this.imageKnifeOption.displayProgress) {
request.addProgressListener({asyncSuccess:(percentValue: number) => {
// 如果进度条百分比 未展示大小,展示其动画
LogUtil.log('ImageKnifeComponent request.addProgressListener callback')
LogUtil.log('ImageKnife ImageKnifeComponent request.addProgressListener callback')
this.runNextFunction(this.displayProgress,percentValue)
}})
}
if (this.imageKnifeOption.retryholderSrc) {
request.retryholder(this.imageKnifeOption.retryholderSrc,{asyncSuccess: (data:ImageKnifeData) => {
LogUtil.log('ImageKnifeComponent request.retryholder callback')
LogUtil.log('ImageKnife ImageKnifeComponent request.retryholder callback')
this.hasDisplayRetryholder = true
this.runNextFunction(this.displayRetryholder,data)
}})
@ -323,7 +323,7 @@ export struct ImageKnifeComponent {
this.configNecessary(request);
this.configCacheStrategy(request);
this.configDisplay(request);
this.configHspContext(request)
this.configHspContext(request);
this.configRenderGpu(request);
if(ImageKnifeGlobal.getInstance().getImageKnife()!=undefined) {
ImageKnifeGlobal.getInstance().getImageKnife()?.call(request);

View File

@ -16,11 +16,11 @@ import {ImageKnife} from './ImageKnife'
import { DiskStrategy } from "../cache/diskstrategy/DiskStrategy"
import { AsyncCallback } from "../imageknife/interface/AsyncCallback"
import { AsyncSuccess } from "../imageknife/interface/AsyncSuccess"
import { IAllCacheInfoCallback } from "../imageknife/interface/IAllCacheInfoCallback"
import { AllCacheInfo, IAllCacheInfoCallback } from "../imageknife/interface/IAllCacheInfoCallback"
import { AUTOMATIC } from "../cache/diskstrategy/enum/AUTOMATIC"
import { BaseTransform } from "../imageknife/transform/BaseTransform"
import { RotateImageTransformation } from "../imageknife/transform/RotateImageTransformation"
import { ImageKnifeData } from "../imageknife/ImageKnifeData"
import { ImageKnifeData, ImageKnifeType } from "../imageknife/ImageKnifeData"
import { CenterCrop } from '../imageknife/transform/pixelmap/CenterCrop'
import { CenterInside } from '../imageknife/transform/pixelmap/CenterInside'
import { FitCenter } from '../imageknife/transform/pixelmap/FitCenter'
@ -28,7 +28,10 @@ import { RoundedCornersTransformation, RoundCorner } from '../imageknife/transfo
import { CropCircleTransformation } from '../imageknife/transform/CropCircleTransformation'
import { CropCircleWithBorderTransformation, rgbColor } from '../imageknife/transform/CropCircleWithBorderTransformation'
import {
CropCircleWithBorderTransformation,
rgbColor
} from '../imageknife/transform/CropCircleWithBorderTransformation'
import { CropSquareTransformation } from '../imageknife/transform/CropSquareTransformation'
import { CropTransformation } from '../imageknife/transform/CropTransformation'
import { CropType } from '../imageknife/transform/CropTransformation'
@ -50,11 +53,18 @@ import { ImageKnifeGlobal } from './ImageKnifeGlobal'
import { BusinessError } from '@ohos.base'
import { ObjectKey } from './ObjectKey'
import common from '@ohos.app.ability.common'
import { GIFFrame } from './utils/gif/GIFFrame'
import { MemoryCacheProxy } from './requestmanage/MemoryCacheProxy'
import { DiskCacheProxy } from './requestmanage/DiskCacheProxy'
import { DiskLruCache } from '../cache/disklrucache'
import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5'
import { FileUtils } from '../cache/FileUtils'
export interface Size {
width: number,
height: number
}
export interface DetachFromLayout {
detach: () => void
}
@ -62,10 +72,12 @@ export interface DetachFromLayout{
export class RequestOption {
// 遍历添加图片http请求头
headers: Map<string, Object> = new Map<string, Object>();
// RequestOption调用header对于的方法
addHeader(key: string, value: Object) {
this.headers.set(key, value);
}
// 全局调用header对应的方法包含RequestOption的形式
addHeaderMap(map: Map<string, Object>) {
this.headers = map;
@ -79,28 +91,24 @@ export class RequestOption {
placeholderFunc: AsyncSuccess<ImageKnifeData> | undefined = undefined;
errorholderSrc: PixelMap | Resource | undefined = undefined;
errorholderFunc: AsyncSuccess<ImageKnifeData> | undefined = undefined;
errorholderData: ImageKnifeData | undefined = undefined;;
errorholderData: ImageKnifeData | undefined = undefined;
;
thumbSizeMultiplier: number = 0;
// 如果存在缩略图则主图延时1s加载
thumbDelayTime: number = 1000
thumbHolderFunc: AsyncSuccess<ImageKnifeData> | undefined = undefined;
requestListeners: Array<AsyncCallback<ImageKnifeData>> | undefined = undefined;
// 进度条
progressFunc: AsyncSuccess<number> | undefined = undefined;
// 重试图层
retryholderSrc: PixelMap | Resource | undefined = undefined;
retryholderFunc: AsyncSuccess<ImageKnifeData> | undefined = undefined;
retryholderData: ImageKnifeData | undefined = undefined;
size: Size = { width: -1, height: -1 };
// 网络下载数据回调
allCacheInfoCallback: IAllCacheInfoCallback | undefined = undefined;
onlyRetrieveFromCache: boolean = false;
isCacheable: boolean = true;
// 开启GPU变换绘制
gpuEnabled: boolean = false;
// 变换相关
@ -110,30 +118,24 @@ export class RequestOption {
generateDataKey: string = "";
filesPath: string = ""; // data/data/包名/files目录
cachesPath: string = ""; // 网络下载默认存储在data/data/包名/cache/ImageKnifeNetworkFolder/目标md5.img下面
placeholderCacheKey: string = "";
retryholderCacheKey: string = "";
errorholderCacheKey: string = "";
// 自定义缓存关键字
signature?: ObjectKey;
// 下载原始文件地址
downloadFilePath: string = "";
// 网络文件下载统一存放
networkCacheFolder: string = "ImageKnifeNetworkFolder"
// 主线图片 状态变化 是否加载完成
// 主图未加载成功 显示占位图 主图加载成功不展示占位图
loadMainReady = false;
// 失败占位图展示状态 当true 表示主图加载失败需要展示失败占位图
loadErrorReady = false;
// 重试占位图展示状态 当true 表示主图加载失败需要展示失败占位图
loadRetryReady = false;
// 缩略图展示
loadThumbnailReady = false;
detachFromLayout: DetachFromLayout = {
detach: () => {
let imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife();
@ -144,6 +146,7 @@ export class RequestOption {
}
// module资源的需要当前的module context
moduleContext?: common.UIAbilityContext = undefined;
constructor() {
// 初始化全局监听
this.requestListeners = new Array();
@ -166,6 +169,7 @@ export class RequestOption {
});
return uuid;
}
setModuleContext(moduleCtx: common.UIAbilityContext) {
this.moduleContext = moduleCtx;
}
@ -173,6 +177,7 @@ export class RequestOption {
getModuleContext(): common.UIAbilityContext | undefined {
return this.moduleContext;
}
/**
* set image Component size
*/
@ -454,6 +459,7 @@ export class RequestOption {
this.transformations = inputs;
return this;
}
// 开启GPU变换绘制
enableGPU() {
this.gpuEnabled = true;
@ -464,6 +470,7 @@ export class RequestOption {
placeholderOnComplete = (imageKnifeData:ImageKnifeData) => {
LogUtil.log("placeholderOnComplete has called!");
LogUtil.log("Main Image is Ready:" + this.loadMainReady);
this.setMemoryCache(imageKnifeData,this.placeholderCacheKey);
if (!this.loadMainReady && !(this.loadErrorReady || this.loadRetryReady) && !this.loadThumbnailReady) {
// 主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图
if (this.placeholderSrc != undefined) {
@ -471,15 +478,18 @@ export class RequestOption {
}
}
}
// 占位图解析失败
placeholderOnError = (error: BusinessError | string) => {
LogUtil.log("占位图解析失败 error =" + error)
}
// 缩略图解析成功
thumbholderOnComplete = (imageKnifeData: ImageKnifeData)=> {
thumbholderOnComplete = (value: PixelMap | GIFFrame[]) => {
let imageKnifeData = new ImageKnifeData();
if ((typeof (value as PixelMap).isEditable) == 'boolean') {
imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value as PixelMap);
} else {
imageKnifeData = ImageKnifeData.createImageGIFFrame(ImageKnifeType.GIFFRAME, value as GIFFrame[]);
}
if (!this.loadMainReady && !(this.loadErrorReady || this.loadRetryReady)) {
// 主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图
if (this.thumbHolderFunc != undefined) {
@ -487,14 +497,13 @@ export class RequestOption {
}
}
}
// 缩略图解析失败
thumbholderOnError = (error?: BusinessError | string) => {
LogUtil.log("缩略图解析失败 error =" + error)
}
// 加载失败 占位图解析成功
errorholderOnComplete = (imageKnifeData:ImageKnifeData) => {
this.setMemoryCache(imageKnifeData,this.errorholderCacheKey);
// 如果有错误占位图 先解析并保存在RequestOption中 等到加载失败时候进行调用
this.errorholderData = imageKnifeData;
if (this.loadErrorReady) {
@ -503,13 +512,12 @@ export class RequestOption {
}
}
}
// 加载失败 占位图解析失败
errorholderOnError = (error: BusinessError | string) => {
LogUtil.log("失败占位图解析失败 error =" + error)
}
retryholderOnComplete = (imageKnifeData:ImageKnifeData) => {
this.setMemoryCache(imageKnifeData,this.retryholderCacheKey);
this.retryholderData = imageKnifeData;
if (this.loadRetryReady) {
if (this.retryholderFunc != undefined) {
@ -517,13 +525,17 @@ export class RequestOption {
}
}
}
retryholderOnError = (error: BusinessError | string) => {
LogUtil.log("重试占位图解析失败 error =" + error)
}
loadComplete = async (imageKnifeData: ImageKnifeData) => {
this.setMemoryCache(imageKnifeData,this.generateCacheKey);
if (typeof this.loadSrc == 'string') {
this.setDiskCache();
}
loadComplete = (imageKnifeData: ImageKnifeData)=>{
this.loadMainReady = true;
// 三级缓存数据加载成功
if (this.requestListeners != undefined) {
for (let i = 0; i < this.requestListeners.length; i++) {
@ -535,6 +547,42 @@ export class RequestOption {
}
}
//显示进度条
if (this.progressFunc) {
this.progressFunc.asyncSuccess(0);
setTimeout(() => {
}, 1000);
this.progressFunc.asyncSuccess(100);
}
//输出缓存相关内容和信息
if (this.allCacheInfoCallback) {
// 内存缓存
let allCacheInfo: AllCacheInfo = {
memoryCacheInfo: { key: '', data: new ImageKnifeData() },
resourceCacheInfo: { key: '', path: '' },
dataCacheInfo: { key: '', path: '' }
};
allCacheInfo.memoryCacheInfo = {
key: this.generateCacheKey,
data: imageKnifeData
}
let mDiskCacheProxy = new DiskCacheProxy(DiskLruCache.create(ImageKnifeGlobal.getInstance()
.getHapContext() as common.UIAbilityContext))
// 变换后缓存
allCacheInfo.resourceCacheInfo = {
key: SparkMD5.hashBinary(this.generateResourceKey) as string,
path: (mDiskCacheProxy.getCachePath() + SparkMD5.hashBinary(this.generateResourceKey)) as string
};
// 原图缓存
allCacheInfo.dataCacheInfo = {
key: SparkMD5.hashBinary(this.generateDataKey) as string,
path: (mDiskCacheProxy.getCachePath() + SparkMD5.hashBinary(this.generateDataKey)) as string
}
this.allCacheInfoCallback.callback(allCacheInfo);
}
if (imageKnifeData.waitSaveDisk) {
// 等落盘结束后主动调用#removeCurrentAndSearchNext方法
} else {
@ -544,21 +592,41 @@ export class RequestOption {
imageKnife.removeRunning(this);
}
}
}
//设置内存缓存
setMemoryCache = (imageKnifeData: ImageKnifeData,cacheKey:string) => {
let memoryCacheProxy = ImageKnifeGlobal.getInstance()
.getImageKnife()?.getMemoryCacheProxy() as MemoryCacheProxy<string, ImageKnifeData>;
memoryCacheProxy.putValue(cacheKey, imageKnifeData);
}
//设置磁盘缓存
setDiskCache = () => {
try {
let diskMemoryCache = ImageKnifeGlobal.getInstance().getImageKnife()?.getDiskMemoryCache();
let dataArraybuffer: ArrayBuffer = DiskLruCache.getFileCacheByFile((ImageKnifeGlobal.getInstance()
.getHapContext() as common.UIAbilityContext).filesDir as string, this.generateDataKey) as ArrayBuffer;
//缓存原图片
if (dataArraybuffer && !diskMemoryCache?.get(this.generateDataKey)) {
diskMemoryCache?.setCacheMapAndSize(this.generateDataKey, dataArraybuffer);
}
//缓存变换后图片
let resourceArraybuffer: ArrayBuffer = DiskLruCache.getFileCacheByFile((ImageKnifeGlobal.getInstance()
.getHapContext() as common.UIAbilityContext).filesDir as string, this.generateResourceKey) as ArrayBuffer;
if (resourceArraybuffer && !diskMemoryCache?.get(this.generateResourceKey)) {
diskMemoryCache?.setCacheMapAndSize(this.generateResourceKey, resourceArraybuffer);
}
} catch (e) {
LogUtil.error("imageknife DiskMemoryCache setDiskCache error :" + e.message);
}
}
// 图片文件落盘之后会自动去寻找下一个数据加载
removeCurrentAndSearchNext = () => {
if (ImageKnifeGlobal.getInstance().getImageKnife() != undefined) {
(ImageKnifeGlobal.getInstance().getImageKnife())?.removeRunning(this);
}
}
loadError = (err: BusinessError | string) => {
LogUtil.log("loadError:" + err);
// 失败占位图展示规则
@ -582,6 +650,95 @@ export class RequestOption {
(ImageKnifeGlobal.getInstance().getImageKnife())?.removeRunning(this);
}
}
addTransformations = (transformationName: string, params: string) => {
switch (transformationName) {
case "BlurTransformation":
let paramList: number [] = JSON.parse(params);
this.transformations.push(new BlurTransformation(paramList[0], paramList[1]));
break;
case "BrightnessFilterTransformation":
let paramList1: number [] = JSON.parse(params);
this.transformations.push(new BrightnessFilterTransformation(paramList1[0]));
break;
case "RotateImageTransformation":
let paramList2: number [] = JSON.parse(params);
this.transformations.push(new RotateImageTransformation(paramList2[0]));
break;
case "GrayscaleTransformation":
this.transformations.push(new GrayscaleTransformation());
break;
case "BlurTransformation":
let paramList3: number [] = JSON.parse(params);
this.transformations.push(new BlurTransformation(paramList3[0]));
break;
case "ContrastFilterTransformation":
let paramList4: number [] = JSON.parse(params);
this.transformations.push(new ContrastFilterTransformation(paramList4[0]));
break;
case "CropCircleTransformation":
this.transformations.push(new CropCircleTransformation());
break;
case "CropCircleWithBorderTransformation":
let paramList5: (number | rgbColor) [] = JSON.parse(params);
this.transformations.push(new CropCircleWithBorderTransformation(paramList5[0] as number, paramList5[1] as rgbColor));
break;
case "CropSquareTransformation":
this.transformations.push(new CropSquareTransformation());
break;
case "InvertFilterTransformation":
this.transformations.push(new InvertFilterTransformation());
break;
case "KuwaharaFilterTransform":
let paramList7: number [] = JSON.parse(params);
this.transformations.push(new KuwaharaFilterTransform(paramList7[0] as number));
break;
case "MaskTransformation":
let paramList8: Resource [] = JSON.parse(params);
this.transformations.push(new MaskTransformation(paramList8[0] as Resource));
break;
case "PixelationFilterTransformation":
let paramList9: number [] = JSON.parse(params);
this.transformations.push(new PixelationFilterTransformation(paramList9[0] as number));
break;
case "RoundedCornersTransformation":
let paramList10: RoundCorner [] = JSON.parse(params);
this.transformations.push(new RoundedCornersTransformation(paramList10[0] as RoundCorner));
break;
case "SepiaFilterTransformation":
this.transformations.push(new SepiaFilterTransformation());
break;
case "SketchFilterTransformation":
this.transformations.push(new SketchFilterTransformation());
break;
case "SwirlFilterTransformation":
let paramList11: (number | Array<number>) [] = JSON.parse(params);
this.transformations.push(new SwirlFilterTransformation(paramList11[0] as number, paramList11[1] as number, paramList11[2] as Array<number>));
break;
case "ToonFilterTransform":
let paramList14: number [] = JSON.parse(params);
this.transformations.push(new ToonFilterTransform(paramList14[0], paramList14[1]));
break;
case "VignetteFilterTransform":
let paramList12: Array<number> [] = JSON.parse(params);
this.transformations.push(new VignetteFilterTransform(paramList12[0], paramList12[1], paramList12[2]));
break;
case "CenterCrop":
this.transformations.push(new CenterCrop());
break;
case "CenterInside":
this.transformations.push(new CenterInside());
break;
case "FitCenter":
this.transformations.push(new FitCenter());
break;
case "CropTransformation":
let paramList13: (number | CropType) [] = JSON.parse(params);
this.transformations.push(new CropTransformation(paramList13[0] as number, paramList13[1] as number, paramList13[2] as CropType));
break;
default:
break
}
}
}

View File

@ -31,21 +31,15 @@ export class ErrorHolderManager<T> {
this.options = option;
}
static execute(option: RequestOption) {
let manager:ErrorHolderManager<ImageKnifeData> = new ErrorHolderManager<ImageKnifeData>(option);
return new Promise(manager.process)
.then(option.errorholderOnComplete).catch(option.errorholderOnError);
}
process = (onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void)=>{
process = (onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void)=>{
this.displayErrorholder(onComplete, onError);
}
private displayErrorholder(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
private displayErrorholder(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
LogUtil.log("displayErrorholder")
if ((typeof (this.options.errorholderSrc as image.PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, this.options.errorholderSrc as PixelMap)
onComplete(imageKnifeData);
onComplete(imageKnifeData?.drawPixelMap?.imagePixelMap as PixelMap);
} else if (typeof this.options.errorholderSrc == 'string') {
} else {
@ -89,16 +83,16 @@ export class ErrorHolderManager<T> {
}
}
private svgProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
private svgProcess(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let svgParseImpl:SVGParseImpl = new SVGParseImpl()
svgParseImpl.parseSvg(this.options,arraybuffer, onComplete,onError);
}
private mediaImageProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
private mediaImageProcess(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let parseImageUtil = new ParseImageUtil()
let success = (value: PixelMap) => {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value)
onComplete(imageKnifeData)
onComplete(imageKnifeData?.drawPixelMap?.imagePixelMap as PixelMap)
}
parseImageUtil.parseImage(arraybuffer, success, onError)
}

View File

@ -25,6 +25,8 @@ import {LogUtil} from '../../imageknife/utils/LogUtil'
import resourceManager from '@ohos.resourceManager';
import image from "@ohos.multimedia.image"
import { BusinessError } from '@ohos.base'
import { GIFFrame } from '../utils/gif/GIFFrame'
export class PlaceHolderManager<T> {
private options: RequestOption;
@ -32,21 +34,16 @@ export class PlaceHolderManager<T> {
this.options = option;
}
static execute(option: RequestOption) {
let manager:PlaceHolderManager<ImageKnifeData> = new PlaceHolderManager<ImageKnifeData>(option);
return new Promise(manager.process)
.then(option.placeholderOnComplete).catch(option.placeholderOnError);
}
process = (onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void)=>{
process = (onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void)=>{
this.displayPlaceholder(onComplete, onError);
}
private displayPlaceholder(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void){
LogUtil.log("displayPlaceholder")
private displayPlaceholder(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void){
LogUtil.log("ImageKnife displayPlaceholder")
if ((typeof (this.options.placeholderSrc as image.PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, this.options.placeholderSrc as PixelMap)
onComplete(imageKnifeData);
onComplete(imageKnifeData?.drawPixelMap?.imagePixelMap as PixelMap);
} else if (typeof this.options.placeholderSrc == 'string') {
} else {
@ -87,16 +84,16 @@ export class PlaceHolderManager<T> {
private svgProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
private svgProcess(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let svgParseImpl:SVGParseImpl = new SVGParseImpl()
svgParseImpl.parseSvg(this.options,arraybuffer, onComplete,onError);
}
private mediaImageProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
private mediaImageProcess(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let parseImageUtil:ParseImageUtil = new ParseImageUtil()
let success = (value: PixelMap) => {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value)
onComplete(imageKnifeData)
onComplete(imageKnifeData?.drawPixelMap?.imagePixelMap as PixelMap)
}
parseImageUtil.parseImage(arraybuffer, success, onError)
}

View File

@ -32,21 +32,15 @@ export class RetryHolderManager<T> {
this.options = option;
}
static execute(option: RequestOption) {
let manager:RetryHolderManager<ImageKnifeData> = new RetryHolderManager<ImageKnifeData>(option);
return new Promise(manager.process)
.then(option.retryholderOnComplete).catch(option.retryholderOnError);
}
process = (onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void)=>{
process = (onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void)=>{
this.displayRetryholder(onComplete, onError);
}
private displayRetryholder(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void){
LogUtil.log("displayRetryholder")
private displayRetryholder(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void){
LogUtil.log("ImageKnife displayRetryholder")
if ((typeof (this.options.retryholderSrc as image.PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, this.options.placeholderSrc as PixelMap)
onComplete(imageKnifeData);
onComplete(imageKnifeData?.drawPixelMap?.imagePixelMap as PixelMap);
} else if (typeof this.options.placeholderSrc == 'string') {
} else {
@ -87,16 +81,16 @@ export class RetryHolderManager<T> {
private svgProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
private svgProcess(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let svgParseImpl = new SVGParseImpl()
svgParseImpl.parseSvg(this.options,arraybuffer, onComplete,onError);
}
private mediaImageProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
private mediaImageProcess(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let parseImageUtil = new ParseImageUtil()
let success = (value: PixelMap) => {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value)
onComplete(imageKnifeData)
onComplete(imageKnifeData?.drawPixelMap?.imagePixelMap as PixelMap)
}
parseImageUtil.parseImage(arraybuffer, success, onError)
}

View File

@ -30,7 +30,7 @@ class RequestData{
}
export class HttpDownloadClient implements IDataFetch {
loadData(request: RequestOption, onComplete: (img: ArrayBuffer) => void, onError: (err: string) => void) {
async loadData(request: RequestOption, onComplete: (img: ArrayBuffer) => void, onError: (err: string) => void) {
try {
let httpRequest = http.createHttp()
let arrayBuffers = new Array<ArrayBuffer>();
@ -64,9 +64,7 @@ export class HttpDownloadClient implements IDataFetch {
request.headers.forEach((value, key) => {
headerObj[key] = value
})
httpRequest.requestInStream(
request.loadSrc as string,
{
let promise = httpRequest.requestInStream(request.loadSrc as string, {
header: headerObj,
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.ARRAY_BUFFER,
@ -74,8 +72,8 @@ export class HttpDownloadClient implements IDataFetch {
readTimeout: 0, // 可选, 默认为60000ms
usingProtocol: http.HttpProtocol.HTTP1_1, // 可选,协议类型默认值由系统自动指定
usingCache: false
}
).then((data)=>{
});
await promise.then((data)=>{
if(data == 200) {
} else {

View File

@ -14,7 +14,7 @@
*/
import { ICache } from "../requestmanage/ICache"
import { DiskLruCache } from "@ohos/disklrucache"
import { DiskLruCache } from "../../cache/disklrucache"
export class DiskCacheProxy implements ICache<string, ArrayBuffer> {
private mDiskLruCache: DiskLruCache;
@ -38,7 +38,7 @@ export class DiskCacheProxy implements ICache<string, ArrayBuffer> {
}
getValue(key: string): ArrayBuffer{
return this.mDiskLruCache.get(key);
return this.mDiskLruCache.get(key) as ArrayBuffer;
}
putValue(key: string, value: ArrayBuffer) {

View File

@ -14,7 +14,7 @@
*/
import { RequestOption, Size } from '../../imageknife/RequestOption'
import { DiskLruCache } from '@ohos/disklrucache'
import { DiskLruCache } from "../../cache/DiskLruCache"
import { LruCache } from '../../cache/LruCache'
import { SparkMD5 } from '../../3rd_party/sparkmd5/spark-md5'
import { MemoryCacheProxy } from '../requestmanage/MemoryCacheProxy'
@ -32,6 +32,7 @@ import { GIFParseImpl } from '../utils/gif/GIFParseImpl'
import { GIFFrame } from '../utils/gif/GIFFrame'
import { LogUtil } from '../../imageknife/utils/LogUtil'
import { BusinessError } from '@ohos.base'
import taskpool from '@ohos.taskpool';
export enum Stage {
@ -62,19 +63,13 @@ export enum RunReason {
export class RequestManager {
private TAG: string = "RequestManager";
private options: RequestOption;
private mMemoryCacheProxy: MemoryCacheProxy<string, ImageKnifeData>;
private mDiskCacheProxy: DiskCacheProxy;
private mIDataFetch: IDataFetch;
private mIResourceFetch: IResourceFetch<ArrayBuffer>;
private mParseImageUtil: IParseImage<PixelMap>;
constructor(option: RequestOption, memoryCache1: LruCache<string, ImageKnifeData>, diskMemoryCache1: DiskLruCache, dataFetch: IDataFetch, resourceFetch: IResourceFetch<ArrayBuffer>) {
constructor(option: RequestOption, dataFetch: IDataFetch, resourceFetch: IResourceFetch<ArrayBuffer>) {
this.options = option;
// 缓存部分
this.mMemoryCacheProxy = new MemoryCacheProxy(memoryCache1);
this.mDiskCacheProxy = new DiskCacheProxy(diskMemoryCache1);
// 网络下载能力
this.mIDataFetch = dataFetch;
@ -85,63 +80,16 @@ export class RequestManager {
this.mParseImageUtil = new ParseImageUtil();
}
static execute(option: RequestOption, memoryCache1: LruCache<string, ImageKnifeData>, diskMemoryCache1: DiskLruCache, dataFetch: IDataFetch, resourceFetch: IResourceFetch<ArrayBuffer>) {
LogUtil.log("RequestManager execute")
let manager = new RequestManager(option, memoryCache1, diskMemoryCache1, dataFetch, resourceFetch);
return new Promise<ImageKnifeData>(manager.process)
.then(option.loadComplete)
.then(manager.loadCompleteAfter)
.catch(option.loadError);
}
loadCompleteAfter =()=>{
try { // 内部消化问题
LogUtil.log("loadCompleteAfter!")
if (this.options.allCacheInfoCallback) {
LogUtil.log("RequestOption =" + JSON.stringify(this.options));
// 内存缓存
let allCacheInfo:AllCacheInfo = {
memoryCacheInfo:{key:'', data:new ImageKnifeData()},
resourceCacheInfo:{key:'', path:''},
dataCacheInfo:{key:'',path:''}
};
let memoryCache = this.mMemoryCacheProxy.getValue(this.options.generateCacheKey);
allCacheInfo.memoryCacheInfo = {
key: this.options.generateCacheKey,
data: memoryCache
}
// 变换后缓存
allCacheInfo.resourceCacheInfo = {
key: SparkMD5.hashBinary(this.options.generateResourceKey) as string,
path: (this.mDiskCacheProxy.getCachePath() + SparkMD5.hashBinary(this.options.generateResourceKey)) as string
};
// 原图缓存
allCacheInfo.dataCacheInfo = {
key: SparkMD5.hashBinary(this.options.generateDataKey) as string,
path: (this.mDiskCacheProxy.getCachePath() + SparkMD5.hashBinary(this.options.generateDataKey)) as string
}
this.options.allCacheInfoCallback.callback(allCacheInfo)
}
} catch (err) {
LogUtil.log("after err =" + err)
}
}
// DecodeJob work
private mStage: Stage = Stage.INITIALIZE;
private mRunReason: RunReason = RunReason.INITIALIZE;
process = (onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void)=>{
LogUtil.log("RequestManager process !");
process = (onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) => {
LogUtil.log("ImageKnife RequestManager process !");
this.loadLeve1MemoryCache(onComplete, onError)
}
private runWrapped(request: RequestOption, runReason: RunReason, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
LogUtil.log("RequestManager runWrapped")
private runWrapped(request: RequestOption, runReason: RunReason, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("ImageKnife RequestManager runWrapped")
if (runReason == RunReason.INITIALIZE) {
this.mStage = this.getNextStage(request, this.mStage);
this.searchLoadFrom(this.options, this.mStage, onComplete, onError);
@ -166,13 +114,13 @@ export class RequestManager {
} else if (current == Stage.FINISHED) {
return Stage.FINISHED;
} else {
throw new Error("Unrecognized stage: " + current);
throw new Error("ImageKnife Unrecognized stage: " + current);
}
}
// 究竟从哪里加载数据
private searchLoadFrom(request: RequestOption, current: Stage, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
LogUtil.log("RequestManager searchLoadFrom")
private searchLoadFrom(request: RequestOption, current: Stage, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("ImageKnife RequestManager searchLoadFrom")
if (current == Stage.RESOURCE_CACHE) {
this.loadDiskFromTransform(request, onComplete, onError);
} else if (current == Stage.DATA_CACHE) {
@ -187,7 +135,9 @@ export class RequestManager {
}
// 加载网络资源
private loadSourceFromNetwork(request: RequestOption, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
private loadSourceFromNetwork(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
try {
LogUtil.log("ImageKnife RequestManager loadSourceFromNetwork")
let success = (arraybuffer: ArrayBuffer) => {
this.downloadSuccess(request, arraybuffer, onComplete, onError)
}
@ -195,47 +145,43 @@ export class RequestManager {
onError(errorMsg)
}
this.mIDataFetch.loadData(request, success, error);
} catch (e) {
LogUtil.error("ImageKnife RequestManager loadSourceFromNetwork error")
}
}
// 加载本地资源
private loadSourceFormNative(request: RequestOption, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
LogUtil.log("RequestManager loadSourceFormNative")
private loadSourceFormNative(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("ImageKnife RequestManager loadSourceFormNative")
// 本地解析后进行一级缓存
let success = (arrayBuffer: ArrayBuffer) => {
// 使用媒体子系统 ImageSource解析文件 获取PixelMap
let fileTypeUtil = new FileTypeUtil();
let typeValue = fileTypeUtil.getFileType(arrayBuffer)
LogUtil.log("RequestManager - 文件类型为= " + typeValue)
LogUtil.log("ImageKnife RequestManager - 文件类型为= " + typeValue)
// gif处理
if (ImageKnifeData.GIF == typeValue && !request.dontAnimateFlag) {
// 处理gif
this.gifProcess(onComplete,onError, arrayBuffer,typeValue,(imageKnifeData)=>{
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
})
this.gifProcess(onComplete, onError, arrayBuffer, typeValue)
} else if (ImageKnifeData.SVG == typeValue) {
// 处理svg
this.svgProcess(request,onComplete,onError,arrayBuffer,typeValue,(imageKnifeData)=>{
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey,imageKnifeData)
})
this.svgProcess(request, onComplete, onError, arrayBuffer, typeValue)
} else {
if (request.transformations[0]) {
request.transformations[0].transform(arrayBuffer, request, {asyncTransform:(error:BusinessError|string, pixelMap: PixelMap|null) => {
request.transformations[0].transform(arrayBuffer, request, {
asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => {
// 输出给Image
if (pixelMap) {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap);
this.mMemoryCacheProxy.putValue(request.generateCacheKey, imageKnifeData);
onComplete(imageKnifeData);
onComplete(pixelMap);
} else {
onError(error);
}
}})
}
})
}
else {
let success = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
this.mMemoryCacheProxy.putValue(request.generateCacheKey, imageKnifeData);
onComplete(imageKnifeData);
onComplete(value);
}
this.mParseImageUtil.parseImage(arrayBuffer, success, onError)
}
@ -245,15 +191,17 @@ export class RequestManager {
if (ctx != undefined) {
this.mIResourceFetch.loadResource(ctx, request.loadSrc as Resource, success, onError);
} else {
onError('RequestManager loadSourceFormNative moduleContext is undefined! please check it')
onError('ImageKnife RequestManager loadSourceFormNative moduleContext is undefined! please check it')
}
}
// 加载磁盘缓存 原图
private loadDiskFromSource(request: RequestOption, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
LogUtil.log("RequestManager loadDiskFromSource")
let cached = this.mDiskCacheProxy.getValue(request.generateDataKey)
private loadDiskFromSource(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("ImageKnife RequestManager loadDiskFromSource")
let cached = DiskLruCache.getFileCacheByFile(request?.moduleContext?.filesDir as string, request.generateDataKey);
if (cached != null && cached.byteLength > 0) {
LogUtil.log("ImageKnife loadDiskFromSource load resource from DiskLruCache")
this.parseDiskFile2PixelMap(request, cached, onComplete, onError)
} else {
this.mStage = Stage.SOURCE;
@ -262,10 +210,11 @@ export class RequestManager {
}
// 加载磁盘缓存 变换后图片
private loadDiskFromTransform(request: RequestOption, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
LogUtil.log("RequestManager loadDiskFromTransform")
let cached = this.mDiskCacheProxy.getValue(request.generateResourceKey)
private loadDiskFromTransform(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("ImageKnife RequestManager loadDiskFromTransform")
let cached = DiskLruCache.getFileCacheByFile(request.moduleContext?.filesDir as string, request.generateResourceKey);
if (cached != null) {
LogUtil.log("ImageKnife loadDiskFromTransform load resource from DiskLruCache")
this.parseDiskTransformFile2PixelMap(request, cached, onComplete, onError)
} else {
this.mStage = Stage.DATA_CACHE;
@ -273,54 +222,47 @@ export class RequestManager {
}
}
parseSource(request: RequestOption, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
LogUtil.log("RequestManager parseSource")
parseSource(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("ImageKnife RequestManager parseSource")
try {
if ((typeof (request.loadSrc as image.PixelMap).isEditable) == 'boolean') {
// PixelMap 外层捕获效率更高,不会进入这里
} else if (typeof request.loadSrc == 'string') {
this.loadSourceFromNetwork(request, onComplete, onError);
} else {
let res = request.loadSrc as Resource;
if (typeof res.id != 'undefined' && typeof res.id != 'undefined') {
if (typeof res.id != 'undefined') {
this.loadSourceFormNative(request, onComplete, onError)
} else {
LogUtil.log("输入参数有问题!")
}
}
} catch (e) {
LogUtil.error("ImageKnife RequestManager parseSource error")
}
}
private loadLeve1MemoryCache(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
LogUtil.log("RequestManager loadLeve1MemoryCache")
// 一级缓存 内存获取
let cache = this.mMemoryCacheProxy.loadMemoryCache(this.options.generateCacheKey, this.options.isCacheable);
if (cache == null || typeof cache == 'undefined') {
// 处理磁盘加载 网络加载
private loadLeve1MemoryCache(onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
try {
this.runWrapped(this.options, this.mRunReason, onComplete, onError)
} else {
// 需要清理状态
cache.waitSaveDisk = false;
onComplete(cache);
return
} catch (e) {
LogUtil.error("ImageKnife loadLeve1MemoryCache error")
}
}
// 解析磁盘文件变成PixeMap
private parseDiskFile2PixelMap(request: RequestOption, source: ArrayBuffer, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
private parseDiskFile2PixelMap(request: RequestOption, source: ArrayBuffer, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("ImageKnife RequestManager parseDiskFile2PixelMap")
// 步骤一文件转为pixelMap 然后变换 给Image组件
let fileTypeUtil = new FileTypeUtil();
let typeValue = fileTypeUtil.getFileType(source);
// 解析磁盘文件 gif 和 svg
if (ImageKnifeData.GIF == typeValue && !request.dontAnimateFlag) {
// 处理gif
this.gifProcess(onComplete,onError,source,typeValue, (imageKnifeData)=>{
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
})
this.gifProcess(onComplete, onError, source, typeValue)
} else if (ImageKnifeData.SVG == typeValue) {
this.svgProcess(request,onComplete,onError, source, typeValue, (imageKnifeData)=>{
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
})
this.svgProcess(request, onComplete, onError, source, typeValue)
} else {
if (this.options.transformations[0]) {
if (this.options.thumbSizeMultiplier) {
@ -338,38 +280,37 @@ export class RequestManager {
}
let thumbCallback = this.options.thumbholderOnComplete;
let thumbError = this.options.thumbholderOnError;
this.options.transformations[0].transform(source, thumbOption,{asyncTransform: (error:BusinessError|string, pixelMap: PixelMap|null) => {
this.options.transformations[0].transform(source, thumbOption, {
asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => {
if (pixelMap) {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap);
thumbCallback(imageKnifeData);
thumbCallback(pixelMap);
} else {
thumbError(error);
}
}})
}
})
setTimeout(() => {
this.options.transformations[0].transform(source, request, {asyncTransform: (error:BusinessError|string, pixelMap: PixelMap|null) => {
this.options.transformations[0].transform(source, request, {
asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => {
if (pixelMap) {
// 保存一份变换后的图片PixelMap到MemoryCache
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
onComplete(imageKnifeData);
onComplete(pixelMap);
} else {
onError(error);
}
}})
}
})
}, this.options.thumbDelayTime);
}
else {
this.options.transformations[0].transform(source, request, {asyncTransform: (error:BusinessError|string, pixelMap: PixelMap|null) => {
this.options.transformations[0].transform(source, request, {
asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => {
if (pixelMap) {
// 保存一份变换后的图片PixelMap到MemoryCache
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
onComplete(imageKnifeData);
onComplete(pixelMap);
} else {
onError(error);
}
}})
}
})
}
} else {
// thumbnail 缩略图部分
@ -377,24 +318,18 @@ export class RequestManager {
let thumbCallback = this.options.thumbholderOnComplete
let thumbError = this.options.thumbholderOnError
let thumbSuccess = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
thumbCallback(imageKnifeData);
thumbCallback(value);
}
this.mParseImageUtil.parseImageThumbnail(request.thumbSizeMultiplier, source, thumbSuccess, thumbError);
setTimeout(() => {
let success = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
onComplete(imageKnifeData);
onComplete(value);
}
this.mParseImageUtil.parseImage(source, success, onError)
}, this.options.thumbDelayTime)
}
else {
} else {
let success = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
onComplete(imageKnifeData);
onComplete(value);
}
this.mParseImageUtil.parseImage(source, success, onError)
}
@ -403,7 +338,8 @@ export class RequestManager {
}
// 解析磁盘变换后文件变成PixeMap
private parseDiskTransformFile2PixelMap(request: RequestOption, source: ArrayBuffer, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
private parseDiskTransformFile2PixelMap(request: RequestOption, source: ArrayBuffer, onComplete: (value: PixelMap) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("ImageKnife RequestManager parseDiskTransformFile2PixelMap")
let fileTypeUtil = new FileTypeUtil();
let typeValue = fileTypeUtil.getFileType(source);
// thumbnail 缩略图部分
@ -411,33 +347,27 @@ export class RequestManager {
let thumbCallback = this.options.thumbholderOnComplete
let thumbError = this.options.thumbholderOnError
let thumbSuccess = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
thumbCallback(imageKnifeData);
thumbCallback(value);
}
this.mParseImageUtil.parseImageThumbnail(request.thumbSizeMultiplier, source, thumbSuccess, thumbError);
setTimeout(() => {
let success = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
onComplete(imageKnifeData);
onComplete(value);
}
this.mParseImageUtil.parseImage(source, success, onError)
}, this.options.thumbDelayTime)
} else {
let success = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value)
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
onComplete(imageKnifeData);
onComplete(value);
}
this.mParseImageUtil.parseImage(source, success, onError)
}
}
private downloadSuccess(request: RequestOption,source: ArrayBuffer, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
LogUtil.log('Download task completed.');
private downloadSuccess(request: RequestOption, source: ArrayBuffer, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
if (source == null || source == undefined || source.byteLength <= 0) {
onError('Download task completed. but download file is empty!')
onError('ImageKnife Download task completed. but download file is empty!')
return
}
@ -460,28 +390,24 @@ export class RequestManager {
// 解析磁盘文件 gif 和 svg
if (ImageKnifeData.GIF == filetype && !this.options.dontAnimateFlag) {
// 处理gif
this.gifProcess(onComplete,onError,source,filetype, (imageKnifeData)=>{
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
})
this.gifProcess(onComplete, onError, source, filetype)
// 保存二级磁盘缓存
Promise.resolve(source)
.then((arraybuffer: ArrayBuffer) => {
this.mDiskCacheProxy.putValue(this.options.generateDataKey, arraybuffer)
DiskLruCache.saveFileCacheOnlyFile(this.options.moduleContext?.filesDir as string, this.options.generateDataKey,arraybuffer);
})
.catch((err: BusinessError) => {
LogUtil.log('download file is =' + ImageKnifeData.GIF + 'and save diskLruCache error =' + (err as BusinessError))
})
} else if (ImageKnifeData.SVG == filetype) {
// 处理svg
this.svgProcess(request,onComplete,onError, source, filetype, (imageKnifeData)=>{
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
})
this.svgProcess(request, onComplete, onError, source, filetype)
// 保存二级磁盘缓存
Promise.resolve(source)
.then((arraybuffer: ArrayBuffer) => {
this.mDiskCacheProxy.putValue(this.options.generateDataKey, arraybuffer)
DiskLruCache.saveFileCacheOnlyFile(this.options.moduleContext?.filesDir as string, this.options.generateDataKey,arraybuffer);
})
.catch((err: BusinessError) => {
LogUtil.log('download file is =' + ImageKnifeData.SVG + 'and save diskLruCache error =' + (err as BusinessError))
@ -495,7 +421,8 @@ export class RequestManager {
this.thumbnailProcess(source, filetype, onComplete, onError);
}
} else {
this.options.transformations[0].transform(source, this.options, {asyncTransform: (error:BusinessError|string, pixelMap: PixelMap|null) => {
this.options.transformations[0].transform(source, this.options, {
asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => {
if (pixelMap) {
if (filetype != null) {
this.saveCacheAndDisk(pixelMap, filetype, onComplete, source);
@ -503,7 +430,8 @@ export class RequestManager {
} else {
onError(error);
}
}})
}
})
}
} else {
// thumbnail 缩略图部分
@ -511,8 +439,7 @@ export class RequestManager {
let thumbCallback = this.options.thumbholderOnComplete
let thumbError = this.options.thumbholderOnError
let thumbSuccess = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
thumbCallback(imageKnifeData);
thumbCallback(value);
}
this.mParseImageUtil.parseImageThumbnail(this.options.thumbSizeMultiplier, source, thumbSuccess, thumbError);
setTimeout(() => {
@ -544,12 +471,9 @@ export class RequestManager {
}
private saveCacheAndDisk(value: PixelMap, filetype:string, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, source:ArrayBuffer) {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
private async saveCacheAndDisk(value: PixelMap, filetype: string, onComplete: (value: PixelMap) => void | PromiseLike<ImageKnifeData>, source: ArrayBuffer) {
let save2DiskCache = (arraybuffer: ArrayBuffer) => {
this.mDiskCacheProxy.putValue(this.options.generateDataKey, arraybuffer)
DiskLruCache.saveFileCacheOnlyFile(this.options.moduleContext?.filesDir as string, this.options.generateDataKey,arraybuffer);
// 落盘之后需要主动移除当前request并且调用下一个加载
let removeCurrentAndSearchNextRun = this.options.removeCurrentAndSearchNext
removeCurrentAndSearchNextRun();
@ -558,12 +482,11 @@ export class RequestManager {
resolve(source);
}
let promise = new Promise(runSave2Disk);
promise.then(save2DiskCache);
imageKnifeData.waitSaveDisk = true;
onComplete(imageKnifeData);
await promise.then(save2DiskCache);
onComplete(value);
}
thumbnailProcess(source:ArrayBuffer, filetype:string, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void){
thumbnailProcess(source: ArrayBuffer, filetype: string, onComplete: (value: PixelMap) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
let thumbOption = new RequestOption();
let ctx = this.options.getModuleContext()
if (ctx != undefined) {
@ -578,30 +501,34 @@ export class RequestManager {
})
let thumbCallback = this.options.thumbholderOnComplete
let thumbError = this.options.thumbholderOnError
this.options.transformations[0].transform(source, thumbOption, {asyncTransform: (error:BusinessError|string, pixelMap: PixelMap|null) => {
this.options.transformations[0].transform(source, thumbOption, {
asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => {
if (pixelMap) {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap);
thumbCallback(imageKnifeData);
thumbCallback(pixelMap);
} else {
thumbError(error);
}
}})
}
})
setTimeout(() => {
this.options.transformations[0].transform(source, this.options,{asyncTransform: (error:BusinessError|string, pixelMap: PixelMap|null) => {
this.options.transformations[0].transform(source, this.options, {
asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => {
if (pixelMap) {
this.saveCacheAndDisk(pixelMap, filetype, onComplete, source);
} else {
onError(error);
}
}})
}
})
}, this.options.thumbDelayTime)
}
private svgProcess(option: RequestOption,onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string, cacheStrategy?: (cacheData: ImageKnifeData) => void) {
private svgProcess(option: RequestOption, onComplete: (value: PixelMap) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void, arraybuffer: ArrayBuffer, typeValue: string, cacheStrategy?: (cacheData: ImageKnifeData) => void) {
let svgParseImpl = new SVGParseImpl()
svgParseImpl.parseSvg(option, arraybuffer, onComplete, onError)
}
private gifProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string, cacheStrategy?: (cacheData: ImageKnifeData) => void) {
private gifProcess(onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void, arraybuffer: ArrayBuffer, typeValue: string, cacheStrategy?: (cacheData: ImageKnifeData) => void) {
let gifParseImpl = new GIFParseImpl()
gifParseImpl.parseGifs(arraybuffer, (data?: GIFFrame[], err?: BusinessError | string) => {
if (err) {
@ -609,20 +536,16 @@ export class RequestManager {
}
LogUtil.log("gifProcess data is null:" + (data == null));
if (!!data) {
let imageKnifeData = this.createImageGIFFrame(ImageKnifeType.GIFFRAME,data)
LogUtil.log('gifProcess 生成gif 返回数据类型')
if(cacheStrategy){
LogUtil.log('gifProcess 生成gif并且存入了缓存策略')
cacheStrategy(imageKnifeData)
}
onComplete(imageKnifeData)
// let imageKnifeData = this.createImageGIFFrame(ImageKnifeType.GIFFRAME, data)
// LogUtil.log('gifProcess 生成gif 返回数据类型')
// if (cacheStrategy) {
// LogUtil.log('gifProcess 生成gif并且存入了缓存策略')
// cacheStrategy(imageKnifeData)
// }
onComplete(data)
} else {
onError('Parse GIF callback data is null, you need check callback data!')
}
})
}
}

View File

@ -20,5 +20,9 @@ export interface BaseTransform<T> {
// 实现类 返回作为key生成的一部分
getName(): string;
getClassName():string;
getConstructorParams():string;
transform(value: ArrayBuffer, request: RequestOption, func: AsyncTransform<T>):void;
}

View File

@ -37,6 +37,14 @@ export class BlurTransformation implements BaseTransform<PixelMap> {
}
}
getClassName() {
return "BlurTransformation";
}
getConstructorParams() {
return JSON.stringify([this._mRadius,this.sampling]);
}
getName() {
return "BlurTransformation _mRadius:" + this._mRadius +"==BlurTransformation sampling:"+ this.sampling;
}

View File

@ -33,6 +33,14 @@ export class BrightnessFilterTransformation implements BaseTransform<PixelMap> {
this._mBrightness = brightness;
}
getClassName(){
return "BrightnessFilterTransformation";
}
getConstructorParams(){
return JSON.stringify([this._mBrightness]);
}
getName() {
return "BrightnessFilterTransformation:" + this._mBrightness;
}

View File

@ -45,6 +45,15 @@ export class ContrastFilterTransformation implements BaseTransform<PixelMap> {
this._mContrast = contrast;
}
getClassName(){
return "ContrastFilterTransformation";
}
getConstructorParams(){
return JSON.stringify([this._mContrast]);
}
getName() {
return "ContrastFilterTransformation:" + this._mContrast;
}

View File

@ -29,6 +29,14 @@ export class CropCircleTransformation implements BaseTransform<PixelMap> {
private mCenterY: number = 0;
private mRadius: number = 0;
getClassName(){
return "CropCircleTransformation";
}
getConstructorParams(){
return "[]";
}
getName() {
return CropCircleTransformation.TAG + ";mCenterX:" + this.mCenterX
+ ";mCenterY:" + this.mCenterY

View File

@ -22,11 +22,13 @@ import {LogUtil} from '../../imageknife/utils/LogUtil'
import image from "@ohos.multimedia.image"
import { BusinessError } from '@ohos.base'
import { Size } from '../../imageknife/RequestOption'
export interface rgbColor {
r_color: number,
g_color: number,
b_color: number,
}
export class CropCircleWithBorderTransformation implements BaseTransform<PixelMap> {
private static TAG: string = "CropCircleTransformation";
private mBorderSize: number = 5;
@ -44,6 +46,18 @@ export class CropCircleWithBorderTransformation implements BaseTransform<PixelMa
this.mBorderSize = border_size;
}
getClassName() {
return "CropCircleWithBorderTransformation";
}
getConstructorParams() {
return JSON.stringify([this.mBorderSize, {
r_color: this.mRColor,
g_color: this.mGColor,
b_color: this.mBColor
}]);
}
getName() {
return CropCircleWithBorderTransformation.TAG + ";mBorderSize:" + this.mBorderSize
+ ";mCenterX:" + this.mCenterX
@ -63,7 +77,8 @@ export class CropCircleWithBorderTransformation implements BaseTransform<PixelMa
return;
}
let imageSource: image.ImageSource = image.createImageSource(buf);
TransformUtils.getPixelMapSize(imageSource, {asyncTransform:(error:BusinessError|string, size:Size|null) => {
TransformUtils.getPixelMapSize(imageSource, {
asyncTransform: (error: BusinessError | string, size: Size | null) => {
if (!size) {
func?.asyncTransform(error, null)
return;
@ -79,7 +94,8 @@ export class CropCircleWithBorderTransformation implements BaseTransform<PixelMa
targetHeight = pixelMapHeight;
}
this.updatePixelMapSize(imageSource, targetWidth, targetHeight, func);
}})
}
})
}
private updatePixelMapSize(imageSource: image.ImageSource, outWith: number, outHeight: number, func?: AsyncTransform<PixelMap>) {

View File

@ -26,6 +26,14 @@ import image from "@ohos.multimedia.image"
export class CropSquareTransformation implements BaseTransform<PixelMap> {
private static TAG: string = "CropSquareTransformation";
getClassName(){
return "CropSquareTransformation";
}
getConstructorParams(){
return '[]';
}
getName() {
return CropSquareTransformation.TAG;
}

View File

@ -35,6 +35,14 @@ export class CropTransformation implements BaseTransform<PixelMap> {
this.mCropType = cropType;
}
getClassName(){
return "CropTransformation";
}
getConstructorParams(){
return JSON.stringify([this.mWidth,this.mHeight ,this.mCropType]);
}
getName() {
return CropTransformation.TAG + ";mWidth:" + this.mWidth
+ ";mHeight:" + this.mHeight

View File

@ -29,6 +29,14 @@ export class GrayscaleTransformation implements BaseTransform<PixelMap> {
return "GrayscaleTransformation";
}
getClassName(){
return "GrayscaleTransformation";
}
getConstructorParams(){
return '[]';
}
async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
if (!buf || buf.byteLength <= 0) {
LogUtil.log(Constants.PROJECT_TAG + ";GrayscaleTransformation buf is empty");

View File

@ -36,6 +36,14 @@ export class InvertFilterTransformation implements BaseTransform<PixelMap> {
return "InvertFilterTransformation";
}
getClassName(){
return "InvertFilterTransformation";
}
getConstructorParams(){
return '[]';
}
async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
if (!buf || buf.byteLength <= 0) {
LogUtil.log(Constants.PROJECT_TAG + ";InvertFilterTransformation buf is empty");

View File

@ -32,6 +32,14 @@ export class KuwaharaFilterTransform implements BaseTransform<PixelMap> {
this._mRadius = radius;
}
getClassName(){
return "KuwaharaFilterTransform";
}
getConstructorParams(){
return JSON.stringify([this._mRadius]);
}
getName() {
return "KuwaharaFilterTransform _mRadius:" + this._mRadius;
}

View File

@ -35,6 +35,14 @@ export class MaskTransformation implements BaseTransform<PixelMap> {
this._mResourceData = maskBitmap;
}
getClassName(){
return "MaskTransformation";
}
getConstructorParams(){
return JSON.stringify([this._mResourceData]);
}
getName() {
return "MaskTransformation:" + this._mResourceData;
}

View File

@ -37,6 +37,14 @@ export class PixelationFilterTransformation implements BaseTransform<PixelMap> {
}
}
getClassName(){
return "PixelationFilterTransformation";
}
getConstructorParams(){
return JSON.stringify([this._mPixel]);
}
getName() {
return "PixelationFilterTransformation" + this._mPixel;
}

View File

@ -34,6 +34,14 @@ export class RotateImageTransformation implements BaseTransform<PixelMap> {
return "RotateImageTransformation" + ";degreesToRotate:" + this.mDegreesToRotate;
}
getClassName(){
return "RotateImageTransformation";
}
getConstructorParams(){
return JSON.stringify([this.mDegreesToRotate]);
}
transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
if (!buf || buf.byteLength <= 0) {
LogUtil.log(Constants.PROJECT_TAG + ";RotateImageTransformation buf is empty");

View File

@ -46,6 +46,19 @@ export class RoundedCornersTransformation implements BaseTransform<PixelMap> {
this.mBottom_right = value.bottom_right;
}
getClassName(){
return "RoundedCornersTransformation";
}
getConstructorParams(){
return JSON.stringify([{
top_left: this.mTop_left,
top_right: this.mTop_right,
bottom_left: this.mBottom_left,
bottom_right: this.mBottom_right
}]);
}
getName() {
return "RoundedCornersTransformation" + ";mTop_left:" + this.mTop_left
+ ";mTop_right:" + this.mTop_right

View File

@ -33,6 +33,14 @@ export class SepiaFilterTransformation implements BaseTransform<PixelMap> {
return "SepiaFilterTransformation";
}
getClassName(){
return "SepiaFilterTransformation";
}
getConstructorParams(){
return '[]';
}
async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
if (!buf || buf.byteLength <= 0) {
LogUtil.log(Constants.PROJECT_TAG + ";SepiaFilterTransformation buf is empty");

View File

@ -24,6 +24,15 @@ import { BusinessError } from '@ohos.base'
import {Size} from '../../imageknife/RequestOption'
export class SketchFilterTransformation implements BaseTransform<PixelMap> {
getClassName(){
return "SketchFilterTransformation";
}
getConstructorParams(){
return '[]';
}
getName() {
return 'SketchFilterTransformation';
}

View File

@ -43,6 +43,14 @@ export class SwirlFilterTransformation implements BaseTransform<PixelMap> {
}
}
getClassName(){
return "SwirlFilterTransformation";
}
getConstructorParams(){
return JSON.stringify([this.radius,this._angle,[this._xCenter,this._yCenter]]);
}
getName() {
return 'SwirlFilterTransformation' + this.radius;
}

View File

@ -37,6 +37,14 @@ export class ToonFilterTransform implements BaseTransform<PixelMap> {
}
}
getClassName(){
return "ToonFilterTransform";
}
getConstructorParams(){
return JSON.stringify([this.threshold,this.quantizationLevels]);
}
getName() {
return "ToonFilterTransform threshold:" + this.threshold + ";quantizationLevels:" + this.quantizationLevels;
}

View File

@ -42,6 +42,14 @@ export class VignetteFilterTransform implements BaseTransform<PixelMap> {
}
}
getClassName(){
return "VignetteFilterTransform";
}
getConstructorParams(){
return JSON.stringify([this.centerPoint,this.vignetteColor,this.vignetteSpace]);
}
getName() {
return "VignetteFilterTransform centerPoint:" + this.centerPoint + ";vignetteColor:" + this.vignetteColor + ";vignetteSpace:" + this.vignetteSpace;
}

View File

@ -20,6 +20,15 @@ import {TransformUtils} from '../TransformUtils'
import {RequestOption} from '../../../imageknife/RequestOption'
import { BusinessError } from '@ohos.base'
export class CenterCrop implements BaseTransform<PixelMap> {
getClassName(){
return "CenterCrop";
}
getConstructorParams(){
return '[]';
}
getName() {
return 'CenterCrop:' + this;
}

View File

@ -23,6 +23,13 @@ export class CenterInside implements BaseTransform<PixelMap> {
getName() {
return 'CenterInside:' + this;
}
getClassName(){
return "CenterInside";
}
getConstructorParams(){
return '[]';
}
transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
if (!buf || buf.byteLength <= 0) {

View File

@ -23,6 +23,13 @@ export class FitCenter implements BaseTransform<PixelMap> {
getName() {
return 'FitCenter:' + this;
}
getClassName(){
return "FitCenter";
}
getConstructorParams(){
return '[]';
}
transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
if (!buf || buf.byteLength <= 0) {

View File

@ -27,33 +27,33 @@ export class ParseImageUtil implements IParseImage<PixelMap> {
// scale(0,1)
parseImageThumbnail(scale: number, imageinfo: ArrayBuffer, onCompleteFunction: (value: PixelMap) => void | PromiseLike<PixelMap>, onErrorFunction: (reason?: BusinessError | string) => void) {
// let imageSource: image.ImageSource = image.createImageSource(imageinfo); // 步骤一文件转为pixelMap 然后变换 给Image组件
// imageSource.getImageInfo().then((value) => {
// let hValue = Math.round(value.size.height * scale);
// let wValue = Math.round(value.size.width * scale);
// let defaultSize: image.Size = {
// height: hValue,
// width: wValue
// };
// let opts: image.DecodingOptions = {
// editable: true,
// desiredSize: defaultSize
// };
//
// imageSource.createPixelMap(opts).then((pixelMap: image.PixelMap) => {
// onCompleteFunction(pixelMap);
// imageSource.release()
// }).catch((err: string) => {
// onErrorFunction(err);
// imageSource.release()
// })
//
// }).catch((err: string) => {
// onErrorFunction(err);
// imageSource.release()
// })
let imageSource: image.ImageSource = image.createImageSource(imageinfo); // 步骤一文件转为pixelMap 然后变换 给Image组件
imageSource.getImageInfo().then((value) => {
let hValue = Math.round(value.size.height * scale);
let wValue = Math.round(value.size.width * scale);
let defaultSize: image.Size = {
height: hValue,
width: wValue
};
let opts: image.DecodingOptions = {
editable: true,
desiredSize: defaultSize
};
taskPoolExecutePixelMap(imageinfo,scale,onCompleteFunction,onErrorFunction); //多线程接口
imageSource.createPixelMap(opts).then((pixelMap: image.PixelMap) => {
onCompleteFunction(pixelMap);
imageSource.release()
}).catch((err: string) => {
onErrorFunction(err);
imageSource.release()
})
}).catch((err: string) => {
onErrorFunction(err);
imageSource.release()
})
// taskPoolExecutePixelMap(imageinfo,scale,onCompleteFunction,onErrorFunction); //多线程接口
}
}
@ -79,14 +79,14 @@ async function taskParseImage(arrayBuffer: ArrayBuffer, scale: number): Promise<
}
function taskPoolExecutePixelMap(arrayBuffer: ArrayBuffer, scale: number, onCompleteFunction: (value: PixelMap) => void | PromiseLike<PixelMap>, onErrorFunction: (reason?: BusinessError | string) => void) {
LogUtil.log("ceshi321 : arrayBuffer长度" + arrayBuffer.byteLength)
let task = new taskpool.Task(taskParseImage, arrayBuffer, scale)
task.setTransferList([])
LogUtil.log("ceshi321 : arrayBuffer长度" + arrayBuffer.byteLength);
let task = new taskpool.Task(taskParseImage, arrayBuffer, scale);
task.setTransferList([]);
taskpool.execute(task).then((pixelmap: Object) => {
LogUtil.log('ceshi321 : Succeeded in creating pixelmap Ui .' + (pixelmap as image.PixelMap).getPixelBytesNumber())
onCompleteFunction(pixelmap as image.PixelMap);
}).catch((err: string) => {
LogUtil.log("ceshi321 : test occur error: " + err)
LogUtil.log("ceshi321 : test occur error: " + err);
onErrorFunction(err);
});
}

View File

@ -36,46 +36,46 @@ export interface gifBackData {
export class GIFParseImpl implements IParseGif {
parseGifs(imageinfo: ArrayBuffer, callback: (data?: GIFFrame[], err?: BusinessError | string) => void) {
// 硬解码流程
// let imageSource = image.createImageSource(imageinfo);
// let decodeOpts: image.DecodingOptions = {
// sampleSize: 1,
// editable: true,
// rotate: 0
// }
// let data:GIFFrame[] = [];
// imageSource.createPixelMapList(decodeOpts).then((pixelList: Array<PixelMap>) => {
// //sdk的api接口发生变更从.getDelayTime() 变为.getDelayTimeList()
// imageSource.getDelayTimeList().then(delayTimes => {
// if (pixelList.length > 0) {
// let pixelmap1 = pixelList[0];
// pixelmap1.getImageInfo().then(imageInfo => {
// for (let i = 0; i < pixelList.length; i++) {
// let frame = new GIFFrame();
// frame.drawPixelMap = pixelList[i];
// frame.dims = { width: imageInfo.size.width, height: imageInfo.size.height, top: 0, left: 0 }
// if (i < delayTimes.length) {
// frame.delay = delayTimes[i];
// } else {
// frame.delay = delayTimes[delayTimes.length - 1]
// }
// data.push(frame)
// }
// callback(data,undefined)
// imageSource.release();
// }).catch((err: string) => {
// imageSource.release();
// callback(undefined,err)
// })
// }
// }).catch((err: string) => {
// imageSource.release();
// callback(undefined,err)
// })
// }).catch((err: string) => {
// imageSource.release();
// callback(undefined,err)
// })
taskPoolExecutePixelMapList(imageinfo,callback); //多线程接口
let imageSource = image.createImageSource(imageinfo);
let decodeOpts: image.DecodingOptions = {
sampleSize: 1,
editable: true,
rotate: 0
}
let data:GIFFrame[] = [];
imageSource.createPixelMapList(decodeOpts).then((pixelList: Array<PixelMap>) => {
//sdk的api接口发生变更从.getDelayTime() 变为.getDelayTimeList()
imageSource.getDelayTimeList().then(delayTimes => {
if (pixelList.length > 0) {
let pixelmap1 = pixelList[0];
pixelmap1.getImageInfo().then(imageInfo => {
for (let i = 0; i < pixelList.length; i++) {
let frame = new GIFFrame();
frame.drawPixelMap = pixelList[i];
frame.dims = { width: imageInfo.size.width, height: imageInfo.size.height, top: 0, left: 0 }
if (i < delayTimes.length) {
frame.delay = delayTimes[i];
} else {
frame.delay = delayTimes[delayTimes.length - 1]
}
data.push(frame)
}
callback(data,undefined)
imageSource.release();
}).catch((err: string) => {
imageSource.release();
callback(undefined,err)
})
}
}).catch((err: string) => {
imageSource.release();
callback(undefined,err)
})
}).catch((err: string) => {
imageSource.release();
callback(undefined,err)
})
//taskPoolExecutePixelMapList(imageinfo,callback); //多线程接口
}
}

View File

@ -19,6 +19,6 @@ import { ImageKnifeData } from '../../ImageKnifeData'
export interface IParseSvg {
// 解析svg
parseSvg:(option: RequestOption, imageInfo: ArrayBuffer | ArrayBufferLike,
onComplete: (value: ImageKnifeData) => void | PromiseLike<ImageKnifeData>,
onComplete: (value: PixelMap) => void | PromiseLike<ImageKnifeData>,
onErrorFunction: (reason?: BusinessError | string) => void)=> void
}

View File

@ -20,7 +20,7 @@ import image from '@ohos.multimedia.image'
export class SVGParseImpl implements IParseSvg {
parseSvg(option: RequestOption, imageInfo: ArrayBuffer,
onComplete: (value: ImageKnifeData) => void | PromiseLike<ImageKnifeData>,
onComplete: (value: PixelMap) => void | PromiseLike<ImageKnifeData>,
onErrorFunction: (reason?: BusinessError | string) => void) {
let imageSource: image.ImageSource = image.createImageSource(imageInfo); // 步骤一文件转为pixelMap 然后变换 给Image组件
@ -36,7 +36,7 @@ export class SVGParseImpl implements IParseSvg {
};
imageSource.createPixelMap(opts).then((pixelMap: image.PixelMap) => {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap)
onComplete(imageKnifeData);
onComplete(imageKnifeData?.drawPixelMap?.imagePixelMap as PixelMap);
imageSource.release()
}).catch((err: string) => {
onErrorFunction(err);