import { ILeaferImage, ILeaferImageConfig, IFunction, IObject, InnerId, ILeaf, IMatrixData, ICanvasPattern, ILeaferImageCacheCanvas, ILeaferImagePatternPaint, ILeaferImageLevel, ISizeData, IImageCrossOrigin, IImageLOD, IInterlace } from '@leafer/interface' import { Platform } from '@leafer/platform' import { Resource } from '@leafer/file' import { IncrementId } from '@leafer/math' import { isUndefined } from '@leafer/data' import { ImageManager } from './ImageManager' const { IMAGE, create } = IncrementId export class LeaferImage implements ILeaferImage { public readonly innerId: InnerId public get tag() { return 'Image' } public get url() { return this.config.url } public lod?: IImageLOD public get crossOrigin(): IImageCrossOrigin { const { crossOrigin } = this.config; return isUndefined(crossOrigin) ? Platform.image.crossOrigin : crossOrigin } public view: any public width: number public height: number public isSVG: boolean public hasAlphaPixel: boolean // check png / svg / webp public get completed() { return this.ready || !!this.error } public ready: boolean public error: IObject public loading: boolean public use = 0 public config: ILeaferImageConfig protected waitComplete: IFunction[] = [] protected cache: ILeaferImageCacheCanvas constructor(config: ILeaferImageConfig) { this.innerId = create(IMAGE) this.config = config || (config = { url: '' }) if (config.view) { const { view } = config this.setView(view.config ? view.view : view) } ImageManager.isFormat('svg', config) && (this.isSVG = true) ImageManager.hasAlphaPixel(config) && (this.hasAlphaPixel = true) } public load(onSuccess?: IFunction, onError?: IFunction, thumbSize?: ISizeData): number { if (!this.loading) { this.loading = true Resource.tasker.add(async () => await Platform.origin['load' + this.tag as 'loadImage'](this.getLoadUrl(thumbSize), this.crossOrigin, this).then(img => { if (thumbSize) this.setThumbView(img) this.setView(img) }).catch((e) => { this.error = e this.onComplete(false) })) } this.waitComplete.push(onSuccess, onError) return this.waitComplete.length - 2 } public unload(index: number, stopEvent?: boolean): void { const l = this.waitComplete if (stopEvent) { const error = l[index + 1] if (error) error({ type: 'stop' }) } l[index] = l[index + 1] = undefined } protected setView(img: any): void { this.ready = true if (!this.width) { this.width = img.width this.height = img.height this.view = img } this.onComplete(true) } protected onComplete(isSuccess: boolean): void { let odd: number this.waitComplete.forEach((item, index) => { odd = index % 2 if (item) { if (isSuccess) { if (!odd) item(this) } else { if (odd) item(this.error) } } }) this.waitComplete.length = 0 this.loading = false } public getFull(_filters?: IObject): any { return this.view } public getCanvas(width: number, height: number, opacity?: number, filters?: IObject, xGap?: number, yGap?: number, smooth?: boolean, interlace?: IInterlace): any { width || (width = this.width) height || (height = this.height) if (this.cache) { // when use > 1, check cache let { params, data } = this.cache for (let i in params) { if (params[i] !== arguments[i]) { data = null; break } } if (data) return data } const canvas = Platform.image.resize(this.view, width, height, xGap, yGap, undefined, smooth, opacity, filters, interlace) this.cache = this.use > 1 ? { data: canvas, params: arguments } : null return canvas } public getPattern(canvas: any, repeat: string | null, transform?: IMatrixData, paint?: ILeaferImagePatternPaint): ICanvasPattern { const pattern = Platform.canvas.createPattern(canvas, repeat) Platform.image.setPatternTransform(pattern, transform, paint) return pattern } public render(canvas: any, x: number, y: number, width: number, height: number, _leaf: ILeaf, _paint: any, _imageScaleX: number, _imageScaleY: number): void { canvas.drawImage(this.view, x, y, width, height) } // need rewrite public getLoadUrl(_thumbSize?: ISizeData): string { return this.url } public setThumbView(_view: number): void { } public getThumbSize(_lod?: IImageLOD): ISizeData { return undefined } public getMinLevel(): number { return undefined } public getLevelData(_level: number, _width?: number, _height?: number,): ILeaferImageLevel { return undefined } public clearLevels(_checkUse?: boolean): void { } public destroyFilter(): void { } public destroy(): void { this.clearLevels() this.destroyFilter() const { view } = this if (view && view.close) view.close() // 可能为 ImageBitmap this.config = { url: '' } this.cache = this.view = null this.waitComplete.length = 0 } }