wpd-codec 3.4.6 → 3.5.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.
Files changed (38) hide show
  1. package/README.md +31 -27
  2. package/dist/container/container.cjs +12 -5
  3. package/dist/container/container.d.cts +2 -1
  4. package/dist/container/container.d.ts +2 -1
  5. package/dist/container/container.js +12 -5
  6. package/dist/container/encryption.d.cts +1 -1
  7. package/dist/container/encryption.d.ts +1 -1
  8. package/dist/container/header.d.cts +1 -19
  9. package/dist/container/header.d.ts +1 -19
  10. package/dist/container/prefix.d.cts +1 -1
  11. package/dist/container/prefix.d.ts +1 -1
  12. package/dist/{diagnostics-DhO7mgqJ.d.cts → diagnostics-fHTFHZ-d.d.cts} +2 -0
  13. package/dist/{diagnostics-DhO7mgqJ.d.ts → diagnostics-fHTFHZ-d.d.ts} +2 -0
  14. package/dist/diagnostics.cjs +2 -0
  15. package/dist/diagnostics.d.cts +1 -1
  16. package/dist/diagnostics.d.ts +1 -1
  17. package/dist/diagnostics.js +2 -0
  18. package/dist/header-Ca8QZVe3.d.cts +20 -0
  19. package/dist/header-Ca8QZVe3.d.ts +20 -0
  20. package/dist/index.d.cts +2 -2
  21. package/dist/index.d.ts +2 -2
  22. package/dist/read.cjs +85 -14
  23. package/dist/read.d.cts +1 -1
  24. package/dist/read.d.ts +1 -1
  25. package/dist/read.js +85 -14
  26. package/dist/stream/furniture.cjs +1 -2
  27. package/dist/stream/furniture.d.cts +2 -2
  28. package/dist/stream/furniture.d.ts +2 -2
  29. package/dist/stream/furniture.js +1 -2
  30. package/dist/stream/ole.cjs +71 -0
  31. package/dist/stream/ole.d.cts +22 -0
  32. package/dist/stream/ole.d.ts +22 -0
  33. package/dist/stream/ole.js +64 -0
  34. package/dist/stream/wpg.cjs +620 -0
  35. package/dist/stream/wpg.d.cts +18 -0
  36. package/dist/stream/wpg.d.ts +18 -0
  37. package/dist/stream/wpg.js +619 -0
  38. package/package.json +4 -4
