wpd-codec 2.1.4 → 3.0.0
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/README.md +1 -0
- package/dist/read.cjs +3 -6
- package/dist/read.js +3 -6
- package/dist/stream/table.cjs +45 -2
- package/dist/stream/table.d.cts +2 -2
- package/dist/stream/table.d.ts +2 -2
- package/dist/stream/table.js +45 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -197,6 +197,7 @@ What the corpus settles:
|
|
|
197
197
|
- **Two readings the specification does not settle, both chosen deliberately.** The Form function states its desired width and its desired length as two independent fields and its orientation as a third, and says nothing about whether the pair is written before or after the rotation — so a landscape form's dimensions go through exactly as written and the flag is reported through `wpd/landscape-orientation-unmapped` rather than rotated on this package's own inference. And a Table Column's `[width]` is the one horizontal dimension in the format the SDK does not tag `(WPU)`, so it is read as WordPerfect Units on the strength of the two gutter fields immediately after it, which are.
|
|
198
198
|
- **Reading a document is not rendering one.** The corpus check confirms that each file reads, that its text is prose, and that the structures above are recovered; it does not compare the result against what WordPerfect itself would display, which would need a reference renderer this family does not have.
|
|
199
199
|
- **The document-area's own file-size bound.** The header's file-size field is honoured only when self-consistent, because the SDK itself warns that a third-party writer failing to update it is a common real-world defect whose symptom is a document reading back blank.
|
|
200
|
+
- **A partially-shaded cell fill's own compositing formula.** A cell whose foreground and background colours are blended at a shading percentage other than 0 or 255 now resolves to a real two-colour `pattern` `ContentCellFill` (ExaDev/documents.js#1024) rather than being flattened to its background colour alone, but the mirrored SDK pages document the RGBS byte layout, not how the shading byte composites the pair — so the background shade byte is read as that layer's own opacity and the foreground's implied coverage is snapped to the nearest `percentN` step `ContentCellPatternTypeSchema` defines, a derivation rather than a cited value. Reported through `wpd/cell-fill-blended`.
|
|
200
201
|
|
|
201
202
|
## Conventions
|
|
202
203
|
|
package/dist/read.cjs
CHANGED
|
@@ -125,11 +125,11 @@ function readCellAttributes(state, nonDeletable, sink) {
|
|
|
125
125
|
const row = require_stream_table.findEmbeddedSubfunction(subfunctions, 128);
|
|
126
126
|
const cellSpanning = spanning === void 0 ? void 0 : require_stream_table.readCellSpanning(spanning);
|
|
127
127
|
const cellFill = fill === void 0 ? void 0 : require_stream_table.readCellFill(fill);
|
|
128
|
-
if (cellFill?.blended === true) reportOnce(state, sink, require_diagnostics.WpdDiagnosticCodes.CellFillBlended, "A cell is filled with a shaded blend of two colours
|
|
128
|
+
if (cellFill?.blended === true) reportOnce(state, sink, require_diagnostics.WpdDiagnosticCodes.CellFillBlended, "A cell is filled with a shaded blend of two colours, resolved to a 'pattern' fill whose density is this reader's own best-effort derivation, not a value confirmed against a specification.");
|
|
129
129
|
return {
|
|
130
130
|
attributes: {
|
|
131
131
|
alignment: information === void 0 ? void 0 : require_stream_table.readCellInformation(information)?.alignment,
|
|
132
|
-
background: cellFill?.
|
|
132
|
+
background: cellFill?.fill,
|
|
133
133
|
columnSpan: cellSpanning?.columnSpan ?? NO_SPAN,
|
|
134
134
|
rowSpan: cellSpanning?.rowSpan ?? NO_SPAN,
|
|
135
135
|
covered: cellSpanning?.coveredFromLeft === true || cellSpanning?.coveredFromAbove === true
|
|
@@ -149,10 +149,7 @@ function closeCell(state, table, attributes) {
|
|
|
149
149
|
blocks,
|
|
150
150
|
...attributes.columnSpan > NO_SPAN ? { colSpan: attributes.columnSpan } : {},
|
|
151
151
|
...attributes.rowSpan > NO_SPAN ? { rowSpan: attributes.rowSpan } : {},
|
|
152
|
-
...attributes.background === void 0 ? {} : { background:
|
|
153
|
-
kind: "solid",
|
|
154
|
-
color: attributes.background
|
|
155
|
-
} }
|
|
152
|
+
...attributes.background === void 0 ? {} : { background: attributes.background }
|
|
156
153
|
};
|
|
157
154
|
table.cells.push(cell);
|
|
158
155
|
}
|
package/dist/read.js
CHANGED
|
@@ -124,11 +124,11 @@ function readCellAttributes(state, nonDeletable, sink) {
|
|
|
124
124
|
const row = findEmbeddedSubfunction(subfunctions, 128);
|
|
125
125
|
const cellSpanning = spanning === void 0 ? void 0 : readCellSpanning(spanning);
|
|
126
126
|
const cellFill = fill === void 0 ? void 0 : readCellFill(fill);
|
|
127
|
-
if (cellFill?.blended === true) reportOnce(state, sink, WpdDiagnosticCodes.CellFillBlended, "A cell is filled with a shaded blend of two colours
|
|
127
|
+
if (cellFill?.blended === true) reportOnce(state, sink, WpdDiagnosticCodes.CellFillBlended, "A cell is filled with a shaded blend of two colours, resolved to a 'pattern' fill whose density is this reader's own best-effort derivation, not a value confirmed against a specification.");
|
|
128
128
|
return {
|
|
129
129
|
attributes: {
|
|
130
130
|
alignment: information === void 0 ? void 0 : readCellInformation(information)?.alignment,
|
|
131
|
-
background: cellFill?.
|
|
131
|
+
background: cellFill?.fill,
|
|
132
132
|
columnSpan: cellSpanning?.columnSpan ?? NO_SPAN,
|
|
133
133
|
rowSpan: cellSpanning?.rowSpan ?? NO_SPAN,
|
|
134
134
|
covered: cellSpanning?.coveredFromLeft === true || cellSpanning?.coveredFromAbove === true
|
|
@@ -148,10 +148,7 @@ function closeCell(state, table, attributes) {
|
|
|
148
148
|
blocks,
|
|
149
149
|
...attributes.columnSpan > NO_SPAN ? { colSpan: attributes.columnSpan } : {},
|
|
150
150
|
...attributes.rowSpan > NO_SPAN ? { rowSpan: attributes.rowSpan } : {},
|
|
151
|
-
...attributes.background === void 0 ? {} : { background:
|
|
152
|
-
kind: "solid",
|
|
153
|
-
color: attributes.background
|
|
154
|
-
} }
|
|
151
|
+
...attributes.background === void 0 ? {} : { background: attributes.background }
|
|
155
152
|
};
|
|
156
153
|
table.cells.push(cell);
|
|
157
154
|
}
|
package/dist/stream/table.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_errors = require("../errors.cjs");
|
|
2
3
|
const require_bytes_view = require("../bytes/view.cjs");
|
|
3
4
|
const require_stream_units = require("./units.cjs");
|
|
4
5
|
//#region src/stream/table.ts
|
|
@@ -123,6 +124,34 @@ function readCellSpanning(data) {
|
|
|
123
124
|
const COLOR_COMPONENT_MAX = 255;
|
|
124
125
|
const RGBS_SIZE = 4;
|
|
125
126
|
const FULL_SHADE = 255;
|
|
127
|
+
const PERCENT_STEPS = [
|
|
128
|
+
[5, "percent5"],
|
|
129
|
+
[10, "percent10"],
|
|
130
|
+
[12, "percent12"],
|
|
131
|
+
[15, "percent15"],
|
|
132
|
+
[20, "percent20"],
|
|
133
|
+
[25, "percent25"],
|
|
134
|
+
[30, "percent30"],
|
|
135
|
+
[35, "percent35"],
|
|
136
|
+
[37, "percent37"],
|
|
137
|
+
[40, "percent40"],
|
|
138
|
+
[45, "percent45"],
|
|
139
|
+
[50, "percent50"],
|
|
140
|
+
[55, "percent55"],
|
|
141
|
+
[60, "percent60"],
|
|
142
|
+
[62, "percent62"],
|
|
143
|
+
[65, "percent65"],
|
|
144
|
+
[70, "percent70"],
|
|
145
|
+
[75, "percent75"],
|
|
146
|
+
[80, "percent80"],
|
|
147
|
+
[85, "percent85"],
|
|
148
|
+
[87, "percent87"],
|
|
149
|
+
[90, "percent90"],
|
|
150
|
+
[95, "percent95"]
|
|
151
|
+
];
|
|
152
|
+
function nearestPercentType(percent) {
|
|
153
|
+
return PERCENT_STEPS.reduce((best, step) => Math.abs(step[0] - percent) < Math.abs(best[0] - percent) ? step : best)[1];
|
|
154
|
+
}
|
|
126
155
|
function colorAt(data, offset) {
|
|
127
156
|
const r = data[offset];
|
|
128
157
|
const g = data[offset + 1];
|
|
@@ -138,9 +167,23 @@ function readCellFill(data) {
|
|
|
138
167
|
const background = colorAt(data, RGBS_SIZE);
|
|
139
168
|
if (background === void 0) return;
|
|
140
169
|
const backgroundShade = data[7];
|
|
170
|
+
if (backgroundShade === void 0 || backgroundShade === FULL_SHADE) return {
|
|
171
|
+
fill: {
|
|
172
|
+
kind: "solid",
|
|
173
|
+
color: background
|
|
174
|
+
},
|
|
175
|
+
blended: false
|
|
176
|
+
};
|
|
177
|
+
const foreground = colorAt(data, 0);
|
|
178
|
+
if (foreground === void 0) throw new require_errors.WpdFormatError("Cell fill has a readable background colour but an unreadable foreground colour, which the RGBS pair's own contiguous layout should make impossible.");
|
|
141
179
|
return {
|
|
142
|
-
|
|
143
|
-
|
|
180
|
+
fill: {
|
|
181
|
+
kind: "pattern",
|
|
182
|
+
patternType: nearestPercentType(100 - backgroundShade / COLOR_COMPONENT_MAX * 100),
|
|
183
|
+
foregroundColor: foreground,
|
|
184
|
+
backgroundColor: background
|
|
185
|
+
},
|
|
186
|
+
blended: true
|
|
144
187
|
};
|
|
145
188
|
}
|
|
146
189
|
//#endregion
|
package/dist/stream/table.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Alignment,
|
|
1
|
+
import { Alignment, ContentCellFill } from "document-schema.js";
|
|
2
2
|
//#region src/stream/table.d.ts
|
|
3
3
|
declare const CHARACTER_TABLE_DEFINITION = 42;
|
|
4
4
|
declare const CHARACTER_DEFINE_TABLE_END = 43;
|
|
@@ -35,7 +35,7 @@ interface WpdCellSpanning {
|
|
|
35
35
|
}
|
|
36
36
|
declare function readCellSpanning(data: Uint8Array): WpdCellSpanning | undefined;
|
|
37
37
|
interface WpdCellFill {
|
|
38
|
-
readonly
|
|
38
|
+
readonly fill: ContentCellFill;
|
|
39
39
|
readonly blended: boolean;
|
|
40
40
|
}
|
|
41
41
|
declare function readCellFill(data: Uint8Array): WpdCellFill | undefined;
|
package/dist/stream/table.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Alignment,
|
|
1
|
+
import { Alignment, ContentCellFill } from "document-schema.js";
|
|
2
2
|
//#region src/stream/table.d.ts
|
|
3
3
|
declare const CHARACTER_TABLE_DEFINITION = 42;
|
|
4
4
|
declare const CHARACTER_DEFINE_TABLE_END = 43;
|
|
@@ -35,7 +35,7 @@ interface WpdCellSpanning {
|
|
|
35
35
|
}
|
|
36
36
|
declare function readCellSpanning(data: Uint8Array): WpdCellSpanning | undefined;
|
|
37
37
|
interface WpdCellFill {
|
|
38
|
-
readonly
|
|
38
|
+
readonly fill: ContentCellFill;
|
|
39
39
|
readonly blended: boolean;
|
|
40
40
|
}
|
|
41
41
|
declare function readCellFill(data: Uint8Array): WpdCellFill | undefined;
|
package/dist/stream/table.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { WpdFormatError } from "../errors.js";
|
|
1
2
|
import { uint16At } from "../bytes/view.js";
|
|
2
3
|
import { pointsFromWpu } from "./units.js";
|
|
3
4
|
//#region src/stream/table.ts
|
|
@@ -122,6 +123,34 @@ function readCellSpanning(data) {
|
|
|
122
123
|
const COLOR_COMPONENT_MAX = 255;
|
|
123
124
|
const RGBS_SIZE = 4;
|
|
124
125
|
const FULL_SHADE = 255;
|
|
126
|
+
const PERCENT_STEPS = [
|
|
127
|
+
[5, "percent5"],
|
|
128
|
+
[10, "percent10"],
|
|
129
|
+
[12, "percent12"],
|
|
130
|
+
[15, "percent15"],
|
|
131
|
+
[20, "percent20"],
|
|
132
|
+
[25, "percent25"],
|
|
133
|
+
[30, "percent30"],
|
|
134
|
+
[35, "percent35"],
|
|
135
|
+
[37, "percent37"],
|
|
136
|
+
[40, "percent40"],
|
|
137
|
+
[45, "percent45"],
|
|
138
|
+
[50, "percent50"],
|
|
139
|
+
[55, "percent55"],
|
|
140
|
+
[60, "percent60"],
|
|
141
|
+
[62, "percent62"],
|
|
142
|
+
[65, "percent65"],
|
|
143
|
+
[70, "percent70"],
|
|
144
|
+
[75, "percent75"],
|
|
145
|
+
[80, "percent80"],
|
|
146
|
+
[85, "percent85"],
|
|
147
|
+
[87, "percent87"],
|
|
148
|
+
[90, "percent90"],
|
|
149
|
+
[95, "percent95"]
|
|
150
|
+
];
|
|
151
|
+
function nearestPercentType(percent) {
|
|
152
|
+
return PERCENT_STEPS.reduce((best, step) => Math.abs(step[0] - percent) < Math.abs(best[0] - percent) ? step : best)[1];
|
|
153
|
+
}
|
|
125
154
|
function colorAt(data, offset) {
|
|
126
155
|
const r = data[offset];
|
|
127
156
|
const g = data[offset + 1];
|
|
@@ -137,9 +166,23 @@ function readCellFill(data) {
|
|
|
137
166
|
const background = colorAt(data, RGBS_SIZE);
|
|
138
167
|
if (background === void 0) return;
|
|
139
168
|
const backgroundShade = data[7];
|
|
169
|
+
if (backgroundShade === void 0 || backgroundShade === FULL_SHADE) return {
|
|
170
|
+
fill: {
|
|
171
|
+
kind: "solid",
|
|
172
|
+
color: background
|
|
173
|
+
},
|
|
174
|
+
blended: false
|
|
175
|
+
};
|
|
176
|
+
const foreground = colorAt(data, 0);
|
|
177
|
+
if (foreground === void 0) throw new WpdFormatError("Cell fill has a readable background colour but an unreadable foreground colour, which the RGBS pair's own contiguous layout should make impossible.");
|
|
140
178
|
return {
|
|
141
|
-
|
|
142
|
-
|
|
179
|
+
fill: {
|
|
180
|
+
kind: "pattern",
|
|
181
|
+
patternType: nearestPercentType(100 - backgroundShade / COLOR_COMPONENT_MAX * 100),
|
|
182
|
+
foregroundColor: foreground,
|
|
183
|
+
backgroundColor: background
|
|
184
|
+
},
|
|
185
|
+
blended: true
|
|
143
186
|
};
|
|
144
187
|
}
|
|
145
188
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wpd-codec",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
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": {
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
"license": "MIT",
|
|
81
81
|
"packageManager": "pnpm@11.6.0",
|
|
82
82
|
"dependencies": {
|
|
83
|
-
"archive-codec": "^1.6.
|
|
84
|
-
"document-schema.js": "^6.2.
|
|
83
|
+
"archive-codec": "^1.6.4",
|
|
84
|
+
"document-schema.js": "^6.2.3",
|
|
85
85
|
"zod": "^4.4.3"
|
|
86
86
|
},
|
|
87
87
|
"devDependencies": {
|