增加图片加载回调的信息数据

Signed-off-by: tyBrave <tianyong21@h-partners.com>
This commit is contained in:
tyBrave 2024-10-23 16:40:06 +08:00
parent 8dd1535646
commit 2d0b6ace7b
9 changed files with 658 additions and 221 deletions

View File

@ -94,7 +94,6 @@ struct TestImageKnifeCallbackPage {
}, },
border: { radius: 50 }, border: { radius: 50 },
onComplete: (event) => { onComplete: (event) => {
console.log("sss--->gif onComplete:" + JSON.stringify(event))
if (event && event.loadingStatus == 0) { if (event && event.loadingStatus == 0) {
this.render_success = JSON.stringify(Date.now()) this.render_success = JSON.stringify(Date.now())
} }

View File

@ -1,6 +0,0 @@
{
"lockfileVersion": 3,
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
"specifiers": {},
"packages": {}
}

View File

@ -19,10 +19,10 @@ import List from '@ohos.util.List';
import LightWeightMap from '@ohos.util.LightWeightMap'; import LightWeightMap from '@ohos.util.LightWeightMap';
import { LogUtil } from './utils/LogUtil'; import { LogUtil } from './utils/LogUtil';
import { ImageKnife } from './ImageKnife'; import { ImageKnife } from './ImageKnife';
import { ImageKnifeData, CacheStrategy } from './model/ImageKnifeData'; import { ImageKnifeData, CacheStrategy, ErrorInfo, TimeInfo } from './model/ImageKnifeData';
import image from '@ohos.multimedia.image'; import image from '@ohos.multimedia.image';
import emitter from '@ohos.events.emitter'; import emitter from '@ohos.events.emitter';
import { Constants } from './utils/Constants'; import { Constants, LoadPhase, LoadPixelMapCode } from './utils/Constants';
import taskpool from '@ohos.taskpool'; import taskpool from '@ohos.taskpool';
import { FileTypeUtil } from './utils/FileTypeUtil'; import { FileTypeUtil } from './utils/FileTypeUtil';
import { IEngineKey } from './key/IEngineKey'; import { IEngineKey } from './key/IEngineKey';
@ -46,9 +46,19 @@ export class ImageKnifeDispatcher {
executingJobMap: LightWeightMap<string, List<ImageKnifeRequestWithSource>> = new LightWeightMap(); executingJobMap: LightWeightMap<string, List<ImageKnifeRequestWithSource>> = new LightWeightMap();
// 开发者可配置全局缓存 // 开发者可配置全局缓存
private engineKey: IEngineKey = new DefaultEngineKey(); private engineKey: IEngineKey = new DefaultEngineKey();
//图片加载信息回调数据
private callBackData: ImageKnifeData = {
source: "",
imageWidth: 0,
imageHeight: 0,
};
private callBackTimeInfo: TimeInfo = {};
showFromMemomry(request: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean): boolean { showFromMemomry(request: ImageKnifeRequest, imageSrc: string | PixelMap | Resource,
LogUtil.log("ImageKnife_DataTime_showFromMemomry.start:" + request.imageKnifeOption.loadSrc + "requestSource=" + requestSource + " isAnimator=" + isAnimator) requestSource: ImageKnifeRequestSource, isAnimator?: boolean): boolean {
LogUtil.log("ImageKnife_DataTime_showFromMemomry.start:" + request.imageKnifeOption.loadSrc + "requestSource=" +
requestSource + " isAnimator=" + isAnimator)
let memoryCheckStartTime = Date.now();
let memoryCache: ImageKnifeData | undefined; let memoryCache: ImageKnifeData | undefined;
if ((typeof (request.imageKnifeOption.loadSrc as image.PixelMap).isEditable) == 'boolean') { if ((typeof (request.imageKnifeOption.loadSrc as image.PixelMap).isEditable) == 'boolean') {
memoryCache = { memoryCache = {
@ -58,26 +68,39 @@ export class ImageKnifeDispatcher {
} }
} else { } else {
memoryCache = ImageKnife.getInstance() memoryCache = ImageKnife.getInstance()
.loadFromMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, request.imageKnifeOption,isAnimator)); .loadFromMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, request.imageKnifeOption,
isAnimator));
}
//记录ImageKnifeRequestSource.SRC 开始内存检查的时间点
if (requestSource == ImageKnifeRequestSource.SRC) {
this.callBackTimeInfo.memoryCheckStartTime = memoryCheckStartTime;
this.callBackTimeInfo.memoryCheckEndTime = Date.now();
this.callBackData.timeInfo = this.callBackTimeInfo;
//设置请求结束的时间点
if (memoryCache !== undefined) {
this.callBackData.timeInfo.requestEndTime = Date.now();
}
} }
if (memoryCache !== undefined) { if (memoryCache !== undefined) {
// 画主图 // 画主图
if (request.requestState === ImageKnifeRequestState.PROGRESS) { if (request.requestState === ImageKnifeRequestState.PROGRESS) {
// 回调请求开始 // 回调请求开始
if (requestSource === ImageKnifeRequestSource.SRC && request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) { if (requestSource === ImageKnifeRequestSource.SRC &&
request.imageKnifeOption.onLoadListener.onLoadStart() request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) {
request.imageKnifeOption.onLoadListener.onLoadStart(this.callBackData)
LogUtil.log("ImageKnife_DataTime_MemoryCache_onLoadStart:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_MemoryCache_onLoadStart:" + request.imageKnifeOption.loadSrc)
} }
LogUtil.log("ImageKnife_DataTime_MemoryCache_showPixelMap.start:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_MemoryCache_showPixelMap.start:" + request.imageKnifeOption.loadSrc)
request.ImageKnifeRequestCallback?.showPixelMap(request.componentVersion, memoryCache.source, requestSource,memoryCache.imageAnimator) request.ImageKnifeRequestCallback?.showPixelMap(request.componentVersion, memoryCache.source, requestSource,
memoryCache.imageAnimator)
LogUtil.log("ImageKnife_DataTime_MemoryCache_showPixelMap.end:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_MemoryCache_showPixelMap.end:" + request.imageKnifeOption.loadSrc)
if (requestSource == ImageKnifeRequestSource.SRC) { if (requestSource == ImageKnifeRequestSource.SRC) {
request.requestState = ImageKnifeRequestState.COMPLETE request.requestState = ImageKnifeRequestState.COMPLETE
// 回调请求开结束 // 回调请求开结束
if (request.imageKnifeOption.onLoadListener?.onLoadSuccess !== undefined) { if (request.imageKnifeOption.onLoadListener?.onLoadSuccess !== undefined) {
request.imageKnifeOption.onLoadListener.onLoadSuccess(memoryCache.source,memoryCache) this.copyCallBackData(this.callBackData, memoryCache);
request.imageKnifeOption.onLoadListener.onLoadSuccess(memoryCache.source, memoryCache)
LogUtil.log("ImageKnife_DataTime_MemoryCache_onLoadSuccess:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_MemoryCache_onLoadSuccess:" + request.imageKnifeOption.loadSrc)
} }
} else if (requestSource == ImageKnifeRequestSource.ERROR_HOLDER) { } else if (requestSource == ImageKnifeRequestSource.ERROR_HOLDER) {
@ -91,15 +114,53 @@ export class ImageKnifeDispatcher {
return false return false
} }
/**
* 设置进入线程前加载图片的callBack信息
* @param beforeCallData
* @param afterCallData
*/
private copyCallBackData(beforeCallData: ImageKnifeData | undefined, afterCallData: ImageKnifeData) {
if (!beforeCallData || !afterCallData) {
return;
}
//设置组件宽高
afterCallData.componentWidth = beforeCallData.componentWidth;
afterCallData.componentHeight = beforeCallData.componentWidth;
//设置图片开始加载时间及其缓存检查时间点
if (beforeCallData.timeInfo) {
if (afterCallData.timeInfo) {
afterCallData.timeInfo.requestStartTime = beforeCallData.timeInfo.requestStartTime;
afterCallData.timeInfo.memoryCheckStartTime = beforeCallData.timeInfo.memoryCheckStartTime;
afterCallData.timeInfo.memoryCheckEndTime = beforeCallData.timeInfo.memoryCheckEndTime;
} else {
afterCallData.timeInfo = beforeCallData.timeInfo;
}
}
}
enqueue(request: ImageKnifeRequest,isAnimator?: boolean): void {
enqueue(request: ImageKnifeRequest, isAnimator?: boolean): void {
if (typeof request.imageKnifeOption.loadSrc == "string") {
this.callBackData.source = request.imageKnifeOption.loadSrc;
}
this.callBackData.componentWidth = request.componentWidth;
this.callBackData.componentHeight = request.componentHeight;
this.callBackTimeInfo.requestStartTime = Date.now();
//1.内存有的话直接渲染 //1.内存有的话直接渲染
if (this.showFromMemomry(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,isAnimator)) { if (this.showFromMemomry(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC, isAnimator)) {
return return
} }
//这里对this.callBackData要进行深拷贝
let call = JSON.parse(JSON.stringify(this.callBackData)) as ImageKnifeData;
//跟隨請求保存回調信息點
request.setImageKnifeData(call);
// 2.内存获取占位图 // 2.内存获取占位图
if (request.imageKnifeOption.placeholderSrc !== undefined) { if (request.imageKnifeOption.placeholderSrc !== undefined) {
if (this.showFromMemomry(request, request.imageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER)) { if (this.showFromMemomry(request, request.imageKnifeOption.placeholderSrc,
ImageKnifeRequestSource.PLACE_HOLDER)) {
request.drawPlayHolderSuccess = true request.drawPlayHolderSuccess = true
} }
} }
@ -108,10 +169,10 @@ export class ImageKnifeDispatcher {
this.jobQueue.add(request) this.jobQueue.add(request)
return return
} }
this.executeJob(request,isAnimator) this.executeJob(request, isAnimator)
} }
executeJob(request: ImageKnifeRequest,isAnimator?: boolean): void { executeJob(request: ImageKnifeRequest, isAnimator?: boolean): void {
LogUtil.log("ImageKnife_DataTime_executeJob.start:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_executeJob.start:" + request.imageKnifeOption.loadSrc)
// 加载占位符 // 加载占位符
if (request.imageKnifeOption.placeholderSrc !== undefined && request.drawPlayHolderSuccess == false) { if (request.imageKnifeOption.placeholderSrc !== undefined && request.drawPlayHolderSuccess == false) {
@ -119,16 +180,18 @@ export class ImageKnifeDispatcher {
} }
// 加载主图 // 加载主图
this.getAndShowImage(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,isAnimator) this.getAndShowImage(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC, isAnimator)
LogUtil.log("ImageKnife_DataTime_executeJob.end:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_executeJob.end:" + request.imageKnifeOption.loadSrc)
} }
/** /**
* 获取和显示图片 * 获取和显示图片
*/ */
getAndShowImage(currentRequest: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean): void { getAndShowImage(currentRequest: ImageKnifeRequest, imageSrc: string | PixelMap | Resource,
requestSource: ImageKnifeRequestSource, isAnimator?: boolean): void {
LogUtil.log("ImageKnife_DataTime_getAndShowImage.start:" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage.start:" + currentRequest.imageKnifeOption.loadSrc)
let memoryKey: string = this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator) let memoryKey: string =
this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption, isAnimator)
let requestList: List<ImageKnifeRequestWithSource> | undefined = this.executingJobMap.get(memoryKey) let requestList: List<ImageKnifeRequestWithSource> | undefined = this.executingJobMap.get(memoryKey)
if (requestList == undefined) { if (requestList == undefined) {
requestList = new List() requestList = new List()
@ -139,28 +202,29 @@ export class ImageKnifeDispatcher {
return return
} }
let isWatchProgress : boolean = false let isWatchProgress: boolean = false
// 回调请求开始 // 回调请求开始
requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => { requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
if (requestWithSource.source === ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) { if (requestWithSource.source === ImageKnifeRequestSource.SRC &&
requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart() requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) {
requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart(currentRequest.getImageKnifeData())
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadStart:" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadStart:" + currentRequest.imageKnifeOption.loadSrc)
} }
if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) { if (requestWithSource.request.imageKnifeOption.progressListener !== undefined &&
requestWithSource.source === ImageKnifeRequestSource.SRC) {
isWatchProgress = true isWatchProgress = true
} }
}); });
let src: string | number = "" let src: string | number = ""
let moduleName: string = "" let moduleName: string = ""
let resName: string = "" let resName: string = ""
if((imageSrc as Resource).id != undefined) { if ((imageSrc as Resource).id != undefined) {
moduleName = (imageSrc as Resource).moduleName moduleName = (imageSrc as Resource).moduleName
src = (imageSrc as Resource).id src = (imageSrc as Resource).id
if(src == -1) { if (src == -1) {
resName = (imageSrc as Resource).params![0] resName = (imageSrc as Resource).params![0]
} }
} else if(typeof imageSrc == "string") { } else if (typeof imageSrc == "string") {
src = imageSrc src = imageSrc
} }
let request: RequestJobRequest = { let request: RequestJobRequest = {
@ -168,61 +232,65 @@ export class ImageKnifeDispatcher {
src: src, src: src,
headers: currentRequest.imageKnifeOption.headerOption, headers: currentRequest.imageKnifeOption.headerOption,
allHeaders: currentRequest.headers, allHeaders: currentRequest.headers,
componentWidth:currentRequest.componentWidth, componentWidth: currentRequest.componentWidth,
componentHeight:currentRequest.componentHeight, componentHeight: currentRequest.componentHeight,
customGetImage: currentRequest.imageKnifeOption.customGetImage, customGetImage: currentRequest.imageKnifeOption.customGetImage,
onlyRetrieveFromCache: currentRequest.imageKnifeOption.onlyRetrieveFromCache, onlyRetrieveFromCache: currentRequest.imageKnifeOption.onlyRetrieveFromCache,
transformation: currentRequest.imageKnifeOption.transformation, transformation: currentRequest.imageKnifeOption.transformation,
writeCacheStrategy: ImageKnife.getInstance() writeCacheStrategy: ImageKnife.getInstance()
.isFileCacheInit() ? currentRequest.imageKnifeOption.writeCacheStrategy : CacheStrategy.Memory, // 未初始化文件缓存时,不写文件缓存 .isFileCacheInit() ? currentRequest.imageKnifeOption.writeCacheStrategy :
CacheStrategy.Memory, // 未初始化文件缓存时,不写文件缓存
engineKey: this.engineKey, engineKey: this.engineKey,
signature: currentRequest.imageKnifeOption.signature, signature: currentRequest.imageKnifeOption.signature,
requestSource: requestSource, requestSource: requestSource,
isWatchProgress: isWatchProgress, isWatchProgress: isWatchProgress,
memoryKey: memoryKey, memoryKey: memoryKey,
fileCacheFolder: ImageKnife.getInstance().getFileCache()?.getCacheFolder(), fileCacheFolder: ImageKnife.getInstance().getFileCache()?.getCacheFolder(),
isAnimator:isAnimator, isAnimator: isAnimator,
moduleName: moduleName == "" ? undefined : moduleName, moduleName: moduleName == "" ? undefined : moduleName,
resName: resName == "" ? undefined : resName resName: resName == "" ? undefined : resName
} }
if(request.customGetImage == undefined) { if (request.customGetImage == undefined) {
request.customGetImage = ImageKnife.getInstance().getCustomGetImage() request.customGetImage = ImageKnife.getInstance().getCustomGetImage()
} }
if (ImageKnife.getInstance().isRequestInSubThread){ if (ImageKnife.getInstance().isRequestInSubThread) {
// 启动线程下载和解码主图 // 启动线程下载和解码主图
LogUtil.log("ImageKnife_DataTime_getAndShowImage_Task.start:" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_Task.start:" + currentRequest.imageKnifeOption.loadSrc)
let task = new taskpool.Task(requestJob, request) let task = new taskpool.Task(requestJob, request)
LogUtil.log("ImageKnife_DataTime_getAndShowImage_Task.end:" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_Task.end:" + currentRequest.imageKnifeOption.loadSrc)
if (isWatchProgress){ if (isWatchProgress) {
emitter.on(Constants.PROGRESS_EMITTER + memoryKey, (data) => { emitter.on(Constants.PROGRESS_EMITTER + memoryKey, (data) => {
this.progressCallBack(requestList! , data?.data?.value as number) this.progressCallBack(requestList!, data?.data?.value as number)
}); });
} }
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(subthread):" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(subthread):" +
currentRequest.imageKnifeOption.loadSrc)
taskpool.execute(task).then((res: Object) => { taskpool.execute(task).then((res: Object) => {
this.doTaskCallback(res as RequestJobResult | undefined, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator); this.doTaskCallback(res as RequestJobResult | undefined, requestList!, currentRequest, memoryKey, imageSrc,
if (isWatchProgress){ requestSource, isAnimator);
if (isWatchProgress) {
emitter.off(Constants.PROGRESS_EMITTER + memoryKey) emitter.off(Constants.PROGRESS_EMITTER + memoryKey)
} }
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:" + currentRequest.imageKnifeOption.loadSrc)
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc)
}).catch((err: BusinessError) => { }).catch((err: BusinessError) => {
LogUtil.error("Fail to requestJob in sub thread src=" + imageSrc + " err=" + err) LogUtil.error("Fail to requestJob in sub thread src=" + imageSrc + " err=" + err)
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc)
if (isWatchProgress){ if (isWatchProgress) {
emitter.off(Constants.PROGRESS_EMITTER + memoryKey) emitter.off(Constants.PROGRESS_EMITTER + memoryKey)
} }
this.executingJobMap.remove(memoryKey); this.executingJobMap.remove(memoryKey);
this.dispatchNextJob(); this.dispatchNextJob();
}) })
} else { //主线程请求 } else { //主线程请求
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(mainthread):" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(mainthread):" +
currentRequest.imageKnifeOption.loadSrc)
requestJob(request, requestList).then((res: RequestJobResult | undefined) => { requestJob(request, requestList).then((res: RequestJobResult | undefined) => {
this.doTaskCallback(res, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator); this.doTaskCallback(res, requestList!, currentRequest, memoryKey, imageSrc, requestSource, isAnimator);
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:" + currentRequest.imageKnifeOption.loadSrc)
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc)
}).catch((err: BusinessError) => { }).catch((err: BusinessError) => {
LogUtil.error("Fail to requestJob in main thread src=" + imageSrc + " err=" + err) LogUtil.error("Fail to requestJob in main thread src=" + imageSrc + " err=" + err)
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc)
@ -237,31 +305,52 @@ export class ImageKnifeDispatcher {
* @param requestList 请求列表 * @param requestList 请求列表
* @param data 进度 * @param data 进度
*/ */
private progressCallBack(requestList:List<ImageKnifeRequestWithSource>, data: number) { private progressCallBack(requestList: List<ImageKnifeRequestWithSource>, data: number) {
for (let i = 0; i < requestList.length; i++) { for (let i = 0; i < requestList.length; i++) {
let requestWithSource:ImageKnifeRequestWithSource = requestList[i] let requestWithSource: ImageKnifeRequestWithSource = requestList[i]
if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) { if (requestWithSource.request.imageKnifeOption.progressListener !== undefined &&
requestWithSource.source === ImageKnifeRequestSource.SRC) {
requestWithSource.request.imageKnifeOption.progressListener(data) requestWithSource.request.imageKnifeOption.progressListener(data)
} }
} }
} }
private doTaskCallback(requestJobResult: RequestJobResult | undefined, requestList: List<ImageKnifeRequestWithSource> , private doTaskCallback(requestJobResult: RequestJobResult | undefined, requestList: List<ImageKnifeRequestWithSource>,
currentRequest: ImageKnifeRequest, memoryKey: string, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean):void { currentRequest: ImageKnifeRequest, memoryKey: string, imageSrc: string | PixelMap | Resource,
LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.start:"+currentRequest.imageKnifeOption.loadSrc) requestSource: ImageKnifeRequestSource, isAnimator?: boolean): void {
if (requestJobResult === undefined){ LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.start:" + currentRequest.imageKnifeOption.loadSrc)
if (requestJobResult === undefined) {
return return
} }
//设置请求结束的时间
if (requestJobResult.callBackData && requestJobResult.callBackData.timeInfo) {
requestJobResult.callBackData.timeInfo.requestEndTime = Date.now();
}
let pixelmap = requestJobResult.pixelMap; let pixelmap = requestJobResult.pixelMap;
if (pixelmap === undefined) { if (pixelmap === undefined) {
LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.pixelmap undefined:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.pixelmap undefined:" +
currentRequest.imageKnifeOption.loadSrc)
requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => { requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
//设置失败回调的时间点
if (requestJobResult.errorCallBackData && requestJobResult.errorCallBackData.timeInfo) {
requestJobResult.errorCallBackData.timeInfo.requestEndTime = Date.now()
let callBackData = requestWithSource.request.getImageKnifeData();
if (callBackData && callBackData.timeInfo) {
requestJobResult.errorCallBackData.timeInfo.requestStartTime = callBackData.timeInfo.requestStartTime;
requestJobResult.errorCallBackData.timeInfo.memoryCheckStartTime =
callBackData.timeInfo.memoryCheckStartTime;
requestJobResult.errorCallBackData.timeInfo.memoryCheckEndTime = callBackData.timeInfo.memoryCheckEndTime;
}
}
// 回调请求失败 // 回调请求失败
if (requestWithSource.source === ImageKnifeRequestSource.SRC && if (requestWithSource.source === ImageKnifeRequestSource.SRC &&
requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadFailed !== undefined && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadFailed !== undefined &&
requestJobResult.loadFail) { requestJobResult.loadFail) {
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadFailed(requestJobResult.loadFail); requestWithSource.request.imageKnifeOption.onLoadListener.onLoadFailed(requestJobResult.loadFail,
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadFailed:"+currentRequest.imageKnifeOption.loadSrc) requestJobResult.errorCallBackData);
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadFailed:" + currentRequest.imageKnifeOption.loadSrc)
} }
if (requestWithSource.source === ImageKnifeRequestSource.SRC && if (requestWithSource.source === ImageKnifeRequestSource.SRC &&
requestWithSource.request.imageKnifeOption.errorholderSrc !== undefined) { requestWithSource.request.imageKnifeOption.errorholderSrc !== undefined) {
@ -278,36 +367,57 @@ export class ImageKnifeDispatcher {
return; return;
} }
// 保存文件缓存 // 保存文件缓存
if (requestJobResult.bufferSize > 0 && currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.Memory) { if (requestJobResult.bufferSize > 0 &&
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveWithoutWriteFile.start:"+currentRequest.imageKnifeOption.loadSrc) currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.Memory) {
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveWithoutWriteFile.start:" +
currentRequest.imageKnifeOption.loadSrc)
ImageKnife.getInstance().saveWithoutWriteFile(requestJobResult.fileKey, requestJobResult.bufferSize); ImageKnife.getInstance().saveWithoutWriteFile(requestJobResult.fileKey, requestJobResult.bufferSize);
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveWithoutWriteFile.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveWithoutWriteFile.end:" +
currentRequest.imageKnifeOption.loadSrc)
}
let imageKnifeData: ImageKnifeData;
if (!requestJobResult.callBackData) {
imageKnifeData = {
source: pixelmap!,
imageWidth: requestJobResult.size == undefined ? 0 : requestJobResult.size.width,
imageHeight: requestJobResult.size == undefined ? 0 : requestJobResult.size.height,
type: requestJobResult.type,
};
} else {
imageKnifeData = requestJobResult.callBackData;
imageKnifeData.source = pixelmap!;
} }
let ImageKnifeData: ImageKnifeData = { if (requestJobResult.pixelMapList != undefined) {
let imageAnimator: Array<ImageFrameInfo> = []
requestJobResult.pixelMapList.forEach((item, index) => {
imageAnimator.push({
src: requestJobResult.pixelMapList![index],
duration: requestJobResult.delayList![index]
})
})
imageKnifeData.imageAnimator = imageAnimator
}
//构建缓存保存的ImageKnifeData
let saveCacheImageData: ImageKnifeData = {
source: pixelmap!, source: pixelmap!,
imageWidth: requestJobResult.size == undefined ? 0 : requestJobResult.size.width, imageWidth: requestJobResult.size == undefined ? 0 : requestJobResult.size.width,
imageHeight: requestJobResult.size == undefined ? 0 : requestJobResult.size.height, imageHeight: requestJobResult.size == undefined ? 0 : requestJobResult.size.height,
type:requestJobResult.type type: requestJobResult.type,
}; imageAnimator: imageKnifeData.imageAnimator
if(requestJobResult.pixelMapList != undefined) {
let imageAnimator: Array<ImageFrameInfo> = []
requestJobResult.pixelMapList.forEach((item,index)=>{
imageAnimator.push({
src:requestJobResult.pixelMapList![index],
duration:requestJobResult.delayList![index]
})
})
ImageKnifeData.imageAnimator = imageAnimator
} }
// 保存内存缓存 // 保存内存缓存
if (currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.File) { if (currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.File) {
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.start:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.start:" +
currentRequest.imageKnifeOption.loadSrc)
ImageKnife.getInstance() ImageKnife.getInstance()
.saveMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator), .saveMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,
ImageKnifeData); isAnimator),
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.end:"+currentRequest.imageKnifeOption.loadSrc) saveCacheImageData);
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.end:" + currentRequest.imageKnifeOption.loadSrc)
} }
if (requestList !== undefined) { if (requestList !== undefined) {
// key相同的request一起绘制 // key相同的request一起绘制
requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => { requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
@ -317,10 +427,12 @@ export class ImageKnifeDispatcher {
requestWithSource.source === ImageKnifeRequestSource.ERROR_HOLDER requestWithSource.source === ImageKnifeRequestSource.ERROR_HOLDER
|| (requestWithSource.source === ImageKnifeRequestSource.PLACE_HOLDER && || (requestWithSource.source === ImageKnifeRequestSource.PLACE_HOLDER &&
requestWithSource.request.requestState === ImageKnifeRequestState.PROGRESS)) { requestWithSource.request.requestState === ImageKnifeRequestState.PROGRESS)) {
LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.start:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.start:" +
currentRequest.imageKnifeOption.loadSrc)
requestWithSource.request.ImageKnifeRequestCallback.showPixelMap(requestWithSource.request.componentVersion, requestWithSource.request.ImageKnifeRequestCallback.showPixelMap(requestWithSource.request.componentVersion,
ImageKnifeData.source, requestWithSource.source,ImageKnifeData.imageAnimator); imageKnifeData.source, requestWithSource.source, imageKnifeData.imageAnimator);
LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.end:" +
currentRequest.imageKnifeOption.loadSrc)
} }
if (requestWithSource.source == ImageKnifeRequestSource.SRC) { if (requestWithSource.source == ImageKnifeRequestSource.SRC) {
@ -328,16 +440,38 @@ export class ImageKnifeDispatcher {
if (requestWithSource.request.imageKnifeOption.onLoadListener && if (requestWithSource.request.imageKnifeOption.onLoadListener &&
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess) { requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess) {
// 回调请求成功 // 回调请求成功
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess(ImageKnifeData.source,ImageKnifeData); this.copyCallBackData(requestWithSource.request.getImageKnifeData(), imageKnifeData);
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadSuccess:"+currentRequest.imageKnifeOption.loadSrc) requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess(imageKnifeData.source,
imageKnifeData);
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadSuccess:" +
currentRequest.imageKnifeOption.loadSrc)
} }
} else if (requestWithSource.source == ImageKnifeRequestSource.ERROR_HOLDER) { } else if (requestWithSource.source == ImageKnifeRequestSource.ERROR_HOLDER) {
requestWithSource.request.requestState = ImageKnifeRequestState.ERROR; requestWithSource.request.requestState = ImageKnifeRequestState.ERROR;
} }
} else { } else {
if (requestWithSource.source == ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadCancel) { if (requestWithSource.source == ImageKnifeRequestSource.SRC &&
// 回调请求成功 requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadCancel) {
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed") // 回调请求取消
//设置失败回调的时间点
let callBackData = requestWithSource.request.getImageKnifeData();
if (requestJobResult.errorCallBackData && requestJobResult.errorCallBackData.timeInfo) {
requestJobResult.errorCallBackData.timeInfo.requestCancelTime = Date.now();
requestJobResult.errorCallBackData.timeInfo.requestEndTime = Date.now()
requestJobResult.errorCallBackData.phase = LoadPhase.PHASE_WILL_SHOW;
requestJobResult.errorCallBackData.code = LoadPixelMapCode.IMAGE_LOAD_CANCEL_FAILED_CODE;
if (callBackData && callBackData.timeInfo) {
requestJobResult.errorCallBackData.timeInfo.requestStartTime =
callBackData.timeInfo.requestStartTime;
requestJobResult.errorCallBackData.timeInfo.memoryCheckStartTime =
callBackData.timeInfo.memoryCheckStartTime;
requestJobResult.errorCallBackData.timeInfo.memoryCheckEndTime =
callBackData.timeInfo.memoryCheckEndTime;
}
}
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed",
requestJobResult.errorCallBackData)
} }
} }
}); });
@ -347,7 +481,7 @@ export class ImageKnifeDispatcher {
} else { } else {
LogUtil.log("error: no requestlist need to draw for key = " + memoryKey); LogUtil.log("error: no requestlist need to draw for key = " + memoryKey);
} }
LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.end:" + currentRequest.imageKnifeOption.loadSrc)
} }
@ -358,14 +492,32 @@ export class ImageKnifeDispatcher {
if (request === undefined) { if (request === undefined) {
LogUtil.log("ImageKnife_DataTime_dispatchNextJob.end:no any job") LogUtil.log("ImageKnife_DataTime_dispatchNextJob.end:no any job")
break // 队列已无任务 break // 队列已无任务
} } else if (request.requestState === ImageKnifeRequestState.PROGRESS) {
else if (request.requestState === ImageKnifeRequestState.PROGRESS) {
LogUtil.log("ImageKnife_DataTime_dispatchNextJob.start executeJob:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_dispatchNextJob.start executeJob:" + request.imageKnifeOption.loadSrc)
this.executeJob(request) this.executeJob(request)
LogUtil.log("ImageKnife_DataTime_dispatchNextJob.end executeJob:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_dispatchNextJob.end executeJob:" + request.imageKnifeOption.loadSrc)
break break
}else if (request.requestState == ImageKnifeRequestState.DESTROY && request.imageKnifeOption.onLoadListener?.onLoadCancel) { } else if (request.requestState == ImageKnifeRequestState.DESTROY &&
request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed") request.imageKnifeOption.onLoadListener?.onLoadCancel) {
//构建回调错误信息
let callBackData = request.getImageKnifeData();
let timeInfo: TimeInfo = {};
timeInfo.requestCancelTime = Date.now();
timeInfo.requestEndTime = Date.now()
timeInfo.requestCancelTime = Date.now();
if (callBackData && callBackData.timeInfo) {
timeInfo.requestStartTime = callBackData.timeInfo.requestStartTime;
timeInfo.memoryCheckStartTime = callBackData.timeInfo.memoryCheckStartTime;
timeInfo.memoryCheckEndTime = callBackData.timeInfo.memoryCheckEndTime;
}
let errorInfo: ErrorInfo = {
phase: LoadPhase.PHASE_THREAD_QUEUE,
code: LoadPixelMapCode.IMAGE_LOAD_CANCEL_FAILED_CODE,
timeInfo:timeInfo
};
request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed", errorInfo)
} }
} }
} }
@ -392,43 +544,56 @@ export class ImageKnifeDispatcher {
* @returns * @returns
*/ */
@Concurrent @Concurrent
async function requestJob(request: RequestJobRequest, requestList?: List<ImageKnifeRequestWithSource>): Promise<RequestJobResult | undefined> { async function requestJob(request: RequestJobRequest,
requestList?: List<ImageKnifeRequestWithSource>): Promise<RequestJobResult | undefined> {
LogUtil.log("ImageKnife_DataTime_requestJob.start:" + request.src + " requestSource=" + request.requestSource) LogUtil.log("ImageKnife_DataTime_requestJob.start:" + request.src + " requestSource=" + request.requestSource)
let src = typeof request.src == "number" ? request.resName != undefined ? request.resName : request.src + "" : request.src let src =
typeof request.src == "number" ? request.resName != undefined ? request.resName : request.src + "" : request.src
// 生成文件缓存key // 生成文件缓存key
let fileKey = request.engineKey.generateFileKey(src, request.signature, request.isAnimator) let fileKey = request.engineKey.generateFileKey(src, request.signature, request.isAnimator)
//定义加载信息回调数据
let callBackData: ImageKnifeData = { source: "", imageWidth: 0, imageHeight: 0 };
//定义图片各个阶段错误信息
let errorCallBackData: ErrorInfo = { code: 0, phase: LoadPhase.PHASE_LOAD }
//获取图片资源 //获取图片资源
let resBuf: ArrayBuffer let resBuf: ArrayBuffer
try { try {
LogUtil.log("ImageKnife_DataTime_requestJob.getImageArrayBuffer.start:" + request.src) LogUtil.log("ImageKnife_DataTime_requestJob.getImageArrayBuffer.start:" + request.src)
resBuf = await ImageKnifeLoader.getImageArrayBuffer(request, requestList, fileKey) resBuf = await ImageKnifeLoader.getImageArrayBuffer(request, requestList, fileKey, callBackData, errorCallBackData)
LogUtil.log("ImageKnife_DataTime_requestJob.getImageArrayBuffer.end:" + request.src) LogUtil.log("ImageKnife_DataTime_requestJob.getImageArrayBuffer.end:" + request.src)
} catch (error) { } catch (error) {
LogUtil.error("ImageKnife_DataTime_requestJob.end: getImageArrayBuffer error " + request.src + " err=" + error) LogUtil.error("ImageKnife_DataTime_requestJob.end: getImageArrayBuffer error " + request.src + " err=" + error)
return ImageKnifeLoader.makeEmptyResult(error) return ImageKnifeLoader.makeEmptyResult(error, errorCallBackData)
} }
// 获取图片类型 // 获取图片类型
let typeValue = new FileTypeUtil().getFileType(resBuf); let typeValue = new FileTypeUtil().getFileType(resBuf);
if(typeValue == null) { if (typeValue == null) {
LogUtil.log("ImageKnife_DataTime_requestJob.end: getFileType is null " + request.src) LogUtil.log("ImageKnife_DataTime_requestJob.end: getFileType is null " + request.src)
return ImageKnifeLoader.makeEmptyResult("request is not a valid image source") return ImageKnifeLoader.makeEmptyResult("request is not a valid image source", errorCallBackData)
} }
// 解析图片
LogUtil.log("ImageKnife_DataTime_requestJob.parseImage.start:" + request.src) LogUtil.log("ImageKnife_DataTime_requestJob.parseImage.start:" + request.src)
let result: RequestJobResult = await ImageKnifeLoader.parseImage(resBuf, typeValue, fileKey, request) let result: RequestJobResult =
await ImageKnifeLoader.parseImage(resBuf, typeValue, fileKey, request, callBackData, errorCallBackData)
LogUtil.log("ImageKnife_DataTime_requestJob.parseImage.end:" + request.src) LogUtil.log("ImageKnife_DataTime_requestJob.parseImage.end:" + request.src)
// 图形变化 // 图形变化
if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined && result?.pixelMap !== undefined && typeof result.pixelMap !== 'string') { if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined &&
result?.pixelMap !== undefined && typeof result.pixelMap !== 'string') {
LogUtil.log("ImageKnife_DataTime_requestJob.transform.start:" + request.src) LogUtil.log("ImageKnife_DataTime_requestJob.transform.start:" + request.src)
result.pixelMap = await request.transformation?.transform(request.context, result.pixelMap, request.componentWidth, request.componentHeight); result.pixelMap = await request.transformation?.transform(request.context, result.pixelMap, request.componentWidth,
request.componentHeight);
LogUtil.log("ImageKnife_DataTime_requestJob.transform.end:" + request.src) LogUtil.log("ImageKnife_DataTime_requestJob.transform.end:" + request.src)
} }
LogUtil.log("ImageKnife_DataTime_requestJob.end:" + request.src) LogUtil.log("ImageKnife_DataTime_requestJob.end:" + request.src)
result.callBackData = callBackData;
result.errorCallBackData = errorCallBackData;
return result return result
} }

