@leafer-in/film 0.0.0-stage → 2.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,41 @@
1
1
  {
2
2
  "name": "@leafer-in/film",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "2.3.2",
4
+ "description": "@leafer-in/film",
5
+ "author": "Chao (Leafer) Wan",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "dist/film.esm.min.js",
9
+ "exports": {
10
+ "import": "./dist/film.esm.min.js",
11
+ "require": "./dist/film.min.cjs",
12
+ "types": "./types/index.d.ts"
13
+ },
14
+ "types": "types/index.d.ts",
15
+ "unpkg": "dist/film.min.js",
16
+ "jsdelivr": "dist/film.min.js",
17
+ "files": [
18
+ "src",
19
+ "types",
20
+ "dist"
21
+ ],
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/leaferjs/leafer-in.git"
25
+ },
26
+ "homepage": "https://github.com/leaferjs/leafer-in/tree/main/packages/film",
27
+ "bugs": "https://github.com/leaferjs/leafer-in/issues",
28
+ "keywords": [
29
+ "leafer film",
30
+ "leafer-film",
31
+ "leafer-in",
32
+ "film",
33
+ "leafer-ui",
34
+ "leaferjs"
35
+ ],
36
+ "peerDependencies": {
37
+ "@leafer-ui/draw": "^2.2.4",
38
+ "@leafer-ui/interface": "^2.2.4",
39
+ "@leafer-in/interface": "^2.2.4"
40
+ }
6
41
  }
