655 lines
30 KiB
Plaintext
655 lines
30 KiB
Plaintext
/*
|
||
* Copyright (C) 2024 Huawei Device Co., Ltd.
|
||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
import {
|
||
CacheStrategy,
|
||
DecodeImageInfo,
|
||
ErrorInfo,
|
||
ImageKnifeData,
|
||
ImageKnifeRequestSource,
|
||
ImageKnifeRequestWithSource, RequestJobRequest,
|
||
TimeInfo } from './model/ImageKnifeData';
|
||
import List from '@ohos.util.List'
|
||
import { FileCache } from './cache/FileCache';
|
||
import { LogUtil } from './utils/LogUtil';
|
||
import { Constants, LoadPhase, LoadPixelMapCode } from './utils/Constants';
|
||
import http from '@ohos.net.http';
|
||
import { combineArrayBuffers } from './utils/ArrayBufferUtils';
|
||
import { BusinessError } from '@kit.BasicServicesKit';
|
||
import fs from '@ohos.file.fs';
|
||
import emitter from '@ohos.events.emitter';
|
||
import image from '@ohos.multimedia.image';
|
||
import { RequestJobResult } from './model/ImageKnifeData'
|
||
import util from '@ohos.util';
|
||
import { FileTypeUtil } from './utils/FileTypeUtil';
|
||
import { DownsampleStrategy } from './downsampling/DownsampleStartegy';
|
||
import { Downsampler } from './downsampling/Downsampler';
|
||
import { common } from '@kit.AbilityKit';
|
||
|
||
class RequestData {
|
||
receiveSize: number = 2000
|
||
totalSize: number = 2000
|
||
}
|
||
|
||
/**
|
||
* ImageKnifeDispatcher 抽取出来的方法,因@Concurrent只能import方法,故抽取到另一个类
|
||
*/
|
||
export class ImageKnifeLoader {
|
||
static execute(request: RequestJobRequest, requestList: List<ImageKnifeRequestWithSource> | undefined, fileKey: string){
|
||
ImageKnifeLoader.getImageArrayBuffer(request,requestList,fileKey)
|
||
}
|
||
static getUnit8Array (resBuf: ArrayBuffer) {
|
||
let unit8 = new Uint8Array(resBuf)
|
||
let unitString = ''
|
||
if (unit8.length >= 3) {
|
||
unitString = unit8[0] + ',' + unit8[1] + ',' + unit8[2]
|
||
} else if (unit8.length > 0 && unit8.length < 3) {
|
||
unitString = unit8.length + ''
|
||
}
|
||
return unitString
|
||
}
|
||
static async parseImage(resBuf: ArrayBuffer, fileKey: string,
|
||
request: RequestJobRequest, callBackData: ImageKnifeData) {
|
||
callBackData.bufSize = resBuf.byteLength;
|
||
let typeValue = new FileTypeUtil().getFileType(resBuf);
|
||
if(typeValue == null) {
|
||
LogUtil.log('requestJob.end: getFileType is null: ' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
|
||
ImageKnifeLoader.makeEmptyResult(request,
|
||
'request is not a valid image source:' + request.src + ',componentId' + request.componentId + ',srcType:' +
|
||
request.requestSource + ',' +
|
||
request.componentVersion + ',buffer:' + resBuf.byteLength + ',unit8:' + ImageKnifeLoader.getUnit8Array(resBuf),
|
||
ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_GET_FORMAT,
|
||
LoadPixelMapCode.IMAGE_PARSE_FORMAT_FAILED_CODE))
|
||
return
|
||
}
|
||
callBackData.type = typeValue;
|
||
if(request.isAnimator) {
|
||
ImageKnifeLoader.parseForAnimatorComponent(resBuf ,typeValue ,fileKey, request, callBackData)
|
||
return
|
||
}
|
||
|
||
if (typeValue === 'gif' || typeValue === 'webp') {
|
||
ImageKnifeLoader.parseAnimatorImage(resBuf ,typeValue ,fileKey , request, callBackData)
|
||
return
|
||
} else if(typeValue == 'svg') {
|
||
ImageKnifeLoader.parseSvgImage(resBuf ,typeValue ,fileKey , request, callBackData)
|
||
return
|
||
}
|
||
|
||
ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request, callBackData)
|
||
}
|
||
|
||
static makeEmptyResult(request:RequestJobRequest,error: string, data?: ImageKnifeData){
|
||
let res: RequestJobResult = {
|
||
pixelMap: undefined,
|
||
bufferSize: 0,
|
||
fileKey: '',
|
||
loadFail: error,
|
||
imageKnifeData: data
|
||
}
|
||
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { 'value': res } })
|
||
}
|
||
|
||
static assembleError(data: ImageKnifeData | undefined, phase: string, code?: number,
|
||
httpCode?: number): ImageKnifeData | undefined {
|
||
let errorCallBackData = data?.errorInfo;
|
||
if (!errorCallBackData) {
|
||
return data;
|
||
}
|
||
errorCallBackData.phase = phase;
|
||
errorCallBackData.code = code? code: 0;
|
||
if (httpCode && httpCode != 0) {
|
||
errorCallBackData.httpCode = httpCode;
|
||
}
|
||
return data
|
||
}
|
||
|
||
static getTimeInfo(callBackData: ImageKnifeData): TimeInfo {
|
||
let timeInfo: TimeInfo;
|
||
if (callBackData.timeInfo) {
|
||
timeInfo = callBackData.timeInfo;
|
||
}else {
|
||
timeInfo = {};
|
||
callBackData.timeInfo = timeInfo;
|
||
}
|
||
return timeInfo;
|
||
}
|
||
|
||
static async parseNormalImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, request: RequestJobRequest, callBackData: ImageKnifeData) {
|
||
let resPixelmap: PixelMap | undefined = undefined
|
||
let timeInfo: TimeInfo = ImageKnifeLoader.getTimeInfo(callBackData);
|
||
|
||
let decodingOptions: image.DecodingOptions = {
|
||
editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false,
|
||
}
|
||
let imageSource: image.ImageSource = image.createImageSource(resBuf)
|
||
if (imageSource === undefined){
|
||
ImageKnifeLoader.makeEmptyResult(request,'image.createImageSource failed', ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CREATE_SOURCE, LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE))
|
||
return
|
||
}
|
||
|
||
let imageInfoSync = imageSource.getImageInfoSync()
|
||
if (imageInfoSync == undefined){
|
||
imageSource.release()
|
||
ImageKnifeLoader.makeEmptyResult(request, 'getImageInfoSync failed')
|
||
return
|
||
}
|
||
let size = imageInfoSync.size
|
||
callBackData.imageWidth = size.width;
|
||
callBackData.imageHeight = size.height;
|
||
|
||
if (request.isAutoImageFit && request.requestSource == ImageKnifeRequestSource.SRC){
|
||
request.componentHeight = request.componentWidth * size.height / size.width
|
||
}
|
||
|
||
try {
|
||
if ((request.downsampType !== DownsampleStrategy.NONE) &&
|
||
request.requestSource == ImageKnifeRequestSource.SRC) {
|
||
decodingOptions =
|
||
ImageKnifeLoader.getDownsamplerDecodingOptions(typeValue, request, size, ImageKnifeRequestSource.SRC)
|
||
}
|
||
} catch (err) {
|
||
imageSource.release()
|
||
ImageKnifeLoader.makeEmptyResult(request, 'getDownsamplerDecodingOptions failed:' + err)
|
||
return
|
||
}
|
||
timeInfo.decodeStartTime = Date.now();
|
||
|
||
await imageSource.createPixelMap(decodingOptions)
|
||
.then((pixelmap: PixelMap) => {
|
||
timeInfo.decodeEndTime = Date.now();
|
||
resPixelmap = pixelmap
|
||
imageSource.release()
|
||
}).catch((error: BusinessError) => {
|
||
timeInfo.decodeEndTime = Date.now();
|
||
imageSource.release()
|
||
ImageKnifeLoader.makeEmptyResult(request, 'createPixelMap failed:' + JSON.stringify(error),
|
||
ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CREATE_PIXEL_MAP, LoadPixelMapCode.IMAGE_DECODE_ERROR_CODE))
|
||
return
|
||
})
|
||
if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined && resPixelmap !== undefined) {
|
||
LogUtil.log('requestJob.transform.start:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
|
||
resPixelmap = await request.transformation?.transform(request.context, resPixelmap, request.componentWidth, request.componentHeight);
|
||
LogUtil.log('requestJob.transform.end:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
|
||
}
|
||
try {
|
||
resPixelmap?.setTransferDetached(true)
|
||
} catch (e) {
|
||
LogUtil.error('PixelMap setTransferDetached failed:' + JSON.stringify(e))
|
||
}
|
||
|
||
//获取各个pixelMap的大小
|
||
if (resPixelmap !== undefined) {
|
||
let decodeImages: 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;
|
||
}
|
||
|
||
let res: RequestJobResult = {
|
||
pixelMap: resPixelmap,
|
||
bufferSize: resBuf.byteLength,
|
||
fileKey: fileKey,
|
||
size:size,
|
||
type:typeValue,
|
||
imageKnifeData:callBackData
|
||
}
|
||
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { 'value': res } })
|
||
}
|
||
static async parseSvgImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string,
|
||
request: RequestJobRequest, callBackData: ImageKnifeData) {
|
||
let resPixelmap: PixelMap | undefined = undefined
|
||
let timeInfo: TimeInfo = ImageKnifeLoader.getTimeInfo(callBackData);
|
||
|
||
let imageSource: image.ImageSource = image.createImageSource(resBuf)
|
||
if (imageSource === undefined){
|
||
ImageKnifeLoader.makeEmptyResult(request,'image.createImageSource failed', ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CREATE_SOURCE, LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE))
|
||
return
|
||
}
|
||
|
||
let imageInfoSync = imageSource.getImageInfoSync()
|
||
if (imageInfoSync == undefined){
|
||
imageSource.release()
|
||
ImageKnifeLoader.makeEmptyResult(request, 'getImageInfoSync failed')
|
||
return
|
||
}
|
||
let size = imageInfoSync.size
|
||
let scale = size.height / size.width
|
||
let hValue = Math.round(request.componentHeight);
|
||
let wValue = Math.round(request.componentWidth);
|
||
let defaultSize: image.Size = {
|
||
height: vp2px(wValue) * scale,
|
||
width: vp2px(wValue)
|
||
};
|
||
let opts: image.DecodingOptions = {
|
||
editable: true,
|
||
desiredSize: defaultSize
|
||
};
|
||
callBackData.imageWidth = size.width;
|
||
callBackData.imageHeight = size.height;
|
||
try {
|
||
if ((request.downsampType !== DownsampleStrategy.NONE) &&
|
||
request.requestSource == ImageKnifeRequestSource.SRC) {
|
||
opts = ImageKnifeLoader.getDownsamplerDecodingOptions(typeValue, request, size)
|
||
}
|
||
} catch (err) {
|
||
imageSource.release()
|
||
ImageKnifeLoader.makeEmptyResult(request,'getDownsamplerDecodingOptions failed:' + err)
|
||
return
|
||
}
|
||
timeInfo.decodeStartTime = Date.now();
|
||
await imageSource.createPixelMap(opts)
|
||
.then((pixelmap: PixelMap) => {
|
||
timeInfo.decodeEndTime = Date.now();
|
||
resPixelmap = pixelmap
|
||
imageSource.release()
|
||
try {
|
||
resPixelmap.setTransferDetached(true)
|
||
} catch (e) {
|
||
LogUtil.error('PixelMap setTransferDetached failed:' + JSON.stringify(e))
|
||
}
|
||
}).catch((error: BusinessError) => {
|
||
timeInfo.decodeEndTime = Date.now();
|
||
imageSource.release()
|
||
ImageKnifeLoader.makeEmptyResult(request,'getImageInfoSync failed:' + JSON.stringify(error), ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CREATE_PIXEL_MAP, LoadPixelMapCode.IMAGE_DECODE_ERROR_CODE))
|
||
return
|
||
})
|
||
|
||
//获取各个pixelMap的大小
|
||
if (resPixelmap && typeof resPixelmap !== 'string') {
|
||
let decodeImages: DecodeImageInfo[] = [];
|
||
let decodeImage: DecodeImageInfo = {
|
||
contentWidth: defaultSize.width,
|
||
contentHeight: defaultSize.height,
|
||
contentSize: (resPixelmap as PixelMap).getPixelBytesNumber()
|
||
}
|
||
decodeImages.push(decodeImage);
|
||
}
|
||
|
||
let res: RequestJobResult = {
|
||
pixelMap: resPixelmap,
|
||
bufferSize: resBuf.byteLength,
|
||
fileKey: fileKey,
|
||
type:typeValue,
|
||
imageKnifeData:callBackData
|
||
}
|
||
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { 'value': res } })
|
||
}
|
||
static async parseAnimatorImage(resBuf: ArrayBuffer, typeValue: string,
|
||
fileKey: string,request: RequestJobRequest, callBackData: ImageKnifeData) {
|
||
let timeInfo: TimeInfo = ImageKnifeLoader.getTimeInfo(callBackData);
|
||
let imageSource: image.ImageSource = image.createImageSource(resBuf)
|
||
if (imageSource === undefined){
|
||
ImageKnifeLoader.makeEmptyResult(request,'image.createImageSource failed', ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_CREATE_SOURCE,LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE))
|
||
return
|
||
}
|
||
|
||
let frameCount = await imageSource.getFrameCount()
|
||
let imageInfoSync = imageSource.getImageInfoSync()
|
||
imageSource.release()
|
||
if (imageInfoSync == undefined){
|
||
ImageKnifeLoader.makeEmptyResult(request, 'getImageInfoSync failed')
|
||
return
|
||
}
|
||
let size = imageInfoSync.size
|
||
callBackData.frameCount = frameCount;
|
||
callBackData.imageWidth = size.width;
|
||
callBackData.imageHeight = size.height;
|
||
|
||
if(frameCount == undefined || frameCount == 1) {
|
||
} else {
|
||
timeInfo.decodeStartTime = Date.now()
|
||
let base64str = 'data:image/' + typeValue + ';base64,' + new util.Base64Helper().encodeToStringSync(new Uint8Array(resBuf))
|
||
timeInfo.diskCheckEndTime = Date.now()
|
||
let res: RequestJobResult = {
|
||
pixelMap: base64str,
|
||
bufferSize: resBuf.byteLength,
|
||
fileKey: fileKey,
|
||
size:size,
|
||
type:typeValue,
|
||
imageKnifeData:callBackData
|
||
}
|
||
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { 'value': res } })
|
||
return
|
||
}
|
||
ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request, callBackData)
|
||
}
|
||
// 为AnimatorComponent解析动图
|
||
static async parseForAnimatorComponent(resBuf: ArrayBuffer, typeValue: string, fileKey: string,request: RequestJobRequest, callBackData: ImageKnifeData) {
|
||
let timeInfo: TimeInfo = ImageKnifeLoader.getTimeInfo(callBackData);
|
||
|
||
if (typeValue === 'gif' || typeValue === 'webp') {
|
||
let imageSource: image.ImageSource = image.createImageSource(resBuf);
|
||
if (imageSource === undefined){
|
||
ImageKnifeLoader.makeEmptyResult(request,'image.createImageSource failed', ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CREATE_SOURCE, LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE))
|
||
return
|
||
}
|
||
let decodingOptions: image.DecodingOptions = {
|
||
editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false,
|
||
}
|
||
|
||
let imageInfoSync = imageSource.getImageInfoSync()
|
||
if (imageInfoSync == undefined){
|
||
imageSource.release()
|
||
ImageKnifeLoader.makeEmptyResult(request, 'getImageInfoSync failed')
|
||
return
|
||
}
|
||
callBackData.imageWidth = imageInfoSync.size.width;
|
||
callBackData.imageHeight = imageInfoSync.size.height;
|
||
let pixelMapList: Array<PixelMap> = []
|
||
let delayList: Array<number> = []
|
||
timeInfo.decodeStartTime = Date.now();
|
||
let decodeImages: Array<DecodeImageInfo> = [];
|
||
await imageSource.createPixelMapList(decodingOptions).then(async (pixelList: Array<PixelMap>) => {
|
||
timeInfo.decodeEndTime = Date.now();
|
||
//sdk的api接口发生变更:从.getDelayTime() 变为.getDelayTimeList()
|
||
await imageSource.getDelayTimeList().then(delayTimes => {
|
||
if (pixelList.length > 0) {
|
||
for (let i = 0; i < pixelList.length; i++) {
|
||
pixelMapList.push(pixelList[i]);
|
||
if (i < delayTimes.length) {
|
||
delayList.push(delayTimes[i]);
|
||
} else {
|
||
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();
|
||
}
|
||
})
|
||
}).catch((error: BusinessError) => {
|
||
imageSource.release()
|
||
timeInfo.decodeEndTime = Date.now();
|
||
ImageKnifeLoader.makeEmptyResult(request,'createPixelMapList failed:' + JSON.stringify(error),
|
||
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_CREATE_PIXEL_MAP,LoadPixelMapCode.IMAGE_DECODE_ERROR_CODE))
|
||
return
|
||
})
|
||
callBackData.decodeImages = decodeImages;
|
||
let res: RequestJobResult = {
|
||
pixelMap: '',
|
||
bufferSize: resBuf.byteLength,
|
||
fileKey: fileKey,
|
||
type: typeValue,
|
||
imageKnifeData:callBackData,
|
||
pixelMapList,
|
||
delayList
|
||
}
|
||
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { 'value': res } })
|
||
} else {
|
||
ImageKnifeLoader.makeEmptyResult(request,'ImageKnifeAnimatorComponent not support format', ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_PARSE_IAMGE,LoadPixelMapCode.IMAGE_FORMAT_ERROR_CODE))
|
||
}
|
||
}
|
||
static getHeaderObj(request:RequestJobRequest){
|
||
const headerObj: Record<string, Object> = {}
|
||
if (request.headers != undefined) {
|
||
request.headers.forEach((value) => {
|
||
headerObj[value.key] = value.value
|
||
})
|
||
} else if (request.allHeaders.size > 0) {
|
||
request.allHeaders.forEach((value, key) => {
|
||
headerObj[key] = value
|
||
})
|
||
}
|
||
return headerObj
|
||
}
|
||
static FileCacheParseImage(request:RequestJobRequest,resBuf:ArrayBuffer,fileKey:string, callBackData: ImageKnifeData){
|
||
try {
|
||
// 保存文件缓存
|
||
if (resBuf !== undefined && request.writeCacheStrategy !== CacheStrategy.Memory) {
|
||
LogUtil.log('requestJob_saveFileCacheOnlyFile.start:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
|
||
FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf , request.fileCacheFolder)
|
||
LogUtil.log('requestJob_saveFileCacheOnlyFile.end:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
|
||
}
|
||
ImageKnifeLoader.parseImage(resBuf,fileKey,request, callBackData)
|
||
} catch (e) {
|
||
ImageKnifeLoader.makeEmptyResult(request,
|
||
'image load FileCacheParseImage error:' + e + ',componentId' + request.componentId + ',srcType:' +
|
||
request.requestSource + ',' + request.componentVersion)
|
||
}
|
||
}
|
||
// 获取图片资源
|
||
static async getImageArrayBuffer(request: RequestJobRequest, requestList: List<ImageKnifeRequestWithSource> | undefined,fileKey:string) {
|
||
let resBuf: ArrayBuffer | undefined
|
||
let loadError: string = ''
|
||
//定义图片各个阶段错误信息
|
||
let error: ErrorInfo = { code: 0, phase: LoadPhase.PHASE_LOAD }
|
||
//定义加载时间点
|
||
let callBackTimeInfo: TimeInfo = {};
|
||
//定义加载信息回调数据
|
||
let callBackData: ImageKnifeData = {
|
||
source: '',
|
||
imageWidth: 0,
|
||
imageHeight: 0,
|
||
timeInfo: callBackTimeInfo,
|
||
errorInfo: error
|
||
};
|
||
|
||
// 判断自定义下载
|
||
if (request.customGetImage !== undefined && request.requestSource == ImageKnifeRequestSource.SRC && typeof request.src == '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) {
|
||
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)
|
||
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)
|
||
}
|
||
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,
|
||
// usingProtocol:http.HttpProtocol.HTTP1_1
|
||
// header: new Header('application/json')
|
||
caPath: request.caPath === undefined ? undefined : request.caPath,
|
||
});
|
||
|
||
promise.then((data: number) => {
|
||
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_NET, undefined, data)
|
||
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, data))
|
||
}
|
||
}).catch((err: Error) => {
|
||
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, undefined))
|
||
});
|
||
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
|
||
}
|
||
} 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();
|
||
ImageKnifeLoader.makeEmptyResult(request,loadError ,callBackData)
|
||
return
|
||
}
|
||
ImageKnifeLoader.parseImage(resBuf,fileKey,request, callBackData)
|
||
}
|
||
static isLocalLoadSrc(context: Object | undefined, loadSrc: string): boolean {
|
||
if (context != undefined) {
|
||
let fileDir: string = (context as common.UIAbilityContext).filesDir as string;
|
||
let cacheDir: string = (context as common.UIAbilityContext).cacheDir as string
|
||
if (loadSrc.startsWith(fileDir) || loadSrc.startsWith(cacheDir)) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
static getDownsamplerDecodingOptions(typeValue: string, request: RequestJobRequest, size: Size,
|
||
SRC?: ImageKnifeRequestSource):image.DecodingOptions {
|
||
let reqSize =
|
||
new Downsampler().calculateScaling(typeValue, size.width, size.height, request.targetWidth, request.targetHeight,
|
||
request.downsampType)
|
||
if (typeValue == 'svg') {
|
||
return {
|
||
editable: true,
|
||
desiredSize: {
|
||
height: vp2px(reqSize.height),
|
||
width: vp2px(reqSize.width)
|
||
}
|
||
|
||
}
|
||
} else {
|
||
return {
|
||
editable: request.requestSource === SRC && request.transformation !== undefined ? true : false,
|
||
desiredSize:{
|
||
width: reqSize.width,
|
||
height: reqSize.height
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} |