From 5e7d9c7f5fe4dd84acbcc115900005043461b039 Mon Sep 17 00:00:00 2001 From: sijainguo Date: Mon, 29 Apr 2024 19:29:42 +0800 Subject: [PATCH] =?UTF-8?q?=E9=99=8D=E9=87=87=E6=A0=B7=20=E6=8A=A5?= =?UTF-8?q?=E9=94=99=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- entry/src/main/ets/pages/DownsamplingPage.ets | 147 +++ .../ets/pages/imageknifeTestCaseIndex.ets | 4 + .../resources/base/profile/main_pages.json | 3 +- library/index.ets | 4 +- .../Downsampling/BaseDownsampling.ets | 4 +- .../Downsampling/DownsampleStartegy.ets | 87 +- .../imageknife/Downsampling/Downsampler.ets | 2 +- .../ets/components/imageknife/ImageKnife.ets | 2 - .../components/imageknife/RequestOption.ets | 1100 ++++++++--------- .../components/imageknife/SendableData.ets | 22 +- .../requestmanage/RequestManager.ets | 19 +- .../imageknife/utils/ParseImageUtil.ets | 2 +- .../imageknife/utils/gif/GIFParseImpl.ets | 38 +- .../imageknife/utils/gif/IParseGif.ets | 6 +- .../imageknife/utils/svg/SVGParseImpl.ets | 15 +- 15 files changed, 755 insertions(+), 700 deletions(-) create mode 100644 entry/src/main/ets/pages/DownsamplingPage.ets diff --git a/entry/src/main/ets/pages/DownsamplingPage.ets b/entry/src/main/ets/pages/DownsamplingPage.ets new file mode 100644 index 0000000..de21508 --- /dev/null +++ b/entry/src/main/ets/pages/DownsamplingPage.ets @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2021 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 { RequestOption, ImageKnifeGlobal, ImageKnifeOption, ImageKnifeComponent } from '@ohos/libraryimageknife' +import { BusinessError } from '@ohos.base' +import { ImageKnifeData } from '@ohos/libraryimageknife' +import { + DownsampleNone, + FitCenter +} from '@ohos/imageknife/src/main/ets/components/inageknife/Downsampling/Downsamplestartegy' + +// PixelMap transform示例 +let mRotate: number = 0; +//let mUrl= "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVqqB" let murl = $r('app.media.pngSample'); let setting = new DownsampleNone() +let mUrl = $r('app.media.pngSample'); +let setting = new DownsampleNone() + +@Entry +@Component +struct DownsamplingPage { + @State url: string = ""; + @State mCropPixelMap?: PixelMap = undefined; + @state mRoundPixelMap?: PixelMap = undefined; + @State mCirclePixelMap?: PixelMap = undefined; + @State mCircleBorderPixelMap?: PixelMap = undefined; + @state mRotatePixelMap?: PixelMap = undefined; + @state mSquarePixelMap?: PixelMap = undefined; + @state mSquarePixelMap1?: PixelMap = undefined; + @state mClipCenterPixelMap?: PixelMap = undefined; + @state mClipBottomPixelMap?: PixelMap = undefined; + @state mGrayscalePixelMap?: PixelMap = undefined; + @state mBrightnessPixelMap?: PixelMap = undefined; + @State mContrastPixelMap?: PixelMap = undefined; + @state mInvertPixelMap?: PixelMap = undefined; + @state mSepiaPixelMap?: PixelMap = undefined; + @State mSketchPixelMap?: PixelMap = undefined; + @state mBlurPixelMap?: PixelMap = undefined; + @state mPixelPixelMap?: PixelMap = undefined; + @State mSwirlPixelMap?: PixelMap = undefined; + @State mMaskPixelMap?: PixelMap = undefined; + @State mKuwaharaPixelMap?: PixelMap = undefined; + @State mToonPixelMap?: PixelMap = undefined; + @State mVignettePixelMap?: PixelMap = undefined; + @State BytesNumber: number = 0; + @State BytesNumber1: number = 0; + @state imageKnifeOption2: ImageKnifeOption = + { + loadSrc: $r('app.media.gifSample'), + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + downsampling: new DownsampleNone() + }; + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) { + Column() { + Column() { + Column() { + Text("大小:" + this.BytesNumber).fontColor(Color.Gray).fontsize(16); + Button() { + Text($r("app.string.trans_square")).fontSize(13).fontColor(Color.White) + } + .height(35) + .width(120) + .margin({ top: 10 }) + .onclick(() => { + this.transformSquare(); + }); + if (this.mSquarePixelMap) { + Image(this.mSquarePixelMap == undefined ? "" : this.mSquarePixelMap!) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + } + }.margin({ top: 10 }); + }.margin({ bottom: 30 }); + Column() { + Column() { + Text("大小:" + this.BytesNumber1).fontColor(Color.Gray).fontSize(16); + Button() { + Text('降采样').fontsize(13).fontColor(Color.White) + } + .height(35).width(120) + .margin({ top: 10 }) + .onClick(() => { + this.transformSquare1(); + }); + if (this.mSquarePixelMap1) { + Image(this.mSquarePixelMap1 == undefined ? '' : this.mSquarePixelMap1!) + .objectFit(ImageFit.Fill) + .width(200) + .height(200) + .margin({ top: 10 }) + } + }.margin({ top: 10 }); + }.margin({ bottom: 30 }); + Column() { + column() { + Text("ImageKnifeComponent用法").fontColor(Color.Gray).fontSize(16); + ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 }) + .width(200) + .height(200) + }.margin({ top: 10 }); + }.margin({ bottom: 30 }); + } + }.width('100%').height('100%'); + } + + //正方形裁剪 + transformSquare() { + let imageKnifeOption = new RequestOption(); + imageKnifeOption.load(murl) + .addListener({ callback: (err: BusinessError | string, data: ImageKnifeData) => { + this.mSquarePixelMap = data.drawPixelMap?.imagePixelMap as PixelMap; + this.BytesNumber = (data.drawPixelMap?.imagePixelMap as PixelMap).getPixelBytesNumber() + return false; + } }) + ImageKnife?.call(imageKnifeOption); + } + + transformSquare1() { + let imageKnifeOption = new RequestOption(); + imageKnifeOption.load(mUrl) + .addListener({ callback: (err: BusinessError | string, data: ImageKnifeData) => { + this.mSquarePixelMap1 = data.drawPixelMap?.imagePixelMap as PixelMap; + this.BytesNumber1 = (data.drawPixelMap?.imagePixelMap as PixelMap).getPixelBytesNumber() + return false; + } }) + .setImageViewsize({ width: 800, height: 500 }) + .downsampleStrategy(new FitCenter()) + ImageKnife?.call(imageKnifeOption); + } +} + +let ImageKnife = ImageKnifeGlobal.getInstance().getImageKnife(); \ No newline at end of file diff --git a/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets b/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets index a951647..97ad633 100644 --- a/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets +++ b/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets @@ -40,6 +40,10 @@ struct IndexFunctionDemo { console.log("优先级加载") router.pushUrl({ url: "pages/testPriorityComponent" }); }).margin({ top: 5, left: 3 }) + Button("下采样加载") + .onClick(() => { + router.pushUrl({ url: "pages/DownsamplingPage" }); + }).margin({ top: 5, left: 3 }) }.width('100%').height(60).backgroundColor(Color.Pink) Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { diff --git a/entry/src/main/resources/base/profile/main_pages.json b/entry/src/main/resources/base/profile/main_pages.json index 3be410f..d678384 100644 --- a/entry/src/main/resources/base/profile/main_pages.json +++ b/entry/src/main/resources/base/profile/main_pages.json @@ -56,6 +56,7 @@ "pages/testImageKnifeHeic", "pages/testImageKnifeNetPlaceholder", "pages/testCustomDataFetchClientWithPage", - "pages/testReuseAblePages" + "pages/testReuseAblePages", + "pages/DownsamplingPage" ] } \ No newline at end of file diff --git a/library/index.ets b/library/index.ets index 5e8d3ca..2316b6e 100644 --- a/library/index.ets +++ b/library/index.ets @@ -130,4 +130,6 @@ export { GIFFrame } from './src/main/ets/components/imageknife/utils/gif/GIFFram export { IDrawLifeCycle } from './src/main/ets/components/imageknife/interface/IDrawLifeCycle' // 日志管理 -export { LogUtil } from './src/main/ets/components/imageknife/utils/LogUtil' \ No newline at end of file +export { LogUtil } from './src/main/ets/components/imageknife/utils/LogUtil' +/*下采样*/ +export {Downsampler} from './src/main/ets/components/imageknife/Downsampling/Downsampler' \ No newline at end of file diff --git a/library/src/main/ets/components/imageknife/Downsampling/BaseDownsampling.ets b/library/src/main/ets/components/imageknife/Downsampling/BaseDownsampling.ets index 9ade775..ec51f3c 100644 --- a/library/src/main/ets/components/imageknife/Downsampling/BaseDownsampling.ets +++ b/library/src/main/ets/components/imageknife/Downsampling/BaseDownsampling.ets @@ -1,6 +1,6 @@ import {lang}from '@kit.ArkTs'; -type ISendable=lang.ISendable; -export interface BaseDownsampling{ +type ISendable = lang.ISendable; +export interface BaseDownsampling extends ISendable{ getName():string getScaleFactor(sourceWidth:number, sourceHeight:number, requestWidth:number, requestHeight:number):number diff --git a/library/src/main/ets/components/imageknife/Downsampling/DownsampleStartegy.ets b/library/src/main/ets/components/imageknife/Downsampling/DownsampleStartegy.ets index 3d6583d..4968d18 100644 --- a/library/src/main/ets/components/imageknife/Downsampling/DownsampleStartegy.ets +++ b/library/src/main/ets/components/imageknife/Downsampling/DownsampleStartegy.ets @@ -2,17 +2,18 @@ import { BaseDownsampling } from './BaseDownsampling' @Sendable export class CenterInside{ - getName() { return "CenterInside"} - getScaleFactor(sourceWidth:number, sourceHeight:number,requestWidth:number, requestHeight:number):number { - - return Math.min(1,FitCenter.getScaleFactor(sourceWidth, sourceHeight, requestWidth, requestHeight)) - } - getSampleSizeRounding(sourceWidth:number, sourceHeight:number, requestWidth:number, requestHeight:number):SampleSizeRounding { - return this.getScaleFactor(sourceWidth, sourceHeight, requestWidth, requestHeight)==1 - ?SampleSizeRounding.QUALITY - :FitCenter.getSampleSizeRounding(sourceWidth, sourceHeight, requestWidth, requestHeight) - - } + getName() { return "CenterInside"} + getScaleFactor(sourceWidth:number, sourceHeight:number,requestWidth:number, requestHeight:number):number { + return Math.min(1,this.getScale(sourceWidth, sourceHeight, requestWidth, requestHeight)) + } + getSampleSizeRounding(sourceWidth:number, sourceHeight:number, requestWidth:number, requestHeight:number):SampleSizeRounding { + return 1 + } + getScale(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number { + let widthPercentage =requestWidth/sourceWidth + let heightPercentage =requestHeight/sourceHeight + return Math.min(widthPercentage,heightPercentage) + } } /*不进行下采样*/ @@ -26,44 +27,62 @@ export class DownsampleNone implements BaseDownsampling{ } getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number { - return SampleSizeRounding.QUALITY + return 1 } } /* 下采样使得图像的组大尺寸在给定的尺寸的1/2之间*/ @Sendable - export class AtMost implements BaseDownsampling{ +export class AtMost implements BaseDownsampling{ getName(){ return "AtMost" } - getScaleFactor(sourceWidth: number, sourceHeight: number, requestWidth:number,requestHeight: number): number { - let maxIntegerFactor=Math.ceil(Math.max(sourceHeight/requestHeight,sourceWidth/requestWidth)); - let lesserOrEqualSampleSize = Math.max(1,highestOneBit(maxIntegerFactor)) - let greaterOrEqualSampleSize = lesserOrEqualSampleSize<<(lesserOrEqualSampleSize> 1); + i |= (i >> 2); + i |= (i >> 4); + i |= (i >> 8); + i |= (i >> 16); + return i - (i >>> 1); + } +} @Sendable export class Atleast implements BaseDownsampling{ getName(){ return "Atleast" } - getScaleFactor(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number { - let minIntegerFactor=Math.floor(Math.min(sourceHeight/requestHeight,sourceWidth/requestWidth)) - - return minIntegerFactor==0?1:1/highestOneBit(minIntegerFactor) - } + getScaleFactor(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number { + let minIntegerFactor=Math.floor(Math.min(sourceHeight/requestHeight,sourceWidth/requestWidth)) + return minIntegerFactor==0?1:1/this.highestOneBit(minIntegerFactor) + } getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number { - return SampleSizeRounding.QUALITY - } + return 1 + } + highestOneBit(i: number): number { + i |= (i >> 1); + i |= (i >> 2); + i |= (i >> 4); + i |= (i >> 8); + i |= (i >> 16); + return i - (i >>> 1); + } } @Sendable export class CenterOutside implements BaseDownsampling{ + static getSampleSizeRounding(orientedSourceWidth: number, orientedSourceHeight: number, targetWidth: number, targetHeight: number): SampleSizeRounding { + throw new Error('Method not implemented.') + } getName(){ return "CenterOutside" } @@ -74,7 +93,7 @@ export class CenterOutside implements BaseDownsampling{ } getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number { - return SampleSizeRounding.QUALITY + return 1 } } @@ -84,13 +103,13 @@ export class FitCenter{ getName(){ return "FitCenter" } - public static getScaleFactor(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number { + getScaleFactor(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number { let widthPercentage =requestWidth/sourceWidth let heightPercentage =requestHeight/sourceHeight return Math.min(widthPercentage,heightPercentage) } - public static getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number { - return SampleSizeRounding.MEMORY + getSampleSizeRounding(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number): number { + return 1 } } diff --git a/library/src/main/ets/components/imageknife/Downsampling/Downsampler.ets b/library/src/main/ets/components/imageknife/Downsampling/Downsampler.ets index b2cfa5f..202ee00 100644 --- a/library/src/main/ets/components/imageknife/Downsampling/Downsampler.ets +++ b/library/src/main/ets/components/imageknife/Downsampling/Downsampler.ets @@ -52,7 +52,7 @@ export class Downsampler { let heightScaleFactor = Math.floor(orientedSourceHeight / outHeight); let scaleFactor = rounding == SampleSizeRounding.MEMORY ? Math.max(widthScaleFactor, heightScaleFactor) : Math.min(widthScaleFactor, heightScaleFactor) // 将整型的缩放因子转换为2的次幂采样大小 - let powerOfTwoSampleSize: number; + let powerOfTwoSampleSize: number = 0; if (rounding == SampleSizeRounding.MEMORY && powerOfTwoSampleSize < (1 / exactScaleFactor)) { powerOfTwoSampleSize = powerOfTwoSampleSize << 1; } diff --git a/library/src/main/ets/components/imageknife/ImageKnife.ets b/library/src/main/ets/components/imageknife/ImageKnife.ets index 8108f8b..6ab3b9b 100644 --- a/library/src/main/ets/components/imageknife/ImageKnife.ets +++ b/library/src/main/ets/components/imageknife/ImageKnife.ets @@ -810,8 +810,6 @@ async function taskExecute(sendData:SendableData,taskData:TaskParams): Promise

