@intactfile/engines 0.2.0 → 0.3.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/dist/detect/index.d.ts +1 -1
- package/dist/detect/index.d.ts.map +1 -1
- package/dist/detect/index.js +77 -0
- package/dist/detect/index.js.map +1 -1
- package/dist/heic/format.d.ts +87 -0
- package/dist/heic/format.d.ts.map +1 -0
- package/dist/heic/format.js +241 -0
- package/dist/heic/format.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/office-legacy/diagnose.d.ts +24 -0
- package/dist/office-legacy/diagnose.d.ts.map +1 -0
- package/dist/office-legacy/diagnose.js +111 -0
- package/dist/office-legacy/diagnose.js.map +1 -0
- package/dist/office-legacy/format.d.ts +89 -0
- package/dist/office-legacy/format.d.ts.map +1 -0
- package/dist/office-legacy/format.js +281 -0
- package/dist/office-legacy/format.js.map +1 -0
- package/dist/office-legacy/index.d.ts +9 -0
- package/dist/office-legacy/index.d.ts.map +1 -0
- package/dist/office-legacy/index.js +18 -0
- package/dist/office-legacy/index.js.map +1 -0
- package/dist/office-legacy/rebuild.d.ts +8 -0
- package/dist/office-legacy/rebuild.d.ts.map +1 -0
- package/dist/office-legacy/rebuild.js +234 -0
- package/dist/office-legacy/rebuild.js.map +1 -0
- package/dist/office-legacy/repair.d.ts +40 -0
- package/dist/office-legacy/repair.d.ts.map +1 -0
- package/dist/office-legacy/repair.js +161 -0
- package/dist/office-legacy/repair.js.map +1 -0
- package/dist/psd/diagnose.d.ts +33 -0
- package/dist/psd/diagnose.d.ts.map +1 -0
- package/dist/psd/diagnose.js +176 -0
- package/dist/psd/diagnose.js.map +1 -0
- package/dist/psd/format.d.ts +106 -0
- package/dist/psd/format.d.ts.map +1 -0
- package/dist/psd/format.js +238 -0
- package/dist/psd/format.js.map +1 -0
- package/dist/psd/index.d.ts +8 -0
- package/dist/psd/index.d.ts.map +1 -0
- package/dist/psd/index.js +13 -0
- package/dist/psd/index.js.map +1 -0
- package/dist/psd/repair.d.ts +36 -0
- package/dist/psd/repair.d.ts.map +1 -0
- package/dist/psd/repair.js +451 -0
- package/dist/psd/repair.js.map +1 -0
- package/dist/raw/diagnose.d.ts +29 -0
- package/dist/raw/diagnose.d.ts.map +1 -0
- package/dist/raw/diagnose.js +95 -0
- package/dist/raw/diagnose.js.map +1 -0
- package/dist/raw/format.d.ts +47 -0
- package/dist/raw/format.d.ts.map +1 -0
- package/dist/raw/format.js +213 -0
- package/dist/raw/format.js.map +1 -0
- package/dist/raw/index.d.ts +7 -0
- package/dist/raw/index.d.ts.map +1 -0
- package/dist/raw/index.js +13 -0
- package/dist/raw/index.js.map +1 -0
- package/dist/raw/repair.d.ts +46 -0
- package/dist/raw/repair.d.ts.map +1 -0
- package/dist/raw/repair.js +94 -0
- package/dist/raw/repair.js.map +1 -0
- package/package.json +14 -2
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { readAll } from "../bytes-util.js";
|
|
2
|
+
import { DEFAULT_PSD_CAPS, findSignature, hasSignatureAt, looksLikePsdAt, mapSections, parseHeader, rowBytes, u16be, u32be, u64be, walkImageResources, } from "./format.js";
|
|
3
|
+
const SCAN_WINDOW = 64 * 1024;
|
|
4
|
+
export function diagnosePsdBytes(b, caps = DEFAULT_PSD_CAPS) {
|
|
5
|
+
const notes = [];
|
|
6
|
+
const base = {
|
|
7
|
+
notes,
|
|
8
|
+
signatureOffset: null,
|
|
9
|
+
version: null,
|
|
10
|
+
width: null,
|
|
11
|
+
height: null,
|
|
12
|
+
channels: null,
|
|
13
|
+
depth: null,
|
|
14
|
+
colorMode: null,
|
|
15
|
+
compression: null,
|
|
16
|
+
hasThumbnail: false,
|
|
17
|
+
prefixBytes: 0,
|
|
18
|
+
};
|
|
19
|
+
const done = (damageClass, confidence) => ({
|
|
20
|
+
damageClass,
|
|
21
|
+
confidence,
|
|
22
|
+
...base,
|
|
23
|
+
});
|
|
24
|
+
if (b.length < 26) {
|
|
25
|
+
notes.push(`file is only ${b.length} bytes: too small to be a PSD`);
|
|
26
|
+
return done("not-psd", "high");
|
|
27
|
+
}
|
|
28
|
+
// Signature location.
|
|
29
|
+
let sigOff = -1;
|
|
30
|
+
if (hasSignatureAt(b, 0))
|
|
31
|
+
sigOff = 0;
|
|
32
|
+
else {
|
|
33
|
+
const at = findSignature(b, SCAN_WINDOW);
|
|
34
|
+
if (at > 0) {
|
|
35
|
+
base.signatureOffset = at;
|
|
36
|
+
base.prefixBytes = at;
|
|
37
|
+
notes.push(`valid 8BPS signature found at offset ${at} (garbage prefix)`);
|
|
38
|
+
// fall through to header validation against the found offset for a richer note
|
|
39
|
+
const h = parseHeader(b, at);
|
|
40
|
+
if (h)
|
|
41
|
+
fillHeader(base, h, notes);
|
|
42
|
+
return done("garbage-prefix", "high");
|
|
43
|
+
}
|
|
44
|
+
if (looksLikePsdAt(b, 0)) {
|
|
45
|
+
base.signatureOffset = 0;
|
|
46
|
+
notes.push('the "8B" marker is present but the full 8BPS signature is damaged');
|
|
47
|
+
return done("signature-damage", "high");
|
|
48
|
+
}
|
|
49
|
+
notes.push("no 8BPS signature at the start and none found within the scan window");
|
|
50
|
+
return done("not-psd", b.length > SCAN_WINDOW ? "medium" : "high");
|
|
51
|
+
}
|
|
52
|
+
base.signatureOffset = sigOff;
|
|
53
|
+
const header = parseHeader(b, sigOff);
|
|
54
|
+
if (!header) {
|
|
55
|
+
notes.push("8BPS signature present but the 26-byte header is invalid (geometry / depth / mode / version)");
|
|
56
|
+
return done("header-damage", "high");
|
|
57
|
+
}
|
|
58
|
+
fillHeader(base, header, notes);
|
|
59
|
+
// Bomb guard.
|
|
60
|
+
if (header.width * header.height > caps.maxPixels) {
|
|
61
|
+
notes.push(`declared ${header.width}x${header.height} exceeds the safety cap: possible decompression bomb`);
|
|
62
|
+
return done("unknown", "high");
|
|
63
|
+
}
|
|
64
|
+
const sec = mapSections(b, header);
|
|
65
|
+
// Color-mode length must match the color mode.
|
|
66
|
+
const cmLen = sec.colorMode.length;
|
|
67
|
+
if (header.colorMode === 3 || header.colorMode === 1 || header.colorMode === 9) {
|
|
68
|
+
if (cmLen !== 0) {
|
|
69
|
+
notes.push(`color-mode data length is ${cmLen} but must be 0 for this color mode: corrupt length field`);
|
|
70
|
+
return done("bad-section-length", "high");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else if (header.colorMode === 2 && cmLen !== 768) {
|
|
74
|
+
notes.push(`indexed color needs a 768-byte palette but the length is ${cmLen}: corrupt length field`);
|
|
75
|
+
return done("bad-section-length", "high");
|
|
76
|
+
}
|
|
77
|
+
// Any declared length larger than the whole file = a corrupt length field, not truncation.
|
|
78
|
+
for (const [name, span] of [
|
|
79
|
+
["colorMode", sec.colorMode],
|
|
80
|
+
["imageResources", sec.imageResources],
|
|
81
|
+
["layerAndMask", sec.layerAndMask],
|
|
82
|
+
]) {
|
|
83
|
+
if (span.length > b.length) {
|
|
84
|
+
notes.push(`${name} declares ${span.length} bytes, larger than the whole file: corrupt length field`);
|
|
85
|
+
return done("bad-section-length", "high");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Image resources: declared non-empty but doesn't start with an 8BIM block.
|
|
89
|
+
if (sec.imageResources.length > 0) {
|
|
90
|
+
const r = sec.imageResources.dataOffset;
|
|
91
|
+
const startsWith8bim = b[r] === 0x38 && b[r + 1] === 0x42 && b[r + 2] === 0x49 && b[r + 3] === 0x4d;
|
|
92
|
+
if (!startsWith8bim) {
|
|
93
|
+
notes.push("image-resources section does not begin with an 8BIM block: corrupt length/offset");
|
|
94
|
+
return done("bad-section-length", "high");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const resWalk = walkImageResources(b, sec.imageResources.dataOffset, sec.imageResources.length);
|
|
98
|
+
base.hasThumbnail = !!resWalk.thumbnail;
|
|
99
|
+
// Truncation: a section that fits in magnitude but runs past EOF.
|
|
100
|
+
if (sec.danglingSections.length > 0) {
|
|
101
|
+
notes.push(`section(s) run past end-of-file: ${sec.danglingSections.join(", ")} — file is truncated`);
|
|
102
|
+
return done("truncated", base.hasThumbnail ? "high" : "medium");
|
|
103
|
+
}
|
|
104
|
+
// Image-data (composite) boundary checks — magnitude only, no pixel decode.
|
|
105
|
+
const idOff = sec.imageDataOffset;
|
|
106
|
+
if (idOff + 2 > b.length) {
|
|
107
|
+
notes.push("file ends before the image-data section: the composite is missing");
|
|
108
|
+
return done(base.hasThumbnail ? "thumbnail-only" : "truncated", base.hasThumbnail ? "high" : "medium");
|
|
109
|
+
}
|
|
110
|
+
const compression = u16be(b, idOff);
|
|
111
|
+
base.compression = compression;
|
|
112
|
+
if (compression > 3) {
|
|
113
|
+
notes.push(`image-data compression flag is ${compression} (must be 0..3): composite header corrupt`);
|
|
114
|
+
return done("composite-corruption", "high");
|
|
115
|
+
}
|
|
116
|
+
const rb = rowBytes(header.width, header.depth);
|
|
117
|
+
const avail = b.length - (idOff + 2);
|
|
118
|
+
if (compression === 0) {
|
|
119
|
+
const need = rb * header.height * header.channels;
|
|
120
|
+
if (need > avail) {
|
|
121
|
+
notes.push(`raw composite needs ${need} bytes but only ${avail} remain: truncated`);
|
|
122
|
+
return done(base.hasThumbnail ? "thumbnail-only" : "truncated", "high");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else if (compression === 1) {
|
|
126
|
+
const entries = header.height * header.channels;
|
|
127
|
+
const entryW = header.version === 2 ? 4 : 2;
|
|
128
|
+
const tableSize = entries * entryW;
|
|
129
|
+
if (2 + tableSize > avail + 2) {
|
|
130
|
+
notes.push("RLE scanline byte-count table is truncated");
|
|
131
|
+
return done(base.hasThumbnail ? "thumbnail-only" : "truncated", "high");
|
|
132
|
+
}
|
|
133
|
+
let sum = 0;
|
|
134
|
+
let p = idOff + 2;
|
|
135
|
+
for (let i = 0; i < entries; i++) {
|
|
136
|
+
sum += entryW === 4 ? u32be(b, p) : u16be(b, p);
|
|
137
|
+
p += entryW;
|
|
138
|
+
}
|
|
139
|
+
if (tableSize + sum > avail) {
|
|
140
|
+
notes.push(`RLE data needs ${tableSize + sum} bytes but only ${avail} remain: truncated`);
|
|
141
|
+
return done(base.hasThumbnail ? "thumbnail-only" : "truncated", "high");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// compression 2/3 (ZIP) boundary can't be checked without inflating; trust presence.
|
|
145
|
+
// Light layer-section sanity (no full parse): a corrupt layer-info length /
|
|
146
|
+
// absurd layer count = the classic "won't open, but the composite is fine".
|
|
147
|
+
if (sec.layerAndMask.length > 0) {
|
|
148
|
+
const lmData = sec.layerAndMask.dataOffset;
|
|
149
|
+
const lenW = header.version === 2 ? 8 : 4;
|
|
150
|
+
if (lmData + lenW + 2 <= b.length) {
|
|
151
|
+
const layerInfoLen = lenW === 8 ? u64be(b, lmData) : u32be(b, lmData);
|
|
152
|
+
const bodyMax = sec.layerAndMask.length - lenW;
|
|
153
|
+
const layerCount = int16(u16be(b, lmData + lenW));
|
|
154
|
+
if (layerInfoLen > bodyMax || Math.abs(layerCount) > 8000) {
|
|
155
|
+
notes.push("layer section is damaged (implausible layer-info length / count); the composite is intact");
|
|
156
|
+
notes.push("layers cannot be reconstructed — repair will hand back the flattened composite");
|
|
157
|
+
return done("layers-damaged", "high");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
notes.push(`PSD OK: ${header.width}x${header.height}, ${header.channels}ch, ${header.depth}-bit, mode ${header.colorMode}`);
|
|
162
|
+
return done("none", "high");
|
|
163
|
+
}
|
|
164
|
+
const int16 = (v) => (v >= 0x8000 ? v - 0x10000 : v);
|
|
165
|
+
function fillHeader(base, h, _notes) {
|
|
166
|
+
base.version = h.version;
|
|
167
|
+
base.width = h.width;
|
|
168
|
+
base.height = h.height;
|
|
169
|
+
base.channels = h.channels;
|
|
170
|
+
base.depth = h.depth;
|
|
171
|
+
base.colorMode = h.colorMode;
|
|
172
|
+
}
|
|
173
|
+
export async function diagnosePsd(src, caps = DEFAULT_PSD_CAPS) {
|
|
174
|
+
return diagnosePsdBytes(await readAll(src), caps);
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=diagnose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.js","sourceRoot":"","sources":["../../src/psd/diagnose.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure PSD/PSB byte primitives: header parse/serialize, the four length-prefixed
|
|
3
|
+
* sections, image-resource (8BIM) walking, the embedded thumbnail, and the
|
|
4
|
+
* composite codec (raw / RLE-PackBits / ZIP). No wasm, no I/O — everything here
|
|
5
|
+
* is plain byte arithmetic, safe in the browser root export and unit-testable.
|
|
6
|
+
*
|
|
7
|
+
* A "repaired PSD" here means the FLATTENED composite is recovered — never the
|
|
8
|
+
* layer stack. See docs/engineering/engine-psd.md. All fields are big-endian.
|
|
9
|
+
*/
|
|
10
|
+
/** "8BPS" */
|
|
11
|
+
export declare const PSD_SIGNATURE: Uint8Array<ArrayBuffer>;
|
|
12
|
+
export type PsdColorMode = number;
|
|
13
|
+
export type PsdCompression = 0 | 1 | 2 | 3;
|
|
14
|
+
export interface PsdHeader {
|
|
15
|
+
version: 1 | 2;
|
|
16
|
+
channels: number;
|
|
17
|
+
height: number;
|
|
18
|
+
width: number;
|
|
19
|
+
depth: number;
|
|
20
|
+
colorMode: PsdColorMode;
|
|
21
|
+
}
|
|
22
|
+
export interface PsdSafetyCaps {
|
|
23
|
+
maxWidth: number;
|
|
24
|
+
maxHeight: number;
|
|
25
|
+
maxPixels: number;
|
|
26
|
+
/** Hard ceiling on the decoded composite (all planes). */
|
|
27
|
+
maxCompositeBytes: number;
|
|
28
|
+
}
|
|
29
|
+
/** PSB tops out at 300000²; cap pixels/bytes well below a memory bomb. */
|
|
30
|
+
export declare const DEFAULT_PSD_CAPS: PsdSafetyCaps;
|
|
31
|
+
export declare const u16be: (b: Uint8Array, o: number) => number;
|
|
32
|
+
export declare const u32be: (b: Uint8Array, o: number) => number;
|
|
33
|
+
/** 64-bit big-endian as a JS number (safe for our bounded offsets). */
|
|
34
|
+
export declare const u64be: (b: Uint8Array, o: number) => number;
|
|
35
|
+
export declare function writeU16be(b: Uint8Array, o: number, v: number): void;
|
|
36
|
+
export declare function writeU32be(b: Uint8Array, o: number, v: number): void;
|
|
37
|
+
export declare function hasSignatureAt(b: Uint8Array, off: number): boolean;
|
|
38
|
+
/** The "8B" fingerprint is present but the full "8BPS" magic is not exact. */
|
|
39
|
+
export declare function looksLikePsdAt(b: Uint8Array, off: number): boolean;
|
|
40
|
+
/** First offset of a valid 8BPS signature within `window`, or -1. */
|
|
41
|
+
export declare function findSignature(b: Uint8Array, window: number): number;
|
|
42
|
+
/** Parse and validate the 26-byte header at `off`. Returns null if implausible. */
|
|
43
|
+
export declare function parseHeader(b: Uint8Array, off?: number): PsdHeader | null;
|
|
44
|
+
export declare function serializeHeader(h: PsdHeader): Uint8Array;
|
|
45
|
+
/** Bytes per scanline for one channel at this width/depth. */
|
|
46
|
+
export declare const rowBytes: (width: number, depth: number) => number;
|
|
47
|
+
/** Length of the color-mode data section forced by color mode (0 unless Indexed/Duotone). */
|
|
48
|
+
export declare function expectedColorModeLen(actualLen: number, colorMode: PsdColorMode): number;
|
|
49
|
+
export interface SectionSpan {
|
|
50
|
+
offset: number;
|
|
51
|
+
dataOffset: number;
|
|
52
|
+
length: number;
|
|
53
|
+
end: number;
|
|
54
|
+
}
|
|
55
|
+
export interface PsdSections {
|
|
56
|
+
header: PsdHeader;
|
|
57
|
+
colorMode: SectionSpan;
|
|
58
|
+
imageResources: SectionSpan;
|
|
59
|
+
layerAndMask: SectionSpan;
|
|
60
|
+
/** Offset of the image-data section (2-byte compression flag lives here). */
|
|
61
|
+
imageDataOffset: number;
|
|
62
|
+
/** Any section whose declared length runs past EOF. */
|
|
63
|
+
danglingSections: string[];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Walk the section chain from offset 26, trusting declared lengths. Records
|
|
67
|
+
* sections that dangle past EOF (the truncation / bad-length signal). Never
|
|
68
|
+
* decodes pixels.
|
|
69
|
+
*/
|
|
70
|
+
export declare function mapSections(b: Uint8Array, header: PsdHeader): PsdSections;
|
|
71
|
+
export interface ResourceBlock {
|
|
72
|
+
id: number;
|
|
73
|
+
offset: number;
|
|
74
|
+
dataOffset: number;
|
|
75
|
+
dataLength: number;
|
|
76
|
+
totalLength: number;
|
|
77
|
+
}
|
|
78
|
+
export interface ResourceWalk {
|
|
79
|
+
blocks: ResourceBlock[];
|
|
80
|
+
/** True byte length of a well-formed resources section (may differ from declared). */
|
|
81
|
+
trueLength: number;
|
|
82
|
+
/** Embedded thumbnail JPEG (resource 1036/1033), if a full FFD8..FFD9 is present. */
|
|
83
|
+
thumbnail?: {
|
|
84
|
+
offset: number;
|
|
85
|
+
length: number;
|
|
86
|
+
resourceId: number;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/** Re-walk the self-delimiting 8BIM resource blocks; recompute the true length. */
|
|
90
|
+
export declare function walkImageResources(b: Uint8Array, start: number, declaredLen: number): ResourceWalk;
|
|
91
|
+
/** Largest complete FFD8..FFD9 JPEG within [from,to). */
|
|
92
|
+
export declare function findJpeg(b: Uint8Array, from: number, to: number): {
|
|
93
|
+
offset: number;
|
|
94
|
+
length: number;
|
|
95
|
+
} | null;
|
|
96
|
+
/**
|
|
97
|
+
* Decode one PackBits scanline from b[pos..end) into up to `outLen` bytes.
|
|
98
|
+
* Returns the row and how many output bytes were produced (short if damaged).
|
|
99
|
+
*/
|
|
100
|
+
export declare function unpackBitsRow(b: Uint8Array, pos: number, end: number, outLen: number): {
|
|
101
|
+
row: Uint8Array;
|
|
102
|
+
produced: number;
|
|
103
|
+
};
|
|
104
|
+
/** Encode one scanline with PackBits (Adobe/TIFF variant). */
|
|
105
|
+
export declare function packBitsRow(row: Uint8Array): Uint8Array;
|
|
106
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/psd/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure PSD/PSB byte primitives: header parse/serialize, the four length-prefixed
|
|
3
|
+
* sections, image-resource (8BIM) walking, the embedded thumbnail, and the
|
|
4
|
+
* composite codec (raw / RLE-PackBits / ZIP). No wasm, no I/O — everything here
|
|
5
|
+
* is plain byte arithmetic, safe in the browser root export and unit-testable.
|
|
6
|
+
*
|
|
7
|
+
* A "repaired PSD" here means the FLATTENED composite is recovered — never the
|
|
8
|
+
* layer stack. See docs/engineering/engine-psd.md. All fields are big-endian.
|
|
9
|
+
*/
|
|
10
|
+
/** "8BPS" */
|
|
11
|
+
export const PSD_SIGNATURE = Uint8Array.of(0x38, 0x42, 0x50, 0x53);
|
|
12
|
+
/** PSB tops out at 300000²; cap pixels/bytes well below a memory bomb. */
|
|
13
|
+
export const DEFAULT_PSD_CAPS = {
|
|
14
|
+
maxWidth: 300_000,
|
|
15
|
+
maxHeight: 300_000,
|
|
16
|
+
maxPixels: 500_000_000,
|
|
17
|
+
maxCompositeBytes: 2 * 1024 * 1024 * 1024,
|
|
18
|
+
};
|
|
19
|
+
// ---- readers / writers -------------------------------------------------------
|
|
20
|
+
export const u16be = (b, o) => ((b[o] << 8) | b[o + 1]) >>> 0;
|
|
21
|
+
export const u32be = (b, o) => ((b[o] << 24) | (b[o + 1] << 16) | (b[o + 2] << 8) | b[o + 3]) >>> 0;
|
|
22
|
+
/** 64-bit big-endian as a JS number (safe for our bounded offsets). */
|
|
23
|
+
export const u64be = (b, o) => u32be(b, o) * 0x1_0000_0000 + u32be(b, o + 4);
|
|
24
|
+
export function writeU16be(b, o, v) {
|
|
25
|
+
b[o] = (v >>> 8) & 0xff;
|
|
26
|
+
b[o + 1] = v & 0xff;
|
|
27
|
+
}
|
|
28
|
+
export function writeU32be(b, o, v) {
|
|
29
|
+
b[o] = (v >>> 24) & 0xff;
|
|
30
|
+
b[o + 1] = (v >>> 16) & 0xff;
|
|
31
|
+
b[o + 2] = (v >>> 8) & 0xff;
|
|
32
|
+
b[o + 3] = v & 0xff;
|
|
33
|
+
}
|
|
34
|
+
export function hasSignatureAt(b, off) {
|
|
35
|
+
return b[off] === 0x38 && b[off + 1] === 0x42 && b[off + 2] === 0x50 && b[off + 3] === 0x53;
|
|
36
|
+
}
|
|
37
|
+
/** The "8B" fingerprint is present but the full "8BPS" magic is not exact. */
|
|
38
|
+
export function looksLikePsdAt(b, off) {
|
|
39
|
+
return b[off] === 0x38 && b[off + 1] === 0x42 && !hasSignatureAt(b, off);
|
|
40
|
+
}
|
|
41
|
+
/** First offset of a valid 8BPS signature within `window`, or -1. */
|
|
42
|
+
export function findSignature(b, window) {
|
|
43
|
+
const limit = Math.min(b.length - 4, window);
|
|
44
|
+
for (let i = 0; i <= limit; i++) {
|
|
45
|
+
if (b[i] === 0x38 && hasSignatureAt(b, i))
|
|
46
|
+
return i;
|
|
47
|
+
}
|
|
48
|
+
return -1;
|
|
49
|
+
}
|
|
50
|
+
const VALID_DEPTHS = new Set([1, 8, 16, 32]);
|
|
51
|
+
const VALID_MODES = new Set([0, 1, 2, 3, 4, 7, 8, 9]);
|
|
52
|
+
/** Parse and validate the 26-byte header at `off`. Returns null if implausible. */
|
|
53
|
+
export function parseHeader(b, off = 0) {
|
|
54
|
+
if (off + 26 > b.length)
|
|
55
|
+
return null;
|
|
56
|
+
if (!hasSignatureAt(b, off))
|
|
57
|
+
return null;
|
|
58
|
+
const version = u16be(b, off + 4);
|
|
59
|
+
if (version !== 1 && version !== 2)
|
|
60
|
+
return null;
|
|
61
|
+
const channels = u16be(b, off + 12);
|
|
62
|
+
const height = u32be(b, off + 14);
|
|
63
|
+
const width = u32be(b, off + 18);
|
|
64
|
+
const depth = u16be(b, off + 22);
|
|
65
|
+
const colorMode = u16be(b, off + 24);
|
|
66
|
+
if (channels < 1 || channels > 56)
|
|
67
|
+
return null;
|
|
68
|
+
if (!VALID_DEPTHS.has(depth))
|
|
69
|
+
return null;
|
|
70
|
+
if (!VALID_MODES.has(colorMode))
|
|
71
|
+
return null;
|
|
72
|
+
const maxDim = version === 2 ? 300_000 : 30_000;
|
|
73
|
+
if (width < 1 || height < 1 || width > maxDim || height > maxDim)
|
|
74
|
+
return null;
|
|
75
|
+
return { version: version, channels, height, width, depth, colorMode };
|
|
76
|
+
}
|
|
77
|
+
export function serializeHeader(h) {
|
|
78
|
+
const b = new Uint8Array(26);
|
|
79
|
+
b.set(PSD_SIGNATURE, 0);
|
|
80
|
+
writeU16be(b, 4, h.version);
|
|
81
|
+
// bytes 6..11 reserved zero (already zero)
|
|
82
|
+
writeU16be(b, 12, h.channels);
|
|
83
|
+
writeU32be(b, 14, h.height);
|
|
84
|
+
writeU32be(b, 18, h.width);
|
|
85
|
+
writeU16be(b, 22, h.depth);
|
|
86
|
+
writeU16be(b, 24, h.colorMode);
|
|
87
|
+
return b;
|
|
88
|
+
}
|
|
89
|
+
/** Bytes per scanline for one channel at this width/depth. */
|
|
90
|
+
export const rowBytes = (width, depth) => Math.ceil((width * depth) / 8);
|
|
91
|
+
/** Length of the color-mode data section forced by color mode (0 unless Indexed/Duotone). */
|
|
92
|
+
export function expectedColorModeLen(actualLen, colorMode) {
|
|
93
|
+
// Indexed (2) = 768-byte palette; Duotone (8) carries opaque data we preserve as-is.
|
|
94
|
+
if (colorMode === 2)
|
|
95
|
+
return 768;
|
|
96
|
+
if (colorMode === 8)
|
|
97
|
+
return actualLen; // preserve whatever is declared
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Walk the section chain from offset 26, trusting declared lengths. Records
|
|
102
|
+
* sections that dangle past EOF (the truncation / bad-length signal). Never
|
|
103
|
+
* decodes pixels.
|
|
104
|
+
*/
|
|
105
|
+
export function mapSections(b, header) {
|
|
106
|
+
const dangling = [];
|
|
107
|
+
const span = (name, offset, lenBytes) => {
|
|
108
|
+
const length = lenBytes === 8 ? u64be(b, offset) : u32be(b, offset);
|
|
109
|
+
const dataOffset = offset + lenBytes;
|
|
110
|
+
const end = dataOffset + length;
|
|
111
|
+
if (end > b.length)
|
|
112
|
+
dangling.push(name);
|
|
113
|
+
return { offset, dataOffset, length, end };
|
|
114
|
+
};
|
|
115
|
+
const colorMode = span('colorMode', 26, 4);
|
|
116
|
+
const cmEnd = Math.min(colorMode.end, b.length);
|
|
117
|
+
const imageResources = span('imageResources', cmEnd, 4);
|
|
118
|
+
const irEnd = Math.min(imageResources.end, b.length);
|
|
119
|
+
const layerAndMask = span('layerAndMask', irEnd, header.version === 2 ? 8 : 4);
|
|
120
|
+
const lmEnd = Math.min(layerAndMask.end, b.length);
|
|
121
|
+
const imageDataOffset = lmEnd;
|
|
122
|
+
return { header, colorMode, imageResources, layerAndMask, imageDataOffset, danglingSections: dangling };
|
|
123
|
+
}
|
|
124
|
+
const even = (n) => (n & 1 ? n + 1 : n);
|
|
125
|
+
/** Re-walk the self-delimiting 8BIM resource blocks; recompute the true length. */
|
|
126
|
+
export function walkImageResources(b, start, declaredLen) {
|
|
127
|
+
const blocks = [];
|
|
128
|
+
const hardEnd = Math.min(start + declaredLen, b.length);
|
|
129
|
+
let p = start;
|
|
130
|
+
let thumbnail;
|
|
131
|
+
while (p + 8 <= b.length) {
|
|
132
|
+
// Stop if we've clearly left the section (no more 8BIM) — self-delimiting walk.
|
|
133
|
+
if (!(b[p] === 0x38 && b[p + 1] === 0x42 && b[p + 2] === 0x49 && b[p + 3] === 0x4d))
|
|
134
|
+
break; // "8BIM"
|
|
135
|
+
const id = u16be(b, p + 4);
|
|
136
|
+
// Pascal name follows the 2-byte ID: 1-byte length + bytes, whole field padded to even.
|
|
137
|
+
let q = p + 6;
|
|
138
|
+
const nameLen = b[q];
|
|
139
|
+
q += 1 + nameLen;
|
|
140
|
+
if ((1 + nameLen) & 1)
|
|
141
|
+
q += 1; // pad to even
|
|
142
|
+
if (q + 4 > b.length)
|
|
143
|
+
break;
|
|
144
|
+
const dataLength = u32be(b, q);
|
|
145
|
+
const dataOffset = q + 4;
|
|
146
|
+
const paddedData = even(dataLength);
|
|
147
|
+
const blockEnd = dataOffset + paddedData;
|
|
148
|
+
if (dataOffset + dataLength > b.length)
|
|
149
|
+
break; // dangling block
|
|
150
|
+
if ((id === 1036 || id === 1033) && !thumbnail) {
|
|
151
|
+
const t = findJpeg(b, dataOffset, dataOffset + dataLength);
|
|
152
|
+
if (t)
|
|
153
|
+
thumbnail = { ...t, resourceId: id };
|
|
154
|
+
}
|
|
155
|
+
blocks.push({ id, offset: p, dataOffset, dataLength, totalLength: blockEnd - p });
|
|
156
|
+
p = blockEnd;
|
|
157
|
+
if (p > hardEnd && blocks.length > 0)
|
|
158
|
+
break; // walked past the declared section
|
|
159
|
+
}
|
|
160
|
+
return { blocks, trueLength: p - start, thumbnail };
|
|
161
|
+
}
|
|
162
|
+
/** Largest complete FFD8..FFD9 JPEG within [from,to). */
|
|
163
|
+
export function findJpeg(b, from, to) {
|
|
164
|
+
const hi = Math.min(to, b.length) - 1;
|
|
165
|
+
for (let i = from; i < hi; i++) {
|
|
166
|
+
if (b[i] === 0xff && b[i + 1] === 0xd8 && b[i + 2] === 0xff) {
|
|
167
|
+
for (let j = i + 2; j < hi; j++) {
|
|
168
|
+
if (b[j] === 0xff && b[j + 1] === 0xd9)
|
|
169
|
+
return { offset: i, length: j + 2 - i };
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
// ---- PackBits (RLE) ----------------------------------------------------------
|
|
177
|
+
/**
|
|
178
|
+
* Decode one PackBits scanline from b[pos..end) into up to `outLen` bytes.
|
|
179
|
+
* Returns the row and how many output bytes were produced (short if damaged).
|
|
180
|
+
*/
|
|
181
|
+
export function unpackBitsRow(b, pos, end, outLen) {
|
|
182
|
+
const row = new Uint8Array(outLen);
|
|
183
|
+
let o = 0;
|
|
184
|
+
let p = pos;
|
|
185
|
+
while (p < end && o < outLen) {
|
|
186
|
+
let n = b[p++];
|
|
187
|
+
if (n >= 128)
|
|
188
|
+
n -= 256;
|
|
189
|
+
if (n >= 0) {
|
|
190
|
+
const count = n + 1;
|
|
191
|
+
for (let i = 0; i < count && p < end && o < outLen; i++)
|
|
192
|
+
row[o++] = b[p++];
|
|
193
|
+
}
|
|
194
|
+
else if (n !== -128) {
|
|
195
|
+
const count = 1 - n;
|
|
196
|
+
if (p >= end)
|
|
197
|
+
break;
|
|
198
|
+
const val = b[p++];
|
|
199
|
+
for (let i = 0; i < count && o < outLen; i++)
|
|
200
|
+
row[o++] = val;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return { row, produced: o };
|
|
204
|
+
}
|
|
205
|
+
/** Encode one scanline with PackBits (Adobe/TIFF variant). */
|
|
206
|
+
export function packBitsRow(row) {
|
|
207
|
+
const out = [];
|
|
208
|
+
const n = row.length;
|
|
209
|
+
let i = 0;
|
|
210
|
+
while (i < n) {
|
|
211
|
+
// count a run of equal bytes
|
|
212
|
+
let runEnd = i + 1;
|
|
213
|
+
while (runEnd < n && row[runEnd] === row[i] && runEnd - i < 128)
|
|
214
|
+
runEnd++;
|
|
215
|
+
const runLen = runEnd - i;
|
|
216
|
+
if (runLen >= 2) {
|
|
217
|
+
out.push(257 - runLen); // (1 - runLen) as unsigned byte
|
|
218
|
+
out.push(row[i]);
|
|
219
|
+
i = runEnd;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
// literal run until the next 2-byte repeat (or 128 max)
|
|
223
|
+
let litEnd = i + 1;
|
|
224
|
+
while (litEnd < n &&
|
|
225
|
+
litEnd - i < 128 &&
|
|
226
|
+
!(litEnd + 1 < n && row[litEnd] === row[litEnd + 1])) {
|
|
227
|
+
litEnd++;
|
|
228
|
+
}
|
|
229
|
+
const litLen = litEnd - i;
|
|
230
|
+
out.push(litLen - 1);
|
|
231
|
+
for (let k = i; k < litEnd; k++)
|
|
232
|
+
out.push(row[k]);
|
|
233
|
+
i = litEnd;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return Uint8Array.from(out);
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/psd/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const repairPsd: (src: import("../byte-source.js").ByteSource, opts?: import("./repair.js").PsdRepairOptions | undefined) => Promise<import("./repair.js").PsdRepairResult>;
|
|
2
|
+
export { repairPsdBytes } from "./repair.js";
|
|
3
|
+
export type { PsdRepairOutcome, PsdRepairReport, PsdRepairOptions, PsdRepairResult, } from "./repair.js";
|
|
4
|
+
export { diagnosePsd, diagnosePsdBytes } from "./diagnose.js";
|
|
5
|
+
export type { PsdDiagnosis, PsdDamageClass } from "./diagnose.js";
|
|
6
|
+
export { PSD_SIGNATURE, DEFAULT_PSD_CAPS, parseHeader, serializeHeader, mapSections, walkImageResources, rowBytes, } from "./format.js";
|
|
7
|
+
export type { PsdHeader, PsdSafetyCaps, PsdCompression, PsdSections, ResourceWalk } from "./format.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/psd/index.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,SAAS,4JAAmB,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC9D,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,QAAQ,GACT,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PSD/PSB engine subpath export (`@intactfile/engines/psd`). Pure TypeScript —
|
|
3
|
+
* pako (MIT) + fast-png (MIT), no wasm — so it is browser-safe. Recovers the
|
|
4
|
+
* FLATTENED composite (never the layer stack). diagnosePsd is pure and also
|
|
5
|
+
* promoted to the root barrel; repairPsd stays behind this subpath and is gated.
|
|
6
|
+
*/
|
|
7
|
+
import { gate } from "../license.js";
|
|
8
|
+
import { repairPsd as _repairPsd } from "./repair.js";
|
|
9
|
+
export const repairPsd = gate(_repairPsd);
|
|
10
|
+
export { repairPsdBytes } from "./repair.js";
|
|
11
|
+
export { diagnosePsd, diagnosePsdBytes } from "./diagnose.js";
|
|
12
|
+
export { PSD_SIGNATURE, DEFAULT_PSD_CAPS, parseHeader, serializeHeader, mapSections, walkImageResources, rowBytes, } from "./format.js";
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/psd/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,SAAS,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAQ7C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE9D,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,QAAQ,GACT,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ByteSource } from "../byte-source.js";
|
|
2
|
+
import { type PsdDamageClass } from "./diagnose.js";
|
|
3
|
+
import { type PsdSafetyCaps } from "./format.js";
|
|
4
|
+
export type PsdRepairOutcome = "success" | "partial" | "failed";
|
|
5
|
+
export interface PsdRepairReport {
|
|
6
|
+
outcome: PsdRepairOutcome;
|
|
7
|
+
damageClass: PsdDamageClass;
|
|
8
|
+
actions: string[];
|
|
9
|
+
notes: string[];
|
|
10
|
+
bytesIn: number;
|
|
11
|
+
bytesOut: number;
|
|
12
|
+
width: number | null;
|
|
13
|
+
height: number | null;
|
|
14
|
+
channels: number | null;
|
|
15
|
+
depth: number | null;
|
|
16
|
+
colorMode: number | null;
|
|
17
|
+
/** False whenever the input carried layers that were dropped when flattening. */
|
|
18
|
+
layersRecovered: boolean;
|
|
19
|
+
rowsRecovered: number | null;
|
|
20
|
+
rowsExpected: number | null;
|
|
21
|
+
previewSource: "composite-png" | "thumbnail-jpeg" | null;
|
|
22
|
+
/** What the returned primary bytes are (psd file, png preview, or jpeg thumbnail). */
|
|
23
|
+
output: "psd" | "png" | "jpeg" | null;
|
|
24
|
+
verified: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface PsdRepairOptions {
|
|
27
|
+
caps?: PsdSafetyCaps;
|
|
28
|
+
}
|
|
29
|
+
export interface PsdRepairResult {
|
|
30
|
+
psd?: Uint8Array;
|
|
31
|
+
preview?: Uint8Array;
|
|
32
|
+
report: PsdRepairReport;
|
|
33
|
+
}
|
|
34
|
+
export declare function repairPsdBytes(input: Uint8Array, opts?: PsdRepairOptions): PsdRepairResult;
|
|
35
|
+
export declare function repairPsd(src: ByteSource, opts?: PsdRepairOptions): Promise<PsdRepairResult>;
|
|
36
|
+
//# sourceMappingURL=repair.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repair.d.ts","sourceRoot":"","sources":["../../src/psd/repair.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAGL,KAAK,aAAa,EAenB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEhE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,WAAW,EAAE,cAAc,CAAC;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,iFAAiF;IACjF,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,eAAe,GAAG,gBAAgB,GAAG,IAAI,CAAC;IACzD,sFAAsF;IACtF,MAAM,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB,MAAM,EAAE,eAAe,CAAC;CACzB;AA8RD,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,GAAE,gBAAqB,GAAG,eAAe,CAiJ9F;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAEtG"}
|