View File

@ -14,8 +14,14 @@
*/ */
import { import {
CacheStrategy, CacheStrategy,
DecodeImageInfo,
ErrorInfo,
ImageKnifeData,
ImageKnifeRequestSource, ImageKnifeRequestSource,
ImageKnifeRequestWithSource, RequestJobRequest } from './model/ImageKnifeData'; ImageKnifeRequestWithSource,
RequestJobRequest,
TimeInfo
} from './model/ImageKnifeData';
import List from '@ohos.util.List' import List from '@ohos.util.List'
import { FileCache } from './cache/FileCache'; import { FileCache } from './cache/FileCache';
import { LogUtil } from './utils/LogUtil'; import { LogUtil } from './utils/LogUtil';
@ -28,6 +34,7 @@ import emitter from '@ohos.events.emitter';
import image from '@ohos.multimedia.image'; import image from '@ohos.multimedia.image';
import { RequestJobResult } from './model/ImageKnifeData' import { RequestJobResult } from './model/ImageKnifeData'
import util from '@ohos.util'; import util from '@ohos.util';
import { LoadPixelMapCode, LoadPhase } from './utils/Constants';
class RequestData { class RequestData {
receiveSize: number = 2000 receiveSize: number = 2000
@ -39,62 +46,104 @@ class RequestData {
*/ */
export class ImageKnifeLoader { export class ImageKnifeLoader {
static async parseImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, static async parseImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string,
request: RequestJobRequest): Promise<RequestJobResult> { request: RequestJobRequest, callBackData: ImageKnifeData, errorCallBackData: ErrorInfo): Promise<RequestJobResult> {
if(request.isAnimator) { if (request.isAnimator) {
return ImageKnifeLoader.parseForAnimatorComponent(resBuf ,typeValue ,fileKey, request) return ImageKnifeLoader.parseForAnimatorComponent(resBuf, typeValue, fileKey, request, callBackData,
errorCallBackData)
} }
if (typeValue === 'gif' || typeValue === 'webp') { if (typeValue === 'gif' || typeValue === 'webp') {
return ImageKnifeLoader.parseAnimatorImage(resBuf ,typeValue ,fileKey , request) return ImageKnifeLoader.parseAnimatorImage(resBuf, typeValue, fileKey, request, callBackData, errorCallBackData)
} else if(typeValue == "svg") { } else if (typeValue == "svg") {
return ImageKnifeLoader.parseSvgImage(resBuf ,typeValue ,fileKey , request) return ImageKnifeLoader.parseSvgImage(resBuf, typeValue, fileKey, request, callBackData, errorCallBackData)
} }
return ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request) return ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request, callBackData, errorCallBackData)
} }
static makeEmptyResult(error: string): RequestJobResult{ static makeEmptyResult(error: string, errorInfo?: ErrorInfo): RequestJobResult {
return { return {
pixelMap: undefined, pixelMap: undefined,
bufferSize: 0, bufferSize: 0,
fileKey: '', fileKey: '',
loadFail: error, loadFail: error,
errorCallBackData: errorInfo
} }
} }
static async parseNormalImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, request: RequestJobRequest):Promise<RequestJobResult> { static throwError(error: string, errorInfo: ErrorInfo, code: number, timeInfo: TimeInfo) {
errorInfo.code = code
errorInfo.timeInfo = timeInfo;
throw new Error(error);
}
static async parseNormalImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string,
request: RequestJobRequest, callBackData: ImageKnifeData, errorCallBackData: ErrorInfo): Promise<RequestJobResult> {
let resPixelmap: PixelMap | undefined = undefined let resPixelmap: PixelMap | undefined = undefined
let timeInfo: TimeInfo = callBackData.timeInfo ? callBackData.timeInfo : {}
let decodingOptions: image.DecodingOptions = { let decodingOptions: image.DecodingOptions = {
editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false, editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true :
false,
} }
let imageSource: image.ImageSource = image.createImageSource(resBuf) let imageSource: image.ImageSource = image.createImageSource(resBuf)
if (imageSource === undefined){ if (imageSource === undefined) {
errorCallBackData.phase = LoadPhase.PHASE_CREATE_SOURCE;
errorCallBackData.code = LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE;
return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed")
} }
let size = (await imageSource.getImageInfo()).size let size = (await imageSource.getImageInfo()).size
callBackData.type = typeValue;
callBackData.imageWidth = size.width;
callBackData.imageHeight = size.height;
callBackData.imageSize = resBuf.byteLength;
callBackData.timeInfo = timeInfo;
timeInfo.decodeStartTime = Date.now();
await imageSource.createPixelMap(decodingOptions) await imageSource.createPixelMap(decodingOptions)
.then((pixelmap: PixelMap) => { .then((pixelmap: PixelMap) => {
resPixelmap = pixelmap resPixelmap = pixelmap
timeInfo.decodeEndTime = Date.now();
imageSource.release() imageSource.release()
}).catch((error: BusinessError) => { }).catch((error: BusinessError) => {
imageSource.release() imageSource.release()
timeInfo.decodeEndTime = Date.now();
errorCallBackData.phase = LoadPhase.PHASE_CREATE_PIXEL_MAP;
errorCallBackData.code = LoadPixelMapCode.IMAGE_DECODE_ERROR_CODE;
errorCallBackData.timeInfo = timeInfo;
return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error)) return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error))
}) })
//获取各个pixelMap的大小
if (resPixelmap && typeof resPixelmap !== "string") {
let decodeImages: Array<DecodeImageInfo> = [];
let size = (resPixelmap as PixelMap).getImageInfoSync().size;
let decodeImage: DecodeImageInfo = {
contentWidth: size.width,
contentHeight: size.height,
contentSize: (resPixelmap as PixelMap).getPixelBytesNumber()
}
decodeImages.push(decodeImage);
callBackData.decodeImages = decodeImages;
}
return { return {
pixelMap: resPixelmap, pixelMap: resPixelmap,
bufferSize: resBuf.byteLength, bufferSize: resBuf.byteLength,
fileKey: fileKey, fileKey: fileKey,
size:size, size: size,
type:typeValue type: typeValue
}; };
} }
static async parseSvgImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, static async parseSvgImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string,
request: RequestJobRequest): Promise<RequestJobResult> { request: RequestJobRequest, callBackData: ImageKnifeData, errorCallBackData: ErrorInfo): Promise<RequestJobResult> {
let resPixelmap: PixelMap | undefined = undefined let resPixelMap: PixelMap | undefined = undefined
let timeInfo: TimeInfo = callBackData.timeInfo ? callBackData.timeInfo : {}
let imageSource: image.ImageSource = image.createImageSource(resBuf) let imageSource: image.ImageSource = image.createImageSource(resBuf)
if (imageSource === undefined){ if (imageSource === undefined) {
errorCallBackData.phase = LoadPhase.PHASE_CREATE_SOURCE;
errorCallBackData.code = LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE;
return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed")
} }
@ -110,59 +159,106 @@ export class ImageKnifeLoader {
editable: true, editable: true,
desiredSize: defaultSize desiredSize: defaultSize
}; };
callBackData.type = typeValue;
callBackData.imageWidth = size.width;
callBackData.imageHeight = size.height;
callBackData.imageSize = resBuf.byteLength;
callBackData.timeInfo = timeInfo;
timeInfo.decodeStartTime = Date.now();
await imageSource.createPixelMap(opts) await imageSource.createPixelMap(opts)
.then((pixelmap: PixelMap) => { .then((pixelMap: PixelMap) => {
resPixelmap = pixelmap resPixelMap = pixelMap
imageSource.release() imageSource.release()
}).catch((error: BusinessError) => { }).catch((error: BusinessError) => {
imageSource.release() imageSource.release()
timeInfo.decodeEndTime = Date.now();
errorCallBackData.phase = LoadPhase.PHASE_CREATE_PIXEL_MAP;
errorCallBackData.code = LoadPixelMapCode.IMAGE_DECODE_ERROR_CODE;
errorCallBackData.timeInfo = timeInfo;
return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error)) return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error))
}) })
//获取各个pixelMap的大小
if (resPixelMap && typeof resPixelMap !== "string") {
let decodeImages: Array<DecodeImageInfo> = [];
let decodeImage: DecodeImageInfo = {
contentWidth: defaultSize.width,
contentHeight: defaultSize.height,
contentSize: (resPixelMap as PixelMap).getPixelBytesNumber()
}
decodeImages.push(decodeImage);
}
return { return {
pixelMap: resPixelmap, pixelMap: resPixelMap,
bufferSize: resBuf.byteLength, bufferSize: resBuf.byteLength,
fileKey: fileKey, fileKey: fileKey,
type:typeValue type: typeValue
}; };
} }
static async parseAnimatorImage(resBuf: ArrayBuffer, typeValue: string, static async parseAnimatorImage(resBuf: ArrayBuffer, typeValue: string,
fileKey: string,request: RequestJobRequest): Promise<RequestJobResult> { fileKey: string, request: RequestJobRequest, callBackData: ImageKnifeData,
errorCallBackData: ErrorInfo): Promise<RequestJobResult> {
let imageSource: image.ImageSource = image.createImageSource(resBuf) let imageSource: image.ImageSource = image.createImageSource(resBuf)
if (imageSource === undefined){ if (imageSource === undefined) {
errorCallBackData.phase = LoadPhase.PHASE_CREATE_SOURCE;
errorCallBackData.code = LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE;
return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed")
} }
let frameCount = await imageSource.getFrameCount() let frameCount = await imageSource.getFrameCount()
let size = (await imageSource.getImageInfo()).size let size = (await imageSource.getImageInfo()).size
callBackData.type = typeValue;
callBackData.frameCount = frameCount;
callBackData.imageWidth = size.width;
callBackData.imageHeight = size.height;
callBackData.imageSize = resBuf.byteLength;
imageSource.release() imageSource.release()
if(frameCount == undefined || frameCount == 1) { if (frameCount == undefined || frameCount == 1) {
} else { } else {
let base64str = "data:image/" + typeValue + ";base64," + new util.Base64Helper().encodeToStringSync(new Uint8Array(resBuf)) let base64str =
"data:image/" + typeValue + ";base64," + new util.Base64Helper().encodeToStringSync(new Uint8Array(resBuf))
return { return {
pixelMap: base64str, pixelMap: base64str,
bufferSize: resBuf.byteLength, bufferSize: resBuf.byteLength,
fileKey: fileKey, fileKey: fileKey,
size:size, size: size,
type:typeValue type: typeValue
}; };
} }
return ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request) return ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request, callBackData, errorCallBackData)
} }
// 为AnimatorComponent解析动图 // 为AnimatorComponent解析动图
static async parseForAnimatorComponent(resBuf: ArrayBuffer, typeValue: string, fileKey: string,request: RequestJobRequest): Promise<RequestJobResult> { static async parseForAnimatorComponent(resBuf: ArrayBuffer, typeValue: string, fileKey: string,
request: RequestJobRequest, callBackData: ImageKnifeData, errorCallBackData: ErrorInfo): Promise<RequestJobResult> {
let timeInfo: TimeInfo = callBackData.timeInfo ? callBackData.timeInfo : {}
callBackData.type = typeValue;
if (typeValue === 'gif' || typeValue === 'webp') { if (typeValue === 'gif' || typeValue === 'webp') {
let imageSource: image.ImageSource = image.createImageSource(resBuf); let imageSource: image.ImageSource = image.createImageSource(resBuf);
if (imageSource === undefined){ if (imageSource === undefined) {
errorCallBackData.phase = LoadPhase.PHASE_CREATE_SOURCE;
errorCallBackData.code = LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE;
return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed")
} }
let decodingOptions: image.DecodingOptions = { let decodingOptions: image.DecodingOptions = {
editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false, editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true :
false,
} }
callBackData.imageWidth = imageSource.getImageInfoSync().size.width;
callBackData.imageHeight = imageSource.getImageInfoSync().size.height;
callBackData.imageSize = resBuf.byteLength;
let pixelMapList: Array<PixelMap> = [] let pixelMapList: Array<PixelMap> = []
let delayList: Array<number> = [] let delayList: Array<number> = []
timeInfo.decodeStartTime = Date.now();
let decodeImages: Array<DecodeImageInfo> = [];
await imageSource.createPixelMapList(decodingOptions).then(async (pixelList: Array<PixelMap>) => { await imageSource.createPixelMapList(decodingOptions).then(async (pixelList: Array<PixelMap>) => {
timeInfo.decodeEndTime = Date.now();
//sdk的api接口发生变更从.getDelayTime() 变为.getDelayTimeList() //sdk的api接口发生变更从.getDelayTime() 变为.getDelayTimeList()
await imageSource.getDelayTimeList().then(delayTimes => { await imageSource.getDelayTimeList().then(delayTimes => {
if (pixelList.length > 0) { if (pixelList.length > 0) {
@ -173,14 +269,29 @@ export class ImageKnifeLoader {
} else { } else {
delayList.push(delayTimes[delayTimes.length - 1]) delayList.push(delayTimes[delayTimes.length - 1])
} }
//获取各个pixelMap的大小
let size = pixelList[i].getImageInfoSync().size
let decodeImage: DecodeImageInfo = {
contentWidth: size.width,
contentHeight: size.height,
contentSize: pixelList[i].getPixelBytesNumber()
}
decodeImages.push(decodeImage);
} }
imageSource.release(); imageSource.release();
} }
}) })
}).catch((error: BusinessError) => { }).catch((error: BusinessError) => {
timeInfo.decodeEndTime = Date.now();
imageSource.release() imageSource.release()
errorCallBackData.phase = LoadPhase.PHASE_CREATE_PIXEL_MAP;
errorCallBackData.code = LoadPixelMapCode.IMAGE_DECODE_ERROR_CODE;
errorCallBackData.timeInfo = timeInfo;
return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error)) return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error))
}) })
callBackData.timeInfo = timeInfo;
callBackData.decodeImages = decodeImages;
errorCallBackData.timeInfo = timeInfo;
return { return {
pixelMap: "", pixelMap: "",
bufferSize: resBuf.byteLength, bufferSize: resBuf.byteLength,
@ -190,47 +301,59 @@ export class ImageKnifeLoader {
delayList delayList
} }
} else { } else {
callBackData.timeInfo = timeInfo;
errorCallBackData.phase = LoadPhase.PHASE_PARSE_IAMGE;
errorCallBackData.timeInfo = timeInfo;
errorCallBackData.code = LoadPixelMapCode.IMAGE_FORMAT_ERROR_CODE
return ImageKnifeLoader.makeEmptyResult("ImageKnifeAnimatorComponent组件仅支持动态图") return ImageKnifeLoader.makeEmptyResult("ImageKnifeAnimatorComponent组件仅支持动态图")
} }
} }
// 获取图片资源 // 获取图片资源
static async getImageArrayBuffer(request: RequestJobRequest, requestList: List<ImageKnifeRequestWithSource> | undefined,fileKey:string): Promise<ArrayBuffer> { static async getImageArrayBuffer(request: RequestJobRequest,
requestList: List<ImageKnifeRequestWithSource> | undefined,
fileKey: string, callBackData: ImageKnifeData, errorCallBackData: ErrorInfo): Promise<ArrayBuffer> {
let resBuf: ArrayBuffer | undefined let resBuf: ArrayBuffer | undefined
let timeInfo: TimeInfo = callBackData.timeInfo ? callBackData.timeInfo : {};
// 判断自定义下载 // 判断自定义下载
if (request.customGetImage !== undefined && request.requestSource == ImageKnifeRequestSource.SRC && typeof request.src == "string") { if (request.customGetImage !== undefined && request.requestSource == ImageKnifeRequestSource.SRC &&
typeof request.src == "string") {
// 先从文件缓存获取 // 先从文件缓存获取
resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder) timeInfo.diskCheckStartTime = Date.now();
resBuf = FileCache.getFileCacheByFile(request.context, fileKey, request.fileCacheFolder)
timeInfo.diskCheckEndTime = Date.now();
if (resBuf === undefined) { if (resBuf === undefined) {
LogUtil.log("start customGetImage src=" + request.src) LogUtil.log("start customGetImage src=" + request.src)
try { try {
resBuf = await request.customGetImage(request.context, request.src) resBuf = await request.customGetImage(request.context, request.src)
LogUtil.log("end customGetImage src=" + request.src) LogUtil.log("end customGetImage src=" + request.src)
} catch (err) { } catch (err) {
throw new Error('customGetImage loadFile failed! err = ' + err) ImageKnifeLoader.throwError('customGetImage loadFile failed! err = ' + err,
errorCallBackData, LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE, timeInfo)
} }
if (resBuf === undefined) { if (resBuf === undefined) {
throw new Error('customGetImage loadFile failed!') ImageKnifeLoader.throwError('customGetImage loadFile failed!',
errorCallBackData, LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE, timeInfo)
} }
// 保存文件缓存 // 保存文件缓存
if (request.writeCacheStrategy !== CacheStrategy.Memory) { if (resBuf && request.writeCacheStrategy !== CacheStrategy.Memory) {
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:" + request.src) LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:" + request.src)
FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf, request.fileCacheFolder) FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf, request.fileCacheFolder)
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:" + request.src) LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:" + request.src)
} }
} }
} } else {
else {
if (typeof request.src === 'string') { if (typeof request.src === 'string') {
if (request.src.indexOf("http://") == 0 || request.src.indexOf("https://") == 0) { //从网络下载 if (request.src.indexOf("http://") == 0 || request.src.indexOf("https://") == 0) { //从网络下载
// 先从文件缓存获取 // 先从文件缓存获取
resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder) timeInfo.diskCheckStartTime = Date.now()
if (resBuf !== undefined){ resBuf = FileCache.getFileCacheByFile(request.context, fileKey, request.fileCacheFolder)
timeInfo.diskCheckEndTime = Date.now()
if (resBuf !== undefined) {
LogUtil.log("success get image from filecache for key = " + fileKey + " src = " + request.src) LogUtil.log("success get image from filecache for key = " + fileKey + " src = " + request.src)
} } else if (request.onlyRetrieveFromCache != true) {
else if (request.onlyRetrieveFromCache != true) {
LogUtil.log("HttpDownloadClient.start:" + request.src) LogUtil.log("HttpDownloadClient.start:" + request.src)
timeInfo.netRequestStartTime = Date.now();
let httpRequest = http.createHttp(); let httpRequest = http.createHttp();
let progress: number = 0 let progress: number = 0
let arrayBuffers = new Array<ArrayBuffer>() let arrayBuffers = new Array<ArrayBuffer>()
@ -246,6 +369,11 @@ export class ImageKnifeLoader {
} }
httpRequest.on("dataReceive", (data: ArrayBuffer) => { httpRequest.on("dataReceive", (data: ArrayBuffer) => {
arrayBuffers.push(data) arrayBuffers.push(data)
//获取http下载的字节数
if (callBackData.bufSize == undefined) {
callBackData.bufSize = 0;
}
callBackData.bufSize += data.byteLength;
}); });
if (request.isWatchProgress) { if (request.isWatchProgress) {
@ -258,10 +386,11 @@ export class ImageKnifeLoader {
if (requestList === undefined) { if (requestList === undefined) {
// 子线程 // 子线程
emitter.emit(Constants.PROGRESS_EMITTER + request.memoryKey, { data: { "value": progress } }) emitter.emit(Constants.PROGRESS_EMITTER + request.memoryKey, { data: { "value": progress } })
}else { } else {
// 主线程请求 // 主线程请求
requestList!.forEach((requestWithSource: ImageKnifeRequestWithSource) => { requestList!.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) { if (requestWithSource.request.imageKnifeOption.progressListener !== undefined &&
requestWithSource.source === ImageKnifeRequestSource.SRC) {
requestWithSource.request.imageKnifeOption.progressListener(progress) requestWithSource.request.imageKnifeOption.progressListener(progress)
} }
}) })
@ -281,42 +410,59 @@ export class ImageKnifeLoader {
}); });
await promise.then((data: number) => { await promise.then((data: number) => {
errorCallBackData.phase = LoadPhase.PHASE_NET
errorCallBackData.httpCode = data;
timeInfo.netRequestEndTime = Date.now();
if (data == 200 || data == 206 || data == 204) { if (data == 200 || data == 206 || data == 204) {
resBuf = combineArrayBuffers(arrayBuffers) resBuf = combineArrayBuffers(arrayBuffers)
} else { } else {
throw new Error("HttpDownloadClient has error, http code =" + JSON.stringify(data)) ImageKnifeLoader.throwError("HttpDownloadClient has error, http code =" + JSON.stringify(data),
errorCallBackData, LoadPixelMapCode.IMAGE_HTTPS_LOAD_FAILED_CODE, timeInfo)
} }
}).catch((err: Error) => { }).catch((err: Error) => {
throw new Error("HttpDownloadClient download ERROR : err = " + JSON.stringify(err)) timeInfo.netRequestEndTime = Date.now();
ImageKnifeLoader.throwError("HttpDownloadClient download ERROR : err = " + JSON.stringify(err),
errorCallBackData, LoadPixelMapCode.IMAGE_HTTPS_LOAD_FAILED_CODE, timeInfo)
}); });
LogUtil.log("HttpDownloadClient.end:" + request.src) LogUtil.log("HttpDownloadClient.end:" + request.src)
// 保存文件缓存 // 保存文件缓存
if (resBuf !== undefined && request.writeCacheStrategy !== CacheStrategy.Memory) { if (resBuf !== undefined && request.writeCacheStrategy !== CacheStrategy.Memory) {
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:"+request.src) LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:" + request.src)
FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf , request.fileCacheFolder) FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf, request.fileCacheFolder)
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:"+request.src) LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:" + request.src)
} }
} } else {
else { ImageKnifeLoader.throwError('onlyRetrieveFromCache,do not fetch image src = ' + request.src,
throw new Error('onlyRetrieveFromCache,do not fetch image src = ' + request.src) errorCallBackData, LoadPixelMapCode.IMAGE_RETRIEVE_CACHE_CODE, timeInfo)
} }
} else if (request.src.startsWith('datashare://') || request.src.startsWith('file://')) { } else if (request.src.startsWith('datashare://') || request.src.startsWith('file://')) {
errorCallBackData.phase = LoadPhase.PHASE_SHARE_FILE
await fs.open(request.src, fs.OpenMode.READ_ONLY).then(async (file) => { await fs.open(request.src, fs.OpenMode.READ_ONLY).then(async (file) => {
await fs.stat(file.fd).then(async (stat) =>{ await fs.stat(file.fd).then(async (stat) => {
let buf = new ArrayBuffer(stat.size); let buf = new ArrayBuffer(stat.size);
await fs.read(file.fd, buf).then((readLen) => { await fs.read(file.fd, buf).then((readLen) => {
resBuf = buf; resBuf = buf;
fs.closeSync(file.fd); fs.closeSync(file.fd);
}).catch((err:BusinessError) => { }).catch((err: BusinessError) => {
throw new Error('LoadDataShareFileClient fs.read err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code) ImageKnifeLoader.throwError('LoadDataShareFileClient fs.read err happened uri=' + request.src +
" err.msg=" +
err?.message + " err.code=" + err?.code,
errorCallBackData, LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE, timeInfo)
}) })
}).catch((err:BusinessError) => { }).catch((err: BusinessError) => {
throw new Error('LoadDataShareFileClient fs.stat err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code) ImageKnifeLoader.throwError('LoadDataShareFileClient fs.stat err happened uri=' + request.src +
" err.msg=" +
err?.message + " err.code=" + err?.code,
errorCallBackData, LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE, timeInfo)
}) })
}).catch((err:BusinessError) => { }).catch((err: BusinessError) => {
throw new Error('LoadDataShareFileClient fs.open err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code) ImageKnifeLoader.throwError('LoadDataShareFileClient fs.open err happened uri=' + request.src +
" err.msg=" +
err?.message + " err.code=" + err?.code,
errorCallBackData, LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE, timeInfo)
}) })
} else { //从本地文件获取 } else { //从本地文件获取
errorCallBackData.phase = LoadPhase.PHASE_LOCAL_FILE
try { try {
let stat = fs.statSync(request.src); let stat = fs.statSync(request.src);
if (stat.size > 0) { if (stat.size > 0) {
@ -326,20 +472,22 @@ export class ImageKnifeLoader {
fs.closeSync(file); fs.closeSync(file);
} }
} catch (err) { } catch (err) {
throw new Error(err) ImageKnifeLoader.throwError(err,
errorCallBackData, LoadPixelMapCode.IMAGE_LOAD_LOCAL_FILE_FAILED_CODE, timeInfo)
} }
} }
} else if (typeof request.src == "number") { //从资源文件获取 } else if (typeof request.src == "number") { //从资源文件获取
let manager = request.context.createModuleContext(request.moduleName).resourceManager let manager = request.context.createModuleContext(request.moduleName).resourceManager
if (resBuf == undefined && request.onlyRetrieveFromCache != true && request.requestSource == ImageKnifeRequestSource.SRC) { if (resBuf == undefined && request.onlyRetrieveFromCache != true &&
if(request.src == -1) { request.requestSource == ImageKnifeRequestSource.SRC) {
if (request.src == -1) {
let resName = request.resName as string let resName = request.resName as string
resBuf = (await manager.getMediaByName(resName.substring(10))).buffer as ArrayBuffer resBuf = (await manager.getMediaByName(resName.substring(10))).buffer as ArrayBuffer
} else { } else {
resBuf = manager.getMediaContentSync(request.src).buffer as ArrayBuffer resBuf = manager.getMediaContentSync(request.src).buffer as ArrayBuffer
} }
} else if (resBuf == undefined && request.requestSource != ImageKnifeRequestSource.SRC) { } else if (resBuf == undefined && request.requestSource != ImageKnifeRequestSource.SRC) {
if(request.src == -1) { if (request.src == -1) {
let resName = request.resName as string let resName = request.resName as string
resBuf = (await manager.getMediaByName(resName.substring(10))).buffer as ArrayBuffer resBuf = (await manager.getMediaByName(resName.substring(10))).buffer as ArrayBuffer
} else { } else {
@ -349,9 +497,13 @@ export class ImageKnifeLoader {
} }
} }
if (resBuf === undefined){ if (resBuf === undefined) {
errorCallBackData.code = LoadPixelMapCode.IMAGE_LOAD_FAILED_CODE
errorCallBackData.timeInfo = timeInfo;
throw new Error('getImageArrayBuffer undefined') throw new Error('getImageArrayBuffer undefined')
} }
callBackData.timeInfo = timeInfo;
errorCallBackData.timeInfo = timeInfo;
return resBuf return resBuf
} }
} }

