@file-viewer/doc 2.1.22 → 2.1.24

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.
@@ -0,0 +1,13 @@
1
+ export declare function detectMimeFromBlipType(blipType: number): string | null;
2
+ /**
3
+ * Inline picture characters often carry a miniature OfficeArt container that
4
+ * points at the BLIP used by the picture. We only need a compact subset of the
5
+ * shape metadata so the higher-level parser can annotate extracted assets with
6
+ * source shape ids and BLIP indices.
7
+ */
8
+ export declare function parseInlineOfficeArtShape(bytes: Uint8Array, startOffset?: number): {
9
+ shapeId: number;
10
+ blipIndex?: number;
11
+ name?: string;
12
+ description?: string;
13
+ } | null;
@@ -0,0 +1,174 @@
1
+ import { BinaryReader } from '../core/binary.js';
2
+ const OFFICEART_CONTAINER = 0x000f;
3
+ const OFFICEART_SP_CONTAINER = 0xf004;
4
+ const OFFICEART_SP = 0xf00a;
5
+ const OFFICEART_FOPT = 0xf00b;
6
+ const OFFICEART_SECONDARY_FOPT = 0xf121;
7
+ const OFFICEART_TERTIARY_FOPT = 0xf122;
8
+ const PROP_PIB = 0x0104;
9
+ const PROP_FILL_BLIP = 0x0186;
10
+ const PROP_PIB_NAME = 0x0105;
11
+ const PROP_SHAPE_NAME = 0x0380;
12
+ const PROP_ALT_TEXT = 0x0381;
13
+ function u16(bytes, offset) {
14
+ if (offset + 2 > bytes.length)
15
+ return 0;
16
+ return (bytes[offset] ?? 0) | ((bytes[offset + 1] ?? 0) << 8);
17
+ }
18
+ function u32(bytes, offset) {
19
+ if (offset + 4 > bytes.length)
20
+ return 0;
21
+ return (((bytes[offset] ?? 0))
22
+ | ((bytes[offset + 1] ?? 0) << 8)
23
+ | ((bytes[offset + 2] ?? 0) << 16)
24
+ | (((bytes[offset + 3] ?? 0) << 24) >>> 0)) >>> 0;
25
+ }
26
+ function decodeUtf16LeText(bytes) {
27
+ if (!bytes?.length)
28
+ return undefined;
29
+ try {
30
+ const value = new TextDecoder('utf-16le').decode(bytes).replace(/\0+$/g, '').trim();
31
+ return value || undefined;
32
+ }
33
+ catch {
34
+ return undefined;
35
+ }
36
+ }
37
+ function decodeAnsiText(bytes) {
38
+ if (!bytes?.length)
39
+ return undefined;
40
+ try {
41
+ const value = new TextDecoder('windows-1252').decode(bytes).replace(/\0+$/g, '').trim();
42
+ return value || undefined;
43
+ }
44
+ catch {
45
+ return undefined;
46
+ }
47
+ }
48
+ function decodeComplexText(bytes) {
49
+ return decodeUtf16LeText(bytes) || decodeAnsiText(bytes);
50
+ }
51
+ export function detectMimeFromBlipType(blipType) {
52
+ switch (blipType) {
53
+ case 0x02: return 'image/emf';
54
+ case 0x03: return 'image/wmf';
55
+ case 0x04: return 'image/pict';
56
+ case 0x05: return 'image/jpeg';
57
+ case 0x06: return 'image/png';
58
+ case 0x07: return 'image/dib';
59
+ case 0x11: return 'image/tiff';
60
+ case 0x12: return 'image/jpeg';
61
+ default: return null;
62
+ }
63
+ }
64
+ function parseOfficeArtRecordHeader(bytes, offset) {
65
+ if (offset < 0 || offset + 8 > bytes.length)
66
+ return null;
67
+ const reader = new BinaryReader(bytes);
68
+ const versionAndInstance = reader.u16(offset);
69
+ const recType = reader.u16(offset + 2);
70
+ const recLen = reader.u32(offset + 4);
71
+ const size = 8 + recLen;
72
+ if (recType < 0xf000 || recType > 0xffff)
73
+ return null;
74
+ if (recLen > bytes.length || offset + size > bytes.length)
75
+ return null;
76
+ return {
77
+ recVer: versionAndInstance & 0x000f,
78
+ recInstance: versionAndInstance >>> 4,
79
+ recType,
80
+ recLen,
81
+ size,
82
+ };
83
+ }
84
+ function parseOfficeArtFopt(bytes, offset, propertyCount) {
85
+ const payloadOffset = offset + 8;
86
+ if (payloadOffset + propertyCount * 6 > bytes.length)
87
+ return [];
88
+ const properties = [];
89
+ let propOffset = payloadOffset;
90
+ let complexOffset = payloadOffset + propertyCount * 6;
91
+ for (let index = 0; index < propertyCount; index += 1) {
92
+ const opid = u16(bytes, propOffset);
93
+ const value = u32(bytes, propOffset + 2);
94
+ propOffset += 6;
95
+ const propertyId = opid & 0x3fff;
96
+ const isBlipId = Boolean((opid >> 14) & 0x1);
97
+ const isComplex = Boolean((opid >> 15) & 0x1);
98
+ let complexData;
99
+ if (isComplex) {
100
+ if (complexOffset + value > bytes.length)
101
+ break;
102
+ complexData = bytes.subarray(complexOffset, complexOffset + value);
103
+ complexOffset += value;
104
+ }
105
+ properties.push({ propertyId, isBlipId, isComplex, value, complexData });
106
+ }
107
+ return properties;
108
+ }
109
+ function scanRecords(bytes, start, end, visitor) {
110
+ let cursor = Math.max(0, start);
111
+ const limit = Math.min(end, bytes.length);
112
+ while (cursor + 8 <= limit) {
113
+ const header = parseOfficeArtRecordHeader(bytes, cursor);
114
+ if (!header || cursor + header.size > limit) {
115
+ cursor += 1;
116
+ continue;
117
+ }
118
+ if (visitor(cursor, header) === true)
119
+ return true;
120
+ if (header.recVer === OFFICEART_CONTAINER) {
121
+ if (scanRecords(bytes, cursor + 8, cursor + header.size, visitor))
122
+ return true;
123
+ }
124
+ cursor += header.size;
125
+ }
126
+ return false;
127
+ }
128
+ /**
129
+ * Inline picture characters often carry a miniature OfficeArt container that
130
+ * points at the BLIP used by the picture. We only need a compact subset of the
131
+ * shape metadata so the higher-level parser can annotate extracted assets with
132
+ * source shape ids and BLIP indices.
133
+ */
134
+ export function parseInlineOfficeArtShape(bytes, startOffset = 0) {
135
+ let result = null;
136
+ scanRecords(bytes, startOffset, bytes.length, (offset, header) => {
137
+ if (header.recType !== OFFICEART_SP_CONTAINER || header.recVer !== OFFICEART_CONTAINER)
138
+ return false;
139
+ const end = offset + header.size;
140
+ let cursor = offset + 8;
141
+ let shapeId = 0;
142
+ let blipIndex;
143
+ let name;
144
+ let description;
145
+ while (cursor + 8 <= end) {
146
+ const child = parseOfficeArtRecordHeader(bytes, cursor);
147
+ if (!child || cursor + child.size > end)
148
+ break;
149
+ if (child.recType === OFFICEART_SP && child.recLen >= 8) {
150
+ shapeId = u32(bytes, cursor + 8);
151
+ }
152
+ else if (child.recType === OFFICEART_FOPT || child.recType === OFFICEART_SECONDARY_FOPT || child.recType === OFFICEART_TERTIARY_FOPT) {
153
+ const properties = parseOfficeArtFopt(bytes, cursor, child.recInstance);
154
+ for (const property of properties) {
155
+ if ((property.isBlipId || property.propertyId === PROP_PIB || property.propertyId === PROP_FILL_BLIP) && property.value > 0) {
156
+ blipIndex = property.value;
157
+ }
158
+ else if (property.propertyId === PROP_SHAPE_NAME) {
159
+ name = decodeComplexText(property.complexData) || name;
160
+ }
161
+ else if (property.propertyId === PROP_ALT_TEXT || property.propertyId === PROP_PIB_NAME) {
162
+ description = decodeComplexText(property.complexData) || description;
163
+ }
164
+ }
165
+ }
166
+ cursor += child.size;
167
+ }
168
+ if (!shapeId)
169
+ return false;
170
+ result = { shapeId, blipIndex, name, description };
171
+ return true;
172
+ });
173
+ return result;
174
+ }
@@ -0,0 +1,10 @@
1
+ export interface ConvertedVectorImage {
2
+ mime: 'image/svg+xml';
3
+ bytes: Uint8Array;
4
+ dataUrl: string;
5
+ width: number;
6
+ height: number;
7
+ sourceMime: 'image/emf' | 'image/wmf';
8
+ recordCount: number;
9
+ }
10
+ export declare function convertMetafileToSvg(mime: string, bytes: Uint8Array): ConvertedVectorImage | null;