package/src/Film.ts ADDED
@@ -0,0 +1,27 @@
1
+ import { IFilm, IFilmInputData, IFilmData, } from '@leafer-ui/interface'
2
+ import { Image, registerUI, dataProcessor, useModule } from '@leafer-ui/draw'
3
+
4
+ import { FilmData } from './data/FilmData'
5
+ import { PaintFilm } from './PaintFilm'
6
+
7
+
8
+ @useModule(PaintFilm)
9
+ @registerUI()
10
+ export class Film<TInputData = IFilmInputData> extends Image<TInputData> implements IFilm {
11
+
12
+ public get __tag() { return 'Film' }
13
+
14
+ @dataProcessor(FilmData)
15
+ declare public __: IFilmData
16
+ }
17
+
18
+ export interface Film {
19
+
20
+ togglePlay(): void
21
+ play(): void
22
+ pause(): void
23
+ stop(): void
24
+
25
+ seekFrame(frameIndex: number): void
26
+
27
+ }
@@ -0,0 +1,201 @@
1
+ import { isUndefined, Platform } from '@leafer-ui/draw'
2
+ import { ICanvasContext2D, IFilmDecoder, IFilmFileType, IFilmFrame, ILeaf, IPointData, IBooleanMap, IFilmPlayOptions } from '@leafer-ui/interface'
3
+
4
+
5
+ interface IFilmDecoderMap {
6
+ [name: string]: { Decoder: any, force?: boolean }
7
+ }
8
+
9
+ export class FilmDecoder implements IFilmDecoder {
10
+
11
+ public width: number // 宽度
12
+ public height: number // 高度
13
+
14
+ public total: number // 总的帧数
15
+ public loop: number // 循环次数,为0表示无限循环
16
+
17
+ public frames: IFilmFrame[] = [] // 帧数据
18
+ public decodedIndex = -1 // 当前解码到第几帧
19
+
20
+ public atlas?: any // 合并图
21
+ public atlasContext?: ICanvasContext2D // 合并图的上下文手柄
22
+ public atlasGrid?: IPointData // 横竖的排列数量
23
+
24
+ public decoder: ImageDecoder // 解码器
25
+
26
+ // 缓冲画布
27
+ public bufferCanvas?: any
28
+ public bufferContext?: ICanvasContext2D
29
+
30
+
31
+ static decoderMap: IFilmDecoderMap = {}
32
+ static supportMap: IBooleanMap = {}
33
+ static maxAtlasSize = Platform.image.maxPatternSize
34
+
35
+ static register(type: IFilmFileType, Decoder: any, force?: boolean): void {
36
+ FilmDecoder.decoderMap[type] = { Decoder, force }
37
+ }
38
+
39
+ static async canUse(mimeType: string) {
40
+ const { supportMap } = this
41
+ let canUse = supportMap[mimeType]
42
+ if (!isUndefined(canUse)) return canUse
43
+ if (typeof ImageDecoder === 'undefined') return false
44
+ canUse = await ImageDecoder.isTypeSupported(mimeType)
45
+ return supportMap[mimeType] = canUse
46
+ }
47
+
48
+
49
+ public createAtlas(): void {
50
+ const { width, height, total } = this
51
+ if (width * height * total <= FilmDecoder.maxAtlasSize) {
52
+ // 合并所有帧到一张大图里(画布能放下所有帧时)
53
+ const columns = Math.ceil(Math.sqrt(total * height / width))
54
+ const rows = Math.ceil(total / columns)
55
+ this.atlasGrid = { x: columns, y: rows }
56
+ this.atlas = Platform.origin.createCanvas(width * columns, height * rows)
57
+ this.atlasContext = this.atlas.getContext('2d')
58
+ }
59
+ }
60
+
61
+ public async decodeHeader(data: ArrayBuffer, type: string): Promise<void> {
62
+ this.decoder = new ImageDecoder({ data, type })
63
+
64
+ await this.decoder.tracks.ready
65
+ const first = await this.decodeFrame(0)
66
+
67
+ const { displayWidth, displayHeight } = first.image, { selectedTrack } = this.decoder.tracks
68
+ this.width = displayWidth
69
+ this.height = displayHeight
70
+ this.total = selectedTrack.frameCount
71
+ this.loop = selectedTrack.repetitionCount
72
+
73
+ this.createAtlas()
74
+ if (this.atlas) this.mergeFrame(0) // 因为已经读取了第一帧,存在合并图时,必须再次合并进去
75
+ }
76
+
77
+ public async decodeFrame(frameIndex: number): Promise<IFilmFrame> {
78
+ const { frames } = this, frame = frames[frameIndex]
79
+ if (frame && !frame.decoding) return frame
80
+
81
+ // 必须顺序解码
82
+ for (let i = this.decodedIndex + 1; i <= frameIndex; i++) {
83
+ await this.decodeOneFrame(i)
84
+ this.decodedIndex = i
85
+ }
86
+
87
+ return frames[frameIndex]
88
+ }
89
+
90
+ public async decodeOneFrame(frameIndex: number): Promise<IFilmFrame> {
91
+ return new Promise((resolve) => {
92
+ this.decoder.decode({ frameIndex }).then(result => {
93
+ const { image } = result
94
+ const frame: IFilmFrame = { image, duration: image.duration / 1000 / 1000 } // duration单位为秒
95
+ this.frames[frameIndex] = frame
96
+ if (this.atlas) this.mergeFrame(frameIndex)
97
+ resolve(frame)
98
+ })
99
+ })
100
+ }
101
+
102
+ // 绘制当前帧到atlas合并图中
103
+ public mergeFrame(frameIndex: number, destoryFrameImage: boolean = true): void {
104
+ const frame = this.frames[frameIndex], { atlasGrid, width, height } = this
105
+ frame.x = (frameIndex % atlasGrid.x) * width
106
+ frame.y = Math.floor(frameIndex / atlasGrid.x) * height
107
+ this.atlasContext.drawImage(frame.image, frame.x, frame.y)
108
+ if (destoryFrameImage) this.destoryFrameImage(frame)
109
+ else delete frame.image
110
+ }
111
+
112
+ public render(canvas: ICanvasContext2D, x: number, y: number, width: number, height: number, leaf: ILeaf, playOptions: IFilmPlayOptions, _imageScaleX: number, _imageScaleY: number): void {
113
+ let { nowIndex, paused, speed, pauseIndex, loop, frameTimer } = playOptions
114
+
115
+ if (isUndefined(nowIndex)) nowIndex = 0
116
+
117
+ const { frames } = this, frame = frames[nowIndex]
118
+
119
+ if (this.renderFrame(frame, canvas, x, y, width, height)) {
120
+
121
+ if (frameTimer) return // 避免重复等待下一帧
122
+ if (!isUndefined(pauseIndex) && nowIndex === pauseIndex) { // 播放到暂停帧为止
123
+ playOptions.paused = true
124
+ return
125
+ }
126
+
127
+ let nextIndex = nowIndex + 1
128
+
129
+ if (nextIndex >= this.total) {
130
+ if (this.loop && isFinite(this.loop)) { // 限制循环次数
131
+ loop = (loop as number || 0) + 1
132
+ if (loop > this.loop) return
133
+ playOptions.loop = loop
134
+ }
135
+ nextIndex = 0
136
+ }
137
+
138
+ if (nextIndex < this.total && !frames[nextIndex]) {
139
+ frames[nextIndex] = { duration: 0, decoding: true } // 先占位,表示正在解码中
140
+ this.decodeFrame(nextIndex).finally(() => {
141
+ if (this.decodedIndex === this.total - 1) this.destroyDecoder()
142
+ })
143
+ }
144
+
145
+ if (paused) return
146
+
147
+ playOptions.frameTimer = setTimeout(() => {
148
+
149
+ playOptions.nowIndex = nextIndex
150
+ delete playOptions.frameTimer
151
+ leaf.forceRender()
152
+
153
+ }, frame.duration * (speed || 1) * 1000)
154
+
155
+ } else {
156
+
157
+ this.renderFrame(frames[nowIndex - 1], canvas, x, y, width, height) // 暂时渲染上一帧顶替
158
+ leaf.forceRender() // 防止停掉
159
+ }
160
+ }
161
+
162
+ private renderFrame(frame: IFilmFrame, canvas: ICanvasContext2D, x: number, y: number, width: number, height: number): boolean {
163
+ const canRender = frame && !frame.decoding, { atlas } = this
164
+ if (canRender) {
165
+ if (atlas) canvas.drawImage(atlas, frame.x, frame.y, this.width, this.height, x, y, width, height)
166
+ else canvas.drawImage(frame.image, x, y, width, height)
167
+ }
168
+ return canRender
169
+ }
170
+
171
+ // 销毁单帧
172
+ public destoryFrame(frameIndex: number, deleteIndex: boolean = true): void {
173
+ const { frames } = this, frame = frames[frameIndex]
174
+ if (frame) {
175
+ this.destoryFrameImage(frame)
176
+ if (deleteIndex) delete frames[frameIndex]
177
+ }
178
+ }
179
+
180
+ // 销毁单帧内的VideoFrame或canvas对象
181
+ public destoryFrameImage(frame: IFilmFrame): void {
182
+ const { image } = frame
183
+ if (image && image.close) image.close()
184
+ delete frame.image
185
+ }
186
+
187
+ public destroyDecoder(): void {
188
+ if (this.decoder) {
189
+ this.decoder.close()
190
+ this.decoder = null
191
+ }
192
+ }
193
+
194
+ public close(): void {
195
+ if (this.atlas) this.atlas = this.atlasContext = null
196
+ this.frames.forEach((_item, index) => this.destoryFrame(index, false))
197
+ this.frames.length = 0
198
+ this.destroyDecoder()
199
+ }
200
+
201
+ }
@@ -0,0 +1,143 @@
1
+ import { IFilmFrame } from '@leafer-ui/interface'
2
+ import { Platform } from '@leafer-ui/draw'
3
+
4
+ import { GifReader } from 'omggif'
5
+
6
+ import { FilmDecoder } from './FilmDecoder'
7
+
8
+
9
+ export class OmgFilmDecoder extends FilmDecoder {
10
+
11
+ public decoder: GifReader | any
12
+
13
+ // 复用 RGBA buffer
14
+ private decodeBuffer!: Uint8ClampedArray
15
+
16
+ // 复用 ImageData(避免每帧 new)
17
+ private sharedImageData!: ImageData
18
+
19
+ // 只保留一个 restore 缓存(disposal=3)
20
+ private restoreImageData: ImageData | null = null
21
+
22
+ // --------------------------------------------------
23
+ // 1️⃣ decodeHeader
24
+ // --------------------------------------------------
25
+
26
+ public async decodeHeader(data: ArrayBuffer): Promise<void> {
27
+ const decoder = this.decoder = new GifReader(new Uint8Array(data))
28
+ const { width, height } = decoder
29
+
30
+ this.width = width
31
+ this.height = height
32
+ this.total = decoder.numFrames()
33
+ this.loop = decoder.loopCount() || 0
34
+
35
+ // 工作 canvas(永远只有一个)
36
+ this.bufferCanvas = Platform.origin.createCanvas(width, height)
37
+ this.bufferContext = this.bufferCanvas.getContext('2d')!
38
+
39
+ // 复用 RGBA buffer
40
+ this.decodeBuffer = new Uint8ClampedArray(width * height * 4)
41
+
42
+ // 复用 ImageData
43
+ this.sharedImageData = this.bufferContext.createImageData(width, height)
44
+
45
+ this.createAtlas()
46
+
47
+ // 首帧必须解
48
+ await this.decodeFrame(0)
49
+ }
50
+
51
+ // --------------------------------------------------
52
+ // 2️⃣ decodeFrame(顺序安全)
53
+ // --------------------------------------------------
54
+
55
+ public async decodeOneFrame(frameIndex: number): Promise<IFilmFrame> {
56
+ const { decoder, decodeBuffer, bufferCanvas, bufferContext, sharedImageData } = this
57
+ const info = decoder.frameInfo(frameIndex)
58
+
59
+ // disposal=3 需要保存当前完整状态
60
+ if (info.disposal === 3) this.restoreImageData = bufferContext.getImageData(0, 0, this.width, this.height)
61
+
62
+ // 解码到 decodeBuffer
63
+ decoder.decodeAndBlitFrameRGBA(frameIndex, decodeBuffer)
64
+
65
+ // 复用 ImageData
66
+ sharedImageData.data.set(decodeBuffer)
67
+
68
+ // 绘制到 buffer
69
+ bufferContext.putImageData(sharedImageData, 0, 0)
70
+
71
+ let image: any
72
+
73
+ if (this.atlas) {
74
+ image = bufferCanvas
75
+ } else {
76
+ image = Platform.origin.createCanvas(this.width, this.height)
77
+ const frameCtx = image.getContext('2d')!
78
+ frameCtx.drawImage(bufferCanvas, 0, 0)
79
+ }
80
+
81
+ const frame: IFilmFrame = { image, duration: (info.delay || 10) / 100 }
82
+
83
+ this.frames[frameIndex] = frame
84
+
85
+ if (this.atlas) this.mergeFrame(frameIndex, false) // false 表示不物理销毁frame.image
86
+
87
+ this.applyDisposal(info)
88
+
89
+ return frame
90
+ }
91
+
92
+ // --------------------------------------------------
93
+ // 3️⃣ disposal 处理
94
+ // --------------------------------------------------
95
+
96
+ private applyDisposal(info: any): void {
97
+ const { bufferContext, restoreImageData } = this
98
+ const disposal = info.disposal
99
+ if (disposal === 2) {
100
+ bufferContext.clearRect(info.x, info.y, info.width, info.height) // 恢复透明(当前帧区域)
101
+ } else if (disposal === 3) {
102
+ if (restoreImageData) {
103
+ bufferContext.putImageData(restoreImageData, 0, 0)
104
+ this.restoreImageData = null
105
+ }
106
+ }
107
+ }
108
+
109
+ // --------------------------------------------------
110
+ // 5️⃣ destoryFrameImage
111
+ // --------------------------------------------------
112
+
113
+ public destoryFrameImage(frame: IFilmFrame): void {
114
+ if (!frame.image) return
115
+
116
+ const canvas = frame.image as HTMLCanvasElement
117
+
118
+ // 强制释放 backing store
119
+ canvas.width = 0
120
+ canvas.height = 0
121
+
122
+ delete frame.image
123
+ }
124
+
125
+ // --------------------------------------------------
126
+ // 释放解码资源
127
+ // --------------------------------------------------
128
+
129
+ public destroyDecoder(): void {
130
+ if (this.bufferCanvas) {
131
+ this.bufferCanvas.width = 0
132
+ this.bufferCanvas.height = 0
133
+
134
+ this.decoder = null
135
+ this.bufferCanvas = null
136
+ this.bufferContext = null
137
+
138
+ this.decodeBuffer = null
139
+ this.sharedImageData = null
140
+ this.restoreImageData = null
141
+ }
142
+ }
143
+ }
@@ -0,0 +1,56 @@
1
+ import { ILeafPaint, IFilmDecoder, IUI } from '@leafer-ui/interface'
2
+ import { isArray } from '@leafer-ui/draw'
3
+
4
+ export class PaintFilm {
5
+
6
+ public element: IUI
7
+
8
+ public get playerOptions(): ILeafPaint { const { fill } = (this.element || this as any).__; return isArray(fill) && fill.find(item => item.type === 'film') }
9
+
10
+ public get decoder(): IFilmDecoder { const { playerOptions } = this; return playerOptions && playerOptions.image && playerOptions.image.view }
11
+
12
+
13
+ constructor(element: IUI) {
14
+ this.element = element
15
+ }
16
+
17
+
18
+ public togglePlay(): void {
19
+ const { playerOptions } = this
20
+ if (playerOptions) {
21
+ if (playerOptions.paused) this.play()
22
+ else this.pause()
23
+ }
24
+ }
25
+
26
+ public play(): void {
27
+ const { playerOptions } = this
28
+ if (playerOptions && playerOptions.paused) {
29
+ delete playerOptions.paused;
30
+ (this.element || this as any).forceRender()
31
+ }
32
+ }
33
+
34
+ public pause(): void {
35
+ const { playerOptions } = this
36
+ if (playerOptions) playerOptions.paused = true
37
+ }
38
+
39
+ public stop(): void {
40
+ const { playerOptions } = this
41
+ if (playerOptions) {
42
+ delete playerOptions.frameTime
43
+ playerOptions.nowIndex = 0
44
+ this.pause()
45
+ }
46
+ }
47
+
48
+ public seekFrame(frameIndex: number): void {
49
+ const { playerOptions } = this
50
+ if (playerOptions) {
51
+ playerOptions.nowIndex = frameIndex;
52
+ (this.element || this as any).forceRender()
53
+ }
54
+ }
55
+
56
+ }
@@ -0,0 +1,9 @@
1
+ import { IMultimediaType } from '@leafer-ui/interface'
2
+ import { ImageData } from '@leafer-ui/draw'
3
+
4
+
5
+ export class FilmData extends ImageData {
6
+
7
+ public get __urlType(): IMultimediaType { return 'film' }
8
+
9
+ }
@@ -0,0 +1,23 @@
1
+ export function getFileExt(url: string): string {
2
+ if (!url) return ''
3
+
4
+ if (url.startsWith('data:')) {
5
+ const head = url.slice(5, url.indexOf(','))
6
+ const slash = head.indexOf('/')
7
+ const semi = head.indexOf(';')
8
+ return slash > -1
9
+ ? head.slice(slash + 1, semi > -1 ? semi : undefined).toLowerCase()
10
+ : ''
11
+ }
12
+
13
+ let end = url.length
14
+ const q = url.indexOf('?')
15
+ const h = url.indexOf('#')
16
+ if (q > -1 && q < end) end = q
17
+ if (h > -1 && h < end) end = h
18
+
19
+ const dot = url.lastIndexOf('.', end)
20
+ const slash = url.lastIndexOf('/', end)
21
+
22
+ return dot > slash ? url.slice(dot + 1, end).toLowerCase() : ''
23
+ }
package/src/index.ts ADDED
@@ -0,0 +1,75 @@
1
+ import { LeaferFilm, Platform, Creator, FileHelper, PaintImage, Resource, Plugin, isObject } from '@leafer-ui/draw'
2
+ import { ILeaferFilm, ILeaferFilmConfig, IImageCrossOrigin, ILeaf, IFilmDecoder, ILeafPaint, IFilmFileType } from '@leafer-ui/interface'
3
+
4
+ import { FilmDecoder } from './FilmDecoder'
5
+ import { OmgFilmDecoder } from './OmgFilmDecoder'
6
+ import { getFileExt } from './helper/ext'
7
+
8
+ export { Film } from './Film'
9
+ export { FilmData } from './data/FilmData'
10
+ export { FilmDecoder } from './FilmDecoder'
11
+ export { PaintFilm } from './PaintFilm'
12
+
13
+
14
+ Plugin.add('flim')
15
+
16
+
17
+ PaintImage.film = function (paint: ILeafPaint, oldPaint?: ILeafPaint): void {
18
+ paint.film = true
19
+ paint.nowIndex = 0
20
+ if (isObject(oldPaint)) {
21
+ paint.nowIndex = oldPaint.nowIndex
22
+ paint.pauseIndex = oldPaint.pauseIndex
23
+ paint.speed = oldPaint.speed
24
+ paint.paused = oldPaint.paused
25
+ paint.loop = oldPaint.loop
26
+ }
27
+ }
28
+
29
+ Creator.film = function (options?: ILeaferFilmConfig): ILeaferFilm {
30
+ return new LeaferFilm(options)
31
+ }
32
+
33
+ Resource.loadFilm = function (key: string, format?: IFilmFileType): Promise<ILeaferFilm> {
34
+ return new Promise((resolve, reject) => {
35
+ const config: ILeaferFilmConfig = { url: key }
36
+ if (format) config.format = format
37
+ const film = Creator.film(config)
38
+ Resource.set(key, film)
39
+ film.load(() => resolve(film), (e: any) => reject(e))
40
+ })
41
+ }
42
+
43
+ LeaferFilm.prototype.render = function (canvas: any, x: number, y: number, width: number, height: number, leaf: ILeaf, paint: any, imageScaleX: number, imageScaleY: number): void {
44
+ this.view.render(canvas, x, y, width, height, leaf, paint, imageScaleX, imageScaleY)
45
+ }
46
+
47
+ FilmDecoder.register('gif', OmgFilmDecoder) // OmgFilmDecoder
48
+
49
+ Platform.origin.loadFilm = async function (url: string, _crossOrigin?: IImageCrossOrigin, leaferFilm?: ILeaferFilm): Promise<any> {
50
+ const buffer = await Platform.origin.loadContent(url, 'arrayBuffer')
51
+
52
+ let ext = getFileExt(url) // 获取文件后缀名
53
+
54
+ if (!ext) {
55
+ if (leaferFilm) ext = leaferFilm.config.format
56
+ if (!ext) ext = 'gif'
57
+ }
58
+
59
+ const mimeType = FileHelper.mimeType(ext)
60
+ const canUseFilmDecoder = await FilmDecoder.canUse(mimeType)
61
+
62
+ let Decoder: any
63
+ const tool = FilmDecoder.decoderMap[ext]
64
+
65
+ if (!tool || (canUseFilmDecoder && !tool.force)) Decoder = FilmDecoder
66
+ else Decoder = tool.Decoder
67
+
68
+ if (!Decoder) throw new Error('no decoder: ' + mimeType)
69
+
70
+ const decoder: IFilmDecoder = new Decoder()
71
+ await decoder.decodeHeader(buffer, mimeType)
72
+
73
+ return decoder
74
+ }
75
+
@@ -0,0 +1,69 @@
1
+ import { IFilmInputData, IFilm, IFilmData, IMultimediaType, IFilmDecoder, IFilmFrame, ICanvasContext2D, IPointData, IBooleanMap, IFilmFileType, ILeaf, IFilmPlayOptions, IUI, ILeafPaint } from '@leafer-ui/interface';
2
+ import { Image, ImageData } from '@leafer-ui/draw';
3
+
4
+ declare class Film<TInputData = IFilmInputData> extends Image<TInputData> implements IFilm {
5
+ get __tag(): string;
6
+ __: IFilmData;
7
+ }
8
+ interface Film {
9
+ togglePlay(): void;
10
+ play(): void;
11
+ pause(): void;
12
+ stop(): void;
13
+ seekFrame(frameIndex: number): void;
14
+ }
15
+
16
+ declare class FilmData extends ImageData {
17
+ get __urlType(): IMultimediaType;
18
+ }
19
+
20
+ interface IFilmDecoderMap {
21
+ [name: string]: {
22
+ Decoder: any;
23
+ force?: boolean;
24
+ };
25
+ }
26
+ declare class FilmDecoder implements IFilmDecoder {
27
+ width: number;
28
+ height: number;
29
+ total: number;
30
+ loop: number;
31
+ frames: IFilmFrame[];
32
+ decodedIndex: number;
33
+ atlas?: any;
34
+ atlasContext?: ICanvasContext2D;
35
+ atlasGrid?: IPointData;
36
+ decoder: ImageDecoder;
37
+ bufferCanvas?: any;
38
+ bufferContext?: ICanvasContext2D;
39
+ static decoderMap: IFilmDecoderMap;
40
+ static supportMap: IBooleanMap;
41
+ static maxAtlasSize: number;
42
+ static register(type: IFilmFileType, Decoder: any, force?: boolean): void;
43
+ static canUse(mimeType: string): Promise<boolean>;
44
+ createAtlas(): void;
45
+ decodeHeader(data: ArrayBuffer, type: string): Promise<void>;
46
+ decodeFrame(frameIndex: number): Promise<IFilmFrame>;
47
+ decodeOneFrame(frameIndex: number): Promise<IFilmFrame>;
48
+ mergeFrame(frameIndex: number, destoryFrameImage?: boolean): void;
49
+ render(canvas: ICanvasContext2D, x: number, y: number, width: number, height: number, leaf: ILeaf, playOptions: IFilmPlayOptions, _imageScaleX: number, _imageScaleY: number): void;
50
+ private renderFrame;
51
+ destoryFrame(frameIndex: number, deleteIndex?: boolean): void;
52
+ destoryFrameImage(frame: IFilmFrame): void;
53
+ destroyDecoder(): void;
54
+ close(): void;
55
+ }
56
+
57
+ declare class PaintFilm {
58
+ element: IUI;
59
+ get playerOptions(): ILeafPaint;
60
+ get decoder(): IFilmDecoder;
61
+ constructor(element: IUI);
62
+ togglePlay(): void;
63
+ play(): void;
64
+ pause(): void;
65
+ stop(): void;
66
+ seekFrame(frameIndex: number): void;
67
+ }
68
+
69
+ export { Film, FilmData, FilmDecoder, PaintFilm };