@@ -0,0 +1,619 @@
1
+ import { byteAt, int16At, uint16At, uint32At } from "../bytes/view.js";
2
+ //#region src/stream/wpg.ts
3
+ const RECORD_START_WPG = 1;
4
+ const RECORD_END_WPG = 2;
5
+ const RECORD_TEXT_DATA = 15;
6
+ const RECORD_POLYLINE = 21;
7
+ const RECORD_RECTANGLE = 24;
8
+ const RECORD_ARC = 25;
9
+ const RECORD_TEXT_BLOCK = 29;
10
+ const RECORD_GROUP = 32;
11
+ const RECORD_PEN_FORE_COLOR = 37;
12
+ const RECORD_DP_PEN_FORE_COLOR = 38;
13
+ const RECORD_PEN_SIZE = 43;
14
+ const RECORD_DP_PEN_SIZE = 44;
15
+ const RECORD_BRUSH_FORE_COLOR = 49;
16
+ const RECORD_DP_BRUSH_FORE_COLOR = 50;
17
+ const RECORD_NAMES = /* @__PURE__ */ new Map([
18
+ [1, "Start WPG"],
19
+ [3, "Form Settings"],
20
+ [4, "Ruler Settings"],
21
+ [5, "Grid Settings"],
22
+ [6, "Layer"],
23
+ [7, "ObjectLink"],
24
+ [8, "Pen Style Definition"],
25
+ [9, "Pattern Definition"],
26
+ [10, "Comment"],
27
+ [11, "Color Transfer"],
28
+ [12, "Color Palette"],
29
+ [13, "DP Color Palette"],
30
+ [14, "Bitmap Data"],
31
+ [15, "Text Data"],
32
+ [16, "Chart Style"],
33
+ [17, "Chart Data"],
34
+ [18, "Object Image"],
35
+ [21, "Polyline"],
36
+ [22, "Polyspline"],
37
+ [23, "Polycurve"],
38
+ [24, "Rectangle"],
39
+ [25, "Arc"],
40
+ [26, "Compound Polygon"],
41
+ [27, "Bitmap"],
42
+ [28, "Text Line"],
43
+ [29, "Text Block"],
44
+ [30, "Text Path"],
45
+ [31, "Chart"],
46
+ [33, "Object Capsule"],
47
+ [34, "Font Settings"],
48
+ [39, "Pen Back Color"],
49
+ [40, "DP Pen Back Color"],
50
+ [41, "Pen Style"],
51
+ [42, "Pen Pattern"],
52
+ [45, "Line Cap"],
53
+ [46, "Line Join"],
54
+ [47, "Brush Gradient"],
55
+ [48, "DP Brush Gradient"],
56
+ [51, "Brush Back Color"],
57
+ [52, "DP Brush Back Color"],
58
+ [53, "Brush Pattern"],
59
+ [54, "Horizontal Line"],
60
+ [55, "Vertical Line"],
61
+ [56, "Poster Settings"],
62
+ [57, "Image State"],
63
+ [58, "Envelope Definition"],
64
+ [59, "Envelope"],
65
+ [60, "Texture Definition"],
66
+ [61, "Brush Texture"],
67
+ [62, "Texture Alignment"],
68
+ [63, "Pen Texture"]
69
+ ]);
70
+ const FLAG_OBJECT_ID = 32;
71
+ const FLAG_EDIT_LOCK = 128;
72
+ const FLAG_PATH_WINDING = 4096;
73
+ const FLAG_FILL = 8192;
74
+ const FLAG_CLOSE = 16384;
75
+ const FLAG_FRAME = 32768;
76
+ const QUARTER_ELLIPSE_KAPPA = 4 / 3 * (Math.SQRT2 - 1);
77
+ const WPG_PRODUCT_TYPE = 1;
78
+ const WPG_FILE_TYPE = 22;
79
+ const WPG_MAJOR_2 = 2;
80
+ const WPG_MAJOR_1 = 1;
81
+ const WPG_PREFIX_HEAD_SIZE = 26;
82
+ const POINTS_PER_INCH = 72;
83
+ const WPG_DEFAULT_BLACK = {
84
+ r: 0,
85
+ g: 0,
86
+ b: 0,
87
+ a: 0
88
+ };
89
+ function readCountField(bytes, cursor) {
90
+ const first = bytes[cursor];
91
+ if (first === void 0) return;
92
+ if (first <= 254) return {
93
+ value: first,
94
+ next: cursor + 1
95
+ };
96
+ if (cursor + 3 > bytes.length) return;
97
+ const shortValue = uint16At(bytes, cursor + 1);
98
+ if ((shortValue & 32768) === 0) return {
99
+ value: shortValue,
100
+ next: cursor + 3
101
+ };
102
+ if (cursor + 5 > bytes.length) return;
103
+ const lowHalf = uint16At(bytes, cursor + 3);
104
+ return {
105
+ value: ((shortValue & 32767) << 16) + lowHalf,
106
+ next: cursor + 5
107
+ };
108
+ }
109
+ function coordinateAt(bytes, offset, doublePrecision) {
110
+ if (!doublePrecision) return int16At(bytes, offset);
111
+ return uint32At(bytes, offset) / 65536;
112
+ }
113
+ function readCharacterization(bytes, cursor, recordEnd) {
114
+ if (cursor + 2 > recordEnd) return;
115
+ const flags = uint16At(bytes, cursor);
116
+ if ((flags & 31) !== 0) return {
117
+ flags,
118
+ geometryAt: -1
119
+ };
120
+ let geometryAt = cursor + 2;
121
+ if ((flags & FLAG_EDIT_LOCK) !== 0) geometryAt += 4;
122
+ if ((flags & FLAG_OBJECT_ID) !== 0) {
123
+ if (geometryAt + 2 > recordEnd) return;
124
+ geometryAt += (uint16At(bytes, geometryAt) & 32768) !== 0 ? 4 : 2;
125
+ }
126
+ if (geometryAt > recordEnd) return;
127
+ return {
128
+ flags,
129
+ geometryAt
130
+ };
131
+ }
132
+ function xToPt(geometry, x) {
133
+ return x / geometry.xPpi * POINTS_PER_INCH;
134
+ }
135
+ function yToPt(geometry, y) {
136
+ return geometry.heightPt - y / geometry.yPpi * POINTS_PER_INCH;
137
+ }
138
+ function strokeOf(geometry, state) {
139
+ if (state.penWidthUnits <= 0) return;
140
+ const opacity = 1 - state.penColor.a;
141
+ return {
142
+ color: {
143
+ r: state.penColor.r,
144
+ g: state.penColor.g,
145
+ b: state.penColor.b
146
+ },
147
+ widthPt: state.penWidthUnits / geometry.xPpi * POINTS_PER_INCH,
148
+ ...opacity < 1 ? { opacity } : {}
149
+ };
150
+ }
151
+ function fillOf(state) {
152
+ return {
153
+ fill: {
154
+ r: state.brushColor.r,
155
+ g: state.brushColor.g,
156
+ b: state.brushColor.b
157
+ },
158
+ fillOpacity: 1 - state.brushColor.a
159
+ };
160
+ }
161
+ function readSingleColor(data) {
162
+ if (data.length < 4) return;
163
+ return {
164
+ r: byteAt(data, 0) / 255,
165
+ g: byteAt(data, 1) / 255,
166
+ b: byteAt(data, 2) / 255,
167
+ a: byteAt(data, 3) / 255
168
+ };
169
+ }
170
+ function readDoubleColor(data) {
171
+ if (data.length < 8) return;
172
+ return {
173
+ r: uint16At(data, 0) / 65535,
174
+ g: uint16At(data, 2) / 65535,
175
+ b: uint16At(data, 4) / 65535,
176
+ a: uint16At(data, 6) / 65535
177
+ };
178
+ }
179
+ function decodeWpgGraphic(bytes, options) {
180
+ let start = -1;
181
+ for (let index = 0; index + WPG_PREFIX_HEAD_SIZE <= bytes.length; index += 1) {
182
+ if (byteAt(bytes, index) !== 255 || byteAt(bytes, index + 1) !== 87 || byteAt(bytes, index + 2) !== 80 || byteAt(bytes, index + 3) !== 67) continue;
183
+ if (byteAt(bytes, index + 8) !== WPG_PRODUCT_TYPE || byteAt(bytes, index + 9) !== WPG_FILE_TYPE) continue;
184
+ start = index;
185
+ break;
186
+ }
187
+ if (start < 0) return;
188
+ const majorVersion = byteAt(bytes, start + 10);
189
+ if (majorVersion === WPG_MAJOR_1) return {
190
+ status: "refused",
191
+ reason: "wpg1"
192
+ };
193
+ if (majorVersion !== WPG_MAJOR_2) return {
194
+ status: "refused",
195
+ reason: "malformed"
196
+ };
197
+ if (uint16At(bytes, start + 12) !== 0) return {
198
+ status: "refused",
199
+ reason: "encrypted"
200
+ };
201
+ const recordStart = uint32At(bytes, start + 4);
202
+ if (recordStart < start + WPG_PREFIX_HEAD_SIZE || recordStart >= bytes.length) return {
203
+ status: "refused",
204
+ reason: "malformed"
205
+ };
206
+ const state = {
207
+ penColor: { ...WPG_DEFAULT_BLACK },
208
+ penWidthUnits: 0,
209
+ brushColor: { ...WPG_DEFAULT_BLACK }
210
+ };
211
+ const vectors = [];
212
+ const shapes = [];
213
+ const skipped = /* @__PURE__ */ new Set();
214
+ const groups = [];
215
+ let geometry;
216
+ let paintOrder = 0;
217
+ let pendingTextBlockFrame;
218
+ let cursor = start + recordStart;
219
+ const recordName = (type) => RECORD_NAMES.get(type) ?? `record type 0x${type.toString(16)}`;
220
+ while (cursor < bytes.length) {
221
+ if (cursor + 2 > bytes.length) break;
222
+ const type = byteAt(bytes, cursor + 1);
223
+ let after = cursor + 2;
224
+ const extension = readCountField(bytes, after);
225
+ if (extension === void 0) break;
226
+ after = extension.next;
227
+ const length = readCountField(bytes, after);
228
+ if (length === void 0) break;
229
+ after = length.next;
230
+ const recordEnd = after + length.value;
231
+ if (recordEnd > bytes.length) break;
232
+ const data = bytes.subarray(after, recordEnd);
233
+ const innermostBefore = groups[groups.length - 1];
234
+ if (innermostBefore !== void 0) innermostBefore.remaining -= 1;
235
+ const swallowed = swallowedByOpenGroup(groups);
236
+ if (type === RECORD_END_WPG && !swallowed) break;
237
+ if (!swallowed) {
238
+ switch (type) {
239
+ case RECORD_START_WPG: {
240
+ if (data.length < 13) {
241
+ skipped.add(recordName(type));
242
+ break;
243
+ }
244
+ const xPpi = uint16At(data, 0);
245
+ const yPpi = uint16At(data, 2);
246
+ const precision = byteAt(data, 4);
247
+ if (xPpi === 0 || yPpi === 0 || precision !== 0 && precision !== 1) return {
248
+ status: "refused",
249
+ reason: "malformed"
250
+ };
251
+ const doublePrecision = precision === 1;
252
+ const coordinateSize = doublePrecision ? 4 : 2;
253
+ const extentAt = 5 + coordinateSize * 4;
254
+ if (extentAt + coordinateSize * 4 > data.length) return {
255
+ status: "refused",
256
+ reason: "malformed"
257
+ };
258
+ const left = coordinateAt(data, extentAt, doublePrecision);
259
+ const bottom = coordinateAt(data, extentAt + coordinateSize, doublePrecision);
260
+ const right = coordinateAt(data, extentAt + coordinateSize * 2, doublePrecision);
261
+ const top = coordinateAt(data, extentAt + coordinateSize * 3, doublePrecision);
262
+ geometry = {
263
+ widthPt: Math.abs(right - left) / xPpi * POINTS_PER_INCH,
264
+ heightPt: Math.abs(top - bottom) / yPpi * POINTS_PER_INCH,
265
+ xPpi,
266
+ yPpi,
267
+ doublePrecision,
268
+ coordinateSize
269
+ };
270
+ break;
271
+ }
272
+ case RECORD_PEN_FORE_COLOR:
273
+ case RECORD_DP_PEN_FORE_COLOR: {
274
+ const color = type === RECORD_PEN_FORE_COLOR ? readSingleColor(data) : readDoubleColor(data);
275
+ if (color !== void 0) state.penColor = color;
276
+ break;
277
+ }
278
+ case RECORD_BRUSH_FORE_COLOR:
279
+ case RECORD_DP_BRUSH_FORE_COLOR: {
280
+ const color = type === RECORD_BRUSH_FORE_COLOR ? readSingleColor(data) : readDoubleColor(data);
281
+ if (color !== void 0) state.brushColor = color;
282
+ break;
283
+ }
284
+ case RECORD_PEN_SIZE:
285
+ if (data.length >= 4) state.penWidthUnits = uint16At(data, 0);
286
+ break;
287
+ case RECORD_DP_PEN_SIZE:
288
+ if (data.length >= 8) state.penWidthUnits = uint32At(data, 0) / 65536;
289
+ break;
290
+ case RECORD_TEXT_BLOCK:
291
+ pendingTextBlockFrame = readTextBlockFrame(data, geometry);
292
+ if (pendingTextBlockFrame === void 0) skipped.add(recordName(type));
293
+ break;
294
+ case RECORD_TEXT_DATA: {
295
+ const frame = pendingTextBlockFrame;
296
+ pendingTextBlockFrame = void 0;
297
+ if (frame === void 0) {
298
+ skipped.add(recordName(type));
299
+ break;
300
+ }
301
+ const blocks = options.foldTextData(data);
302
+ shapes.push({
303
+ frame,
304
+ insetLeftPt: 0,
305
+ insetTopPt: 0,
306
+ insetRightPt: 0,
307
+ insetBottomPt: 0,
308
+ blocks: [...blocks],
309
+ paintOrder
310
+ });
311
+ paintOrder += 1;
312
+ break;
313
+ }
314
+ case RECORD_GROUP: break;
315
+ default: {
316
+ const vector = geometry === void 0 ? void 0 : readPrimitiveVector(type, data, geometry, state);
317
+ if (vector === void 0) skipped.add(recordName(type));
318
+ else {
319
+ vectors.push({
320
+ ...vector,
321
+ paintOrder
322
+ });
323
+ paintOrder += 1;
324
+ }
325
+ break;
326
+ }
327
+ }
328
+ if (type !== RECORD_TEXT_BLOCK) pendingTextBlockFrame = void 0;
329
+ }
330
+ while (groups.length > 0 && groups[groups.length - 1]?.remaining === 0) groups.pop();
331
+ if (extension.value > 0) groups.push({
332
+ remaining: extension.value,
333
+ membersWalk: !swallowed && (type === RECORD_GROUP || type === RECORD_TEXT_BLOCK && pendingTextBlockFrame !== void 0)
334
+ });
335
+ cursor = recordEnd;
336
+ }
337
+ if (geometry === void 0) return {
338
+ status: "refused",
339
+ reason: "malformed"
340
+ };
341
+ return {
342
+ status: "decoded",
343
+ sizePt: {
344
+ widthPt: geometry.widthPt,
345
+ heightPt: geometry.heightPt
346
+ },
347
+ vectors,
348
+ shapes,
349
+ skippedRecords: [...skipped]
350
+ };
351
+ }
352
+ function swallowedByOpenGroup(groups) {
353
+ const innermost = groups[groups.length - 1];
354
+ return innermost !== void 0 && !innermost.membersWalk;
355
+ }
356
+ function readTextBlockFrame(data, geometry) {
357
+ if (geometry === void 0) return;
358
+ const characterization = readCharacterization(data, 0, data.length);
359
+ if (characterization === void 0 || characterization.geometryAt < 0 || characterization.geometryAt + geometry.coordinateSize * 4 > data.length) return;
360
+ const at = characterization.geometryAt;
361
+ return frameFromCorners(geometry, coordinateAt(data, at, geometry.doublePrecision), coordinateAt(data, at + geometry.coordinateSize, geometry.doublePrecision), coordinateAt(data, at + geometry.coordinateSize * 2, geometry.doublePrecision), coordinateAt(data, at + geometry.coordinateSize * 3, geometry.doublePrecision));
362
+ }
363
+ function frameFromCorners(geometry, x1, y1, x2, y2) {
364
+ const left = Math.min(xToPt(geometry, x1), xToPt(geometry, x2));
365
+ const right = Math.max(xToPt(geometry, x1), xToPt(geometry, x2));
366
+ const top = Math.min(yToPt(geometry, y1), yToPt(geometry, y2));
367
+ const bottom = Math.max(yToPt(geometry, y1), yToPt(geometry, y2));
368
+ return {
369
+ xPt: left,
370
+ yPt: top,
371
+ widthPt: right - left,
372
+ heightPt: bottom - top
373
+ };
374
+ }
375
+ function readPrimitiveVector(type, data, geometry, state) {
376
+ const characterization = readCharacterization(data, 0, data.length);
377
+ if (characterization === void 0 || characterization.geometryAt < 0) return;
378
+ const { flags, geometryAt } = characterization;
379
+ const stroke = (flags & FLAG_FRAME) !== 0 ? strokeOf(geometry, state) : void 0;
380
+ switch (type) {
381
+ case RECORD_POLYLINE: return readPolyline(data, geometry, flags, geometryAt, stroke, state);
382
+ case RECORD_RECTANGLE: return readWpgRectangle(data, geometry, flags, geometryAt, stroke, state);
383
+ case RECORD_ARC: return readWpgFullEllipse(data, geometry, flags, geometryAt, stroke, state);
384
+ default: return;
385
+ }
386
+ }
387
+ function readPolyline(data, geometry, flags, geometryAt, stroke, state) {
388
+ if (geometryAt + 2 > data.length) return;
389
+ const count = uint16At(data, geometryAt);
390
+ let at = geometryAt + 2;
391
+ const points = [];
392
+ for (let index = 0; index < count; index += 1) {
393
+ if (at + geometry.coordinateSize * 2 > data.length) return;
394
+ points.push({
395
+ xPt: xToPt(geometry, coordinateAt(data, at, geometry.doublePrecision)),
396
+ yPt: yToPt(geometry, coordinateAt(data, at + geometry.coordinateSize, geometry.doublePrecision))
397
+ });
398
+ at += geometry.coordinateSize * 2;
399
+ }
400
+ const firstPoint = points[0];
401
+ if (firstPoint === void 0) return;
402
+ const secondPoint = points[1];
403
+ const closed = (flags & FLAG_CLOSE) !== 0;
404
+ const filled = (flags & FLAG_FILL) !== 0;
405
+ if (points.length === 2 && secondPoint !== void 0 && !closed && stroke !== void 0) return {
406
+ kind: "line",
407
+ from: firstPoint,
408
+ to: secondPoint,
409
+ stroke
410
+ };
411
+ const frame = boundingFrame(points);
412
+ const local = points.map((point) => ({
413
+ xPt: point.xPt - frame.xPt,
414
+ yPt: point.yPt - frame.yPt
415
+ }));
416
+ const subpath = {
417
+ start: {
418
+ xPt: firstPoint.xPt - frame.xPt,
419
+ yPt: firstPoint.yPt - frame.yPt
420
+ },
421
+ segments: local.slice(1).map((point) => ({
422
+ kind: "line",
423
+ to: point
424
+ })),
425
+ closed
426
+ };
427
+ const fill = filled ? fillOf(state) : void 0;
428
+ return {
429
+ kind: "path",
430
+ frame,
431
+ subpaths: [subpath],
432
+ ...fill !== void 0 ? {
433
+ fill: fill.fill,
434
+ ...fill.fillOpacity < 1 ? { fillOpacity: fill.fillOpacity } : {},
435
+ ...(flags & FLAG_PATH_WINDING) !== 0 ? { fillRule: "nonzero" } : {}
436
+ } : {},
437
+ ...stroke !== void 0 ? { stroke } : {}
438
+ };
439
+ }
440
+ function boundingFrame(points) {
441
+ let minX = Number.POSITIVE_INFINITY;
442
+ let minY = Number.POSITIVE_INFINITY;
443
+ let maxX = Number.NEGATIVE_INFINITY;
444
+ let maxY = Number.NEGATIVE_INFINITY;
445
+ for (const point of points) {
446
+ minX = Math.min(minX, point.xPt);
447
+ minY = Math.min(minY, point.yPt);
448
+ maxX = Math.max(maxX, point.xPt);
449
+ maxY = Math.max(maxY, point.yPt);
450
+ }
451
+ return {
452
+ xPt: minX,
453
+ yPt: minY,
454
+ widthPt: maxX - minX,
455
+ heightPt: maxY - minY
456
+ };
457
+ }
458
+ function readWpgRectangle(data, geometry, flags, geometryAt, stroke, state) {
459
+ const coordinateSize = geometry.coordinateSize;
460
+ if (geometryAt + coordinateSize * 6 > data.length) return;
461
+ const xll = coordinateAt(data, geometryAt, geometry.doublePrecision);
462
+ const yll = coordinateAt(data, geometryAt + coordinateSize, geometry.doublePrecision);
463
+ const xur = coordinateAt(data, geometryAt + coordinateSize * 2, geometry.doublePrecision);
464
+ const yur = coordinateAt(data, geometryAt + coordinateSize * 3, geometry.doublePrecision);
465
+ const rx = coordinateAt(data, geometryAt + coordinateSize * 4, geometry.doublePrecision);
466
+ const ry = coordinateAt(data, geometryAt + coordinateSize * 5, geometry.doublePrecision);
467
+ const frame = frameFromCorners(geometry, xll, yll, xur, yur);
468
+ const fill = (flags & FLAG_FILL) !== 0 ? fillOf(state) : void 0;
469
+ const fillFields = fill !== void 0 ? {
470
+ fill: fill.fill,
471
+ ...fill.fillOpacity < 1 ? { fillOpacity: fill.fillOpacity } : {}
472
+ } : {};
473
+ if (rx <= 0 || ry <= 0) return {
474
+ kind: "rect",
475
+ frame,
476
+ ...fillFields,
477
+ ...stroke !== void 0 ? { stroke } : {}
478
+ };
479
+ const cornerRxPt = Math.min(rx / geometry.xPpi * POINTS_PER_INCH, frame.widthPt / 2);
480
+ const cornerRyPt = Math.min(ry / geometry.yPpi * POINTS_PER_INCH, frame.heightPt / 2);
481
+ const kx = cornerRxPt * QUARTER_ELLIPSE_KAPPA;
482
+ const ky = cornerRyPt * QUARTER_ELLIPSE_KAPPA;
483
+ const width = frame.widthPt;
484
+ const height = frame.heightPt;
485
+ const left = {
486
+ xPt: 0,
487
+ yPt: height / 2
488
+ };
489
+ return {
490
+ kind: "path",
491
+ frame,
492
+ subpaths: [{
493
+ start: left,
494
+ closed: true,
495
+ segments: [
496
+ {
497
+ kind: "line",
498
+ to: {
499
+ xPt: cornerRxPt,
500
+ yPt: 0
501
+ }
502
+ },
503
+ {
504
+ kind: "cubic",
505
+ control1: {
506
+ xPt: cornerRxPt - kx,
507
+ yPt: 0
508
+ },
509
+ control2: {
510
+ xPt: width,
511
+ yPt: cornerRyPt - ky
512
+ },
513
+ to: {
514
+ xPt: width,
515
+ yPt: cornerRyPt
516
+ }
517
+ },
518
+ {
519
+ kind: "line",
520
+ to: {
521
+ xPt: width,
522
+ yPt: height - cornerRyPt
523
+ }
524
+ },
525
+ {
526
+ kind: "cubic",
527
+ control1: {
528
+ xPt: width,
529
+ yPt: height - cornerRyPt + ky
530
+ },
531
+ control2: {
532
+ xPt: width - cornerRxPt + kx,
533
+ yPt: height
534
+ },
535
+ to: {
536
+ xPt: width - cornerRxPt,
537
+ yPt: height
538
+ }
539
+ },
540
+ {
541
+ kind: "line",
542
+ to: {
543
+ xPt: cornerRxPt,
544
+ yPt: height
545
+ }
546
+ },
547
+ {
548
+ kind: "cubic",
549
+ control1: {
550
+ xPt: cornerRxPt - kx,
551
+ yPt: height
552
+ },
553
+ control2: {
554
+ xPt: 0,
555
+ yPt: height - cornerRyPt + ky
556
+ },
557
+ to: {
558
+ xPt: 0,
559
+ yPt: height - cornerRyPt
560
+ }
561
+ },
562
+ {
563
+ kind: "line",
564
+ to: {
565
+ xPt: 0,
566
+ yPt: cornerRyPt
567
+ }
568
+ },
569
+ {
570
+ kind: "cubic",
571
+ control1: {
572
+ xPt: 0,
573
+ yPt: cornerRyPt - ky
574
+ },
575
+ control2: {
576
+ xPt: cornerRxPt - kx,
577
+ yPt: 0
578
+ },
579
+ to: {
580
+ xPt: cornerRxPt,
581
+ yPt: 0
582
+ }
583
+ },
584
+ {
585
+ kind: "line",
586
+ to: left
587
+ }
588
+ ]
589
+ }],
590
+ ...fillFields,
591
+ ...stroke !== void 0 ? { stroke } : {}
592
+ };
593
+ }
594
+ function readWpgFullEllipse(data, geometry, flags, geometryAt, stroke, state) {
595
+ const coordinateSize = geometry.coordinateSize;
596
+ if (geometryAt + coordinateSize * 8 + 1 > data.length) return;
597
+ const cx = coordinateAt(data, geometryAt, geometry.doublePrecision);
598
+ const cy = coordinateAt(data, geometryAt + coordinateSize, geometry.doublePrecision);
599
+ const rx = coordinateAt(data, geometryAt + coordinateSize * 2, geometry.doublePrecision);
600
+ const ry = coordinateAt(data, geometryAt + coordinateSize * 3, geometry.doublePrecision);
601
+ const ix = coordinateAt(data, geometryAt + coordinateSize * 4, geometry.doublePrecision);
602
+ const iy = coordinateAt(data, geometryAt + coordinateSize * 5, geometry.doublePrecision);
603
+ const ex = coordinateAt(data, geometryAt + coordinateSize * 6, geometry.doublePrecision);
604
+ const ey = coordinateAt(data, geometryAt + coordinateSize * 7, geometry.doublePrecision);
605
+ if (ix !== ex || iy !== ey) return;
606
+ const frame = frameFromCorners(geometry, cx - rx, cy - ry, cx + rx, cy + ry);
607
+ const fill = (flags & FLAG_FILL) !== 0 ? fillOf(state) : void 0;
608
+ return {
609
+ kind: "ellipse",
610
+ frame,
611
+ ...fill !== void 0 ? {
612
+ fill: fill.fill,
613
+ ...fill.fillOpacity < 1 ? { fillOpacity: fill.fillOpacity } : {}
614
+ } : {},
615
+ ...stroke !== void 0 ? { stroke } : {}
616
+ };
617
+ }
618
+ //#endregion
619
+ export { decodeWpgGraphic };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wpd-codec",
3
- "version": "3.4.6",
3
+ "version": "3.5.1",
4
4
  "description": "Hand-written read-only WordPerfect 6.x-X6 (.wpd) reader over document-schema.js's ContentDocument",
5
5
  "type": "module",
6
6
  "repository": {
@@ -63,7 +63,7 @@
63
63
  "test:coverage": "turbo run _test:coverage",
64
64
  "_test:coverage": "vitest run --project unit --coverage",
65
65
  "test:mutation": "turbo run _test:mutation",
66
- "_test:mutation": "stryker run stryker.config.mjs",
66
+ "_test:mutation": "stryker run stryker.config.ts",
67
67
  "test:smoke": "turbo run _test:smoke",
68
68
  "_test:smoke": "vitest run --project smoke",
69
69
  "prepare": "husky",
@@ -80,8 +80,8 @@
80
80
  "license": "MIT",
81
81
  "packageManager": "pnpm@11.6.0",
82
82
  "dependencies": {
83
- "archive-codec": "1.10.8",
84
- "document-schema.js": "7.10.0",
83
+ "archive-codec": "1.11.1",
84
+ "document-schema.js": "7.11.1",
85
85
  "zod": "4.4.3"
86
86
  },
87
87
  "devDependencies": {