View File

@ -53,23 +53,28 @@ export struct ImageKnifeComponent {
aboutToAppear(): void { aboutToAppear(): void {
this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
if(this.syncLoad) { //针对部分消息列表最新消息的图片闪动问题建议使用同步方式在aboutToAppear时加载图片 if (this.syncLoad) { //针对部分消息列表最新消息的图片闪动问题建议使用同步方式在aboutToAppear时加载图片
let engineKey: IEngineKey = new DefaultEngineKey(); let engineKey: IEngineKey = new DefaultEngineKey();
let memoryCacheSrc: ImageKnifeData | undefined = ImageKnife.getInstance() let memoryCacheSrc: ImageKnifeData | undefined = ImageKnife.getInstance()
.loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,this.imageKnifeOption)) .loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,
if (memoryCacheSrc !== undefined){ this.imageKnifeOption))
LogUtil.log("aboutToAppear success load loadSrc from memory cache for loadSrc = "+ this.imageKnifeOption.loadSrc) if (memoryCacheSrc !== undefined) {
LogUtil.log("aboutToAppear success load loadSrc from memory cache for loadSrc = " +
this.imageKnifeOption.loadSrc)
this.pixelMap = memoryCacheSrc.source; this.pixelMap = memoryCacheSrc.source;
}else{ } else {
LogUtil.log("aboutToAppear fail load loadSrc from memory cache for loadSrc = "+ this.imageKnifeOption.loadSrc) LogUtil.log("aboutToAppear fail load loadSrc from memory cache for loadSrc = " + this.imageKnifeOption.loadSrc)
if (this.imageKnifeOption.placeholderSrc !== undefined){ if (this.imageKnifeOption.placeholderSrc !== undefined) {
let memoryCachePlace: ImageKnifeData | undefined = ImageKnife.getInstance() let memoryCachePlace: ImageKnifeData | undefined = ImageKnife.getInstance()
.loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.placeholderSrc!,ImageKnifeRequestSource.PLACE_HOLDER,this.imageKnifeOption)) .loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.placeholderSrc!,
if (memoryCachePlace !== undefined){ ImageKnifeRequestSource.PLACE_HOLDER, this.imageKnifeOption))
LogUtil.log("aboutToAppear success load placeholderSrc from memory cache for placeholderSrc = " + this.imageKnifeOption.placeholderSrc) if (memoryCachePlace !== undefined) {
LogUtil.log("aboutToAppear success load placeholderSrc from memory cache for placeholderSrc = " +
this.imageKnifeOption.placeholderSrc)
this.pixelMap = memoryCachePlace.source; this.pixelMap = memoryCachePlace.source;
}else{ } else {
LogUtil.log("aboutToAppear fail load placeholderSrc from memory cache for placeholderSrc = " + this.imageKnifeOption.placeholderSrc) LogUtil.log("aboutToAppear fail load placeholderSrc from memory cache for placeholderSrc = " +
this.imageKnifeOption.placeholderSrc)
} }
} }
} }
@ -87,7 +92,7 @@ export struct ImageKnifeComponent {
/** /**
* 对已DESTROY的组件不再发起请求 * 对已DESTROY的组件不再发起请求
*/ */
private clearLastRequest(){ private clearLastRequest() {
if (this.request !== undefined) { if (this.request !== undefined) {
this.request.requestState = ImageKnifeRequestState.DESTROY this.request.requestState = ImageKnifeRequestState.DESTROY
this.request = undefined this.request = undefined
@ -104,7 +109,7 @@ export struct ImageKnifeComponent {
.syncLoad(this.syncLoad) .syncLoad(this.syncLoad)
.draggable(false) .draggable(false)
.onComplete(this.imageKnifeOption.onComplete) .onComplete(this.imageKnifeOption.onComplete)
.onSizeChange((oldValue:SizeOptions, newValue:SizeOptions) => { .onSizeChange((oldValue: SizeOptions, newValue: SizeOptions) => {
this.currentWidth = newValue.width as number this.currentWidth = newValue.width as number
this.currentHeight = newValue.height as number this.currentHeight = newValue.height as number
this.lastWidth = oldValue.width as number this.lastWidth = oldValue.width as number
@ -138,7 +143,8 @@ export struct ImageKnifeComponent {
height, height,
this.componentVersion, this.componentVersion,
{ {
showPixelMap: async (version: number, pixelMap: PixelMap | string, requestSource: ImageKnifeRequestSource) => { showPixelMap: async (version: number, pixelMap: PixelMap | string,
requestSource: ImageKnifeRequestSource) => {
if (version !== this.componentVersion) { if (version !== this.componentVersion) {
return //针对reuse场景不显示历史图片 return //针对reuse场景不显示历史图片
} }
@ -154,10 +160,14 @@ export struct ImageKnifeComponent {
this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
} else if (requestSource == ImageKnifeRequestSource.PLACE_HOLDER) { } else if (requestSource == ImageKnifeRequestSource.PLACE_HOLDER) {
this.objectFit = this.objectFit =
this.imageKnifeOption.placeholderObjectFit === undefined ? (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : this.imageKnifeOption.placeholderObjectFit this.imageKnifeOption.placeholderObjectFit === undefined ?
(this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) :
this.imageKnifeOption.placeholderObjectFit
} else { } else {
this.objectFit = this.objectFit =
this.imageKnifeOption.errorholderObjectFit === undefined ? (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : this.imageKnifeOption.errorholderObjectFit this.imageKnifeOption.errorholderObjectFit === undefined ?
(this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) :
this.imageKnifeOption.errorholderObjectFit
} }
} }
}) })

View File

@ -20,12 +20,56 @@ import common from '@ohos.app.ability.common';
import { Size } from '@kit.ArkUI' import { Size } from '@kit.ArkUI'
export interface ImageKnifeData { export interface ImageKnifeData {
source: PixelMap | string, source: PixelMap | string, // url
imageWidth: number, imageWidth: number, // 原始宽高大小
imageHeight: number, imageHeight: number,
type?:string, imageSize?: number,
imageAnimator?: Array<ImageFrameInfo> type?: string,
imageAnimator?: Array<ImageFrameInfo>,
bufSize?: number, // 网络请求字节数
componentWidth?: number //组件宽高
componentHeight?: number
frameCount ?: number // 帧
decodeImages?: Array<DecodeImageInfo> //Image组件或者ImageAnimator组件可以加载一张或者多张
timeInfo?: TimeInfo // 加载图片的各个时间点
} }
/**
* 解码后的图片的size
*/
export interface DecodeImageInfo {
contentWidth ?: number // 解码后宽高
contentHeight?: number
contentSize ?: number // 大小
}
/**
* 加载的错误信息
*/
export interface ErrorInfo {
phase: string, //图片加载阶段信息,如:网络加载阶段,缓存获取阶段及其解码阶段等
code: number,
timeInfo?: TimeInfo,
httpCode?: number
}
/**
* lru检查时间点
*/
export interface TimeInfo {
requestStartTime?: number,
requestEndTime?: number,
requestCancelTime?: number,
memoryCheckStartTime?: number,
memoryCheckEndTime?: number,
diskCheckStartTime?: number,
diskCheckEndTime?: number,
netRequestStartTime?: number,
netRequestEndTime?: number,
decodeStartTime?: number,
decodeEndTime?: number,
}
/** /**
* onComplete成功回调 * onComplete成功回调
*/ */
@ -40,6 +84,7 @@ export interface EventImage {
contentOffsetX: number; contentOffsetX: number;
contentOffsetY: number; contentOffsetY: number;
} }
/** /**
* 缓存策略 * 缓存策略
*/ */
@ -75,10 +120,12 @@ export interface RequestJobResult {
bufferSize: number bufferSize: number
fileKey: string fileKey: string
loadFail?: string, loadFail?: string,
size?:Size, size?: Size,
type?: string, type?: string,
pixelMapList?:Array<PixelMap>, pixelMapList?: Array<PixelMap>,
delayList?: Array<number> delayList?: Array<number>,
callBackData?: ImageKnifeData,
errorCallBackData?: ErrorInfo
} }
/** /**
@ -102,7 +149,7 @@ export interface RequestJobRequest {
memoryKey: string memoryKey: string
fileCacheFolder: string, fileCacheFolder: string,
isAnimator?: boolean, isAnimator?: boolean,
moduleName?:string, moduleName?: string,
resName?: string resName?: string
} }

View File

@ -14,7 +14,7 @@
*/ */
import taskpool from '@ohos.taskpool'; import taskpool from '@ohos.taskpool';
import common from '@ohos.app.ability.common' import common from '@ohos.app.ability.common'
import { CacheStrategy, ImageKnifeData,EventImage } from './ImageKnifeData'; import { CacheStrategy, ImageKnifeData, EventImage, ErrorInfo } from './ImageKnifeData';
import { PixelMapTransformation } from '../transform/PixelMapTransformation'; import { PixelMapTransformation } from '../transform/PixelMapTransformation';
import { drawing } from '@kit.ArkGraphics2D'; import { drawing } from '@kit.ArkGraphics2D';
@ -22,16 +22,18 @@ export interface HeaderOptions {
key: string; key: string;
value: Object; value: Object;
} }
interface AnimatorType { interface AnimatorType {
state?: AnimationStatus state?: AnimationStatus
iterations?: number iterations?: number
reverse?: boolean reverse?: boolean
onStart?:()=>void onStart?: () => void
onFinish?:()=>void onFinish?: () => void
onPause?:()=>void onPause?: () => void
onCancel?:()=>void onCancel?: () => void
onRepeat?:()=>void onRepeat?: () => void
} }
@ObservedV2 @ObservedV2
export class AnimatorOption { export class AnimatorOption {
@Trace @Trace
@ -41,16 +43,17 @@ export class AnimatorOption {
@Trace @Trace
reverse?: boolean = false reverse?: boolean = false
@Trace @Trace
onStart?:()=>void onStart?: () => void
@Trace @Trace
onFinish?:()=>void onFinish?: () => void
@Trace @Trace
onPause?:()=>void onPause?: () => void
@Trace @Trace
onCancel?:()=>void onCancel?: () => void
@Trace @Trace
onRepeat?:()=>void onRepeat?: () => void
constructor(option?:AnimatorType) {
constructor(option?: AnimatorType) {
this.state = option?.state this.state = option?.state
this.iterations = option?.iterations this.iterations = option?.iterations
this.reverse = option?.reverse this.reverse = option?.reverse
@ -61,6 +64,7 @@ export class AnimatorOption {
this.onRepeat = option?.onRepeat this.onRepeat = option?.onRepeat
} }
} }
interface ImageOption { interface ImageOption {
// 主图资源 // 主图资源
loadSrc: string | PixelMap | Resource loadSrc: string | PixelMap | Resource
@ -69,6 +73,7 @@ interface ImageOption {
// 失败占位图 // 失败占位图
errorholderSrc?: string | PixelMap | Resource errorholderSrc?: string | PixelMap | Resource
headerOption?: Array<HeaderOptions>; headerOption?: Array<HeaderOptions>;
// 自定义缓存关键字 // 自定义缓存关键字
signature?: string signature?: string
// 主图填充效果 // 主图填充效果
@ -88,9 +93,10 @@ interface ImageOption {
progressListener?: (progress: number) => void; progressListener?: (progress: number) => void;
transformation?: PixelMapTransformation transformation?: PixelMapTransformation
onLoadListener?: OnLoadCallBack | undefined; onLoadListener?: OnLoadCallBack | undefined;
onComplete?:(event:EventImage | undefined) => void onComplete?: (event: EventImage | undefined) => void
drawingColorFilter?: ColorFilter | drawing.ColorFilter drawingColorFilter?: ColorFilter | drawing.ColorFilter
} }
@ObservedV2 @ObservedV2
export class ImageKnifeOption { export class ImageKnifeOption {
// 主图资源 // 主图资源
@ -119,9 +125,10 @@ export class ImageKnifeOption {
progressListener?: (progress: number) => void; progressListener?: (progress: number) => void;
@Trace transformation?: PixelMapTransformation @Trace transformation?: PixelMapTransformation
onLoadListener?: OnLoadCallBack | undefined; onLoadListener?: OnLoadCallBack | undefined;
onComplete?:(event:EventImage | undefined) => void onComplete?: (event: EventImage | undefined) => void
drawingColorFilter?: ColorFilter | drawing.ColorFilter drawingColorFilter?: ColorFilter | drawing.ColorFilter | ResourceColor
constructor(option?:ImageOption) {
constructor(option?: ImageOption) {
this.loadSrc = option?.loadSrc == undefined ? "" : option?.loadSrc this.loadSrc = option?.loadSrc == undefined ? "" : option?.loadSrc
this.placeholderSrc = option?.placeholderSrc this.placeholderSrc = option?.placeholderSrc
this.errorholderSrc = option?.errorholderSrc this.errorholderSrc = option?.errorholderSrc
@ -149,13 +156,14 @@ export class ImageKnifeOption {
*/ */
export interface OnLoadCallBack { export interface OnLoadCallBack {
// 请求开始 // 请求开始
onLoadStart?: () => void; onLoadStart?: (imageKnifeData?: ImageKnifeData) => void;
// 请求成功 // 请求成功
onLoadSuccess?: (data: string | PixelMap | undefined, imageKnifeData: ImageKnifeData) => void; onLoadSuccess?: (data: string | PixelMap | undefined, imageKnifeData: ImageKnifeData) => void;
// 请求结束 // 请求结束
onLoadFailed?: (err: string) => void; onLoadFailed?: (err: string, errorInfo?: ErrorInfo) => void;
// 请求取消 // 请求取消
onLoadCancel?: (reason: string) => void; onLoadCancel?: (reason: string, errorInfo?: ErrorInfo) => void;
} }

View File

@ -14,7 +14,7 @@
*/ */
import { ImageKnifeOption } from './ImageKnifeOption'; import { ImageKnifeOption } from './ImageKnifeOption';
import common from '@ohos.app.ability.common'; import common from '@ohos.app.ability.common';
import { ImageKnifeRequestSource } from './ImageKnifeData'; import { ImageKnifeData, ImageKnifeRequestSource } from './ImageKnifeData';
export class ImageKnifeRequest { export class ImageKnifeRequest {
@ -26,13 +26,15 @@ export class ImageKnifeRequest {
context: common.UIAbilityContext context: common.UIAbilityContext
ImageKnifeRequestCallback: ImageKnifeRequestCallback ImageKnifeRequestCallback: ImageKnifeRequestCallback
componentVersion: number = 0 componentVersion: number = 0
headers: Map<string,Object> = new Map<string,Object>() headers: Map<string, Object> = new Map<string, Object>()
private imageCallBackData: ImageKnifeData | undefined = undefined;
constructor(option: ImageKnifeOption, constructor(option: ImageKnifeOption,
uIAbilityContext: common.UIAbilityContext, uIAbilityContext: common.UIAbilityContext,
width: number, width: number,
height: number, height: number,
version: number, version: number,
ImageKnifeRequestCallback: ImageKnifeRequestCallback) { ImageKnifeRequestCallback: ImageKnifeRequestCallback) {
this.imageKnifeOption = option this.imageKnifeOption = option
this.context = uIAbilityContext this.context = uIAbilityContext
this.componentWidth = width this.componentWidth = width
@ -40,6 +42,7 @@ export class ImageKnifeRequest {
this.componentVersion = version this.componentVersion = version
this.ImageKnifeRequestCallback = ImageKnifeRequestCallback this.ImageKnifeRequestCallback = ImageKnifeRequestCallback
} }
// RequestOption调用header对于的方法 // RequestOption调用header对于的方法
addHeader(key: string, value: Object) { addHeader(key: string, value: Object) {
this.headers.set(key, value); this.headers.set(key, value);
@ -53,6 +56,14 @@ export class ImageKnifeRequest {
} }
}) })
} }
setImageKnifeData(data: ImageKnifeData) {
this.imageCallBackData = data;
}
getImageKnifeData(): ImageKnifeData | undefined {
return this.imageCallBackData
}
} }
export enum ImageKnifeRequestState { export enum ImageKnifeRequestState {
@ -64,5 +75,6 @@ export enum ImageKnifeRequestState {
export interface ImageKnifeRequestCallback { export interface ImageKnifeRequestCallback {
showPixelMap: (version: number, pixelMap: PixelMap | string , requestSource: ImageKnifeRequestSource,imageAnimator?: Array<ImageFrameInfo>) => void; showPixelMap: (version: number, pixelMap: PixelMap | string, requestSource: ImageKnifeRequestSource,
imageAnimator?: Array<ImageFrameInfo>) => void;
} }

View File

@ -15,3 +15,53 @@
export class Constants { export class Constants {
public static PROGRESS_EMITTER: string = "progressEmitter" public static PROGRESS_EMITTER: string = "progressEmitter"
} }
/**
* 图片加载的code
*/
export enum LoadPixelMapCode {
// createImageSource error code
IMAGE_SOURCE_ERROR_CODE = 100001,
// createPixelMap error code
IMAGE_DECODE_ERROR_CODE = 100002,
//ImageKnifeAnimatorComponent组件仅支持动态图 code
IMAGE_FORMAT_ERROR_CODE = 100003,
//load failed code
IMAGE_LOAD_FAILED_CODE = 100004,
//自定义下载失败 code
IMAGE_CUSTOM_LOAD_FAILED_CODE = 100005,
// http请求失败 code
IMAGE_HTTPS_LOAD_FAILED_CODE = 100006,
//设置onlyRetrieveFromCache 导致的加载失败的code
IMAGE_RETRIEVE_CACHE_CODE = 100007,
//加载共享图片失败
IMAGE_LOAD_SHARE_FILE_FAILED_CODE = 100008,
//加载本地文件图片失败
IMAGE_LOAD_LOCAL_FILE_FAILED_CODE = 100009,
// 取消请求加载code
IMAGE_LOAD_CANCEL_FAILED_CODE = 1000010
}
/**
* 图片加载的各个阶段
*/
export enum LoadPhase {
// 图片加载阶段
PHASE_LOAD = "load",
// 网络请求下载阶段
PHASE_NET = "net",
// createPixelMap 阶段
PHASE_CREATE_SOURCE = "createImageSource",
//createPixelMap 阶段
PHASE_CREATE_PIXEL_MAP = "createPixelMap",
//请求队列排队阶段
PHASE_THREAD_QUEUE = "thread_queue",
//图片解析阶段
PHASE_PARSE_IAMGE = "parseImage",
//加载解析datashare:// 或者file:// 阶段
PHASE_SHARE_FILE = "datashare_or_file",
//加载解析本地文件阶段
PHASE_LOCAL_FILE = "load_local_file",
//图片加载解析完成,即将显示的阶段
PHASE_WILL_SHOW = "will_show",
}