libpag 4.5.0 → 4.5.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.
Files changed (80) hide show
  1. package/LICENSE.txt +1589 -0
  2. package/README.md +172 -10
  3. package/README.zh_CN.md +114 -15
  4. package/lib/libpag.cjs.js +5420 -6176
  5. package/lib/libpag.cjs.js.map +1 -1
  6. package/lib/libpag.esm.js +5420 -6176
  7. package/lib/libpag.esm.js.map +1 -1
  8. package/lib/libpag.min.js +1 -1
  9. package/lib/libpag.min.js.map +1 -1
  10. package/lib/libpag.umd.js +5420 -6176
  11. package/lib/libpag.umd.js.map +1 -1
  12. package/lib/libpag.wasm +0 -0
  13. package/package.json +23 -11
  14. package/src/.pag.wasm-mt.md5 +1 -0
  15. package/src/.pag.wasm.md5 +1 -1
  16. package/src/core/matrix.ts +1 -2
  17. package/src/core/video-reader.ts +73 -94
  18. package/src/interfaces.ts +8 -17
  19. package/src/pag-composition.ts +12 -5
  20. package/src/pag-file.ts +146 -129
  21. package/src/pag-font.ts +1 -3
  22. package/src/pag-image-layer.ts +1 -2
  23. package/src/pag-image.ts +1 -3
  24. package/src/pag-layer.ts +2 -3
  25. package/src/pag-player.ts +7 -6
  26. package/src/pag-solid-layer.ts +1 -2
  27. package/src/pag-surface.ts +1 -2
  28. package/src/pag-text-layer.ts +1 -2
  29. package/src/pag-view.ts +3 -14
  30. package/src/pag.ts +0 -6
  31. package/src/types.ts +46 -3
  32. package/src/utils/decorators.ts +0 -42
  33. package/src/utils/type-utils.ts +1 -9
  34. package/src/utils/ua.ts +0 -1
  35. package/src/wasm/libpag.js +7 -6
  36. package/src/wasm/libpag.wasm +0 -0
  37. package/src/wasm-mt/libpag.js +2 -0
  38. package/src/wasm-mt/libpag.wasm +0 -0
  39. package/src/wechat/pag-file.ts +1 -2
  40. package/src/wechat/pag-image.ts +0 -2
  41. package/src/wechat/pag-view.ts +1 -2
  42. package/types/third_party/tgfx/web/src/core/path-rasterizer.d.ts +4 -0
  43. package/types/third_party/tgfx/web/src/core/scaler-context.d.ts +9 -2
  44. package/types/third_party/tgfx/web/src/utils/decorators.d.ts +0 -2
  45. package/types/web/src/core/video-reader.d.ts +4 -3
  46. package/types/web/src/interfaces.d.ts +8 -15
  47. package/types/web/src/pag-composition.d.ts +3 -3
  48. package/types/web/src/pag-file.d.ts +4 -4
  49. package/types/web/src/pag-player.d.ts +2 -2
  50. package/types/web/src/pag-view.d.ts +1 -1
  51. package/types/web/src/types.d.ts +12 -3
  52. package/types/web/src/utils/decorators.d.ts +0 -2
  53. package/types/web/src/utils/ua.d.ts +0 -1
  54. package/types/web/tsconfig.json +19 -0
  55. package/lib/libpag.worker.cjs.js +0 -794
  56. package/lib/libpag.worker.cjs.js.map +0 -1
  57. package/lib/libpag.worker.esm.js +0 -789
  58. package/lib/libpag.worker.esm.js.map +0 -1
  59. package/lib/libpag.worker.js +0 -800
  60. package/lib/libpag.worker.js.map +0 -1
  61. package/lib/libpag.worker.min.js +0 -2
  62. package/lib/libpag.worker.min.js.map +0 -1
  63. package/src/worker/client.ts +0 -76
  64. package/src/worker/events.ts +0 -41
  65. package/src/worker/pag-file.ts +0 -90
  66. package/src/worker/pag-image.ts +0 -43
  67. package/src/worker/pag-view.ts +0 -171
  68. package/src/worker/utils.ts +0 -29
  69. package/src/worker/video-reader.ts +0 -62
  70. package/src/worker/worker.ts +0 -169
  71. package/types/third_party/tgfx/web/src/core/web-mask.d.ts +0 -26
  72. package/types/web/src/utils/canvas.d.ts +0 -4
  73. package/types/web/src/worker/client.d.ts +0 -16
  74. package/types/web/src/worker/events.d.ts +0 -32
  75. package/types/web/src/worker/pag-file.d.ts +0 -33
  76. package/types/web/src/worker/pag-image.d.ts +0 -8
  77. package/types/web/src/worker/pag-view.d.ts +0 -67
  78. package/types/web/src/worker/utils.d.ts +0 -7
  79. package/types/web/src/worker/video-reader.d.ts +0 -16
  80. package/types/web/src/worker/worker.d.ts +0 -13
