diff --git a/library/src/main/ets/components/imageknife/RequestOption.ets b/library/src/main/ets/components/imageknife/RequestOption.ets index 4d4e547..97f6d48 100644 --- a/library/src/main/ets/components/imageknife/RequestOption.ets +++ b/library/src/main/ets/components/imageknife/RequestOption.ets @@ -12,545 +12,671 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { ImageKnife } from './ImageKnife' +import { DiskStrategy } from "../cache/diskstrategy/DiskStrategy" +import { AsyncCallback } from "../imageknife/interface/AsyncCallback" +import { AsyncSuccess } from "../imageknife/interface/AsyncSuccess" +import { AllCacheInfo, IAllCacheInfoCallback } from "../imageknife/interface/IAllCacheInfoCallback" +import { AUTOMATIC } from "../cache/diskstrategy/enum/AUTOMATIC" +import { BaseTransform } from "../imageknife/transform/BaseTransform" +import { RotateImageTransformation } from "../imageknife/transform/RotateImageTransformation" +import { ImageKnifeData, ImageKnifeType } from "../imageknife/ImageKnifeData" +import { CenterCrop } from '../imageknife/transform/pixelmap/CenterCrop' +import { CenterInside } from '../imageknife/transform/pixelmap/CenterInside' +import { FitCenter } from '../imageknife/transform/pixelmap/FitCenter' +import { RoundedCornersTransformation, RoundCorner } from '../imageknife/transform/RoundedCornersTransformation' -import { RequestOption, Size } from '../../imageknife/RequestOption' -import { DiskLruCache } from "../../cache/DiskLruCache" -import { LruCache } from '../../cache/LruCache' -import { SparkMD5 } from '../../3rd_party/sparkmd5/spark-md5' -import { MemoryCacheProxy } from '../requestmanage/MemoryCacheProxy' -import { DiskCacheProxy } from '../requestmanage/DiskCacheProxy' -import { FileTypeUtil } from '../utils/FileTypeUtil' -import { IDataFetch } from '../../imageknife/networkmanage/IDataFetch' -import { IResourceFetch } from '../../imageknife/resourcemanage/IResourceFetch' -import { ImageKnifeData, ImageKnifeType } from '../ImageKnifeData' -import { AllCacheInfo } from '../../imageknife/interface/IAllCacheInfoCallback' -import { ParseImageUtil } from '../utils/ParseImageUtil' -import { IParseImage } from '../interface/IParseImage' -import image from '@ohos.multimedia.image' -import { SVGParseImpl } from '../utils/svg/SVGParseImpl' -import { GIFParseImpl } from '../utils/gif/GIFParseImpl' -import { GIFFrame } from '../utils/gif/GIFFrame' -import { LogUtil } from '../../imageknife/utils/LogUtil' +import { CropCircleTransformation } from '../imageknife/transform/CropCircleTransformation' + +import { + CropCircleWithBorderTransformation, + rgbColor +} from '../imageknife/transform/CropCircleWithBorderTransformation' +import { CropSquareTransformation } from '../imageknife/transform/CropSquareTransformation' +import { CropTransformation } from '../imageknife/transform/CropTransformation' +import { CropType } from '../imageknife/transform/CropTransformation' +import { GrayscaleTransformation } from '../imageknife/transform/GrayscaleTransformation' +import { BrightnessFilterTransformation } from '../imageknife/transform/BrightnessFilterTransformation' +import { ContrastFilterTransformation } from '../imageknife/transform/ContrastFilterTransformation' +import { InvertFilterTransformation } from '../imageknife/transform/InvertFilterTransformation' +import { SepiaFilterTransformation } from '../imageknife/transform/SepiaFilterTransformation' +import { SketchFilterTransformation } from '../imageknife/transform/SketchFilterTransformation' +import { BlurTransformation } from '../imageknife/transform/BlurTransformation' +import { PixelationFilterTransformation } from '../imageknife/transform/PixelationFilterTransformation' +import { MaskTransformation } from '../imageknife/transform/MaskTransformation' +import { SwirlFilterTransformation } from '../imageknife/transform/SwirlFilterTransformation' +import { KuwaharaFilterTransform } from '../imageknife/transform/KuwaharaFilterTransform' +import { ToonFilterTransform } from '../imageknife/transform/ToonFilterTransform' +import { VignetteFilterTransform } from '../imageknife/transform/VignetteFilterTransform' +import { LogUtil } from '../imageknife/utils/LogUtil' +import { ImageKnifeGlobal } from './ImageKnifeGlobal' import { BusinessError } from '@ohos.base' -import { DataFetchResult } from '../networkmanage/DataFetchResult' +import { ObjectKey } from './ObjectKey' +import common from '@ohos.app.ability.common' +import { GIFFrame } from './utils/gif/GIFFrame' +import { DiskCacheProxy } from './requestmanage/DiskCacheProxy' +import { DiskLruCache } from '../cache/DiskLruCache' +import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5' +import { FileUtils } from '../cache/FileUtils' +import util from '@ohos.util' +import { DataFetchResult } from './networkmanage/DataFetchResult' +import { BaseDownsampling } from './Downsampling/BaseDownsampling' -export enum Stage { - - INITIALIZE, - - RESOURCE_CACHE, - - DATA_CACHE, - - SOURCE, - - ENCODE, - - FINISHED, +export interface Size { + width: number, + height: number } - -export enum RunReason { - - INITIALIZE, - - SWITCH_TO_SOURCE_SERVICE, - - DECODE_DATA, +export enum CacheType { + Default, + //缓存 + Cache, + //磁盘 + Disk } -export class RequestManager { - private TAG: string = "RequestManager"; - private options: RequestOption; - private mIDataFetch: IDataFetch; - private mIResourceFetch: IResourceFetch; - private mParseImageUtil: IParseImage; - private diskMemoryCache: DiskLruCache; +export interface DetachFromLayout { + detach: () => void +} - constructor(option: RequestOption,diskMemoryCache: DiskLruCache, dataFetch: IDataFetch, resourceFetch: IResourceFetch) { - this.options = option; +export enum Priority { + HIGH = 0, + MEDIUM = 1, + LOW = 2 +} +export class RequestOption { + // 遍历添加图片http请求头 + headers: Map = new Map(); - this.diskMemoryCache = diskMemoryCache; - // 网络下载能力 - this.mIDataFetch = dataFetch; - - // 本地数据解析能力 - this.mIResourceFetch = resourceFetch; - - // 解析image能力 - this.mParseImageUtil = new ParseImageUtil(); + // RequestOption调用header对于的方法 + addHeader(key: string, value: Object) { + this.headers.set(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) - } - - 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) - } - } - - 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); - } - } - - // 究竟从哪里加载数据 - 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") - } + // 全局调用header对应的方法,包含RequestOption的形式 + addHeaderMap(map: Map) { + map.forEach((value, key) => { + if (!this.headers.has(key)) { + this.addHeader(key, value); } - } 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) - } + // 优先级 + 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); } } - let ctx = request.getModuleContext(); + } + // module资源的需要当前的module context + moduleContext?: common.UIAbilityContext = undefined; + + constructor() { + // 初始化全局监听 + this.requestListeners = new Array(); + + let ctx = ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext if (ctx != undefined) { - 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); + this.moduleContext = ctx; } } - - // 加载磁盘缓存 变换后图片 - 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); - } + setPriority(priority: Priority) { + this.priority = priority + } + setTransformations( array:Array>){ + this.transformations = array; + } + generateUUID(): string { + return SparkMD5.hashBinary(JSON.stringify(this.loadSrc)) as string; } - 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") - } - + setModuleContext(moduleCtx: common.UIAbilityContext) { + this.moduleContext = moduleCtx; } - 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") - } + getModuleContext(): common.UIAbilityContext | undefined { + return this.moduleContext; } - // 解析磁盘文件变成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) - } - } - } + /** + * set image Component size + */ + setImageViewSize(imageSize: Size) { + this.size.width = imageSize.width; + this.size.height = imageSize.height; + return this; } - // 解析磁盘变换后文件变成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) - } + getFilesPath() { + return this.filesPath; } - private downloadSuccess(request: RequestOption, source: ArrayBuffer, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike, onError: (reason?: BusinessError | string) => void) { + setFilesPath(path: string) { + this.filesPath = path; + } - if (source == null || source == undefined || source.byteLength <= 0) { - onError('ImageKnife Download task completed. but download file is empty!') + 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; + } + return this; + } + + addProgressListener(func?: AsyncSuccess) { + this.progressFunc = func; + return this; + } + + addListener(func: AsyncCallback) { + if (this.requestListeners != undefined) { + this.requestListeners?.push(func); + } + return this; + } + + addAllCacheInfoCallback(func: IAllCacheInfoCallback) { + this.allCacheInfoCallback = func; + return this; + } + + skipMemoryCache(skip: boolean) { + this.isCacheable = !skip; + return this; + } + + retrieveDataFromCache(flag: boolean) { + this.onlyRetrieveFromCache = flag; + } + + rotateImage(degreesToRotate: number | undefined) { + if (degreesToRotate == undefined) { return } - - // 下载成功之后 去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) - } - } - } + let rotateImage = new RotateImageTransformation(degreesToRotate); + this.transformations.push(rotateImage); + return this; } - createImagePixelMap(imageKnifeType: ImageKnifeType, imageKnifeValue: PixelMap): ImageKnifeData { - return ImageKnifeData.createImagePixelMap(imageKnifeType, imageKnifeValue); + centerCrop() { + this.transformations.push(new CenterCrop()); + return this; } - createImageGIFFrame(imageKnifeType: ImageKnifeType, imageKnifeValue: GIFFrame[]): ImageKnifeData { - return ImageKnifeData.createImageGIFFrame(imageKnifeType, imageKnifeValue); + centerInside() { + this.transformations.push(new CenterInside()); + 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); + fitCenter() { + this.transformations.push(new FitCenter()); + return this; } - 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!') + roundedCorners(obj: RoundCorner | undefined) { + if (obj == undefined) { return } - thumbOption.setImageViewSize({ - width: Math.round(this.options.thumbSizeMultiplier * this.options.size.width), - height: Math.round(this.options.thumbSizeMultiplier * this.options.size.height) + let transformation = new RoundedCornersTransformation({ + top_left: obj.top_left, + top_right: obj.top_right, + bottom_left: obj.bottom_left, + bottom_right: obj.bottom_right }) - 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, this.options, { - asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => { - if (pixelMap) { - this.saveCacheAndDisk(pixelMap, filetype, onComplete, source); - } else { - onError(error); - } - } - }) - }, this.options.thumbDelayTime) + this.transformations.push(transformation); + return 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) + cropCircle() { + let transformation = new CropCircleTransformation() + this.transformations.push(transformation); + return this; } - 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) + 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) } - 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!') + } + } + // 占位图解析失败 + 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; + } + } + } + //输出缓存相关内容和信息 + 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); + } + } + } + + // 图片文件落盘之后会自动去寻找下一个数据加载 + removeCurrentAndSearchNext = () => { + if (ImageKnifeGlobal.getInstance().getImageKnife() != undefined) { + (ImageKnifeGlobal.getInstance().getImageKnife())?.removeRunning(this); + } + } + 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; + } + } + } + // 加载失败之后 + if (ImageKnifeGlobal.getInstance().getImageKnife() != undefined) { + (ImageKnifeGlobal.getInstance().getImageKnife())?.removeRunning(this); + } } } + +