@intactfile/engines 0.1.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 +68 -0
- package/dist/archive/diagnose.d.ts +37 -0
- package/dist/archive/diagnose.d.ts.map +1 -0
- package/dist/archive/diagnose.js +165 -0
- package/dist/archive/diagnose.js.map +1 -0
- package/dist/archive/format.d.ts +52 -0
- package/dist/archive/format.d.ts.map +1 -0
- package/dist/archive/format.js +87 -0
- package/dist/archive/format.js.map +1 -0
- package/dist/archive/host.d.ts +83 -0
- package/dist/archive/host.d.ts.map +1 -0
- package/dist/archive/host.js +92 -0
- package/dist/archive/host.js.map +1 -0
- package/dist/archive/index.d.ts +22 -0
- package/dist/archive/index.d.ts.map +1 -0
- package/dist/archive/index.js +19 -0
- package/dist/archive/index.js.map +1 -0
- package/dist/archive/salvage.d.ts +73 -0
- package/dist/archive/salvage.d.ts.map +1 -0
- package/dist/archive/salvage.js +210 -0
- package/dist/archive/salvage.js.map +1 -0
- package/dist/byte-source.d.ts +19 -0
- package/dist/byte-source.d.ts.map +1 -0
- package/dist/byte-source.js +16 -0
- package/dist/byte-source.js.map +1 -0
- package/dist/bytesource/blob.d.ts +14 -0
- package/dist/bytesource/blob.d.ts.map +1 -0
- package/dist/bytesource/blob.js +23 -0
- package/dist/bytesource/blob.js.map +1 -0
- package/dist/crc32.d.ts +2 -0
- package/dist/crc32.d.ts.map +1 -0
- package/dist/crc32.js +18 -0
- package/dist/crc32.js.map +1 -0
- package/dist/detect/index.d.ts +16 -0
- package/dist/detect/index.d.ts.map +1 -0
- package/dist/detect/index.js +159 -0
- package/dist/detect/index.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/jpeg/browser-loader.d.ts +21 -0
- package/dist/jpeg/browser-loader.d.ts.map +1 -0
- package/dist/jpeg/browser-loader.js +28 -0
- package/dist/jpeg/browser-loader.js.map +1 -0
- package/dist/jpeg/diagnose.d.ts +50 -0
- package/dist/jpeg/diagnose.d.ts.map +1 -0
- package/dist/jpeg/diagnose.js +124 -0
- package/dist/jpeg/diagnose.js.map +1 -0
- package/dist/jpeg/exif.d.ts +11 -0
- package/dist/jpeg/exif.d.ts.map +1 -0
- package/dist/jpeg/exif.js +50 -0
- package/dist/jpeg/exif.js.map +1 -0
- package/dist/jpeg/format.d.ts +106 -0
- package/dist/jpeg/format.d.ts.map +1 -0
- package/dist/jpeg/format.js +248 -0
- package/dist/jpeg/format.js.map +1 -0
- package/dist/jpeg/index.d.ts +18 -0
- package/dist/jpeg/index.d.ts.map +1 -0
- package/dist/jpeg/index.js +14 -0
- package/dist/jpeg/index.js.map +1 -0
- package/dist/jpeg/mozjpeg-host.d.ts +60 -0
- package/dist/jpeg/mozjpeg-host.d.ts.map +1 -0
- package/dist/jpeg/mozjpeg-host.js +138 -0
- package/dist/jpeg/mozjpeg-host.js.map +1 -0
- package/dist/jpeg/repair.d.ts +89 -0
- package/dist/jpeg/repair.d.ts.map +1 -0
- package/dist/jpeg/repair.js +216 -0
- package/dist/jpeg/repair.js.map +1 -0
- package/dist/node.d.ts +11 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +29 -0
- package/dist/node.js.map +1 -0
- package/dist/pdf/browser-loader.d.ts +30 -0
- package/dist/pdf/browser-loader.d.ts.map +1 -0
- package/dist/pdf/browser-loader.js +21 -0
- package/dist/pdf/browser-loader.js.map +1 -0
- package/dist/pdf/diagnose.d.ts +23 -0
- package/dist/pdf/diagnose.d.ts.map +1 -0
- package/dist/pdf/diagnose.js +113 -0
- package/dist/pdf/diagnose.js.map +1 -0
- package/dist/pdf/format.d.ts +61 -0
- package/dist/pdf/format.d.ts.map +1 -0
- package/dist/pdf/format.js +150 -0
- package/dist/pdf/format.js.map +1 -0
- package/dist/pdf/index.d.ts +17 -0
- package/dist/pdf/index.d.ts.map +1 -0
- package/dist/pdf/index.js +12 -0
- package/dist/pdf/index.js.map +1 -0
- package/dist/pdf/qpdf-host.d.ts +66 -0
- package/dist/pdf/qpdf-host.d.ts.map +1 -0
- package/dist/pdf/qpdf-host.js +149 -0
- package/dist/pdf/qpdf-host.js.map +1 -0
- package/dist/pdf/rebuild.d.ts +32 -0
- package/dist/pdf/rebuild.d.ts.map +1 -0
- package/dist/pdf/rebuild.js +90 -0
- package/dist/pdf/rebuild.js.map +1 -0
- package/dist/pdf/repair.d.ts +61 -0
- package/dist/pdf/repair.d.ts.map +1 -0
- package/dist/pdf/repair.js +167 -0
- package/dist/pdf/repair.js.map +1 -0
- package/dist/png/diagnose.d.ts +50 -0
- package/dist/png/diagnose.d.ts.map +1 -0
- package/dist/png/diagnose.js +261 -0
- package/dist/png/diagnose.js.map +1 -0
- package/dist/png/format.d.ts +133 -0
- package/dist/png/format.d.ts.map +1 -0
- package/dist/png/format.js +350 -0
- package/dist/png/format.js.map +1 -0
- package/dist/png/index.d.ts +13 -0
- package/dist/png/index.d.ts.map +1 -0
- package/dist/png/index.js +10 -0
- package/dist/png/index.js.map +1 -0
- package/dist/png/repair.d.ts +31 -0
- package/dist/png/repair.d.ts.map +1 -0
- package/dist/png/repair.js +335 -0
- package/dist/png/repair.js.map +1 -0
- package/dist/sqlite/diagnose.d.ts +31 -0
- package/dist/sqlite/diagnose.d.ts.map +1 -0
- package/dist/sqlite/diagnose.js +169 -0
- package/dist/sqlite/diagnose.js.map +1 -0
- package/dist/sqlite/format.d.ts +103 -0
- package/dist/sqlite/format.d.ts.map +1 -0
- package/dist/sqlite/format.js +237 -0
- package/dist/sqlite/format.js.map +1 -0
- package/dist/sqlite/index.d.ts +24 -0
- package/dist/sqlite/index.d.ts.map +1 -0
- package/dist/sqlite/index.js +19 -0
- package/dist/sqlite/index.js.map +1 -0
- package/dist/sqlite/recover.d.ts +66 -0
- package/dist/sqlite/recover.d.ts.map +1 -0
- package/dist/sqlite/recover.js +305 -0
- package/dist/sqlite/recover.js.map +1 -0
- package/dist/sqlite/scan.d.ts +94 -0
- package/dist/sqlite/scan.d.ts.map +1 -0
- package/dist/sqlite/scan.js +356 -0
- package/dist/sqlite/scan.js.map +1 -0
- package/dist/sqlite/sqlite-host.d.ts +37 -0
- package/dist/sqlite/sqlite-host.d.ts.map +1 -0
- package/dist/sqlite/sqlite-host.js +80 -0
- package/dist/sqlite/sqlite-host.js.map +1 -0
- package/dist/sqlite/wal.d.ts +14 -0
- package/dist/sqlite/wal.d.ts.map +1 -0
- package/dist/sqlite/wal.js +79 -0
- package/dist/sqlite/wal.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/video/diagnose.d.ts +41 -0
- package/dist/video/diagnose.d.ts.map +1 -0
- package/dist/video/diagnose.js +188 -0
- package/dist/video/diagnose.js.map +1 -0
- package/dist/video/format.d.ts +87 -0
- package/dist/video/format.d.ts.map +1 -0
- package/dist/video/format.js +273 -0
- package/dist/video/format.js.map +1 -0
- package/dist/video/index.d.ts +21 -0
- package/dist/video/index.d.ts.map +1 -0
- package/dist/video/index.js +17 -0
- package/dist/video/index.js.map +1 -0
- package/dist/video/libav-host.d.ts +88 -0
- package/dist/video/libav-host.d.ts.map +1 -0
- package/dist/video/libav-host.js +66 -0
- package/dist/video/libav-host.js.map +1 -0
- package/dist/video/mp4-rebuild.d.ts +167 -0
- package/dist/video/mp4-rebuild.d.ts.map +1 -0
- package/dist/video/mp4-rebuild.js +270 -0
- package/dist/video/mp4-rebuild.js.map +1 -0
- package/dist/video/mp4box-host.d.ts +62 -0
- package/dist/video/mp4box-host.d.ts.map +1 -0
- package/dist/video/mp4box-host.js +209 -0
- package/dist/video/mp4box-host.js.map +1 -0
- package/dist/video/reconstruct.d.ts +97 -0
- package/dist/video/reconstruct.d.ts.map +1 -0
- package/dist/video/reconstruct.js +271 -0
- package/dist/video/reconstruct.js.map +1 -0
- package/dist/video/remux.d.ts +85 -0
- package/dist/video/remux.d.ts.map +1 -0
- package/dist/video/remux.js +350 -0
- package/dist/video/remux.js.map +1 -0
- package/dist/zip/diagnose.d.ts +22 -0
- package/dist/zip/diagnose.d.ts.map +1 -0
- package/dist/zip/diagnose.js +126 -0
- package/dist/zip/diagnose.js.map +1 -0
- package/dist/zip/format.d.ts +79 -0
- package/dist/zip/format.d.ts.map +1 -0
- package/dist/zip/format.js +129 -0
- package/dist/zip/format.js.map +1 -0
- package/dist/zip/repair.d.ts +32 -0
- package/dist/zip/repair.d.ts.map +1 -0
- package/dist/zip/repair.js +82 -0
- package/dist/zip/repair.js.map +1 -0
- package/dist/zip/salvage.d.ts +23 -0
- package/dist/zip/salvage.d.ts.map +1 -0
- package/dist/zip/salvage.js +140 -0
- package/dist/zip/salvage.js.map +1 -0
- package/dist/zip/scan.d.ts +64 -0
- package/dist/zip/scan.d.ts.map +1 -0
- package/dist/zip/scan.js +386 -0
- package/dist/zip/scan.js.map +1 -0
- package/dist/zip/writer.d.ts +14 -0
- package/dist/zip/writer.d.ts.map +1 -0
- package/dist/zip/writer.js +131 -0
- package/dist/zip/writer.js.map +1 -0
- package/package.json +71 -0
- package/src/archive/LICENSE-unrar.txt +53 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { FLAG_DATA_DESCRIPTOR, LFH_FIXED_SIZE, SIG_EOCD, SIG_LFH, U32_MAX, parseLocalHeader, readU32, } from '../zip/format.js';
|
|
2
|
+
const SCAN_WINDOW = 64 * 1024;
|
|
3
|
+
function ascii(b, from, to) {
|
|
4
|
+
let s = '';
|
|
5
|
+
for (let i = from; i < Math.min(to, b.length); i++)
|
|
6
|
+
s += String.fromCharCode(b[i]);
|
|
7
|
+
return s;
|
|
8
|
+
}
|
|
9
|
+
function indexOfBytes(haystack, needle, from = 0) {
|
|
10
|
+
outer: for (let i = from; i + needle.length <= haystack.length; i++) {
|
|
11
|
+
for (let j = 0; j < needle.length; j++) {
|
|
12
|
+
if (haystack[i + j] !== needle[j])
|
|
13
|
+
continue outer;
|
|
14
|
+
}
|
|
15
|
+
return i;
|
|
16
|
+
}
|
|
17
|
+
return -1;
|
|
18
|
+
}
|
|
19
|
+
/** Quick, trusting walk over the first local headers just to collect entry names. */
|
|
20
|
+
async function probeZipEntryNames(src, base) {
|
|
21
|
+
const names = [];
|
|
22
|
+
let pos = base;
|
|
23
|
+
for (let i = 0; i < 16; i++) {
|
|
24
|
+
const fixed = await src.read(pos, LFH_FIXED_SIZE);
|
|
25
|
+
if (fixed.length < LFH_FIXED_SIZE || readU32(fixed, 0) !== SIG_LFH)
|
|
26
|
+
break;
|
|
27
|
+
const h = parseLocalHeader(fixed);
|
|
28
|
+
if (!h || h.nameLength === 0 || h.nameLength > 4096)
|
|
29
|
+
break;
|
|
30
|
+
const nameBytes = await src.read(pos + LFH_FIXED_SIZE, h.nameLength);
|
|
31
|
+
names.push(new TextDecoder('utf-8').decode(nameBytes));
|
|
32
|
+
if (h.flags & FLAG_DATA_DESCRIPTOR || h.compressedSize === U32_MAX)
|
|
33
|
+
break;
|
|
34
|
+
pos += LFH_FIXED_SIZE + h.nameLength + h.extraLength + h.compressedSize;
|
|
35
|
+
}
|
|
36
|
+
return names;
|
|
37
|
+
}
|
|
38
|
+
function ooxmlContainer(names) {
|
|
39
|
+
if (!names.some((n) => n === '[Content_Types].xml'))
|
|
40
|
+
return 'zip';
|
|
41
|
+
if (names.some((n) => n.startsWith('word/')))
|
|
42
|
+
return 'docx';
|
|
43
|
+
if (names.some((n) => n.startsWith('xl/')))
|
|
44
|
+
return 'xlsx';
|
|
45
|
+
if (names.some((n) => n.startsWith('ppt/')))
|
|
46
|
+
return 'pptx';
|
|
47
|
+
return 'ooxml';
|
|
48
|
+
}
|
|
49
|
+
async function detectZipAt(src, base, confidence, notes) {
|
|
50
|
+
const names = await probeZipEntryNames(src, base);
|
|
51
|
+
const container = ooxmlContainer(names);
|
|
52
|
+
if (container !== 'zip')
|
|
53
|
+
notes.push('OOXML package detected via [Content_Types].xml');
|
|
54
|
+
return { format: 'zip', container, confidence, notes };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Magic-byte format sniffing with garbage-prefix tolerance. Shared diagnosis
|
|
58
|
+
* entry point for the app UI.
|
|
59
|
+
*/
|
|
60
|
+
export async function detectFormat(src) {
|
|
61
|
+
const notes = [];
|
|
62
|
+
const head = await src.read(0, Math.min(src.size, 4096));
|
|
63
|
+
if (head.length < 4) {
|
|
64
|
+
return { format: 'unknown', confidence: 'low', notes: ['file too small to identify'] };
|
|
65
|
+
}
|
|
66
|
+
// PNG
|
|
67
|
+
if (head[0] === 0x89 && head[1] === 0x50 && head[2] === 0x4e && head[3] === 0x47 &&
|
|
68
|
+
head[4] === 0x0d && head[5] === 0x0a && head[6] === 0x1a && head[7] === 0x0a) {
|
|
69
|
+
return { format: 'png', confidence: 'high', notes };
|
|
70
|
+
}
|
|
71
|
+
// JPEG
|
|
72
|
+
if (head[0] === 0xff && head[1] === 0xd8 && head[2] === 0xff) {
|
|
73
|
+
return { format: 'jpeg', confidence: 'high', notes };
|
|
74
|
+
}
|
|
75
|
+
// RIFF (WAV / AVI)
|
|
76
|
+
if (ascii(head, 0, 4) === 'RIFF' && head.length >= 12) {
|
|
77
|
+
const kind = ascii(head, 8, 12);
|
|
78
|
+
if (kind === 'WAVE')
|
|
79
|
+
return { format: 'wav', container: 'riff', confidence: 'high', notes };
|
|
80
|
+
if (kind === 'AVI ')
|
|
81
|
+
return { format: 'avi', container: 'riff', confidence: 'high', notes };
|
|
82
|
+
notes.push(`unrecognized RIFF type "${kind.trim()}"`);
|
|
83
|
+
return { format: 'riff', container: 'riff', confidence: 'medium', notes };
|
|
84
|
+
}
|
|
85
|
+
// EBML (MKV / WebM)
|
|
86
|
+
if (head[0] === 0x1a && head[1] === 0x45 && head[2] === 0xdf && head[3] === 0xa3) {
|
|
87
|
+
const header = ascii(head, 0, head.length);
|
|
88
|
+
if (header.includes('webm'))
|
|
89
|
+
return { format: 'webm', confidence: 'high', notes };
|
|
90
|
+
if (header.includes('matroska'))
|
|
91
|
+
return { format: 'mkv', confidence: 'high', notes };
|
|
92
|
+
notes.push('EBML header without a recognizable DocType');
|
|
93
|
+
return { format: 'mkv', confidence: 'medium', notes };
|
|
94
|
+
}
|
|
95
|
+
// ZIP at offset 0
|
|
96
|
+
if (readU32(head, 0) === SIG_LFH) {
|
|
97
|
+
return detectZipAt(src, 0, 'high', notes);
|
|
98
|
+
}
|
|
99
|
+
if (readU32(head, 0) === SIG_EOCD) {
|
|
100
|
+
notes.push('empty zip archive (EOCD only)');
|
|
101
|
+
return { format: 'zip', container: 'zip', confidence: 'high', notes };
|
|
102
|
+
}
|
|
103
|
+
// PDF at offset 0
|
|
104
|
+
if (ascii(head, 0, 5) === '%PDF-') {
|
|
105
|
+
return { format: 'pdf', confidence: 'high', notes };
|
|
106
|
+
}
|
|
107
|
+
// MP4 / MOV: ftyp box at start
|
|
108
|
+
if (head.length >= 12 && ascii(head, 4, 8) === 'ftyp') {
|
|
109
|
+
const brand = ascii(head, 8, 12);
|
|
110
|
+
const boxSize = readU32be(head, 0);
|
|
111
|
+
if (boxSize < 8 || boxSize > src.size)
|
|
112
|
+
notes.push('implausible ftyp box size');
|
|
113
|
+
const isMov = brand.startsWith('qt');
|
|
114
|
+
return {
|
|
115
|
+
format: isMov ? 'mov' : 'mp4',
|
|
116
|
+
container: brand.trim(),
|
|
117
|
+
confidence: boxSize >= 8 && boxSize <= src.size ? 'high' : 'medium',
|
|
118
|
+
notes,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
// MP3 with ID3 tag
|
|
122
|
+
if (ascii(head, 0, 3) === 'ID3') {
|
|
123
|
+
return { format: 'mp3', confidence: 'high', notes };
|
|
124
|
+
}
|
|
125
|
+
// Tolerant scans over a larger window.
|
|
126
|
+
const window = src.size <= head.length ? head : await src.read(0, Math.min(src.size, SCAN_WINDOW));
|
|
127
|
+
const pdfAt = indexOfBytes(window, [0x25, 0x50, 0x44, 0x46, 0x2d]); // %PDF-
|
|
128
|
+
if (pdfAt > 0) {
|
|
129
|
+
notes.push(`PDF header found at offset ${pdfAt} (garbage prefix)`);
|
|
130
|
+
return { format: 'pdf', confidence: pdfAt <= 1024 ? 'high' : 'medium', notes };
|
|
131
|
+
}
|
|
132
|
+
const ftypAt = indexOfBytes(window, [0x66, 0x74, 0x79, 0x70]); // 'ftyp'
|
|
133
|
+
if (ftypAt >= 4) {
|
|
134
|
+
const brand = ascii(window, ftypAt + 4, ftypAt + 8);
|
|
135
|
+
notes.push(`ftyp box found at offset ${ftypAt - 4}`);
|
|
136
|
+
return { format: brand.startsWith('qt') ? 'mov' : 'mp4', container: brand.trim(), confidence: 'medium', notes };
|
|
137
|
+
}
|
|
138
|
+
const zipAt = indexOfBytes(window, [0x50, 0x4b, 0x03, 0x04]);
|
|
139
|
+
if (zipAt > 0) {
|
|
140
|
+
notes.push(`zip local header found at offset ${zipAt} (garbage prefix)`);
|
|
141
|
+
return detectZipAt(src, zipAt, 'medium', notes);
|
|
142
|
+
}
|
|
143
|
+
// Bare MPEG frame sync (weak signal, checked last).
|
|
144
|
+
const b1 = head[1];
|
|
145
|
+
if (head[0] === 0xff &&
|
|
146
|
+
(b1 & 0xe0) === 0xe0 &&
|
|
147
|
+
((b1 >> 3) & 0x03) !== 1 && // MPEG version: reserved
|
|
148
|
+
((b1 >> 1) & 0x03) !== 0 && // layer: reserved
|
|
149
|
+
head[2] >>> 4 !== 0x0f // bitrate: invalid
|
|
150
|
+
) {
|
|
151
|
+
notes.push('bare MPEG audio frame sync (no ID3 tag)');
|
|
152
|
+
return { format: 'mp3', confidence: 'medium', notes };
|
|
153
|
+
}
|
|
154
|
+
return { format: 'unknown', confidence: 'low', notes: [...notes, 'no known magic bytes matched'] };
|
|
155
|
+
}
|
|
156
|
+
function readU32be(b, o) {
|
|
157
|
+
return ((b[o] << 24) | (b[o + 1] << 16) | (b[o + 2] << 8) | b[o + 3]) >>> 0;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/detect/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type { ByteSource } from './byte-source.js';
|
|
2
|
+
export { MemorySource } from './byte-source.js';
|
|
3
|
+
export { BlobSource } from './bytesource/blob.js';
|
|
4
|
+
export { crc32 } from './crc32.js';
|
|
5
|
+
export type { Confidence } from './types.js';
|
|
6
|
+
export { diagnoseZip, analyzeZip } from './zip/diagnose.js';
|
|
7
|
+
export type { ZipDiagnosis, DamageClass, ZipAnalysis } from './zip/diagnose.js';
|
|
8
|
+
export { repairZip } from './zip/repair.js';
|
|
9
|
+
export type { RepairReport, RepairEntryReport } from './zip/repair.js';
|
|
10
|
+
export { scanLocalEntries, findEocd } from './zip/scan.js';
|
|
11
|
+
export type { ScanResult, ScannedEntry, EocdResult } from './zip/scan.js';
|
|
12
|
+
export { validateEntry } from './zip/salvage.js';
|
|
13
|
+
export type { ValidatedEntry, EntryStatus } from './zip/salvage.js';
|
|
14
|
+
export { buildZip } from './zip/writer.js';
|
|
15
|
+
export type { OutEntry } from './zip/writer.js';
|
|
16
|
+
export { parseLocalHeader, parseZip64Extra, parseEocd, reconcileDeclaredSize, localHeaderLooksSane, } from './zip/format.js';
|
|
17
|
+
export type { LocalHeader, Zip64Extra, Eocd } from './zip/format.js';
|
|
18
|
+
export { detectFormat } from './detect/index.js';
|
|
19
|
+
export type { FormatDetection, FileFormat } from './detect/index.js';
|
|
20
|
+
export { diagnosePdf } from './pdf/diagnose.js';
|
|
21
|
+
export type { PdfDiagnosis, PdfDamageClass } from './pdf/diagnose.js';
|
|
22
|
+
export { diagnoseVideo } from './video/diagnose.js';
|
|
23
|
+
export type { VideoDiagnosis, VideoDamageClass, VideoContainer, VideoBoxInfo } from './video/diagnose.js';
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC5D,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC3D,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,YAAY,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAErE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIrE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAItE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { MemorySource } from './byte-source.js';
|
|
2
|
+
export { BlobSource } from './bytesource/blob.js';
|
|
3
|
+
export { crc32 } from './crc32.js';
|
|
4
|
+
export { diagnoseZip, analyzeZip } from './zip/diagnose.js';
|
|
5
|
+
export { repairZip } from './zip/repair.js';
|
|
6
|
+
export { scanLocalEntries, findEocd } from './zip/scan.js';
|
|
7
|
+
export { validateEntry } from './zip/salvage.js';
|
|
8
|
+
export { buildZip } from './zip/writer.js';
|
|
9
|
+
export { parseLocalHeader, parseZip64Extra, parseEocd, reconcileDeclaredSize, localHeaderLooksSane, } from './zip/format.js';
|
|
10
|
+
export { detectFormat } from './detect/index.js';
|
|
11
|
+
// PDF diagnosis is pure byte-scanning (no qpdf wasm in its import chain), so it
|
|
12
|
+
// is safe in the browser-facing root export; repairPdf stays behind './pdf'.
|
|
13
|
+
export { diagnosePdf } from './pdf/diagnose.js';
|
|
14
|
+
// Video diagnosis is likewise pure own parsing (no libav.js in its import
|
|
15
|
+
// chain); remuxVideo stays behind './video'.
|
|
16
|
+
export { diagnoseVideo } from './video/diagnose.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE3D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,gFAAgF;AAChF,6EAA6E;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,0EAA0E;AAC1E,6CAA6C;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-side loader for the @jsquash/jpeg codec wasm. Hand the result of
|
|
3
|
+
* `createBrowserJpegLoader()` to `setJpegLoader()` before calling
|
|
4
|
+
* `repairJpeg()` in a browser.
|
|
5
|
+
*
|
|
6
|
+
* The two .wasm files are NOT bundled: they must be served as same-origin
|
|
7
|
+
* static assets (apps/www/app copy them to /engines/jpeg/ at build time).
|
|
8
|
+
* Same-origin is a product requirement — "your file never leaves your device"
|
|
9
|
+
* stays verifiable in the Network tab only if no third-party host is involved.
|
|
10
|
+
* The @jsquash JS wrappers themselves are bundled and pulled into the './jpeg'
|
|
11
|
+
* lazy chunk; only the wasm is fetched, and only on the first repair.
|
|
12
|
+
*/
|
|
13
|
+
import type { JpegCodecLoader } from './mozjpeg-host.js';
|
|
14
|
+
/** Where the app serves the codec wasm from. */
|
|
15
|
+
export declare const DEFAULT_JPEG_BASE_URL = "/engines/jpeg/";
|
|
16
|
+
/**
|
|
17
|
+
* Build a loader for `setJpegLoader()`. `baseUrl` is the same-origin directory
|
|
18
|
+
* the two wasm files are served from; trailing slash optional.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createBrowserJpegLoader(baseUrl?: string): () => Promise<JpegCodecLoader>;
|
|
21
|
+
//# sourceMappingURL=browser-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-loader.d.ts","sourceRoot":"","sources":["../../src/jpeg/browser-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,gDAAgD;AAChD,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AActD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,MAA8B,GAAG,MAAM,OAAO,CAAC,eAAe,CAAC,CAQ/G"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Where the app serves the codec wasm from. */
|
|
2
|
+
export const DEFAULT_JPEG_BASE_URL = '/engines/jpeg/';
|
|
3
|
+
async function compileFrom(url) {
|
|
4
|
+
if (typeof WebAssembly.compileStreaming === 'function') {
|
|
5
|
+
try {
|
|
6
|
+
return await WebAssembly.compileStreaming(fetch(url));
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
// Fall back when the server doesn't send application/wasm.
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const res = await fetch(url);
|
|
13
|
+
return WebAssembly.compile(await res.arrayBuffer());
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Build a loader for `setJpegLoader()`. `baseUrl` is the same-origin directory
|
|
17
|
+
* the two wasm files are served from; trailing slash optional.
|
|
18
|
+
*/
|
|
19
|
+
export function createBrowserJpegLoader(baseUrl = DEFAULT_JPEG_BASE_URL) {
|
|
20
|
+
const b = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
|
21
|
+
const decUrl = `${b}mozjpeg_dec.wasm`;
|
|
22
|
+
const encUrl = `${b}mozjpeg_enc.wasm`;
|
|
23
|
+
return async () => ({
|
|
24
|
+
decodeModule: () => compileFrom(decUrl),
|
|
25
|
+
encodeModule: () => compileFrom(encUrl),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=browser-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-loader.js","sourceRoot":"","sources":["../../src/jpeg/browser-loader.ts"],"names":[],"mappings":"AAcA,gDAAgD;AAChD,MAAM,CAAC,MAAM,qBAAqB,GAAG,gBAAgB,CAAC;AAEtD,KAAK,UAAU,WAAW,CAAC,GAAW;IACpC,IAAI,OAAO,WAAW,CAAC,gBAAgB,KAAK,UAAU,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,OAAO,MAAM,WAAW,CAAC,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,2DAA2D;QAC7D,CAAC;IACH,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,OAAO,WAAW,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,UAAkB,qBAAqB;IAC7E,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC;IAC1D,MAAM,MAAM,GAAG,GAAG,CAAC,kBAAkB,CAAC;IACtC,MAAM,MAAM,GAAG,GAAG,CAAC,kBAAkB,CAAC;IACtC,OAAO,KAAK,IAAI,EAAE,CAAC,CAAC;QAClB,YAAY,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC;QACvC,YAAY,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC;KACxC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural JPEG diagnosis via a pure marker scan — no wasm anywhere in this
|
|
3
|
+
* import chain, so it is cheap and safe to run before any repair (and in the
|
|
4
|
+
* browser without loading the codec).
|
|
5
|
+
*
|
|
6
|
+
* It reports the presence and order of the framing markers (SOI/APPn/DQT/DHT/
|
|
7
|
+
* SOF/SOS/EOI), classifies the damage, and — as a triage hint — measures the
|
|
8
|
+
* Shannon entropy of the entropy-coded scan region. High entropy means real
|
|
9
|
+
* compressed pixel data is still there (salvageable); near-zero entropy means
|
|
10
|
+
* the scan was zeroed or overwritten (no software can bring those pixels back,
|
|
11
|
+
* per docs/03 §4).
|
|
12
|
+
*
|
|
13
|
+
* Honesty: a truncated file is never called "fine"; a file whose scan was
|
|
14
|
+
* overwritten is flagged as such rather than reported as recoverable.
|
|
15
|
+
*/
|
|
16
|
+
import type { ByteSource } from '../byte-source.js';
|
|
17
|
+
import type { Confidence } from '../types.js';
|
|
18
|
+
export type JpegDamageClass = 'none' | 'header-damage' | 'truncated' | 'marker-corruption' | 'garbage-prefix' | 'not-jpeg' | 'unknown';
|
|
19
|
+
export interface JpegDiagnosis {
|
|
20
|
+
damageClass: JpegDamageClass;
|
|
21
|
+
confidence: Confidence;
|
|
22
|
+
notes: string[];
|
|
23
|
+
/** Offset of SOI (0xFFD8); 0 normally, > 0 for a garbage prefix, null if absent. */
|
|
24
|
+
soiOffset: number | null;
|
|
25
|
+
hasEoi: boolean;
|
|
26
|
+
hasSof: boolean;
|
|
27
|
+
hasSos: boolean;
|
|
28
|
+
hasDqt: boolean;
|
|
29
|
+
hasDht: boolean;
|
|
30
|
+
/** Framing markers in the order the sequential walk saw them. */
|
|
31
|
+
markerOrder: string[];
|
|
32
|
+
/** Frame dimensions from SOF, when a SOF segment is readable. */
|
|
33
|
+
width: number | null;
|
|
34
|
+
height: number | null;
|
|
35
|
+
/**
|
|
36
|
+
* Shannon entropy (bits/byte) of the scan region, or null when there is no
|
|
37
|
+
* scan. A hint, not a verdict: ~7+ = live compressed data; ~0 = destroyed.
|
|
38
|
+
*/
|
|
39
|
+
scanEntropy: number | null;
|
|
40
|
+
}
|
|
41
|
+
/** Below this, a scan region looks zeroed/overwritten rather than compressed. */
|
|
42
|
+
export declare const LOW_SCAN_ENTROPY = 1.5;
|
|
43
|
+
/** How far in we still look for a shifted SOI (garbage prefix). */
|
|
44
|
+
export declare const SOI_SCAN_WINDOW: number;
|
|
45
|
+
/**
|
|
46
|
+
* Diagnose a JPEG from raw bytes. Pure and side-effect free; never loads the
|
|
47
|
+
* codec.
|
|
48
|
+
*/
|
|
49
|
+
export declare function diagnoseJpeg(src: ByteSource): Promise<JpegDiagnosis>;
|
|
50
|
+
//# sourceMappingURL=diagnose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.d.ts","sourceRoot":"","sources":["../../src/jpeg/diagnose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAa9C,MAAM,MAAM,eAAe,GACvB,MAAM,GACN,eAAe,GACf,WAAW,GACX,mBAAmB,GACnB,gBAAgB,GAChB,UAAU,GACV,SAAS,CAAC;AAEd,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,eAAe,CAAC;IAC7B,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,oFAAoF;IACpF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,iEAAiE;IACjE,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,iEAAiE;IACjE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;;;OAGG;IACH,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,mEAAmE;AACnE,eAAO,MAAM,eAAe,QAAU,CAAC;AAEvC;;;GAGG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,CAgI1E"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { M_DHT, M_DQT, findSoi, isSofMarker, readSofDimensions, readU16BE, scanMarkerPresence, scanMarkers, shannonEntropy, } from './format.js';
|
|
2
|
+
/** Below this, a scan region looks zeroed/overwritten rather than compressed. */
|
|
3
|
+
export const LOW_SCAN_ENTROPY = 1.5;
|
|
4
|
+
/** How far in we still look for a shifted SOI (garbage prefix). */
|
|
5
|
+
export const SOI_SCAN_WINDOW = 1 << 16;
|
|
6
|
+
/**
|
|
7
|
+
* Diagnose a JPEG from raw bytes. Pure and side-effect free; never loads the
|
|
8
|
+
* codec.
|
|
9
|
+
*/
|
|
10
|
+
export async function diagnoseJpeg(src) {
|
|
11
|
+
const notes = [];
|
|
12
|
+
const base = {
|
|
13
|
+
notes,
|
|
14
|
+
soiOffset: null,
|
|
15
|
+
hasEoi: false,
|
|
16
|
+
hasSof: false,
|
|
17
|
+
hasSos: false,
|
|
18
|
+
hasDqt: false,
|
|
19
|
+
hasDht: false,
|
|
20
|
+
markerOrder: [],
|
|
21
|
+
width: null,
|
|
22
|
+
height: null,
|
|
23
|
+
scanEntropy: null,
|
|
24
|
+
};
|
|
25
|
+
const done = (damageClass, confidence) => ({
|
|
26
|
+
damageClass,
|
|
27
|
+
confidence,
|
|
28
|
+
...base,
|
|
29
|
+
});
|
|
30
|
+
if (src.size === 0) {
|
|
31
|
+
notes.push('file is empty');
|
|
32
|
+
return done('not-jpeg', 'high');
|
|
33
|
+
}
|
|
34
|
+
const bytes = await src.read(0, src.size);
|
|
35
|
+
const soi = findSoi(bytes, SOI_SCAN_WINDOW);
|
|
36
|
+
if (soi === -1) {
|
|
37
|
+
notes.push(`no SOI (0xFFD8) marker in the first ${Math.min(bytes.length, SOI_SCAN_WINDOW)} bytes`);
|
|
38
|
+
return done('not-jpeg', bytes.length <= SOI_SCAN_WINDOW ? 'high' : 'medium');
|
|
39
|
+
}
|
|
40
|
+
base.soiOffset = soi;
|
|
41
|
+
// The strict sequential walk is the source of truth: it skips every segment
|
|
42
|
+
// by its declared length, so nested markers inside an intact APP1/EXIF
|
|
43
|
+
// thumbnail never leak into presence detection. Only when the walk breaks
|
|
44
|
+
// before resolving SOS (a destroyed/garbled header) do we fall back to a
|
|
45
|
+
// robust byte-level marker scan to find whatever survived past the break.
|
|
46
|
+
const seq = scanMarkers(bytes, soi);
|
|
47
|
+
const firstSof = seq.segments.find((s) => isSofMarker(s.marker));
|
|
48
|
+
base.hasDqt = seq.segments.some((s) => s.marker === M_DQT);
|
|
49
|
+
base.hasDht = seq.segments.some((s) => s.marker === M_DHT);
|
|
50
|
+
base.hasSof = firstSof !== undefined;
|
|
51
|
+
base.hasSos = seq.sosOffset !== -1;
|
|
52
|
+
base.hasEoi = seq.hasEoi;
|
|
53
|
+
let sosOffset = seq.sosOffset;
|
|
54
|
+
let eoiOffset = seq.eoiOffset;
|
|
55
|
+
let sofOffset = firstSof?.offset ?? -1;
|
|
56
|
+
const framingBroken = seq.badMarker || seq.overflow || seq.truncatedHeader;
|
|
57
|
+
if (!base.hasSos && framingBroken) {
|
|
58
|
+
const pres = scanMarkerPresence(bytes, soi + 2);
|
|
59
|
+
base.hasDqt = pres.hasDqt;
|
|
60
|
+
base.hasDht = pres.hasDht;
|
|
61
|
+
base.hasSof = pres.hasSof;
|
|
62
|
+
base.hasSos = pres.hasSos;
|
|
63
|
+
base.hasEoi = pres.hasEoi;
|
|
64
|
+
sosOffset = pres.sosOffset;
|
|
65
|
+
eoiOffset = pres.eoiOffset;
|
|
66
|
+
sofOffset = pres.sofOffset;
|
|
67
|
+
}
|
|
68
|
+
base.markerOrder = ['SOI', ...seq.segments.map((s) => s.name), ...(seq.hasEoi ? ['EOI'] : [])];
|
|
69
|
+
if (sofOffset !== -1) {
|
|
70
|
+
const dims = readSofDimensions(bytes, sofOffset);
|
|
71
|
+
if (dims) {
|
|
72
|
+
base.width = dims.width;
|
|
73
|
+
base.height = dims.height;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Entropy of the scan region, when a SOS was resolved.
|
|
77
|
+
if (sosOffset !== -1) {
|
|
78
|
+
const sosLen = readU16BE(bytes, sosOffset + 2);
|
|
79
|
+
const scanStart = sosOffset + 2 + sosLen;
|
|
80
|
+
const scanEnd = base.hasEoi && eoiOffset !== -1 ? eoiOffset : bytes.length;
|
|
81
|
+
base.scanEntropy = shannonEntropy(bytes, scanStart, scanEnd);
|
|
82
|
+
}
|
|
83
|
+
// --- Classification ------------------------------------------------------
|
|
84
|
+
if (soi > 0) {
|
|
85
|
+
notes.push(`SOI found at offset ${soi} (garbage prefix of ${soi} bytes)`);
|
|
86
|
+
if (!base.hasSos)
|
|
87
|
+
notes.push('no scan segment after the prefix; there may be little to recover');
|
|
88
|
+
return done('garbage-prefix', base.hasSos && base.hasEoi ? 'high' : 'medium');
|
|
89
|
+
}
|
|
90
|
+
const liveScan = base.scanEntropy !== null && base.scanEntropy >= LOW_SCAN_ENTROPY;
|
|
91
|
+
if (!base.hasSos) {
|
|
92
|
+
if (framingBroken) {
|
|
93
|
+
notes.push('file ends inside the JPEG header, before the scan (SOS) — truncated early');
|
|
94
|
+
return done('truncated', 'medium');
|
|
95
|
+
}
|
|
96
|
+
notes.push('no SOS marker: no image scan data present');
|
|
97
|
+
return done(base.hasSof || base.hasDqt || base.hasDht ? 'truncated' : 'unknown', 'low');
|
|
98
|
+
}
|
|
99
|
+
if (!base.hasEoi) {
|
|
100
|
+
notes.push('SOS present but no trailing EOI: the scan was cut off (truncated)');
|
|
101
|
+
if (base.scanEntropy !== null)
|
|
102
|
+
notes.push(`scan entropy ${base.scanEntropy.toFixed(2)} bits/byte`);
|
|
103
|
+
return done('truncated', liveScan ? 'high' : 'medium');
|
|
104
|
+
}
|
|
105
|
+
if (!base.hasSof || !base.hasDqt || !base.hasDht) {
|
|
106
|
+
const missing = [!base.hasSof && 'SOF', !base.hasDqt && 'DQT', !base.hasDht && 'DHT']
|
|
107
|
+
.filter(Boolean)
|
|
108
|
+
.join(', ');
|
|
109
|
+
notes.push(`scan and EOI survived but header tables are gone (missing ${missing})`);
|
|
110
|
+
notes.push('a healthy same-camera reference photo can donate the missing header');
|
|
111
|
+
return done('header-damage', liveScan ? 'high' : 'medium');
|
|
112
|
+
}
|
|
113
|
+
if (seq.badMarker || seq.overflow) {
|
|
114
|
+
notes.push('all key markers exist but the segment framing is broken mid-header (marker corruption)');
|
|
115
|
+
return done('marker-corruption', 'medium');
|
|
116
|
+
}
|
|
117
|
+
if (base.scanEntropy !== null && base.scanEntropy < LOW_SCAN_ENTROPY) {
|
|
118
|
+
notes.push(`structure is intact but the scan region entropy is only ${base.scanEntropy.toFixed(2)} bits/byte — ` +
|
|
119
|
+
'the pixel data looks zeroed or overwritten, which no repair can undo');
|
|
120
|
+
return done('marker-corruption', 'medium');
|
|
121
|
+
}
|
|
122
|
+
return done('none', 'high');
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=diagnose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.js","sourceRoot":"","sources":["../../src/jpeg/diagnose.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Return the embedded EXIF thumbnail JPEG as bytes, or null when there is
|
|
3
|
+
* none / it cannot be read. Never throws.
|
|
4
|
+
*/
|
|
5
|
+
export declare function extractExifThumbnail(bytes: Uint8Array): Promise<Uint8Array | null>;
|
|
6
|
+
/**
|
|
7
|
+
* Read the EXIF orientation tag (1..8), or null when absent/unreadable. Handy
|
|
8
|
+
* for a correctly-rotated preview; never throws.
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractExifOrientation(bytes: Uint8Array): Promise<number | null>;
|
|
11
|
+
//# sourceMappingURL=exif.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exif.d.ts","sourceRoot":"","sources":["../../src/jpeg/exif.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAYxF;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWtF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EXIF thumbnail extraction via exifr 7.1.3 (MIT). Pure JS (no wasm), but kept
|
|
3
|
+
* off the diagnosis path and imported only by the repair flow.
|
|
4
|
+
*
|
|
5
|
+
* Most camera/phone JPEGs embed a small JPEG thumbnail in the APP1/EXIF IFD1.
|
|
6
|
+
* When the main image is unsalvageable (scan overwritten, header destroyed
|
|
7
|
+
* with no donor), that thumbnail is often the only real pixels left — a
|
|
8
|
+
* guaranteed, honest preview fallback ("we could only recover the embedded
|
|
9
|
+
* thumbnail", never presented as the repaired full-resolution image).
|
|
10
|
+
*/
|
|
11
|
+
import exifr from 'exifr';
|
|
12
|
+
/**
|
|
13
|
+
* Return the embedded EXIF thumbnail JPEG as bytes, or null when there is
|
|
14
|
+
* none / it cannot be read. Never throws.
|
|
15
|
+
*/
|
|
16
|
+
export async function extractExifThumbnail(bytes) {
|
|
17
|
+
try {
|
|
18
|
+
// exifr accepts a Uint8Array/Buffer directly and returns the raw thumbnail
|
|
19
|
+
// JPEG (Uint8Array in Node, ArrayBuffer in browsers).
|
|
20
|
+
const thumb = await exifr.thumbnail(bytes);
|
|
21
|
+
if (!thumb)
|
|
22
|
+
return null;
|
|
23
|
+
if (thumb instanceof Uint8Array)
|
|
24
|
+
return thumb.length > 0 ? thumb : null;
|
|
25
|
+
if (thumb instanceof ArrayBuffer)
|
|
26
|
+
return thumb.byteLength > 0 ? new Uint8Array(thumb) : null;
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Read the EXIF orientation tag (1..8), or null when absent/unreadable. Handy
|
|
35
|
+
* for a correctly-rotated preview; never throws.
|
|
36
|
+
*/
|
|
37
|
+
export async function extractExifOrientation(bytes) {
|
|
38
|
+
try {
|
|
39
|
+
const meta = await exifr.parse(bytes, { pick: ['Orientation'], translateValues: false });
|
|
40
|
+
if (meta && typeof meta === 'object' && 'Orientation' in meta) {
|
|
41
|
+
const o = meta.Orientation;
|
|
42
|
+
return typeof o === 'number' ? o : null;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=exif.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exif.js","sourceRoot":"","sources":["../../src/jpeg/exif.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,KAAiB;IAC1D,IAAI,CAAC;QACH,2EAA2E;QAC3E,sDAAsD;QACtD,MAAM,KAAK,GAAY,MAAM,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACpD,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,KAAK,YAAY,UAAU;YAAE,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QACxE,IAAI,KAAK,YAAY,WAAW;YAAE,OAAO,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7F,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,KAAiB;IAC5D,IAAI,CAAC;QACH,MAAM,IAAI,GAAY,MAAM,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,aAAa,CAAC,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,CAAC;QAClG,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,aAAa,IAAI,IAAI,EAAE,CAAC;YAC9D,MAAM,CAAC,GAAI,IAAkC,CAAC,WAAW,CAAC;YAC1D,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1C,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|