package/lib/libpag.wasm CHANGED
Binary file
package/package.json CHANGED
@@ -1,30 +1,36 @@
1
1
  {
2
2
  "name": "libpag",
3
- "version": "4.5.0",
3
+ "version": "4.5.2",
4
4
  "description": "Portable Animated Graphics",
5
5
  "main": "lib/libpag.cjs.js",
6
6
  "module": "lib/libpag.esm.js",
7
7
  "browser": "lib/libpag.umd.js",
8
8
  "typings": "types/web/pag.d.ts",
9
9
  "scripts": {
10
- "build:js": "rimraf --glob lib/*.js lib/*.map types/* && rollup -c ./script/rollup.config.js && tsc -p ./tsconfig.type.json",
11
- "build:wx:js": "rimraf --glob wechat/lib/*.js wechat/lib/*.map wechat/lib/*.br wechat/types/* && rollup -c ./script/rollup.config.wx.js && tsc -p ./wechat/tsconfig.type.json && brotli ./wechat/lib/libpag.wasm",
12
- "build": "node script/cmake.demo.js && npm run build:js",
10
+ "build:js:mt": "rimraf --glob lib-mt/*.js lib-mt/*.map types/* && rollup -c ./script/rollup.config.js --environment ARCH:wasm-mt && tsc -p ./tsconfig.type.json && cp -r ./tsconfig.json ./types/web/ && node script/restore.replace.js -a wasm-mt",
11
+ "build:js:st": "rimraf --glob lib/*.js lib/*.map types/* && rollup -c ./script/rollup.config.js --environment ARCH:wasm && tsc -p ./tsconfig.type.json && cp -r ./tsconfig.json ./types/web/ && node script/restore.replace.js -a wasm",
12
+ "build:wx:js": "rimraf --glob wechat/lib/*.js wechat/lib/*.map wechat/lib/*.br wechat/types/* && rollup -c ./script/rollup.config.wx.js && tsc -p ./wechat/tsconfig.type.json && cp -r ./tsconfig.json ./wechat/types/web/ && brotli ./wechat/lib/libpag.wasm",
13
+ "build:mt": "node script/cmake.demo.js -a wasm-mt && npm run build:js:mt",
14
+ "build:st": "node script/cmake.demo.js -a wasm && npm run build:js:st",
13
15
  "build:wx": "node script/cmake.demo.wx.js && npm run build:wx:js",
14
- "build:debug": "node script/cmake.demo.js --debug && npm run build:js",
16
+ "build:debug:mt": "node script/cmake.demo.js -a wasm-mt --debug && npm run build:js:mt",
17
+ "build:debug:st": "node script/cmake.demo.js -a wasm --debug && npm run build:js:st",
15
18
  "build:wx:debug": "node script/cmake.demo.wx.js --debug && npm run build:wx:js",
16
- "dev": "rollup -c ./script/rollup.config.dev.js -w",
19
+ "dev:mt": "rollup -c ./script/rollup.config.dev.js -w --environment ARCH:wasm-mt",
20
+ "dev:st": "rollup -c ./script/rollup.config.dev.js -w --environment ARCH:wasm",
17
21
  "dev:wx": "rollup -c ./script/rollup.config.wx.dev.js -w",
18
22
  "dev:wx:brotli": "./script/brotli.sh",
19
23
  "eslint": "eslint --ext .ts src/ --config .eslintrc.js",
20
24
  "eslint:fix": "eslint --ext .ts src/ --fix",
21
25
  "prettier": "prettier --check \"src/**/*.ts\"",
22
26
  "prettier:fix": "prettier --write \"src/**/*.ts\"",
23
- "test": "node ./script/test.js",
24
- "cypress": "cypress run --browser chrome",
25
- "server": "http-server -p 8080 . -c-1 --cors -o demo",
27
+ "UnitTest": "node ./script/UnitTest.js",
28
+ "cypress": "cypress run --browser electron --headless ",
26
29
  "doc": "rimraf api-docs && typedoc --entryPointStrategy expand ./src --tsconfig ./tsconfig.doc.json",
27
- "brotli": "brotli ./lib/libpag.wasm"
30
+ "brotli": "brotli ./lib/libpag.wasm",
31
+ "server:mt": "node server.js wasm-mt",
32
+ "server:st": "node server.js wasm",
33
+ "server:cypress": "http-server -p 8080"
28
34
  },
29
35
  "repository": {
30
36
  "type": "git",
@@ -47,6 +53,7 @@
47
53
  "eslint": "~9.22.0",
48
54
  "eslint-config-alloy": "~5.1.2",
49
55
  "http-server": "~14.1.1",
56
+ "minimist": "^1.2.8",
50
57
  "prettier": "~2.7.1",
51
58
  "rimraf": "~5.0.10",
52
59
  "rollup": "~2.79.1",
@@ -72,5 +79,10 @@
72
79
  "zenoslin",
73
80
  "lvpengwei"
74
81
  ],
75
- "author": "libpag"
82
+ "author": "libpag",
83
+ "dependencies": {
84
+ "abort-controller": "^3.0.0",
85
+ "cross-spawn": "^7.0.6",
86
+ "express": "^5.1.0"
87
+ }
76
88
  }
