-
-
Notifications
You must be signed in to change notification settings - Fork 6
/
index.js
82 lines (61 loc) · 2.02 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import fs from 'node:fs';
import {readChunk} from 'read-chunk';
import {includes} from 'uint8array-extras';
// https://en.wikipedia.org/wiki/JPEG
// SOF2 [0xFF, 0xC2] = Start Of Frame (Progressive DCT)
const SOF2 = new Uint8Array([0xFF, 0xC2]);
const MAX_BUFFER = 65_536;
const fromBuffer = buffer => includes(buffer, SOF2);
const isProgressive = {};
isProgressive.buffer = fromBuffer;
isProgressive.stream = readableStream => new Promise((resolve, reject) => {
// The first byte is for the previous last byte if we have multiple data events.
const buffer = new Uint8Array(1 + MAX_BUFFER);
let bytesRead = 0;
function end() {
resolve(false);
}
function cleanup(value) {
resolve(value);
readableStream.removeListener('data', onData);
readableStream.removeListener('end', end);
readableStream.removeListener('error', reject);
}
function onData(data) {
if (bytesRead >= MAX_BUFFER) {
return cleanup(false);
}
buffer.set(data.subarray(0, MAX_BUFFER), 1);
if (fromBuffer(buffer)) {
return cleanup(true);
}
bytesRead += data.byteLength;
buffer.set(data.at(-1));
}
readableStream.on('data', onData);
readableStream.on('end', end);
readableStream.on('error', reject);
});
// The metadata section has a maximum size of 65536 bytes
isProgressive.file = async filePath => fromBuffer(await readChunk(filePath, {length: MAX_BUFFER}));
isProgressive.fileSync = filepath => {
// We read two bytes at a time here as it usually appears early in the file and reading 65536 would be wasteful
const BUFFER_LENGTH = 2;
const buffer = new Uint8Array(1 + BUFFER_LENGTH);
const read = fs.openSync(filepath, 'r');
let bytesRead = BUFFER_LENGTH;
let isProgressive = false;
let position = 0;
while (bytesRead !== 0 && position < MAX_BUFFER) {
bytesRead = fs.readSync(read, buffer, 1, BUFFER_LENGTH, position);
isProgressive = fromBuffer(buffer);
if (isProgressive) {
break;
}
position += bytesRead;
buffer.set(buffer.at(-1), 0);
}
fs.closeSync(read);
return isProgressive;
};
export default isProgressive;