void -} +export class RequestManager { + private TAG: string = "RequestManager"; + private options: RequestOption; + private mIDataFetch: IDataFetch; + private mIResourceFetch: IResourceFetch; + private mParseImageUtil: IParseImage; + private diskMemoryCache: DiskLruCache; -export enum Priority { - HIGH = 0, - MEDIUM = 1, - LOW = 2 -} -export class RequestOption { - // 遍历添加图片http请求头 - headers: Map = new Map(); + constructor(option: RequestOption,diskMemoryCache: DiskLruCache, dataFetch: IDataFetch, resourceFetch: IResourceFetch) { + this.options = option; - // RequestOption调用header对于的方法 - addHeader(key: string, value: Object) { - this.headers.set(key, value); + this.diskMemoryCache = diskMemoryCache; + // 网络下载能力 + this.mIDataFetch = dataFetch; + + // 本地数据解析能力 + this.mIResourceFetch = resourceFetch; + + // 解析image能力 + this.mParseImageUtil = new ParseImageUtil(); } - // 全局调用header对应的方法,包含RequestOption的形式 - addHeaderMap(map: Map) { - map.forEach((value, key) => { - if (!this.headers.has(key)) { - this.addHeader(key, value); - } - }) + // DecodeJob work + private mStage: Stage = Stage.INITIALIZE; + private mRunReason: RunReason = RunReason.INITIALIZE; + process = (onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, onError: (reason?: BusinessError | string) => void) => { + LogUtil.log("ImageKnife RequestManager process !"); + this.loadLeve1MemoryCache(onComplete, onError) } - // 优先级 - priority: Priority = Priority.MEDIUM; - uuid: string = '' // 唯一标识 - loadSrc: string | PixelMap | Resource = ''; - strategy: DiskStrategy = new AUTOMATIC(); - //下采样相关 - downsampType: BaseDownsampling = new BaseDownsamplings() - dontAnimateFlag = false; - placeholderSrc: string | PixelMap | Resource | undefined = undefined; - placeholderFunc: AsyncSuccess | undefined = undefined; - errorholderSrc: PixelMap | Resource | undefined = undefined; - errorholderFunc: AsyncSuccess | undefined = undefined; - errorholderData: ImageKnifeData | undefined = undefined; - thumbSizeMultiplier: number = 0; - // 如果存在缩略图,则主图延时1s加载 - thumbDelayTime: number = 1000 - thumbHolderFunc: AsyncSuccess | undefined = undefined; - requestListeners: Array> | undefined = undefined; - // 进度条 - progressFunc: AsyncSuccess | undefined = undefined; - // 后备回调符 - fallbackSrc: PixelMap | Resource | undefined = undefined; - fallbackFunc: AsyncSuccess | undefined = undefined; - fallbackData: ImageKnifeData | undefined = undefined; - // 重试图层 - retryholderSrc: PixelMap | Resource | undefined = undefined; - retryholderFunc: AsyncSuccess | undefined = undefined; - retryholderData: ImageKnifeData | undefined = undefined; - size: Size = { width: -1, height: -1 }; - // 网络下载数据回调 - allCacheInfoCallback: IAllCacheInfoCallback | undefined = undefined; - onlyRetrieveFromCache: boolean = false; - isCacheable: boolean = true; - // 开启GPU变换绘制 - gpuEnabled: boolean = false; - // 变换相关 - transformations: Array> = new Array(); - generateCacheKey: string = ""; - generateResourceKey: string = ""; - generateDataKey: string = ""; - filesPath: string = ""; // data/data/包名/files目录 - cachesPath: string = ""; // 网络下载默认存储在data/data/包名/cache/ImageKnifeNetworkFolder/目标md5.img下面 - placeholderCacheKey: string = ""; - retryholderCacheKey: string = ""; - errorholderCacheKey: string = ""; - // string类型占位图相关缓存key值 - placeholderRegisterCacheKey: string = ""; - placeholderRegisterMemoryCacheKey: string = ""; - fallbackCacheKey: string = ""; - // 自定义缓存关键字 - signature?: ObjectKey; - // 设置是否使用应用自定义的方式加载图片 - customGetImage?: (context: Context, src: string) => Promise; - // 下载原始文件地址 - downloadFilePath: string = ""; - //磁盘缓存文件路径 - diskMemoryCachePath: string =""; - // 网络文件下载统一存放 - networkCacheFolder: string = "ImageKnifeNetworkFolder" - // 主线图片 状态变化 是否加载完成 - // 主图未加载成功 显示占位图 主图加载成功不展示占位图 - loadMainReady = false; - // 失败占位图展示状态 当true 表示主图加载失败需要展示失败占位图 - loadErrorReady = false; - // 重试占位图展示状态 当true 表示主图加载失败需要展示失败占位图 - loadRetryReady = false; - // 后备回调符展示状态 当true 表占位图加载失败需要展示后备回调符 - loadFallBackReady = false; - // 缩略图展示 - loadThumbnailReady = false; - detachFromLayout: DetachFromLayout = { - detach: () => { - let imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife(); - if (imageKnife != undefined) { - imageKnife.remove(this.uuid); - } + private runWrapped(request: RequestOption, runReason: RunReason, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, onError: (reason?: BusinessError | string) => void) { + LogUtil.log("ImageKnife RequestManager runWrapped") + if (runReason == RunReason.INITIALIZE) { + this.mStage = this.getNextStage(request, this.mStage); + this.searchLoadFrom(this.options, this.mStage, onComplete, onError); + } else { + throw new Error("Unrecognized run reason: " + runReason) } } - // module资源的需要当前的module context - moduleContext?: common.UIAbilityContext = undefined; - constructor() { - // 初始化全局监听 - this.requestListeners = new Array(); + private getNextStage(request: RequestOption, current: Stage): Stage { + if (current == Stage.INITIALIZE) { + return request.strategy.decodeCachedResource() + ? Stage.RESOURCE_CACHE + : this.getNextStage(request, Stage.RESOURCE_CACHE); + } else if (current == Stage.RESOURCE_CACHE) { + return request.strategy.decodeCachedData() + ? Stage.DATA_CACHE + : this.getNextStage(request, Stage.DATA_CACHE); + } else if (current == Stage.DATA_CACHE) { + return request.onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE; + } else if (current == Stage.SOURCE) { + return Stage.FINISHED; + } else if (current == Stage.FINISHED) { + return Stage.FINISHED; + } else { + throw new Error("ImageKnife Unrecognized stage: " + current); + } + } - let ctx = ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext + // 究竟从哪里加载数据 + private searchLoadFrom(request: RequestOption, current: Stage, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, onError: (reason?: BusinessError | string) => void) { + LogUtil.log("ImageKnife RequestManager searchLoadFrom") + if (current == Stage.RESOURCE_CACHE) { + this.loadDiskFromTransform(request, onComplete, onError); + } else if (current == Stage.DATA_CACHE) { + this.loadDiskFromSource(request, onComplete, onError); + } else if (current == Stage.SOURCE) { + this.parseSource(request, onComplete, onError) + } else if (current == Stage.FINISHED) { + onError("在仅从缓存获取数据中,未获取到数据!") + } else { + throw new Error("Unrecognized stage: " + current); + } + } + + // 加载网络资源 + private async loadSourceFromNetwork(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, onError: (reason?: BusinessError | string) => void) { + try { + LogUtil.log("ImageKnife RequestManager loadSourceFromNetwork") + let result: DataFetchResult = await this.mIDataFetch.loadData(request); + if(result.error){ + onError(result.error) + }else{ + if(result.data){ + this.downloadSuccess(request, result.data, onComplete, onError) + }else{ + onError("datafetch data is null") + } + } + } catch (e) { + LogUtil.error("ImageKnife RequestManager loadSourceFromNetwork error") + } + } + + // 加载本地资源 + private loadSourceFormNative(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, onError: (reason?: BusinessError | string) => void) { + LogUtil.log("ImageKnife RequestManager loadSourceFormNative") + // 本地解析后进行一级缓存 + let success = (arrayBuffer: ArrayBuffer) => { + // 使用媒体子系统 ImageSource解析文件 获取PixelMap + let fileTypeUtil = new FileTypeUtil(); + let typeValue = fileTypeUtil.getFileType(arrayBuffer) + LogUtil.log("ImageKnife RequestManager - 文件类型为= " + typeValue) + // gif、webp处理 + if ((ImageKnifeData.GIF == typeValue || ImageKnifeData.WEBP == typeValue) && !request.dontAnimateFlag) { + // 处理gif、webp + this.gifProcess(onComplete, onError, arrayBuffer, typeValue) + } else if (ImageKnifeData.SVG == typeValue) { + // 处理svg + this.svgProcess(request, onComplete, onError, arrayBuffer, typeValue) + } else { + if (request.transformations[0]) { + request.transformations[0].transform(arrayBuffer, request, { + asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => { + // 输出给Image + if (pixelMap) { + onComplete(pixelMap); + } else { + onError(error); + } + } + }) + } + else { + let success = (value: PixelMap) => { + onComplete(value); + } + this.mParseImageUtil.parseImage(arrayBuffer, success, onError,request) + } + } + } + let ctx = request.getModuleContext(); if (ctx != undefined) { - this.moduleContext = ctx; + this.mIResourceFetch.loadResource(ctx, request.loadSrc as Resource, success, onError); + } else { + onError('ImageKnife RequestManager loadSourceFormNative moduleContext is undefined! please check it') + } + + } + + // 加载磁盘缓存 原图 + private loadDiskFromSource(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, onError: (reason?: BusinessError | string) => void) { + LogUtil.log("ImageKnife RequestManager loadDiskFromSource") + let cached = this.diskMemoryCache.get(request.generateDataKey); + if (cached != null && cached.byteLength > 0) { + LogUtil.log("ImageKnife loadDiskFromSource load resource from DiskLruCache") + this.parseDiskFile2PixelMap(request, cached, onComplete, onError) + } else { + this.mStage = Stage.SOURCE; + this.mStage = request.onlyRetrieveFromCache? Stage.FINISHED : Stage.SOURCE + this.searchLoadFrom(this.options, this.mStage, onComplete, onError); } } - setPriority(priority: Priority) { - this.priority = priority - } - setTransformations( array:Array>){ - this.transformations = array; - } - generateUUID(): string { - return SparkMD5.hashBinary(JSON.stringify(this.loadSrc)) as string; - } - setModuleContext(moduleCtx: common.UIAbilityContext) { - this.moduleContext = moduleCtx; - } - - getModuleContext(): common.UIAbilityContext | undefined { - return this.moduleContext; - } - - /** - * set image Component size - */ - setImageViewSize(imageSize: Size) { - this.size.width = imageSize.width; - this.size.height = imageSize.height; - return this; - } - - getFilesPath() { - return this.filesPath; - } - - setFilesPath(path: string) { - this.filesPath = path; - } - - getCachesPath() { - return this.cachesPath; - } - - setCachesPath(path: string) { - this.cachesPath = path; - } - - load(src: string | PixelMap | Resource) { - this.loadSrc = src; - // 初始化唯一标识,可以用这个标识找到ImageKnife中的对象 - this.uuid = this.generateUUID(); - return this; - } - - diskCacheStrategy(strategy: DiskStrategy) { - this.strategy = strategy; - return this; - } - - dontAnimate() { - this.dontAnimateFlag = true; - return this; - } - - // 仅支持 本地图片 - placeholder(src: string | PixelMap | Resource, func?: AsyncSuccess) { - this.placeholderSrc = src; - this.placeholderFunc = func; - return this; - } - - errorholder(src: PixelMap | Resource, func?: AsyncSuccess) { - this.errorholderSrc = src; - this.errorholderFunc = func; - return this; - } - - fallback(src: PixelMap | Resource, func?: AsyncSuccess) { - this.fallbackSrc = src; - this.fallbackFunc = func; - return this; - } - - retryholder(src: PixelMap | Resource, func?: AsyncSuccess) { - this.retryholderSrc = src; - this.retryholderFunc = func; - return this; - } - - thumbnail(sizeMultiplier: number, func?: AsyncSuccess, displayTime?: number) { - this.thumbSizeMultiplier = sizeMultiplier; - this.thumbHolderFunc = func; - if (displayTime) { - this.thumbDelayTime = displayTime; + // 加载磁盘缓存 变换后图片 + private loadDiskFromTransform(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, onError: (reason?: BusinessError | string) => void) { + LogUtil.log("ImageKnife RequestManager loadDiskFromTransform") + let cached = this.diskMemoryCache.get(request.generateResourceKey); + if (cached != null) { + LogUtil.log("ImageKnife loadDiskFromTransform load resource from DiskLruCache") + this.parseDiskTransformFile2PixelMap(request, cached, onComplete, onError) + } else { + this.mStage = Stage.DATA_CACHE; + this.searchLoadFrom(this.options, this.mStage, onComplete, onError); } - return this; } - addProgressListener(func?: AsyncSuccess) { - this.progressFunc = func; - return this; - } - - addListener(func: AsyncCallback) { - if (this.requestListeners != undefined) { - this.requestListeners?.push(func); + parseSource(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, onError: (reason?: BusinessError | string) => void) { + LogUtil.log("ImageKnife RequestManager parseSource") + try { + if ((typeof (request.loadSrc as image.PixelMap).isEditable) == 'boolean') { + // PixelMap 外层捕获效率更高,不会进入这里 + } else if (typeof request.loadSrc == 'string') { + this.loadSourceFromNetwork(request, onComplete, onError); + } else { + let res = request.loadSrc as Resource; + if (typeof res.id != 'undefined') { + this.loadSourceFormNative(request, onComplete, onError) + } else { + LogUtil.log("输入参数有问题!") + } + } + } catch (e) { + LogUtil.error("ImageKnife RequestManager parseSource error") } - return this; + } - addAllCacheInfoCallback(func: IAllCacheInfoCallback) { - this.allCacheInfoCallback = func; - return this; + private loadLeve1MemoryCache(onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, onError: (reason?: BusinessError | string) => void) { + try { + this.runWrapped(this.options, this.mRunReason, onComplete, onError) + } catch (e) { + LogUtil.error("ImageKnife loadLeve1MemoryCache error") + } } - skipMemoryCache(skip: boolean) { - this.isCacheable = !skip; - return this; + // 解析磁盘文件变成PixeMap + private parseDiskFile2PixelMap(request: RequestOption, source: ArrayBuffer, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, onError: (reason?: BusinessError | string) => void) { + LogUtil.log("ImageKnife RequestManager parseDiskFile2PixelMap") + // 步骤一:文件转为pixelMap 然后变换 给Image组件 + let fileTypeUtil = new FileTypeUtil(); + let typeValue = fileTypeUtil.getFileType(source); + // 解析磁盘文件 gif、webp 和 svg + if ((ImageKnifeData.GIF == typeValue || ImageKnifeData.WEBP == typeValue) && !request.dontAnimateFlag) { + // 处理gif、webp + this.gifProcess(onComplete, onError, source, typeValue) + } else if (ImageKnifeData.SVG == typeValue) { + this.svgProcess(request, onComplete, onError, source, typeValue) + } else { + if (this.options.transformations[0]) { + if (this.options.thumbSizeMultiplier) { + let thumbOption: RequestOption = new RequestOption(); + thumbOption.setImageViewSize({ + width: Math.round(this.options.thumbSizeMultiplier * this.options.size.width), + height: Math.round(this.options.thumbSizeMultiplier * this.options.size.height) + }) + let ctx = this.options.getModuleContext() + if (ctx != undefined) { + thumbOption.setModuleContext(ctx) + } else { + onError('RequestManager parseDiskFile2PixelMap moduleContext is undefined, please check it!') + return + } + let thumbCallback = this.options.thumbholderOnComplete; + let thumbError = this.options.thumbholderOnError; + this.options.transformations[0].transform(source, thumbOption, { + asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => { + if (pixelMap) { + thumbCallback(pixelMap); + } else { + thumbError(error); + } + } + }) + setTimeout(() => { + this.options.transformations[0].transform(source, request, { + asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => { + if (pixelMap) { + onComplete(pixelMap); + } else { + onError(error); + } + } + }) + }, this.options.thumbDelayTime); + } + else { + this.options.transformations[0].transform(source, request, { + asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => { + if (pixelMap) { + onComplete(pixelMap); + } else { + onError(error); + } + } + }) + } + } else { + // thumbnail 缩略图部分 + if (request.thumbSizeMultiplier) { + let thumbCallback = this.options.thumbholderOnComplete + let thumbError = this.options.thumbholderOnError + let thumbSuccess = (value: PixelMap) => { + thumbCallback(value); + } + this.mParseImageUtil.parseImageThumbnail(request.thumbSizeMultiplier, source, thumbSuccess, thumbError); + setTimeout(() => { + let success = (value: PixelMap) => { + onComplete(value); + } + this.mParseImageUtil.parseImage(source, success, onError, request) + }, this.options.thumbDelayTime) + } else { + let success = (value: PixelMap) => { + onComplete(value); + } + this.mParseImageUtil.parseImage(source, success, onError, request) + } + } + } } - retrieveDataFromCache(flag: boolean) { - this.onlyRetrieveFromCache = flag; + // 解析磁盘变换后文件变成PixeMap + private parseDiskTransformFile2PixelMap(request: RequestOption, source: ArrayBuffer, onComplete: (value: PixelMap) => void | PromiseLike, onError: (reason?: BusinessError | string) => void) { + LogUtil.log("ImageKnife RequestManager parseDiskTransformFile2PixelMap") + let fileTypeUtil = new FileTypeUtil(); + let typeValue = fileTypeUtil.getFileType(source); + // thumbnail 缩略图部分 + if (request.thumbSizeMultiplier) { + let thumbCallback = this.options.thumbholderOnComplete + let thumbError = this.options.thumbholderOnError + let thumbSuccess = (value: PixelMap) => { + thumbCallback(value); + } + this.mParseImageUtil.parseImageThumbnail(request.thumbSizeMultiplier, source, thumbSuccess, thumbError); + setTimeout(() => { + let success = (value: PixelMap) => { + onComplete(value); + } + this.mParseImageUtil.parseImage(source, success, onError, request) + }, this.options.thumbDelayTime) + } else { + let success = (value: PixelMap) => { + onComplete(value); + } + this.mParseImageUtil.parseImage(source, success, onError, request) + } } - rotateImage(degreesToRotate: number | undefined) { - if (degreesToRotate == undefined) { + private downloadSuccess(request: RequestOption, source: ArrayBuffer, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, onError: (reason?: BusinessError | string) => void) { + + if (source == null || source == undefined || source.byteLength <= 0) { + onError('ImageKnife Download task completed. but download file is empty!') return } - let rotateImage = new RotateImageTransformation(degreesToRotate); - this.transformations.push(rotateImage); - return this; + + // 下载成功之后 去data/data/包名/唯一路径/文件名 读取数据 + // 步骤一:文件转为pixelMap 然后变换 给Image组件 + // 步骤二: 文件名保存一份全局 + // 步骤三:查看文件是否支持 非支持类型直接返回 + let fileTypeUtil = new FileTypeUtil(); + let filetype: string | null = fileTypeUtil.getFileType(source); + if (filetype == null) { + onError("下载文件解析后类型为null,请检查数据源!"); + return; + } + + if (!fileTypeUtil.isImage(source)) { + onError("暂不支持 下载文件类型!类型=" + filetype); + return; + } + + // 解析磁盘文件 gif、webp 和 svg + if ((ImageKnifeData.GIF == filetype || ImageKnifeData.WEBP == filetype) && !this.options.dontAnimateFlag) { + // 处理gif、webp + this.gifProcess(onComplete, onError, source, filetype) + + // 保存二级磁盘缓存 + Promise.resolve(source) + .then((arraybuffer: ArrayBuffer) => { + this.diskMemoryCache.set(this.options.generateDataKey,arraybuffer); + }) + .catch((err: BusinessError) => { + LogUtil.log('download file is =' + ImageKnifeData.GIF + 'and save diskLruCache error =' + (err as BusinessError)) + }) + } else if (ImageKnifeData.SVG == filetype) { + // 处理svg + this.svgProcess(request, onComplete, onError, source, filetype) + + // 保存二级磁盘缓存 + Promise.resolve(source) + .then((arraybuffer: ArrayBuffer) => { + this.diskMemoryCache.set(this.options.generateDataKey,arraybuffer); + }) + .catch((err: BusinessError) => { + LogUtil.log('download file is =' + ImageKnifeData.SVG + 'and save diskLruCache error =' + (err as BusinessError)) + }) + } else { + // 进行变换 + if (this.options.transformations[0]) { + // thumbnail 缩略图部分 + if (this.options.thumbSizeMultiplier) { + if (filetype != null) { + this.thumbnailProcess(source, filetype, onComplete, onError); + } + } else { + this.options.transformations[0].transform(source, this.options, { + asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => { + if (pixelMap) { + if (filetype != null) { + this.saveCacheAndDisk(pixelMap, filetype, onComplete, source); + } + } else { + onError(error); + } + } + }) + } + } else { + // thumbnail 缩略图部分 + if (this.options.thumbSizeMultiplier) { + let thumbCallback = this.options.thumbholderOnComplete + let thumbError = this.options.thumbholderOnError + let thumbSuccess = (value: PixelMap) => { + thumbCallback(value); + } + this.mParseImageUtil.parseImageThumbnail(this.options.thumbSizeMultiplier, source, thumbSuccess, thumbError); + setTimeout(() => { + let success = (value: PixelMap) => { + if (filetype != null) { + this.saveCacheAndDisk(value, filetype, onComplete, source); + } + } + this.mParseImageUtil.parseImage(source, success, onError, request) + }, this.options.thumbDelayTime) + } else { + let success = (value: PixelMap) => { + if (filetype != null) { + this.saveCacheAndDisk(value, filetype, onComplete, source); + } + } + this.mParseImageUtil.parseImage(source, success, onError, request) + } + } + } } - centerCrop() { - this.transformations.push(new CenterCrop()); - return this; + createImagePixelMap(imageKnifeType: ImageKnifeType, imageKnifeValue: PixelMap): ImageKnifeData { + return ImageKnifeData.createImagePixelMap(imageKnifeType, imageKnifeValue); } - centerInside() { - this.transformations.push(new CenterInside()); - return this; + createImageGIFFrame(imageKnifeType: ImageKnifeType, imageKnifeValue: GIFFrame[]): ImageKnifeData { + return ImageKnifeData.createImageGIFFrame(imageKnifeType, imageKnifeValue); } - fitCenter() { - this.transformations.push(new FitCenter()); - return this; + + private async saveCacheAndDisk(value: PixelMap, filetype: string, onComplete: (value: PixelMap) => void | PromiseLike, source: ArrayBuffer) { + let save2DiskCache = (arraybuffer: ArrayBuffer) => { + this.diskMemoryCache.set(this.options.generateDataKey,arraybuffer); + // 落盘之后需要主动移除当前request并且调用下一个加载 + let removeCurrentAndSearchNextRun = this.options.removeCurrentAndSearchNext; + removeCurrentAndSearchNextRun(); + } + let runSave2Disk = (resolve: (value: ArrayBuffer) => void | PromiseLike, reject: (reason?: BusinessError | string) => void) => { + resolve(source); + } + let promise = new Promise(runSave2Disk); + await promise.then(save2DiskCache); + onComplete(value); } - roundedCorners(obj: RoundCorner | undefined) { - if (obj == undefined) { + thumbnailProcess(source: ArrayBuffer, filetype: string, onComplete: (value: PixelMap) => void | PromiseLike, onError: (reason?: BusinessError | string) => void) { + let thumbOption = new RequestOption(); + let ctx = this.options.getModuleContext() + if (ctx != undefined) { + thumbOption.setModuleContext(ctx) + } else { + onError('RequestManager thumbnailProcess moduleContext is undefined, please check it!') return } - let transformation = new RoundedCornersTransformation({ - top_left: obj.top_left, - top_right: obj.top_right, - bottom_left: obj.bottom_left, - bottom_right: obj.bottom_right + thumbOption.setImageViewSize({ + width: Math.round(this.options.thumbSizeMultiplier * this.options.size.width), + height: Math.round(this.options.thumbSizeMultiplier * this.options.size.height) }) - this.transformations.push(transformation); - return this; - } - - cropCircle() { - let transformation = new CropCircleTransformation() - this.transformations.push(transformation); - return this; - } - - cropCircleWithBorder(border: number | undefined, obj: rgbColor | undefined) { - if (border == undefined || obj == undefined) { - return - } - let transformation = new CropCircleWithBorderTransformation(border, obj) - this.transformations.push(transformation); - return this; - } - - cropSquare() { - let transformation = new CropSquareTransformation() - this.transformations.push(transformation); - return this; - } - - crop(width: number | undefined, height: number | undefined, cropType: CropType | undefined) { - if (width == undefined || height == undefined || cropType == undefined) { - return - } - let transformation = new CropTransformation(width, height, cropType) - this.transformations.push(transformation); - return this; - } - - grayscale() { - let transformation = new GrayscaleTransformation() - this.transformations.push(transformation); - return this; - } - - brightnessFilter(brightness: number | undefined) { - if (brightness == undefined) { - return - } - let transformation = new BrightnessFilterTransformation(brightness) - this.transformations.push(transformation); - return this; - } - - contrastFilter(contrast: number | undefined) { - if (contrast == undefined) { - return - } - let transformation = new ContrastFilterTransformation(contrast) - this.transformations.push(transformation); - return this; - } - - invertFilter() { - let transformation = new InvertFilterTransformation() - this.transformations.push(transformation); - return this; - } - - sepiaFilter() { - let transformation = new SepiaFilterTransformation() - this.transformations.push(transformation); - return this; - } - - sketchFilter() { - let transformation = new SketchFilterTransformation() - this.transformations.push(transformation); - return this; - } - - blur(radius: number | undefined, sampling?: number) { - if (radius == undefined) { - return - } - if (sampling == undefined) { - let transformation = new BlurTransformation(radius) - this.transformations.push(transformation); - } else { - let transformation = new BlurTransformation(radius, sampling) - this.transformations.push(transformation); - } - return this; - } - - pixelationFilter(pixel: number | undefined) { - if (pixel == undefined) { - return - } - let transformation = new PixelationFilterTransformation(pixel) - this.transformations.push(transformation); - return this; - } - - swirlFilter(degree: number | undefined) { - if (degree == undefined) { - return - } - let transformation = new SwirlFilterTransformation(degree) - this.transformations.push(transformation); - return this; - } - - mask(maskResource: Resource | undefined) { - if (maskResource == undefined) { - return - } - let transformation = new MaskTransformation(maskResource) - this.transformations.push(transformation); - return this; - } - - kuwaharaFilter(radius: number | undefined) { - if (radius == undefined) { - return - } - let transformation = new KuwaharaFilterTransform(radius); - this.transformations.push(transformation); - return this; - } - - toonFilter(threshold: number | undefined, quantizationLevels: number | undefined) { - if (threshold == undefined || quantizationLevels == undefined) { - return - } - let transformation = new ToonFilterTransform(threshold, quantizationLevels); - this.transformations.push(transformation); - return this; - } - - vignetteFilter(centerPoint: Array | undefined, vignetteColor: Array | undefined, vignetteSpace: Array | undefined) { - if (centerPoint == undefined || vignetteColor == undefined || vignetteSpace == undefined) { - return - } - let transformation = new VignetteFilterTransform(centerPoint, vignetteColor, vignetteSpace); - this.transformations.push(transformation); - return this; - } - - transform(input: BaseTransform) { - this.transformations.push(input); - return this; - } - - transforms(inputs: BaseTransform[]) { - this.transformations = inputs; - return this; - } - - // 开启GPU变换绘制 - enableGPU() { - this.gpuEnabled = true; - return this; - } - downsampleStrategy(downsampType: ESObject){ - this.downsampType = downsampType - return this; - } - - // 占位图解析成功 - placeholderOnComplete = (imageKnifeData:ImageKnifeData) => { - LogUtil.log("placeholderOnComplete has called!"); - LogUtil.log("Main Image is Ready:" + this.loadMainReady); - if (!this.loadMainReady && !(this.loadErrorReady || this.loadRetryReady) && !this.loadThumbnailReady) { - // 主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图 - if (this.placeholderSrc != undefined) { - this.placeholderFunc?.asyncSuccess(imageKnifeData) - } - } - } - // 占位图解析失败 - placeholderOnError = (error: BusinessError | string) => { - LogUtil.log("占位图解析失败 error =" + error) - } - // 缩略图解析成功 - thumbholderOnComplete = (value: PixelMap | GIFFrame[]) => { - let imageKnifeData = new ImageKnifeData(); - if ((typeof (value as PixelMap).isEditable) == 'boolean') { - imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value as PixelMap); - } else { - imageKnifeData = ImageKnifeData.createImageGIFFrame(ImageKnifeType.GIFFRAME, value as GIFFrame[]); - } - if (!this.loadMainReady && !(this.loadErrorReady || this.loadRetryReady)) { - // 主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图 - if (this.thumbHolderFunc != undefined) { - this.thumbHolderFunc?.asyncSuccess(imageKnifeData) - } - } - } - // 缩略图解析失败 - thumbholderOnError = (error?: BusinessError | string) => { - LogUtil.log("缩略图解析失败 error =" + error) - } - // 加载失败 占位图解析成功 - errorholderOnComplete = (imageKnifeData:ImageKnifeData) => { - // 如果有错误占位图 先解析并保存在RequestOption中 等到加载失败时候进行调用 - this.errorholderData = imageKnifeData; - if (this.loadErrorReady) { - if (this.errorholderFunc != undefined) { - this.errorholderFunc.asyncSuccess(imageKnifeData) - } - } - } - // 加载失败 占位图解析失败 - errorholderOnError = (error: BusinessError | string) => { - LogUtil.log("失败占位图解析失败 error =" + error) - } - retryholderOnComplete = (imageKnifeData:ImageKnifeData) => { - this.retryholderData = imageKnifeData; - if (this.loadRetryReady) { - if (this.retryholderFunc != undefined) { - this.retryholderFunc?.asyncSuccess(imageKnifeData) - } - } - } - retryholderOnError = (error: BusinessError | string) => { - LogUtil.log("重试占位图解析失败 error =" + error) - } - //占位图加载失败 后备回调符解析成功 - fallbackOnComplete = (imageKnifeData:ImageKnifeData) => { - this.fallbackData = imageKnifeData; - if (this.loadFallBackReady) { - if (this.fallbackFunc != undefined) { - this.fallbackFunc?.asyncSuccess(imageKnifeData); - } - } - } - // 后备回调符解析失败 - fallbackOnError = (error: BusinessError | string) => { - LogUtil.error("失败占位图解析失败 error =" + JSON.stringify(error)); - } - loadComplete = (imageKnifeData: ImageKnifeData) => { - this.loadMainReady = true; - // 三级缓存数据加载成功 - if (this.requestListeners != undefined) { - for (let i = 0; i < this.requestListeners.length; i++) { - let requestListener = this.requestListeners[i]; - let boolInterception = requestListener.callback("", imageKnifeData); - if (boolInterception) { - break; + let thumbCallback = this.options.thumbholderOnComplete + let thumbError = this.options.thumbholderOnError + this.options.transformations[0].transform(source, thumbOption, { + asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => { + if (pixelMap) { + thumbCallback(pixelMap); + } else { + thumbError(error); } } - } - //输出缓存相关内容和信息 - if (this.allCacheInfoCallback) { - // 内存缓存 - let allCacheInfo: AllCacheInfo = { - memoryCacheInfo: { key: '', data: new ImageKnifeData() }, - resourceCacheInfo: { key: '', path: '' }, - dataCacheInfo: { key: '', path: '' } - }; - allCacheInfo.memoryCacheInfo = { - key: this.generateCacheKey, - data: imageKnifeData - } - let mDiskCacheProxy = new DiskCacheProxy(DiskLruCache.create(ImageKnifeGlobal.getInstance() - .getHapContext() as common.UIAbilityContext)) - // 变换后缓存 - allCacheInfo.resourceCacheInfo = { - key: SparkMD5.hashBinary(this.generateResourceKey) as string, - path: (mDiskCacheProxy.getCachePath() + SparkMD5.hashBinary(this.generateResourceKey)) as string - }; - - // 原图缓存 - allCacheInfo.dataCacheInfo = { - key: SparkMD5.hashBinary(this.generateDataKey) as string, - path: (mDiskCacheProxy.getCachePath() + SparkMD5.hashBinary(this.generateDataKey)) as string - } - this.allCacheInfoCallback.callback(allCacheInfo); - } - - if (imageKnifeData.waitSaveDisk) { - // 等落盘结束后主动调用#removeCurrentAndSearchNext方法 - } else { - // 非落盘情况,直接进行寻找下一个加载 - let imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife(); - if (imageKnife != undefined) { - imageKnife.removeRunning(this); - } - } + }) + setTimeout(() => { + this.options.transformations[0].transform(source, this.options, { + asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => { + if (pixelMap) { + this.saveCacheAndDisk(pixelMap, filetype, onComplete, source); + } else { + onError(error); + } + } + }) + }, this.options.thumbDelayTime) } - // 图片文件落盘之后会自动去寻找下一个数据加载 - removeCurrentAndSearchNext = () => { - if (ImageKnifeGlobal.getInstance().getImageKnife() != undefined) { - (ImageKnifeGlobal.getInstance().getImageKnife())?.removeRunning(this); - } + private svgProcess(option: RequestOption, onComplete: (value: PixelMap) => void | PromiseLike, onError: (reason?: BusinessError | string) => void, arraybuffer: ArrayBuffer, typeValue: string, cacheStrategy?: (cacheData: ImageKnifeData) => void) { + let svgParseImpl = new SVGParseImpl() + svgParseImpl.parseSvg(option, arraybuffer, onComplete, onError) } - loadError = (err: BusinessError | string) => { - LogUtil.log("loadError:" + err); - // 失败占位图展示规则 - if (this.retryholderFunc) { - // 重试图层优先于加载失败展示 - this.loadRetryReady = true; - if (this.retryholderData != null) { - this.retryholderFunc.asyncSuccess(this.retryholderData) - } - } else if (!this.retryholderFunc && !this.placeholderFunc && this.fallbackFunc) { - this.loadFallBackReady = true; - if (this.fallbackData != null) { - this.fallbackFunc.asyncSuccess(this.fallbackData); - } - } else { - // 失败图层标记,如果已经有数据直接展示失败图层 - this.loadErrorReady = true; - if (this.errorholderData != null) { - if (this.errorholderFunc != undefined) { - this.errorholderFunc.asyncSuccess(this.errorholderData) - } - } - } - if (this.requestListeners != undefined) { - for (let i = 0; i < this.requestListeners.length; i++) { - let requestListener = this.requestListeners[i]; - let boolInterception = requestListener.callback(err as string, new ImageKnifeData()); - if (boolInterception) { - break; - } + private gifProcess(onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, onError: (reason?: BusinessError | string) => void, arraybuffer: ArrayBuffer, typeValue: string, cacheStrategy?: (cacheData: ImageKnifeData) => void) { + let gifParseImpl = new GIFParseImpl() + gifParseImpl.parseGifs(arraybuffer, (data?: GIFFrame[], err?: BusinessError | string) => { + if (err) { + onError(err) } - } - // 加载失败之后 - if (ImageKnifeGlobal.getInstance().getImageKnife() != undefined) { - (ImageKnifeGlobal.getInstance().getImageKnife())?.removeRunning(this); - } + LogUtil.log("gifProcess data is null:" + (data == null)); + if (!!data) { + // let imageKnifeData = this.createImageGIFFrame(ImageKnifeType.GIFFRAME, data) + // LogUtil.log('gifProcess 生成gif 返回数据类型') + // if (cacheStrategy) { + // LogUtil.log('gifProcess 生成gif并且存入了缓存策略') + // cacheStrategy(imageKnifeData) + // } + onComplete(data) + } else { + onError('Parse GIF callback data is null, you need check callback data!') + } + }) } } - - diff --git a/library/src/main/ets/components/imageknife/SendableData.ets b/library/src/main/ets/components/imageknife/SendableData.ets index 28c1d7c..eb02777 100644 --- a/library/src/main/ets/components/imageknife/SendableData.ets +++ b/library/src/main/ets/components/imageknife/SendableData.ets @@ -41,8 +41,6 @@ export class SendableData{ private diskMemoryCachePath: string = ''; private diskMemoryCache?: DiskLruCache; private dataFetch: IDataFetch = new DownloadClient(); - private placeholderRegisterCacheKey: string = ""; - private placeholderRegisterMemoryCacheKey: string = ""; private downsampType: BaseDownsampling = new DownsampleNone(); public setDataFetch(value: IDataFetch) { this.dataFetch = value; @@ -181,24 +179,8 @@ export class SendableData{ return this.usageType; } - public setPlaceHolderRegisterCacheKey(value: string) { - this.placeholderRegisterCacheKey = value; - } - - public getPlaceHolderRegisterCacheKey(): string { - return this.placeholderRegisterCacheKey; - } - - public setPlaceHolderRegisterMemoryCacheKey(value: string) { - this.placeholderRegisterMemoryCacheKey = value; - } - - public getPlaceHolderRegisterMemoryCacheKey(): string { - return this.placeholderRegisterMemoryCacheKey; - } - - public setDownsampType(Type: BaseDownsampling) { - this.downsampType = Type; + public setDownsampType(Type: BaseDownsampling): BaseDownsampling{ + return this.downsampType = Type; } public getDownsampType(): BaseDownsampling { diff --git a/library/src/main/ets/components/imageknife/requestmanage/RequestManager.ets b/library/src/main/ets/components/imageknife/requestmanage/RequestManager.ets index 84b7094..74efddd 100644 --- a/library/src/main/ets/components/imageknife/requestmanage/RequestManager.ets +++ b/library/src/main/ets/components/imageknife/requestmanage/RequestManager.ets @@ -33,7 +33,6 @@ import { GIFFrame } from '../utils/gif/GIFFrame' import { LogUtil } from '../../imageknife/utils/LogUtil' import { BusinessError } from '@ohos.base' import { DataFetchResult } from '../networkmanage/DataFetchResult' -import { RequestOption } from '../RequestOption'; export enum Stage { @@ -167,7 +166,7 @@ export class RequestManager { // gif、webp处理 if ((ImageKnifeData.GIF == typeValue || ImageKnifeData.WEBP == typeValue) && !request.dontAnimateFlag) { // 处理gif、webp - this.gifProcess(onComplete, onError, arrayBuffer, typeValue) + this.gifProcess(onComplete, onError, arrayBuffer, typeValue,request) } else if (ImageKnifeData.SVG == typeValue) { // 处理svg this.svgProcess(request, onComplete, onError, arrayBuffer, typeValue) @@ -188,7 +187,7 @@ export class RequestManager { let success = (value: PixelMap) => { onComplete(value); } - this.mParseImageUtil.parseImage(arrayBuffer, success, onError,request, request) + this.mParseImageUtil.parseImage(arrayBuffer, success, onError,request) } } } @@ -534,9 +533,17 @@ export class RequestManager { svgParseImpl.parseSvg(option, arraybuffer, onComplete, onError) } - private gifProcess(onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, onError: (reason?: BusinessError | string) => void, arraybuffer: ArrayBuffer, typeValue: string, cacheStrategy?: (cacheData: ImageKnifeData) => void) { + private gifProcess( + onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, + onError: (reason?: BusinessError | string) => void, + arraybuffer: ArrayBuffer, + typeValue: string, + request?:RequestOption, + cacheStrategy?: (cacheData: ImageKnifeData) => void + ) { let gifParseImpl = new GIFParseImpl() - gifParseImpl.parseGifs(arraybuffer, (data?: GIFFrame[], err?: BusinessError | string) => { + gifParseImpl.parseGifs( + arraybuffer, (data?: GIFFrame[], err?: BusinessError | string) => { if (err) { onError(err) } @@ -552,6 +559,6 @@ export class RequestManager { } else { onError('Parse GIF callback data is null, you need check callback data!') } - }) + },request) } } diff --git a/library/src/main/ets/components/imageknife/utils/ParseImageUtil.ets b/library/src/main/ets/components/imageknife/utils/ParseImageUtil.ets index b004153..d6fd0c5 100644 --- a/library/src/main/ets/components/imageknife/utils/ParseImageUtil.ets +++ b/library/src/main/ets/components/imageknife/utils/ParseImageUtil.ets @@ -43,7 +43,7 @@ export class ParseImageUtil implements IParseImage { editable: true, desiredSize: defaultSize }; - if(request.downsampType.getName()!=='DownsampleNone'){ + if(request?.downsampType.getName()!=='DownsampleNone'){ const b:ESObject = new Downsampler().calculateScaling(imageinfo, hValue, wValue,request) opts= { editable: true, diff --git a/library/src/main/ets/components/imageknife/utils/gif/GIFParseImpl.ets b/library/src/main/ets/components/imageknife/utils/gif/GIFParseImpl.ets index abe1a37..7039608 100644 --- a/library/src/main/ets/components/imageknife/utils/gif/GIFParseImpl.ets +++ b/library/src/main/ets/components/imageknife/utils/gif/GIFParseImpl.ets @@ -34,7 +34,11 @@ export interface gifBackData { } export class GIFParseImpl implements IParseGif { - parseGifs(imageinfo: ArrayBuffer, callback: (data?: GIFFrame[], err?: BusinessError | string) => void) { + parseGifs( + imageinfo: ArrayBuffer, + callback: (data?: GIFFrame[], err?: BusinessError | string) => void, + _request?: RequestOption + ) { // 硬解码流程 let imageSource = image.createImageSource(imageinfo); let decodeOpts: image.DecodingOptions = { @@ -42,7 +46,29 @@ export class GIFParseImpl implements IParseGif { editable: true, rotate: 0 } - let data:GIFFrame[] = []; + let hValue: number = 0 + let wValue: number = 0 + imageSource.getImageInfo().then((value) => { + hValue = Math.round(value.size, height); + wValue = Math.round(value.size, height); + console.log('原始宽高:', JSON.stringify(value.size)) + console.log('classType', JSON.stringify(_request?.downsampType.getName())) + console.log('classType2', hValue, wValue) + if (_request?.downsampType.getName() !== 'DownsampleNone') { + const b: ESObject = new Downsampler().calculateScaling(imageinfo, Math.round(value.size.height), Math.round(value.size.width), _request) + console.log("classType1", JSON.stringify(b)) + decodeOpts = { + sampleSize: 1, + editable: true, + rotate: 0, + desiredSize: { + width: b.targetWidth, + height: b.targetHeight + } + } + } + }) + let data: GIFFrame[] = []; imageSource.createPixelMapList(decodeOpts).then((pixelList: Array) => { //sdk的api接口发生变更:从.getDelayTime() 变为.getDelayTimeList() imageSource.getDelayTimeList().then(delayTimes => { @@ -60,20 +86,20 @@ export class GIFParseImpl implements IParseGif { } data.push(frame) } - callback(data,undefined) + callback(data, undefined) imageSource.release(); }).catch((err: string) => { imageSource.release(); - callback(undefined,err) + callback(undefined, err) }) } }).catch((err: string) => { imageSource.release(); - callback(undefined,err) + callback(undefined, err) }) }).catch((err: string) => { imageSource.release(); - callback(undefined,err) + callback(undefined, err) }) } } \ No newline at end of file diff --git a/library/src/main/ets/components/imageknife/utils/gif/IParseGif.ets b/library/src/main/ets/components/imageknife/utils/gif/IParseGif.ets index d80f388..c83a64d 100644 --- a/library/src/main/ets/components/imageknife/utils/gif/IParseGif.ets +++ b/library/src/main/ets/components/imageknife/utils/gif/IParseGif.ets @@ -17,5 +17,9 @@ import { GIFFrame } from './GIFFrame' import worker from '@ohos.worker'; export interface IParseGif{ // gif解析 - parseGifs:(imageinfo: ArrayBuffer, callback: (data?:GIFFrame[], err?:BusinessError|string) => void, worker?:worker.ThreadWorker,runMainThread?:boolean)=>void + parseGifs:( + imageinfo: ArrayBuffer, + callback: (data?:GIFFrame[], err?:BusinessError|string) => void, + request:ESObject, + worker?:worker.ThreadWorker,runMainThread?:boolean)=>void } \ No newline at end of file diff --git a/library/src/main/ets/components/imageknife/utils/svg/SVGParseImpl.ets b/library/src/main/ets/components/imageknife/utils/svg/SVGParseImpl.ets index 51f0843..a7c69cf 100644 --- a/library/src/main/ets/components/imageknife/utils/svg/SVGParseImpl.ets +++ b/library/src/main/ets/components/imageknife/utils/svg/SVGParseImpl.ets @@ -17,6 +17,7 @@ import { RequestOption } from '../../RequestOption' import { BusinessError } from '@ohos.base' import { ImageKnifeData, ImageKnifeType } from '../../ImageKnifeData' import image from '@ohos.multimedia.image' +import { Downsampler } from '../../Downsampling/Downsampler' export class SVGParseImpl implements IParseSvg { parseSvg(option: RequestOption, imageInfo: ArrayBuffer, @@ -24,20 +25,10 @@ export class SVGParseImpl implements IParseSvg { onErrorFunction: (reason?: BusinessError | string) => void) { let imageSource: image.ImageSource = image.createImageSource(imageInfo); // 步骤一:文件转为pixelMap 然后变换 给Image组件 - let hValue = Math.round(option.size.height); - let wValue = Math.round(option.size.width); - let defaultSize: image.Size = { - height: hValue, - width: wValue - }; - let opts: image.DecodingOptions = { - editable: true, - desiredSize: defaultSize - }; - imageSource.getInageInfo().then((value) => { + imageSource.getImageInfo().then((value) => { let hValue = Math.round(value.size.height); let wValue = Math.round(value.size.width); - let defaultSize: image.size = { + let defaultSize: image.Size = { height: hValue, width: wValue };