@@ -0,0 +1 @@
1
+ 53d489bb760a7dc7b27cb35553a623dc
package/src/.pag.wasm.md5 CHANGED
@@ -1 +1 @@
1
- 9f603d49b2d0761f6c6f617228d6bed8
1
+ 7374d597974e20c8dac8212554df8937
@@ -1,9 +1,8 @@
1
1
  import { PAGModule } from '../pag-module';
2
- import { destroyVerify, wasmAwaitRewind } from '../utils/decorators';
2
+ import { destroyVerify } from '../utils/decorators';
3
3
  import { MatrixIndex } from '../types';
4
4
 
5
5
  @destroyVerify
6
- @wasmAwaitRewind
7
6
  export class Matrix {
8
7
  /**
9
8
  * Sets Matrix to:
@@ -5,11 +5,8 @@ import {
5
5
  VIDEO_PLAYBACK_RATE_MIN,
6
6
  } from '../constant';
7
7
  import { addListener, removeListener, removeAllListeners } from '../utils/video-listener';
8
- import { IPHONE, WECHAT, SAFARI_OR_IOS_WEBVIEW, WORKER } from '../utils/ua';
8
+ import { IPHONE, WECHAT, SAFARI_OR_IOS_WEBVIEW } from '../utils/ua';
9
9
  import { PAGModule } from '../pag-module';
10
- import { WorkerMessageType } from '../worker/events';
11
- import { WorkerVideoReader } from '../worker/video-reader';
12
- import { postMessage } from '../worker/utils';
13
10
 
14
11
  import type { TimeRange, VideoReader as VideoReaderInterfaces } from '../interfaces';
15
12
  import type { PAGPlayer } from '../pag-player';
@@ -49,34 +46,13 @@ const waitVideoCanPlay = (videoElement: HTMLVideoElement) => {
49
46
  };
50
47
 
51
48
  export class VideoReader {
52
- public static async create(
49
+ public static create(
53
50
  source: Uint8Array | HTMLVideoElement,
54
51
  width: number,
55
52
  height: number,
56
53
  frameRate: number,
57
54
  staticTimeRanges: TimeRange[],
58
- ): Promise<VideoReaderInterfaces> {
59
- if (WORKER) {
60
- const proxyId = await new Promise<number>((resolve) => {
61
- // TODO: source as HTMLVideoElement in WebWorker version.
62
- const uint8Array = source as Uint8Array;
63
- const buffer = uint8Array.buffer.slice(uint8Array.byteOffset, uint8Array.byteOffset + uint8Array.byteLength);
64
- postMessage(
65
- self,
66
- {
67
- name: WorkerMessageType.VideoReader_constructor,
68
- args: [buffer, width, height, frameRate, staticTimeRanges, true],
69
- },
70
- (res) => {
71
- resolve(res);
72
- },
73
- [buffer],
74
- );
75
- });
76
- const videoReader = new WorkerVideoReader(proxyId);
77
- PAGModule.currentPlayer?.linkVideoReader(videoReader);
78
- return videoReader;
79
- }
55
+ ): VideoReaderInterfaces {
80
56
  return new VideoReader(source, width, height, frameRate, staticTimeRanges);
81
57
  }
82
58
 
@@ -95,6 +71,7 @@ export class VideoReader {
95
71
  private height = 0;
96
72
  private bitmapCanvas: OffscreenCanvas | null = null;
97
73
  private bitmapCtx: OffscreenCanvasRenderingContext2D | null = null;
74
+ private currentFrame: number=0;
98
75
 
99
76
  public constructor(
100
77
  source: Uint8Array | HTMLVideoElement,
@@ -102,7 +79,6 @@ export class VideoReader {
102
79
  height: number,
103
80
  frameRate: number,
104
81
  staticTimeRanges: TimeRange[],
105
- isWorker = false,
106
82
  ) {
107
83
  if (isInstanceOf(source, globalThis.HTMLVideoElement)) {
108
84
  this.videoEl = source as HTMLVideoElement;
@@ -118,7 +94,8 @@ export class VideoReader {
118
94
  waitVideoCanPlay(this.videoEl).then(() => {
119
95
  this.canplay = true;
120
96
  });
121
- const blob = new Blob([source as Uint8Array], { type: 'video/mp4' });
97
+ const buffer = (source as Uint8Array).slice();
98
+ const blob = new Blob([buffer], { type: 'video/mp4' });
122
99
  this.videoEl.src = URL.createObjectURL(blob);
123
100
  if (IPHONE) {
124
101
  // use load() will make a bug on Chrome.
@@ -132,80 +109,82 @@ export class VideoReader {
132
109
  if (UHD_RESOLUTION < width || UHD_RESOLUTION < height) {
133
110
  this.disablePlaybackRate = true;
134
111
  }
135
- if (!isWorker) {
136
- this.linkPlayer(PAGModule.currentPlayer);
137
- }
138
112
  }
139
113
 
140
- public async prepare(targetFrame: number, playbackRate: number) {
141
- this.setError(null); // reset error
142
- this.isSought = false; // reset seek status
143
- const { currentTime } = this.videoEl!;
144
- const targetTime = targetFrame / this.frameRate;
145
- if (currentTime === 0 && targetTime === 0) {
146
- if (!this.canplay && !SAFARI_OR_IOS_WEBVIEW) {
147
- await waitVideoCanPlay(this.videoEl!);
148
- } else {
149
- try {
150
- await this.play();
151
- } catch (e) {
152
- this.setError(e);
153
- }
154
- await new Promise<void>((resolve) => {
155
- requestAnimationFrame(() => {
156
- this.pause();
114
+ public async prepare(targetFrame: number, playbackRate: number): Promise<void> {
115
+ const promise =new Promise<void>(async (resolve, reject) => {
116
+ this.setError(null); // reset error
117
+ this.isSought = false; // reset seek status
118
+ const { currentTime } = this.videoEl!;
119
+ const targetTime = targetFrame / this.frameRate;
120
+
121
+ if (currentTime === 0 && targetTime === 0) {
122
+ if (!this.canplay && !SAFARI_OR_IOS_WEBVIEW) {
123
+ await waitVideoCanPlay(this.videoEl!);
124
+ } else {
125
+ try {
126
+ await this.play();
127
+ } catch (e) {
128
+ this.setError(e);
129
+ this.currentFrame = targetFrame;
130
+ reject(e);
131
+ return;
132
+ }
133
+ await new Promise<void>((resolveInner) => {
134
+ requestAnimationFrame(() => {
135
+ this.pause();
136
+ resolveInner();
137
+ });
138
+ });
139
+ }
140
+ } else {
141
+ if (Math.round(targetTime * this.frameRate) === Math.round(currentTime * this.frameRate)) {
142
+ // Current frame
143
+ } else if (this.staticTimeRanges?.contains(targetFrame)) {
144
+ // Static frame
145
+ await this.seek(targetTime, false);
146
+ this.currentFrame = targetFrame;
147
+ resolve(); // Ensure promise resolves
148
+ return;
149
+ } else if (Math.abs(currentTime - targetTime) < (1 / this.frameRate) * VIDEO_DECODE_WAIT_FRAME) {
150
+ // Within tolerable frame rate deviation
151
+ } else {
152
+ // Seek and play
153
+ this.isSought = true;
154
+ await this.seek(targetTime);
155
+ this.currentFrame = targetFrame;
157
156
  resolve();
158
- });
159
- });
160
- }
161
- } else {
162
- if (Math.round(targetTime * this.frameRate) === Math.round(currentTime * this.frameRate)) {
163
- // Current frame
164
- } else if (this.staticTimeRanges?.contains(targetFrame)) {
165
- // Static frame
166
- await this.seek(targetTime, false);
167
- return;
168
- } else if (Math.abs(currentTime - targetTime) < (1 / this.frameRate) * VIDEO_DECODE_WAIT_FRAME) {
169
- // Within tolerable frame rate deviation
170
- } else {
171
- // Seek and play
172
- this.isSought = true;
173
- await this.seek(targetTime);
174
- return;
175
- }
176
- }
157
+ return;
158
+ }
159
+ }
177
160
 
178
- const targetPlaybackRate = Math.min(Math.max(playbackRate, VIDEO_PLAYBACK_RATE_MIN), VIDEO_PLAYBACK_RATE_MAX);
179
- if (!this.disablePlaybackRate && this.videoEl!.playbackRate !== targetPlaybackRate) {
180
- this.videoEl!.playbackRate = targetPlaybackRate;
181
- }
161
+ const targetPlaybackRate = Math.min(Math.max(playbackRate, VIDEO_PLAYBACK_RATE_MIN), VIDEO_PLAYBACK_RATE_MAX);
162
+ if (!this.disablePlaybackRate && this.videoEl!.playbackRate !== targetPlaybackRate) {
163
+ this.videoEl!.playbackRate = targetPlaybackRate;
164
+ }
182
165
 
183
- if (this.isPlaying && this.videoEl!.paused) {
184
- try {
185
- await this.play();
186
- } catch (e) {
187
- this.setError(e);
188
- }
189
- }
166
+ if (this.isPlaying && this.videoEl!.paused) {
167
+ try {
168
+ await this.play();
169
+ } catch (e) {
170
+ this.setError(e);
171
+ this.currentFrame = targetFrame;
172
+ reject(e);
173
+ return;
174
+ }
175
+ }
176
+ this.currentFrame = targetFrame;
177
+ resolve();
178
+ });
179
+ await promise;
190
180
  }
191
181
 
192
- public getVideo() {
193
- return this.videoEl;
182
+ public getCurrentFrame(): number {
183
+ return this.currentFrame;
194
184
  }
195
185
 
196
- // Only work in web worker version
197
- public async generateBitmap() {
198
- // Batter than createImageBitmap from video element in benchmark
199
- if (!this.bitmapCanvas) {
200
- this.bitmapCanvas = new OffscreenCanvas(this.width, this.height);
201
- this.bitmapCanvas!.width = this.width;
202
- this.bitmapCanvas!.height = this.height;
203
- this.bitmapCtx = this.bitmapCanvas.getContext('2d') as OffscreenCanvasRenderingContext2D | null;
204
- }
205
- this.bitmapCtx?.fillRect(0, 0, this.width, this.height);
206
- this.bitmapCtx?.drawImage(this.videoEl as HTMLVideoElement, 0, 0, this.width, this.height);
207
- this.bitmap = await createImageBitmap(this.bitmapCanvas);
208
- return this.bitmap;
186
+ public getVideo() {
187
+ return this.videoEl;
209
188
  }
210
189
 
211
190
  public async play() {
package/src/interfaces.ts CHANGED
@@ -1,4 +1,3 @@
1
- import type { WebFont } from '@tgfx/core/web-mask';
2
1
  import type { ctor, Point, Rect, Vector } from './types';
3
2
 
4
3
  export interface TimeRange {
@@ -32,30 +31,22 @@ export interface FontMetrics {
32
31
  capHeight: number;
33
32
  }
34
33
 
34
+ export interface Stroke {
35
+ width: number;
36
+ cap: ctor;
37
+ join: ctor;
38
+ miterLimit: number;
39
+ }
40
+
35
41
  export interface ScalerContext {
36
42
  fontString: (fauxBold: boolean, fauxItalic: boolean) => string;
37
43
  getAdvance: (text: string) => number;
38
44
  getBounds: (text: string, fauxBold: boolean, fauxItalic: boolean) => Rect;
39
45
  getFontMetrics: () => FontMetrics;
40
- generateImage: (text: string, bounds: Rect) => TexImageSource | OffscreenCanvas;
46
+ readPixels: (text: string, bounds: Rect, fauxBold: boolean, stroke?: Stroke) => Uint8Array | null;
41
47
  }
42
48
 
43
49
  export interface ScalerContextConstructor {
44
50
  isEmoji: (text: string) => boolean;
45
51
  new (fontName: string, fontStyle: string, size: number, fauxBold: boolean, fauxItalic: boolean): ScalerContext;
46
52
  }
47
-
48
- export interface WebMask {
49
- fillPath: (path: Path2D, fillType: ctor) => void;
50
- fillText: (webFont: WebFont, texts: Vector<string>, positions: Vector<Point>, matrixWasmIns: any) => void;
51
- strokeText: (
52
- webFont: WebFont,
53
- stroke: { width: number; cap: ctor; join: ctor; miterLimit: number },
54
- texts: Vector<string>,
55
- positions: Vector<Point>,
56
- matrixWasmIns: any,
57
- ) => void;
58
- clear: () => void;
59
- }
60
-
61
- export type WebMaskConstructor = new (canvas: HTMLCanvasElement | OffscreenCanvas) => WebMask;
@@ -1,12 +1,11 @@
1
1
  import { PAGModule } from './pag-module';
2
2
  import { PAGLayer } from './pag-layer';
3
- import { destroyVerify, wasmAwaitRewind } from './utils/decorators';
3
+ import { destroyVerify } from './utils/decorators';
4
4
  import { layer2typeLayer, proxyVector } from './utils/type-utils';
5
5
 
6
- import type { Marker } from './types';
6
+ import {type Marker,VecArray } from './types';
7
7
 
8
8
  @destroyVerify
9
- @wasmAwaitRewind
10
9
  export class PAGComposition extends PAGLayer {
11
10
  /**
12
11
  * Make a empty PAGComposition with specified size.
@@ -149,7 +148,11 @@ export class PAGComposition extends PAGLayer {
149
148
  public getLayersByName(layerName: string) {
150
149
  const wasmIns = this.wasmIns._getLayersByName(layerName);
151
150
  if (!wasmIns) throw new Error(`Get layers by ${layerName} fail!`);
152
- return proxyVector(wasmIns, layer2typeLayer);
151
+ const layerArray = VecArray.create();
152
+ for (const wasmIn of wasmIns) {
153
+ layerArray.push(layer2typeLayer(wasmIn));
154
+ }
155
+ return layerArray;
153
156
  }
154
157
  /**
155
158
  * Returns an array of layers that lie under the specified point. The point is in pixels and from
@@ -158,6 +161,10 @@ export class PAGComposition extends PAGLayer {
158
161
  public getLayersUnderPoint(localX: number, localY: number) {
159
162
  const wasmIns = this.wasmIns._getLayersUnderPoint(localX, localY);
160
163
  if (!wasmIns) throw new Error(`Get layers under point ${localX},${localY} fail!`);
161
- return proxyVector(wasmIns, layer2typeLayer);
164
+ const layerArray = VecArray.create();
165
+ for (const wasmIn of wasmIns) {
166
+ layerArray.push(layer2typeLayer(wasmIn));
167
+ }
168
+ return layerArray;
162
169
  }
163
170
  }