@swf2es/format 0.0.0-stage → 0.1.1
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/LICENSE +202 -0
- package/LICENSE.third-party +35 -0
- package/README.md +22 -2
- package/dist/abc-names.d.ts +3 -0
- package/dist/abc-names.d.ts.map +1 -0
- package/dist/abc-names.js +127 -0
- package/dist/abc-names.js.map +1 -0
- package/dist/actions.d.ts +106 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +223 -0
- package/dist/actions.js.map +1 -0
- package/dist/air-descriptor.d.ts +11 -0
- package/dist/air-descriptor.d.ts.map +1 -0
- package/dist/air-descriptor.js +64 -0
- package/dist/air-descriptor.js.map +1 -0
- package/dist/api-versions.d.ts +12 -0
- package/dist/api-versions.d.ts.map +1 -0
- package/dist/api-versions.js +23 -0
- package/dist/api-versions.js.map +1 -0
- package/dist/bitmap.d.ts +34 -0
- package/dist/bitmap.d.ts.map +1 -0
- package/dist/bitmap.js +200 -0
- package/dist/bitmap.js.map +1 -0
- package/dist/button.d.ts +39 -0
- package/dist/button.d.ts.map +1 -0
- package/dist/button.js +61 -0
- package/dist/button.js.map +1 -0
- package/dist/compression.d.ts +47 -0
- package/dist/compression.d.ts.map +1 -0
- package/dist/compression.js +201 -0
- package/dist/compression.js.map +1 -0
- package/dist/display.d.ts +106 -0
- package/dist/display.d.ts.map +1 -0
- package/dist/display.js +306 -0
- package/dist/display.js.map +1 -0
- package/dist/filters.d.ts +66 -0
- package/dist/filters.d.ts.map +1 -0
- package/dist/filters.js +137 -0
- package/dist/filters.js.map +1 -0
- package/dist/font.d.ts +60 -0
- package/dist/font.d.ts.map +1 -0
- package/dist/font.js +169 -0
- package/dist/font.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/pbj.d.ts +178 -0
- package/dist/pbj.d.ts.map +1 -0
- package/dist/pbj.js +485 -0
- package/dist/pbj.js.map +1 -0
- package/dist/shape.d.ts +152 -0
- package/dist/shape.d.ts.map +1 -0
- package/dist/shape.js +412 -0
- package/dist/shape.js.map +1 -0
- package/dist/sound.d.ts +71 -0
- package/dist/sound.d.ts.map +1 -0
- package/dist/sound.js +92 -0
- package/dist/sound.js.map +1 -0
- package/dist/swf.d.ts +77 -0
- package/dist/swf.d.ts.map +1 -0
- package/dist/swf.js +164 -0
- package/dist/swf.js.map +1 -0
- package/dist/tags.d.ts +57 -0
- package/dist/tags.d.ts.map +1 -0
- package/dist/tags.js +59 -0
- package/dist/tags.js.map +1 -0
- package/dist/text.d.ts +75 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +136 -0
- package/dist/text.js.map +1 -0
- package/dist/zip.d.ts +17 -0
- package/dist/zip.d.ts.map +1 -0
- package/dist/zip.js +92 -0
- package/dist/zip.js.map +1 -0
- package/package.json +33 -3
- package/src/abc-names.ts +138 -0
- package/src/actions.ts +319 -0
- package/src/air-descriptor.ts +84 -0
- package/src/api-versions.ts +27 -0
- package/src/bitmap.ts +259 -0
- package/src/button.ts +99 -0
- package/src/compression.ts +243 -0
- package/src/display.ts +419 -0
- package/src/filters.ts +206 -0
- package/src/font.ts +238 -0
- package/src/index.ts +151 -0
- package/src/pbj.ts +651 -0
- package/src/shape.ts +618 -0
- package/src/sound.ts +173 -0
- package/src/swf.ts +234 -0
- package/src/tags.ts +58 -0
- package/src/text.ts +213 -0
- package/src/zip.ts +135 -0
package/src/font.ts
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// DefineFont through DefineFont3: a font's glyphs, the outlines a field that
|
|
2
|
+
// embeds it draws, and its layout, the advances, kerning, ascent and
|
|
3
|
+
// descent a field's text is laid out by.
|
|
4
|
+
import { readString, utf8 } from "./display.js";
|
|
5
|
+
import { readRecords, type ShapeRecord } from "./shape.js";
|
|
6
|
+
import { type Rect, SwfReader, type Tag } from "./swf.js";
|
|
7
|
+
import { DefineFont, DefineFont3, DefineFontInfo2 } from "./tags.js";
|
|
8
|
+
import { type FontName, readFontName } from "./text.js";
|
|
9
|
+
|
|
10
|
+
export interface Glyph {
|
|
11
|
+
/** The character, a UTF-16 code unit, or -1 before a legacy font has a character table. */
|
|
12
|
+
code: number;
|
|
13
|
+
/** Its outline: shape records of one fill, in the font's units, y down from the baseline. */
|
|
14
|
+
records: ShapeRecord[];
|
|
15
|
+
/** The advance and bounds from the layout, in the font's units; 0 and null without one. */
|
|
16
|
+
advance: number;
|
|
17
|
+
bounds: Rect | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface Font {
|
|
21
|
+
id: number;
|
|
22
|
+
name: string;
|
|
23
|
+
bold: boolean;
|
|
24
|
+
italic: boolean;
|
|
25
|
+
/** Units to the em: 1024 for DefineFont and DefineFont2, 20480 for DefineFont3. */
|
|
26
|
+
em: number;
|
|
27
|
+
/** In the order of the code table, which is by code. */
|
|
28
|
+
glyphs: Glyph[];
|
|
29
|
+
/** Whether the tag has a layout: without one a field cannot lay text out in it. */
|
|
30
|
+
layout: boolean;
|
|
31
|
+
ascent: number;
|
|
32
|
+
descent: number;
|
|
33
|
+
leading: number;
|
|
34
|
+
/** Kerning adjustments by pair, `first << 16 | second`, in the font's units. */
|
|
35
|
+
kerning: Map<number, number>;
|
|
36
|
+
/**
|
|
37
|
+
* DefineFontAlignZones' CSM hint, how much advanced anti-aliasing
|
|
38
|
+
* thickens its stems: 0 thin, 1 medium, 2 thick; none without the tag.
|
|
39
|
+
*/
|
|
40
|
+
csmHint?: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** DefineFont4's CFF data, when embedded; a tag without it still has a name and style. */
|
|
44
|
+
export interface Font4 {
|
|
45
|
+
id: number;
|
|
46
|
+
name: string;
|
|
47
|
+
bold: boolean;
|
|
48
|
+
italic: boolean;
|
|
49
|
+
data: Uint8Array | null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** DefineFont4 (91): a name, style, and optional OpenType CFF bytes. */
|
|
53
|
+
export function readFont4(bytes: Uint8Array, tag: Tag): Font4 {
|
|
54
|
+
const r = new SwfReader(bytes, tag.offset, tag.offset + tag.length);
|
|
55
|
+
const id = r.u16();
|
|
56
|
+
const flags = r.u8();
|
|
57
|
+
const name = readString(r);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
id,
|
|
61
|
+
name,
|
|
62
|
+
bold: (flags & 1) !== 0,
|
|
63
|
+
italic: (flags & 2) !== 0,
|
|
64
|
+
data: flags & 4 ? bytes.subarray(r.pos, r.end) : null,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** DefineFont (10), whose first offset gives the glyph count; its name and codes come separately. */
|
|
69
|
+
function readFont1(bytes: Uint8Array, tag: Tag): Font {
|
|
70
|
+
const r = new SwfReader(bytes, tag.offset, tag.offset + tag.length);
|
|
71
|
+
const font: Font = {
|
|
72
|
+
id: r.u16(),
|
|
73
|
+
name: "",
|
|
74
|
+
bold: false,
|
|
75
|
+
italic: false,
|
|
76
|
+
em: 1024,
|
|
77
|
+
glyphs: [],
|
|
78
|
+
layout: false,
|
|
79
|
+
ascent: 0,
|
|
80
|
+
descent: 0,
|
|
81
|
+
leading: 0,
|
|
82
|
+
kerning: new Map(),
|
|
83
|
+
};
|
|
84
|
+
const table = r.pos;
|
|
85
|
+
const first = r.u16();
|
|
86
|
+
if (r.overrun || first < 2 || first % 2 !== 0 || table + first > r.end) {
|
|
87
|
+
return font;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const offsets = [first];
|
|
91
|
+
for (let i = 1; i < first / 2; i++) {
|
|
92
|
+
const offset = r.u16();
|
|
93
|
+
if (offset < offsets[i - 1] || table + offset > r.end) {
|
|
94
|
+
return font;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
offsets.push(offset);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
offsets.push(r.end - table);
|
|
101
|
+
for (let i = 0; i < offsets.length - 1; i++) {
|
|
102
|
+
const start = offsets[i];
|
|
103
|
+
const end = offsets[i + 1];
|
|
104
|
+
const records = readRecords(new SwfReader(bytes, table + start, table + end), 1).records;
|
|
105
|
+
font.glyphs.push({ code: -1, records, advance: 0, bounds: null });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return font;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** A legacy font's name, style and glyph-to-character mapping, supplied after its outlines. */
|
|
112
|
+
export interface FontInfo extends FontName {
|
|
113
|
+
codes: number[];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** DefineFontInfo (13) or DefineFontInfo2 (62); the latter has a language byte before its codes. */
|
|
117
|
+
export function readFontInfo(bytes: Uint8Array, tag: Tag): FontInfo {
|
|
118
|
+
const r = new SwfReader(bytes, tag.offset, tag.offset + tag.length);
|
|
119
|
+
const id = r.u16();
|
|
120
|
+
const length = r.u8();
|
|
121
|
+
const name = utf8(bytes.subarray(r.pos, Math.min(r.pos + length, r.end))).replace(/\0+$/, "");
|
|
122
|
+
r.pos += length;
|
|
123
|
+
const flags = r.u8();
|
|
124
|
+
if (tag.code === DefineFontInfo2) {
|
|
125
|
+
r.u8();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const codes: number[] = [];
|
|
129
|
+
const size = flags & 1 ? 2 : 1;
|
|
130
|
+
while (r.pos + size <= r.end) {
|
|
131
|
+
codes.push(size === 2 ? r.u16() : r.u8());
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return { id, name, bold: (flags & 2) !== 0, italic: (flags & 4) !== 0, codes };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** DefineFont (10), DefineFont2 (48) or DefineFont3 (75), as far as the tag goes. */
|
|
138
|
+
export function readFont(bytes: Uint8Array, tag: Tag): Font {
|
|
139
|
+
if (tag.code === DefineFont) {
|
|
140
|
+
return readFont1(bytes, tag);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const named = readFontName(bytes, tag);
|
|
144
|
+
const r = new SwfReader(bytes, tag.offset, tag.offset + tag.length);
|
|
145
|
+
r.u16();
|
|
146
|
+
const flags = r.u8();
|
|
147
|
+
r.u8();
|
|
148
|
+
r.pos += 1 + r.u8();
|
|
149
|
+
const hasLayout = (flags & 0x80) !== 0;
|
|
150
|
+
const wideOffsets = (flags & 0x08) !== 0;
|
|
151
|
+
const wideCodes = (flags & 0x04) !== 0;
|
|
152
|
+
const count = r.u16();
|
|
153
|
+
const table = r.pos;
|
|
154
|
+
const offset = () => (wideOffsets ? r.u32() : r.u16());
|
|
155
|
+
const offsets: number[] = [];
|
|
156
|
+
for (let i = 0; i < count; i++) {
|
|
157
|
+
offsets.push(offset());
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const codeTable = count > 0 ? offset() : 0;
|
|
161
|
+
const glyphs: Glyph[] = [];
|
|
162
|
+
for (let i = 0; i < count; i++) {
|
|
163
|
+
const shape = new SwfReader(bytes, table + offsets[i], tag.offset + tag.length);
|
|
164
|
+
glyphs.push({ code: 0, records: readRecords(shape, 1).records, advance: 0, bounds: null });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const font: Font = {
|
|
168
|
+
...named,
|
|
169
|
+
em: tag.code === DefineFont3 ? 20480 : 1024,
|
|
170
|
+
glyphs,
|
|
171
|
+
layout: false,
|
|
172
|
+
ascent: 0,
|
|
173
|
+
descent: 0,
|
|
174
|
+
leading: 0,
|
|
175
|
+
kerning: new Map(),
|
|
176
|
+
};
|
|
177
|
+
if (count > 0) {
|
|
178
|
+
r.pos = table + codeTable;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const code = () => (wideCodes ? r.u16() : r.u8());
|
|
182
|
+
for (const glyph of glyphs) {
|
|
183
|
+
glyph.code = code();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (!hasLayout || r.overrun) {
|
|
187
|
+
return font;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
font.ascent = r.u16();
|
|
191
|
+
font.descent = r.u16();
|
|
192
|
+
font.leading = r.s16();
|
|
193
|
+
for (const glyph of glyphs) {
|
|
194
|
+
glyph.advance = r.s16();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
for (const glyph of glyphs) {
|
|
198
|
+
glyph.bounds = r.rect();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const pairs = r.u16();
|
|
202
|
+
for (let i = 0; i < pairs && !r.overrun; i++) {
|
|
203
|
+
const first = code();
|
|
204
|
+
const second = code();
|
|
205
|
+
font.kerning.set((first << 16) | second, r.s16());
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
font.layout = !r.overrun;
|
|
209
|
+
return font;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** The glyph for a character, by a binary search of the code table, as Flash finds it: null for one the font lacks. */
|
|
213
|
+
export function glyphOf(font: Font, code: number): Glyph | null {
|
|
214
|
+
let lo = 0;
|
|
215
|
+
let hi = font.glyphs.length - 1;
|
|
216
|
+
while (lo <= hi) {
|
|
217
|
+
const mid = (lo + hi) >> 1;
|
|
218
|
+
const c = font.glyphs[mid].code;
|
|
219
|
+
if (c === code) {
|
|
220
|
+
return font.glyphs[mid];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (c < code) {
|
|
224
|
+
lo = mid + 1;
|
|
225
|
+
} else {
|
|
226
|
+
hi = mid - 1;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** DefineFontAlignZones (73): the font it is for and its CSM hint; the zones themselves are not read. */
|
|
234
|
+
export function readFontAlignZones(bytes: Uint8Array, tag: Tag): { id: number; csmHint: number } {
|
|
235
|
+
const r = new SwfReader(bytes, tag.offset, tag.offset + tag.length);
|
|
236
|
+
const id = r.u16();
|
|
237
|
+
return { id, csmHint: r.u8() >> 6 };
|
|
238
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsers for the SWF container and its tags: shapes, fonts, text, bitmaps,
|
|
3
|
+
* sounds, buttons and filters, a DoABC's bytes, which codegen parses, and
|
|
4
|
+
* the AVM1 action blocks, which it compiles; and Pixel Bender's bytecode,
|
|
5
|
+
* which a script hands flash.display.Shader. Also an AIR application's
|
|
6
|
+
* descriptor, and the ZIP archives AIR packages are.
|
|
7
|
+
* The compiler and the player both use this package, so it must stay free of
|
|
8
|
+
* DOM and node APIs.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export { abcReferences } from "./abc-names.js";
|
|
12
|
+
export {
|
|
13
|
+
type ActionBlock,
|
|
14
|
+
type ActionList,
|
|
15
|
+
type ActionOwner,
|
|
16
|
+
ButtonCondition,
|
|
17
|
+
ClipEvent,
|
|
18
|
+
readActions,
|
|
19
|
+
} from "./actions.js";
|
|
20
|
+
export { type AirDescriptor, readAirDescriptor } from "./air-descriptor.js";
|
|
21
|
+
export { AIR_API_VERSION, API_VERSION, checkApiVersion } from "./api-versions.js";
|
|
22
|
+
export { type Bitmap, isBitmapTag, readBitmap } from "./bitmap.js";
|
|
23
|
+
export {
|
|
24
|
+
BUTTON_DOWN,
|
|
25
|
+
BUTTON_HIT_TEST,
|
|
26
|
+
BUTTON_OVER,
|
|
27
|
+
BUTTON_UP,
|
|
28
|
+
type Button,
|
|
29
|
+
type ButtonRecord,
|
|
30
|
+
readButton,
|
|
31
|
+
} from "./button.js";
|
|
32
|
+
export {
|
|
33
|
+
CompressedDataError,
|
|
34
|
+
CompressedDataTooLargeError,
|
|
35
|
+
decompressSwf,
|
|
36
|
+
decompressSwfPrefix,
|
|
37
|
+
deflateCompress,
|
|
38
|
+
LZMA_HEADER,
|
|
39
|
+
lzmaByteArrayCompress,
|
|
40
|
+
lzmaByteArrayUncompress,
|
|
41
|
+
type ZlibLevel,
|
|
42
|
+
zlibCompress,
|
|
43
|
+
zlibUncompress,
|
|
44
|
+
} from "./compression.js";
|
|
45
|
+
export {
|
|
46
|
+
type Place,
|
|
47
|
+
readBinaryData,
|
|
48
|
+
readDoAbc,
|
|
49
|
+
readExports,
|
|
50
|
+
readFrameLabel,
|
|
51
|
+
readPlace,
|
|
52
|
+
readRemove,
|
|
53
|
+
readScalingGrid,
|
|
54
|
+
readSceneData,
|
|
55
|
+
readSprite,
|
|
56
|
+
readString,
|
|
57
|
+
readSymbolClass,
|
|
58
|
+
type SceneData,
|
|
59
|
+
} from "./display.js";
|
|
60
|
+
export { type FilterColor, readFilters, type SwfFilter } from "./filters.js";
|
|
61
|
+
export {
|
|
62
|
+
type Font,
|
|
63
|
+
type Font4,
|
|
64
|
+
type FontInfo,
|
|
65
|
+
type Glyph,
|
|
66
|
+
glyphOf,
|
|
67
|
+
readFont,
|
|
68
|
+
readFont4,
|
|
69
|
+
readFontAlignZones,
|
|
70
|
+
readFontInfo,
|
|
71
|
+
} from "./font.js";
|
|
72
|
+
export {
|
|
73
|
+
PBJ_RULES,
|
|
74
|
+
PBJ_STRING,
|
|
75
|
+
PBJ_TYPE_SIZES,
|
|
76
|
+
PBJ_TYPES,
|
|
77
|
+
type PbjCompute,
|
|
78
|
+
PbjError,
|
|
79
|
+
type PbjIf,
|
|
80
|
+
type PbjInput,
|
|
81
|
+
type PbjKernel,
|
|
82
|
+
type PbjLoad,
|
|
83
|
+
type PbjMetadata,
|
|
84
|
+
PbjOp,
|
|
85
|
+
type PbjOperation,
|
|
86
|
+
type PbjParameter,
|
|
87
|
+
type PbjRegister,
|
|
88
|
+
type PbjRule,
|
|
89
|
+
type PbjSample,
|
|
90
|
+
type PbjSelect,
|
|
91
|
+
pbjFloatType,
|
|
92
|
+
readPbj,
|
|
93
|
+
} from "./pbj.js";
|
|
94
|
+
export {
|
|
95
|
+
type ColorTransform,
|
|
96
|
+
type Fill,
|
|
97
|
+
type Gradient,
|
|
98
|
+
type GradientStop,
|
|
99
|
+
IDENTITY,
|
|
100
|
+
type Line,
|
|
101
|
+
type Matrix,
|
|
102
|
+
type MorphShape,
|
|
103
|
+
readColorTransform,
|
|
104
|
+
readMatrix,
|
|
105
|
+
readMorphShape,
|
|
106
|
+
readShape,
|
|
107
|
+
type Shape,
|
|
108
|
+
type ShapeRecord,
|
|
109
|
+
} from "./shape.js";
|
|
110
|
+
export {
|
|
111
|
+
type ButtonSounds,
|
|
112
|
+
readButtonSound,
|
|
113
|
+
readSound,
|
|
114
|
+
readSoundInfo,
|
|
115
|
+
readSoundStreamBlock,
|
|
116
|
+
readSoundStreamHead,
|
|
117
|
+
readStartSound,
|
|
118
|
+
type Sound,
|
|
119
|
+
type SoundEnvelopePoint,
|
|
120
|
+
type SoundInfo,
|
|
121
|
+
type SoundStreamBlock,
|
|
122
|
+
type SoundStreamHead,
|
|
123
|
+
type StartSound,
|
|
124
|
+
} from "./sound.js";
|
|
125
|
+
export {
|
|
126
|
+
backgroundColor,
|
|
127
|
+
fileAttributes,
|
|
128
|
+
isAs3,
|
|
129
|
+
type Rect,
|
|
130
|
+
readSwf,
|
|
131
|
+
readSwfHeader,
|
|
132
|
+
readTags,
|
|
133
|
+
type Swf,
|
|
134
|
+
type SwfCompression,
|
|
135
|
+
type SwfHeader,
|
|
136
|
+
SwfReader,
|
|
137
|
+
type Tag,
|
|
138
|
+
} from "./swf.js";
|
|
139
|
+
export * as tags from "./tags.js";
|
|
140
|
+
export {
|
|
141
|
+
type CsmTextSettings,
|
|
142
|
+
type EditText,
|
|
143
|
+
type FontName,
|
|
144
|
+
readCsmTextSettings,
|
|
145
|
+
readEditText,
|
|
146
|
+
readFontName,
|
|
147
|
+
readStaticText,
|
|
148
|
+
type StaticText,
|
|
149
|
+
type TextRecord,
|
|
150
|
+
} from "./text.js";
|
|
151
|
+
export { readZip, type ZipEntry, ZipError } from "./zip.js";
|