!458 优化ImageKnifeLoader类的getImageArrayBuffer方法
Merge pull request !458 from 刘海康/master
This commit is contained in:
commit
933cc284ec
|
@ -214,9 +214,7 @@ export class ImageKnifeDispatcher {
|
||||||
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) {
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ import { FileTypeUtil } from './utils/FileTypeUtil';
|
||||||
import { DownsampleStrategy } from './downsampling/DownsampleStartegy';
|
import { DownsampleStrategy } from './downsampling/DownsampleStartegy';
|
||||||
import { Downsampler } from './downsampling/Downsampler';
|
import { Downsampler } from './downsampling/Downsampler';
|
||||||
import { common } from '@kit.AbilityKit';
|
import { common } from '@kit.AbilityKit';
|
||||||
|
import { ImageLoaderFactory } from './loaderStrategy/ImageLoaderFactory';
|
||||||
|
|
||||||
class RequestData {
|
class RequestData {
|
||||||
receiveSize: number = 2000
|
receiveSize: number = 2000
|
||||||
|
@ -445,178 +446,14 @@ export class ImageKnifeLoader {
|
||||||
errorInfo: error
|
errorInfo: error
|
||||||
};
|
};
|
||||||
|
|
||||||
// 判断自定义下载
|
const loaderStrategy = ImageLoaderFactory.getLoaderStrategy(request);
|
||||||
if (request.customGetImage !== undefined && request.requestSource == ImageKnifeRequestSource.SRC && typeof request.src == 'string') {
|
if (loaderStrategy) {
|
||||||
// 先从文件缓存获取
|
await loaderStrategy.loadImage(request, requestList, fileKey, callBackData, callBackTimeInfo);
|
||||||
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_CUSTOM_LOAD)
|
} else {
|
||||||
callBackTimeInfo.diskCheckStartTime = Date.now();
|
loadError = `Unsupported request type: ${request.src}`;
|
||||||
resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder)
|
|
||||||
callBackTimeInfo.diskCheckEndTime = Date.now();
|
|
||||||
if (resBuf === undefined) {
|
|
||||||
LogUtil.log('start customGetImage src=' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
|
|
||||||
const headerObj: Record<string, Object> = ImageKnifeLoader.getHeaderObj(request)
|
|
||||||
try {
|
|
||||||
request.customGetImage(request.context, request.src, headerObj)
|
|
||||||
.then((buffer)=>{
|
|
||||||
if(buffer != undefined) {
|
|
||||||
ImageKnifeLoader.FileCacheParseImage(request,buffer,fileKey,callBackData)
|
|
||||||
} else {
|
|
||||||
loadError = 'customGetImage loadFail undefined'
|
|
||||||
ImageKnifeLoader.makeEmptyResult(request,loadError, ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CUSTOM_LOAD, LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE))
|
|
||||||
}
|
|
||||||
}).catch((err:string)=>{
|
|
||||||
ImageKnifeLoader.makeEmptyResult(request,err, ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CUSTOM_LOAD, LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE))
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
loadError = 'customGetImage loadFail failed'
|
|
||||||
ImageKnifeLoader.makeEmptyResult(request,loadError + e, ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CUSTOM_LOAD, LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE))
|
|
||||||
}
|
|
||||||
LogUtil.log('end customGetImage src=' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (typeof request.src === 'string') {
|
|
||||||
if (request.src.indexOf('http://') == 0 || request.src.indexOf('https://') == 0) { //从网络下载
|
|
||||||
// 先从文件缓存获取
|
|
||||||
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_NET)
|
|
||||||
LogUtil.log('get fileCache buffer start:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
|
|
||||||
callBackTimeInfo.diskCheckStartTime = Date.now()
|
|
||||||
resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder)
|
|
||||||
callBackTimeInfo.diskCheckEndTime = Date.now()
|
|
||||||
LogUtil.log('get fileCache buffer end:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
|
|
||||||
if (resBuf !== undefined){
|
|
||||||
LogUtil.log('success get image from filecache for key = ' + fileKey + ' src = ' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
|
|
||||||
}
|
|
||||||
else if (request.onlyRetrieveFromCache != true) {
|
|
||||||
LogUtil.log('HttpDownloadClient.start:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
|
|
||||||
callBackTimeInfo.netRequestStartTime = Date.now();
|
|
||||||
let httpRequest = http.createHttp();
|
|
||||||
let progress: number = 0
|
|
||||||
let arrayBuffers:ArrayBuffer[] = []
|
|
||||||
const headerObj: Record<string, Object> = ImageKnifeLoader.getHeaderObj(request)
|
|
||||||
httpRequest.on('dataReceive', (data: ArrayBuffer) => {
|
|
||||||
arrayBuffers.push(data)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (request.isWatchProgress) {
|
|
||||||
httpRequest.on('dataReceiveProgress', (data: RequestData) => {
|
|
||||||
// 下载进度
|
|
||||||
if (data != undefined && (typeof data.receiveSize == 'number') && (typeof data.totalSize == 'number')) {
|
|
||||||
let percent = Math.round(((data.receiveSize * 1.0) / (data.totalSize * 1.0)) * 100)
|
|
||||||
if (progress !== percent) {
|
|
||||||
progress = percent
|
|
||||||
if (requestList === undefined) {
|
|
||||||
// 子线程
|
|
||||||
emitter.emit(Constants.PROGRESS_EMITTER + request.memoryKey, { data: { 'value': progress } })
|
|
||||||
}else {
|
|
||||||
// 主线程请求
|
|
||||||
requestList!.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
|
|
||||||
if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) {
|
|
||||||
requestWithSource.request.imageKnifeOption.progressListener(progress)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
let promise = httpRequest.requestInStream(request.src, {
|
|
||||||
header: headerObj,
|
|
||||||
method: http.RequestMethod.GET,
|
|
||||||
expectDataType: http.HttpDataType.ARRAY_BUFFER,
|
|
||||||
connectTimeout: request.connectTimeout == undefined ? 60000 : request.connectTimeout,
|
|
||||||
readTimeout: request.readTimeout == undefined ? 30000 : request.readTimeout,
|
|
||||||
caPath: request.caPath === undefined ? undefined : request.caPath,
|
|
||||||
});
|
|
||||||
|
|
||||||
promise.then((data: number) => {
|
|
||||||
LogUtil.log('HttpDownloadClient.end:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
|
|
||||||
callBackData.httpCode = data
|
|
||||||
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_NET, undefined)
|
|
||||||
callBackTimeInfo.netRequestEndTime = Date.now();
|
|
||||||
if (data == 200 || data == 206 || data == 204) {
|
|
||||||
resBuf = combineArrayBuffers(arrayBuffers)
|
|
||||||
ImageKnifeLoader.FileCacheParseImage(request,resBuf,fileKey, callBackData)
|
|
||||||
} else {
|
|
||||||
loadError = 'HttpDownloadClient has error, http code =' + JSON.stringify(data)
|
|
||||||
ImageKnifeLoader.makeEmptyResult(request,loadError, ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_NET, LoadPixelMapCode.IMAGE_HTTPS_LOAD_FAILED_CODE))
|
|
||||||
}
|
|
||||||
}).catch((err: BusinessError) => {
|
|
||||||
callBackData.httpCode = err.code
|
|
||||||
loadError = 'HttpDownloadClient download ERROR : err = ' + JSON.stringify(err)
|
|
||||||
callBackTimeInfo.netRequestEndTime = Date.now();
|
|
||||||
ImageKnifeLoader.makeEmptyResult(request,loadError, ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_NET, LoadPixelMapCode.IMAGE_HTTPS_LOAD_FAILED_CODE))
|
|
||||||
});
|
|
||||||
return
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
callBackTimeInfo.netRequestEndTime = Date.now();
|
|
||||||
loadError = 'onlyRetrieveFromCache,do not fetch image src = ' + request.src
|
|
||||||
}
|
|
||||||
} else if (request.src.startsWith('datashare://') || request.src.startsWith('file://')) {
|
|
||||||
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_SHARE_FILE)
|
|
||||||
await fs.open(request.src, fs.OpenMode.READ_ONLY).then(async (file) => {
|
|
||||||
await fs.stat(file.fd).then(async (stat) =>{
|
|
||||||
let buf = new ArrayBuffer(stat.size);
|
|
||||||
await fs.read(file.fd, buf).then((readLen) => {
|
|
||||||
resBuf = buf;
|
|
||||||
fs.closeSync(file.fd);
|
|
||||||
}).catch((err:BusinessError) => {
|
|
||||||
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_SHARE_FILE, LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE)
|
|
||||||
loadError = 'LoadDataShareFileClient fs.read err happened uri=' + request.src + ' err.msg=' + err?.message + ' err.code=' + err?.code
|
|
||||||
})
|
|
||||||
}).catch((err:BusinessError) => {
|
|
||||||
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_SHARE_FILE, LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE)
|
|
||||||
loadError = 'LoadDataShareFileClient fs.stat err happened uri=' + request.src + ' err.msg=' + err?.message + ' err.code=' + err?.code
|
|
||||||
})
|
|
||||||
}).catch((err:BusinessError) => {
|
|
||||||
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_SHARE_FILE, LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE)
|
|
||||||
loadError = 'LoadDataShareFileClient fs.open err happened uri=' + request.src + ' err.msg=' + err?.message + ' err.code=' + err?.code
|
|
||||||
})
|
|
||||||
} else if (ImageKnifeLoader.isLocalLoadSrc(request.context, request.src)) { //从本地文件获取
|
|
||||||
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_LOCAL_FILE)
|
|
||||||
try {
|
|
||||||
let stat = fs.statSync(request.src);
|
|
||||||
if (stat.size > 0) {
|
|
||||||
let file = fs.openSync(request.src, fs.OpenMode.READ_ONLY);
|
|
||||||
resBuf = new ArrayBuffer(stat.size);
|
|
||||||
fs.readSync(file.fd, resBuf);
|
|
||||||
fs.closeSync(file);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_LOCAL_FILE, LoadPixelMapCode.IMAGE_LOAD_LOCAL_FILE_FAILED_CODE)
|
|
||||||
loadError = 'LocalLoadSrc:' + request.src + ',err:' + err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
loadError = 'Parameter not supported:' + request.src
|
|
||||||
}
|
|
||||||
} else if (typeof request.src == 'number') { //从资源文件获取
|
|
||||||
let manager = request.context.createModuleContext(request.moduleName).resourceManager
|
|
||||||
if (resBuf == undefined && request.onlyRetrieveFromCache != true && request.requestSource == ImageKnifeRequestSource.SRC) {
|
|
||||||
if(request.src == -1) {
|
|
||||||
let resName = request.resName as string
|
|
||||||
resBuf = (await manager.getMediaByName(resName.substring(resName.lastIndexOf(".") + 1))).buffer as ArrayBuffer
|
|
||||||
} else {
|
|
||||||
resBuf = manager.getMediaContentSync(request.src).buffer as ArrayBuffer
|
|
||||||
}
|
|
||||||
} else if (resBuf == undefined && request.requestSource != ImageKnifeRequestSource.SRC) {
|
|
||||||
if(request.src == -1) {
|
|
||||||
let resName = request.resName as string
|
|
||||||
resBuf = (await manager.getMediaByName(resName.substring(resName.lastIndexOf(".") + 1))).buffer as ArrayBuffer
|
|
||||||
} else {
|
|
||||||
resBuf = manager.getMediaContentSync(request.src).buffer as ArrayBuffer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resBuf === undefined){
|
|
||||||
callBackTimeInfo.requestEndTime = Date.now();
|
callBackTimeInfo.requestEndTime = Date.now();
|
||||||
ImageKnifeLoader.makeEmptyResult(request,loadError ,callBackData)
|
ImageKnifeLoader.makeEmptyResult(request, loadError, callBackData);
|
||||||
return
|
|
||||||
}
|
}
|
||||||
ImageKnifeLoader.parseImage(resBuf,fileKey,request, callBackData)
|
|
||||||
}
|
}
|
||||||
static isLocalLoadSrc(context: Object | undefined, loadSrc: string): boolean {
|
static isLocalLoadSrc(context: Object | undefined, loadSrc: string): boolean {
|
||||||
if (context != undefined) {
|
if (context != undefined) {
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 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 { FileCache } from '../cache/FileCache';
|
||||||
|
import { IImageLoaderStrategy } from './IImageLoaderStrategy';
|
||||||
|
import { ImageKnifeLoader } from '../ImageKnifeLoader';
|
||||||
|
import { ImageKnifeData, ImageKnifeRequestWithSource, RequestJobRequest, TimeInfo } from '../model/ImageKnifeData';
|
||||||
|
import { LoadPhase, LoadPixelMapCode } from '../utils/Constants';
|
||||||
|
import { LogUtil } from '../utils/LogUtil';
|
||||||
|
import List from '@ohos.util.List';
|
||||||
|
|
||||||
|
// 自定义加载策略
|
||||||
|
export class CustomLoaderStrategy implements IImageLoaderStrategy {
|
||||||
|
async loadImage(
|
||||||
|
request: RequestJobRequest,
|
||||||
|
requestList: List<ImageKnifeRequestWithSource> | undefined,
|
||||||
|
fileKey: string,
|
||||||
|
callBackData: ImageKnifeData,
|
||||||
|
callBackTimeInfo: TimeInfo
|
||||||
|
): Promise<void> {
|
||||||
|
let resBuf: ArrayBuffer | undefined;
|
||||||
|
let loadError: string = '';
|
||||||
|
|
||||||
|
// 从文件缓存获取
|
||||||
|
ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CUSTOM_LOAD);
|
||||||
|
callBackTimeInfo.diskCheckStartTime = Date.now();
|
||||||
|
resBuf = FileCache.getFileCacheByFile(request.context, fileKey, request.fileCacheFolder);
|
||||||
|
callBackTimeInfo.diskCheckEndTime = Date.now();
|
||||||
|
|
||||||
|
if (resBuf !== undefined) {
|
||||||
|
ImageKnifeLoader.parseImage(resBuf, fileKey, request, callBackData);
|
||||||
|
} else if (!request.onlyRetrieveFromCache) {
|
||||||
|
LogUtil.log('start customGetImage src=' + request.componentId + ',srcType:' + request.requestSource + ',' +
|
||||||
|
request.componentVersion);
|
||||||
|
const headerObj: Record<string, Object> = ImageKnifeLoader.getHeaderObj(request);
|
||||||
|
try {
|
||||||
|
request.customGetImage!(request.context, request.src as string, headerObj)
|
||||||
|
.then((buffer)=>{
|
||||||
|
if(buffer !== undefined && buffer !== null) {
|
||||||
|
ImageKnifeLoader.FileCacheParseImage(request,buffer,fileKey,callBackData);
|
||||||
|
} else {
|
||||||
|
loadError = 'customGetImage loadFail undefined';
|
||||||
|
ImageKnifeLoader.makeEmptyResult(request,loadError, ImageKnifeLoader.assembleError(callBackData,
|
||||||
|
LoadPhase.PHASE_CUSTOM_LOAD, LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE));
|
||||||
|
}
|
||||||
|
}).catch((err:string)=>{
|
||||||
|
ImageKnifeLoader.makeEmptyResult(request,err, ImageKnifeLoader.assembleError(callBackData,
|
||||||
|
LoadPhase.PHASE_CUSTOM_LOAD, LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE));
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
loadError = 'customGetImage loadFail failed';
|
||||||
|
ImageKnifeLoader.makeEmptyResult(request,loadError + e, ImageKnifeLoader.assembleError(callBackData,
|
||||||
|
LoadPhase.PHASE_CUSTOM_LOAD, LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE));
|
||||||
|
}
|
||||||
|
LogUtil.log('end customGetImage src=' + request.componentId + ',srcType:' +
|
||||||
|
request.requestSource + ',' + request.componentVersion);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
loadError = `onlyRetrieveFromCache, do not fetch image src = ${request.src}`;
|
||||||
|
ImageKnifeLoader.makeEmptyResult(request, loadError, callBackData);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 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 { RequestJobRequest, ImageKnifeRequestWithSource, ImageKnifeData, TimeInfo } from '../model/ImageKnifeData';
|
||||||
|
import { IImageLoaderStrategy } from './IImageLoaderStrategy';
|
||||||
|
import List from '@ohos.util.List';
|
||||||
|
import { ImageKnifeLoader } from '../ImageKnifeLoader';
|
||||||
|
import { LoadPhase, LoadPixelMapCode } from '../utils/Constants';
|
||||||
|
import fs from '@ohos.file.fs';
|
||||||
|
|
||||||
|
export class FileLocalLoadStrategy implements IImageLoaderStrategy {
|
||||||
|
loadImage(request: RequestJobRequest, requestList: List<ImageKnifeRequestWithSource> | undefined, fileKey: string,
|
||||||
|
callBackData: ImageKnifeData, callBackTimeInfo: TimeInfo): Promise<void> {
|
||||||
|
let resBuf: ArrayBuffer | undefined;
|
||||||
|
let loadError: string = '';
|
||||||
|
if (typeof request.src === 'string' && ImageKnifeLoader.isLocalLoadSrc(request.context, request.src)) {
|
||||||
|
ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_LOCAL_FILE);
|
||||||
|
try {
|
||||||
|
const stat = fs.statSync(request.src);
|
||||||
|
if (stat.size > 0) {
|
||||||
|
const file = fs.openSync(request.src, fs.OpenMode.READ_ONLY);
|
||||||
|
resBuf = new ArrayBuffer(stat.size);
|
||||||
|
fs.readSync(file.fd, resBuf);
|
||||||
|
fs.closeSync(file);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_LOCAL_FILE,
|
||||||
|
LoadPixelMapCode.IMAGE_LOAD_LOCAL_FILE_FAILED_CODE);
|
||||||
|
loadError = `LocalLoadSrc: ${request.src}, err: ${err}`;
|
||||||
|
ImageKnifeLoader.makeEmptyResult(request, loadError,
|
||||||
|
ImageKnifeLoader.assembleError(
|
||||||
|
callBackData,
|
||||||
|
LoadPhase.PHASE_LOCAL_FILE,
|
||||||
|
LoadPixelMapCode.IMAGE_LOAD_LOCAL_FILE_FAILED_CODE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loadError = `Parameter not supported: ${request.src}`;
|
||||||
|
ImageKnifeLoader.makeEmptyResult(request, loadError, callBackData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resBuf === undefined || resBuf === null) {
|
||||||
|
callBackTimeInfo.requestEndTime = Date.now();
|
||||||
|
ImageKnifeLoader.makeEmptyResult(request, loadError, callBackData);
|
||||||
|
} else {
|
||||||
|
ImageKnifeLoader.parseImage(resBuf, fileKey, request, callBackData);
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 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 { ImageKnifeData, RequestJobRequest, TimeInfo, ImageKnifeRequestWithSource } from '../model/ImageKnifeData';
|
||||||
|
import fs from '@ohos.file.fs';
|
||||||
|
import { IImageLoaderStrategy } from './IImageLoaderStrategy';
|
||||||
|
import List from '@ohos.util.List';
|
||||||
|
import { ImageKnifeLoader } from '../ImageKnifeLoader';
|
||||||
|
import { LoadPhase, LoadPixelMapCode } from '../utils/Constants';
|
||||||
|
import { BusinessError } from '@kit.BasicServicesKit';
|
||||||
|
|
||||||
|
export class FileSystemLoaderStrategy implements IImageLoaderStrategy {
|
||||||
|
async loadImage(request: RequestJobRequest, requestList: List<ImageKnifeRequestWithSource> | undefined,
|
||||||
|
fileKey: string, callBackData: ImageKnifeData, callBackTimeInfo: TimeInfo
|
||||||
|
): Promise<void> {
|
||||||
|
let resBuf: ArrayBuffer | undefined;
|
||||||
|
let loadError: string = '';
|
||||||
|
|
||||||
|
if (typeof request.src === 'string' &&
|
||||||
|
(request.src.startsWith('datashare://') || request.src.startsWith('file://'))) {
|
||||||
|
ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_SHARE_FILE);
|
||||||
|
await fs.open(request.src, fs.OpenMode.READ_ONLY).then(async (file) => {
|
||||||
|
await fs.stat(file.fd).then(async (stat) => {
|
||||||
|
let buf = new ArrayBuffer(stat.size);
|
||||||
|
await fs.read(file.fd, buf).then((readLen) => {
|
||||||
|
resBuf = buf;
|
||||||
|
fs.closeSync(file.fd);
|
||||||
|
}).catch((err: BusinessError) => {
|
||||||
|
ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_SHARE_FILE,
|
||||||
|
LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE)
|
||||||
|
loadError = 'LoadDataShareFileClient fs.read err happened uri=' + request.src + ' err.msg=' + err?.message +
|
||||||
|
' err.code=' + err?.code
|
||||||
|
})
|
||||||
|
}).catch((err: BusinessError) => {
|
||||||
|
ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_SHARE_FILE,
|
||||||
|
LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE)
|
||||||
|
loadError = 'LoadDataShareFileClient fs.stat err happened uri=' + request.src + ' err.msg=' + err?.message +
|
||||||
|
' err.code=' + err?.code
|
||||||
|
})
|
||||||
|
}).catch((err: BusinessError) => {
|
||||||
|
ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_SHARE_FILE,
|
||||||
|
LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE)
|
||||||
|
loadError = 'LoadDataShareFileClient fs.open err happened uri=' + request.src + ' err.msg=' + err?.message +
|
||||||
|
' err.code=' + err?.code
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (resBuf === undefined || resBuf === null) {
|
||||||
|
callBackTimeInfo.requestEndTime = Date.now();
|
||||||
|
ImageKnifeLoader.makeEmptyResult(request, loadError, callBackData);
|
||||||
|
} else {
|
||||||
|
ImageKnifeLoader.parseImage(resBuf, fileKey, request, callBackData);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 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 { FileCache } from '../cache/FileCache';
|
||||||
|
import { IImageLoaderStrategy } from './IImageLoaderStrategy';
|
||||||
|
import {
|
||||||
|
ImageKnifeData,
|
||||||
|
ImageKnifeRequestSource,
|
||||||
|
ImageKnifeRequestWithSource,
|
||||||
|
RequestJobRequest,
|
||||||
|
TimeInfo
|
||||||
|
} from '../model/ImageKnifeData';
|
||||||
|
import http from '@ohos.net.http';
|
||||||
|
import { ImageKnifeLoader } from '../ImageKnifeLoader';
|
||||||
|
import { combineArrayBuffers } from '../utils/ArrayBufferUtils';
|
||||||
|
import { BusinessError, emitter } from '@kit.BasicServicesKit';
|
||||||
|
import { Constants, LoadPhase, LoadPixelMapCode } from '../utils/Constants';
|
||||||
|
import { LogUtil } from '../utils/LogUtil';
|
||||||
|
import List from '@ohos.util.List';
|
||||||
|
|
||||||
|
class RequestData {
|
||||||
|
public receiveSize: number = 2000
|
||||||
|
public totalSize: number = 2000
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTP加载策略
|
||||||
|
export class HttpLoaderStrategy implements IImageLoaderStrategy {
|
||||||
|
async loadImage(
|
||||||
|
request: RequestJobRequest,
|
||||||
|
requestList: List<ImageKnifeRequestWithSource> | undefined,
|
||||||
|
fileKey: string,
|
||||||
|
callBackData: ImageKnifeData,
|
||||||
|
callBackTimeInfo: TimeInfo
|
||||||
|
): Promise<void> {
|
||||||
|
let resBuf: ArrayBuffer | undefined;
|
||||||
|
let loadError: string = '';
|
||||||
|
|
||||||
|
// 从文件缓存获取
|
||||||
|
ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_NET);
|
||||||
|
callBackTimeInfo.diskCheckStartTime = Date.now();
|
||||||
|
resBuf = FileCache.getFileCacheByFile(request.context, fileKey, request.fileCacheFolder);
|
||||||
|
callBackTimeInfo.diskCheckEndTime = Date.now();
|
||||||
|
|
||||||
|
if (resBuf !== undefined) {
|
||||||
|
LogUtil.log(`success get image from filecache for key = ${fileKey} src = ${request.componentId},
|
||||||
|
srcType:${request.requestSource}, ${request.componentVersion}`);
|
||||||
|
ImageKnifeLoader.parseImage(resBuf, fileKey, request, callBackData);
|
||||||
|
} else if (request.onlyRetrieveFromCache !== true) {
|
||||||
|
LogUtil.log(`HttpDownloadClient.start: ${request.componentId}, srcType:${request.requestSource},
|
||||||
|
${request.componentVersion}`);
|
||||||
|
callBackTimeInfo.netRequestStartTime = Date.now();
|
||||||
|
const httpRequest = http.createHttp();
|
||||||
|
let progress: number = 0;
|
||||||
|
const arrayBuffers: ArrayBuffer[] = [];
|
||||||
|
const headerObj: Record<string, Object> = ImageKnifeLoader.getHeaderObj(request);
|
||||||
|
|
||||||
|
httpRequest.on('dataReceive', (data: ArrayBuffer) => {
|
||||||
|
arrayBuffers.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (request.isWatchProgress) {
|
||||||
|
httpRequest.on('dataReceiveProgress', (data: RequestData) => {
|
||||||
|
if (data != undefined && typeof data.receiveSize === 'number' && typeof data.totalSize === 'number') {
|
||||||
|
const percent = Math.round(((data.receiveSize * 1.0) / (data.totalSize * 1.0)) * 100);
|
||||||
|
if (progress !== percent) {
|
||||||
|
progress = percent;
|
||||||
|
if (requestList === undefined) {
|
||||||
|
// 子线程
|
||||||
|
emitter.emit(Constants.PROGRESS_EMITTER + request.memoryKey, { data: { 'value': progress } });
|
||||||
|
} else {
|
||||||
|
// 主线程请求
|
||||||
|
requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
|
||||||
|
if (requestWithSource.request.imageKnifeOption.progressListener !== undefined &&
|
||||||
|
requestWithSource.source === ImageKnifeRequestSource.SRC) {
|
||||||
|
requestWithSource.request.imageKnifeOption.progressListener(progress);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let promise = httpRequest.requestInStream(request.src as string, {
|
||||||
|
header: headerObj,
|
||||||
|
method: http.RequestMethod.GET,
|
||||||
|
expectDataType: http.HttpDataType.ARRAY_BUFFER,
|
||||||
|
connectTimeout: request.connectTimeout === undefined || request.connectTimeout === null ?
|
||||||
|
60000 : request.connectTimeout,
|
||||||
|
readTimeout: request.readTimeout === undefined || request.readTimeout === null?
|
||||||
|
30000 : request.readTimeout,
|
||||||
|
caPath: request.caPath
|
||||||
|
});
|
||||||
|
promise.then((data: number) => {
|
||||||
|
callBackData.httpCode = data;
|
||||||
|
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_NET, undefined);
|
||||||
|
callBackTimeInfo.netRequestEndTime = Date.now();
|
||||||
|
if (data == 200 || data == 206 || data == 204) {
|
||||||
|
resBuf = combineArrayBuffers(arrayBuffers);
|
||||||
|
ImageKnifeLoader.FileCacheParseImage(request,resBuf,fileKey, callBackData);
|
||||||
|
} else {
|
||||||
|
loadError = 'HttpDownloadClient has error, http code =' + JSON.stringify(data);
|
||||||
|
ImageKnifeLoader.makeEmptyResult(request,loadError, ImageKnifeLoader.assembleError(callBackData,
|
||||||
|
LoadPhase.PHASE_NET, LoadPixelMapCode.IMAGE_HTTPS_LOAD_FAILED_CODE));
|
||||||
|
}
|
||||||
|
}).catch((err: BusinessError) => {
|
||||||
|
callBackData.httpCode = err.code;
|
||||||
|
loadError = 'HttpDownloadClient download ERROR : err = ' + JSON.stringify(err);
|
||||||
|
callBackTimeInfo.netRequestEndTime = Date.now();
|
||||||
|
ImageKnifeLoader.makeEmptyResult(request,loadError, ImageKnifeLoader.assembleError(callBackData,
|
||||||
|
LoadPhase.PHASE_NET, LoadPixelMapCode.IMAGE_HTTPS_LOAD_FAILED_CODE));
|
||||||
|
});
|
||||||
|
LogUtil.log('HttpDownloadClient.end:' + request.componentId + ',srcType:' +
|
||||||
|
request.requestSource + ',' + request.componentVersion);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
callBackTimeInfo.netRequestEndTime = Date.now();
|
||||||
|
loadError = `onlyRetrieveFromCache, do not fetch image src = ${request.src}`;
|
||||||
|
ImageKnifeLoader.makeEmptyResult(request, loadError, callBackData);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 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 { ImageKnifeData, ImageKnifeRequestWithSource, RequestJobRequest, TimeInfo } from '../model/ImageKnifeData';
|
||||||
|
import List from '@ohos.util.List';
|
||||||
|
|
||||||
|
// 定义图片加载策略接口
|
||||||
|
export interface IImageLoaderStrategy {
|
||||||
|
loadImage(
|
||||||
|
request: RequestJobRequest,
|
||||||
|
requestList: List<ImageKnifeRequestWithSource> | undefined,
|
||||||
|
fileKey: string,
|
||||||
|
callBackData: ImageKnifeData,
|
||||||
|
callBackTimeInfo: TimeInfo
|
||||||
|
): Promise<void>;
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 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 { CustomLoaderStrategy } from './CustomLoaderStrategy';
|
||||||
|
import { FileSystemLoaderStrategy } from './FileSystemLoaderStrategy';
|
||||||
|
import { HttpLoaderStrategy } from './HttpLoaderStrategy';
|
||||||
|
import { IImageLoaderStrategy } from './IImageLoaderStrategy';
|
||||||
|
import { ImageKnifeRequestSource, RequestJobRequest } from '../model/ImageKnifeData';
|
||||||
|
import { ResourceLoaderStrategy } from './ResourceLoaderStrategy';
|
||||||
|
import { FileLocalLoadStrategy } from './FileLocalLoadStrategy';
|
||||||
|
|
||||||
|
export class ImageLoaderFactory {
|
||||||
|
static getLoaderStrategy(request: RequestJobRequest): IImageLoaderStrategy | null {
|
||||||
|
if (request.customGetImage !== undefined &&
|
||||||
|
request.requestSource === ImageKnifeRequestSource.SRC &&
|
||||||
|
typeof request.src === 'string'
|
||||||
|
) {
|
||||||
|
return new CustomLoaderStrategy();
|
||||||
|
} else if (typeof request.src === 'string') {
|
||||||
|
if (request.src.startsWith('http://') || request.src.startsWith('https://')) {
|
||||||
|
return new HttpLoaderStrategy();
|
||||||
|
} else if (request.src.startsWith('datashare://') || request.src.startsWith('file://')) {
|
||||||
|
return new FileSystemLoaderStrategy();
|
||||||
|
} else {
|
||||||
|
return new FileLocalLoadStrategy();
|
||||||
|
}
|
||||||
|
} else if (typeof request.src === 'number') {
|
||||||
|
return new ResourceLoaderStrategy();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 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 { IImageLoaderStrategy } from './IImageLoaderStrategy';
|
||||||
|
import {
|
||||||
|
ImageKnifeData,
|
||||||
|
ImageKnifeRequestSource,
|
||||||
|
ImageKnifeRequestWithSource,
|
||||||
|
RequestJobRequest,
|
||||||
|
TimeInfo
|
||||||
|
} from '../model/ImageKnifeData';
|
||||||
|
import List from '@ohos.util.List';
|
||||||
|
import { application } from '@kit.AbilityKit';
|
||||||
|
import { ImageKnifeLoader } from '../ImageKnifeLoader';
|
||||||
|
|
||||||
|
export class ResourceLoaderStrategy implements IImageLoaderStrategy {
|
||||||
|
async loadImage(
|
||||||
|
request: RequestJobRequest,
|
||||||
|
requestList: List<ImageKnifeRequestWithSource> | undefined,
|
||||||
|
fileKey: string,
|
||||||
|
callBackData: ImageKnifeData,
|
||||||
|
callBackTimeInfo: TimeInfo
|
||||||
|
): Promise<void> {
|
||||||
|
let resBuf: ArrayBuffer | undefined;
|
||||||
|
let loadError: string = '';
|
||||||
|
|
||||||
|
if (typeof request.src === 'number') {
|
||||||
|
const moduleContext = await application.createModuleContext(request.context, request.moduleName);
|
||||||
|
const manager = moduleContext.resourceManager;
|
||||||
|
if ((resBuf == undefined && request.onlyRetrieveFromCache !== true &&
|
||||||
|
request.requestSource === ImageKnifeRequestSource.SRC) ||
|
||||||
|
(resBuf == undefined && request.requestSource !== ImageKnifeRequestSource.SRC)) {
|
||||||
|
if (request.src === -1) {
|
||||||
|
const resName = request.resName as string;
|
||||||
|
resBuf =
|
||||||
|
(await manager.getMediaByName(resName.substring(resName.lastIndexOf('.') + 1))).buffer as ArrayBuffer;
|
||||||
|
} else {
|
||||||
|
resBuf = request.resName ?
|
||||||
|
manager.getRawFileContentSync(request.resName).buffer.slice(0) :
|
||||||
|
(manager.getMediaContentSync(request.src)).buffer as ArrayBuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resBuf === undefined || resBuf === null){
|
||||||
|
callBackTimeInfo.requestEndTime = Date.now();
|
||||||
|
loadError = 'Resource load error';
|
||||||
|
ImageKnifeLoader.makeEmptyResult(request, loadError ,callBackData);
|
||||||
|
} else {
|
||||||
|
ImageKnifeLoader.parseImage(resBuf,fileKey,request, callBackData);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue