byte-codec 0.0.0 → 1.0.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.
- package/README.md +43 -0
- package/dist/bytes/crc32-BVCBBYa3.d.cts +4 -0
- package/dist/bytes/crc32-BVCBBYa3.d.ts +4 -0
- package/dist/bytes/crc32.cjs +21 -0
- package/dist/bytes/crc32.js +20 -0
- package/dist/bytes/flate-CbSD2OU9.d.cts +12 -0
- package/dist/bytes/flate-CbSD2OU9.d.ts +12 -0
- package/dist/bytes/flate.cjs +53 -0
- package/dist/bytes/flate.js +49 -0
- package/dist/bytes/reader-CDx_NmAQ.d.cts +20 -0
- package/dist/bytes/reader-CDx_NmAQ.d.ts +20 -0
- package/dist/bytes/reader.cjs +60 -0
- package/dist/bytes/reader.js +58 -0
- package/dist/bytes/writer-B9uaqo-B.d.cts +13 -0
- package/dist/bytes/writer-B9uaqo-B.d.ts +13 -0
- package/dist/bytes/writer.cjs +37 -0
- package/dist/bytes/writer.js +35 -0
- package/dist/image/jpeg-info-Dh6D8PRh.d.cts +12 -0
- package/dist/image/jpeg-info-Dh6D8PRh.d.ts +12 -0
- package/dist/image/jpeg-info.cjs +71 -0
- package/dist/image/jpeg-info.js +70 -0
- package/dist/image/png-decode-Dvizumot.d.cts +14 -0
- package/dist/image/png-decode-Dvizumot.d.ts +14 -0
- package/dist/image/png-decode.cjs +181 -0
- package/dist/image/png-decode.js +180 -0
- package/dist/image/png-encode-C5Jj9gBX.d.ts +9 -0
- package/dist/image/png-encode-CpwBOmkg.d.cts +9 -0
- package/dist/image/png-encode.cjs +64 -0
- package/dist/image/png-encode.js +63 -0
- package/dist/image/png-filter-5L1Q0PDF.d.cts +6 -0
- package/dist/image/png-filter-5L1Q0PDF.d.ts +6 -0
- package/dist/image/png-filter.cjs +95 -0
- package/dist/image/png-filter.js +93 -0
- package/dist/index-VKR9nd94.d.ts +9 -0
- package/dist/index-v-4chATX.d.cts +9 -0
- package/dist/index.cjs +23 -0
- package/dist/index.js +9 -0
- package/package.json +67 -2
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# byte-codec
|
|
2
|
+
|
|
3
|
+
[](https://github.com/ExaDev/byte-codec) [](https://www.npmjs.com/package/byte-codec) [](https://github.com/ExaDev/byte-codec/releases/latest)
|
|
4
|
+
|
|
5
|
+
> Generic byte-level primitives (ByteWriter, ByteReader, CRC-32, deflate/inflate) and PNG/JPEG image encoding/decoding with zero PDF knowledge — the shared utility package for the documents.js family.
|
|
6
|
+
|
|
7
|
+
Extracted from [pdf-codec](https://github.com/ExaDev/pdf-codec), where these utilities lived as a directory-isolated subgraph under `src/bytes/` + `src/image/` with no PDF imports. Both pdf-codec and documents.js consume them from this neutral home rather than one fetching byte utilities from a backend.
|
|
8
|
+
|
|
9
|
+
## Getting started
|
|
10
|
+
|
|
11
|
+
Requires Node.js `>=20` and pnpm `11.6.0`.
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
pnpm install
|
|
15
|
+
pnpm build # tsdown -> dist/ (ESM + CJS + .d.ts)
|
|
16
|
+
pnpm test # vitest
|
|
17
|
+
pnpm typecheck # tsc --noEmit
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## What it provides
|
|
21
|
+
|
|
22
|
+
| Module | Exports |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `bytes/writer` | `ByteWriter` (chunked growable byte-output builder), `concatBytes` |
|
|
25
|
+
| `bytes/reader` | `ByteReader` (sequential big/little-endian byte reader), `isAsciiWhitespace` |
|
|
26
|
+
| `bytes/crc32` | `crc32` (IEEE 802.3 / ZIP / PNG polynomial table-driven CRC-32) |
|
|
27
|
+
| `bytes/flate` | `deflate`, `inflate`, `inflateTolerant` (fflate-backed DEFLATE compression/decompression with a safety cap) |
|
|
28
|
+
| `image/png-encode` | `encodePng` (raw RGB/RGBA pixels → PNG bytes) |
|
|
29
|
+
| `image/png-decode` | `decodePng` (PNG bytes → raw pixels), `RawImage` |
|
|
30
|
+
| `image/png-filter` | `filterScanlines`, `unfilterScanlines` (the five PNG scanline filters) |
|
|
31
|
+
| `image/jpeg-info` | `readJpegInfo` (JPEG header reader: dimensions, components, progressive flag — no sample decoding) |
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
pnpm add byte-codec
|
|
37
|
+
# or
|
|
38
|
+
npm install byte-codec
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## License
|
|
42
|
+
|
|
43
|
+
MIT
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/bytes/crc32.ts
|
|
3
|
+
const CRC32_POLYNOMIAL = 3988292384;
|
|
4
|
+
const BYTE_VALUES = 256;
|
|
5
|
+
const BITS_PER_BYTE = 8;
|
|
6
|
+
const CRC32_TABLE = (() => {
|
|
7
|
+
const table = new Uint32Array(BYTE_VALUES);
|
|
8
|
+
for (let n = 0; n < BYTE_VALUES; n++) {
|
|
9
|
+
let c = n;
|
|
10
|
+
for (let k = 0; k < BITS_PER_BYTE; k++) c = (c & 1) === 1 ? CRC32_POLYNOMIAL ^ c >>> 1 : c >>> 1;
|
|
11
|
+
table[n] = c >>> 0;
|
|
12
|
+
}
|
|
13
|
+
return table;
|
|
14
|
+
})();
|
|
15
|
+
function crc32(bytes) {
|
|
16
|
+
let crc = 4294967295;
|
|
17
|
+
for (const byte of bytes) crc = CRC32_TABLE[(crc ^ byte) & 255] ^ crc >>> 8;
|
|
18
|
+
return (crc ^ 4294967295) >>> 0;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
exports.crc32 = crc32;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/bytes/crc32.ts
|
|
2
|
+
const CRC32_POLYNOMIAL = 3988292384;
|
|
3
|
+
const BYTE_VALUES = 256;
|
|
4
|
+
const BITS_PER_BYTE = 8;
|
|
5
|
+
const CRC32_TABLE = (() => {
|
|
6
|
+
const table = new Uint32Array(BYTE_VALUES);
|
|
7
|
+
for (let n = 0; n < BYTE_VALUES; n++) {
|
|
8
|
+
let c = n;
|
|
9
|
+
for (let k = 0; k < BITS_PER_BYTE; k++) c = (c & 1) === 1 ? CRC32_POLYNOMIAL ^ c >>> 1 : c >>> 1;
|
|
10
|
+
table[n] = c >>> 0;
|
|
11
|
+
}
|
|
12
|
+
return table;
|
|
13
|
+
})();
|
|
14
|
+
function crc32(bytes) {
|
|
15
|
+
let crc = 4294967295;
|
|
16
|
+
for (const byte of bytes) crc = CRC32_TABLE[(crc ^ byte) & 255] ^ crc >>> 8;
|
|
17
|
+
return (crc ^ 4294967295) >>> 0;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { crc32 };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/bytes/flate.d.ts
|
|
2
|
+
declare const MAX_INFLATE_OUTPUT_BYTES: number;
|
|
3
|
+
type DeflateLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
|
|
4
|
+
declare function deflate(data: Uint8Array<ArrayBuffer>, level?: DeflateLevel): Uint8Array<ArrayBuffer>;
|
|
5
|
+
declare function inflate(data: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>;
|
|
6
|
+
interface InflateResult {
|
|
7
|
+
readonly bytes: Uint8Array<ArrayBuffer>;
|
|
8
|
+
readonly recovered: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare function inflateTolerant(data: Uint8Array<ArrayBuffer>): InflateResult;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { DeflateLevel, InflateResult, MAX_INFLATE_OUTPUT_BYTES, deflate, inflate, inflateTolerant };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/bytes/flate.d.ts
|
|
2
|
+
declare const MAX_INFLATE_OUTPUT_BYTES: number;
|
|
3
|
+
type DeflateLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
|
|
4
|
+
declare function deflate(data: Uint8Array<ArrayBuffer>, level?: DeflateLevel): Uint8Array<ArrayBuffer>;
|
|
5
|
+
declare function inflate(data: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>;
|
|
6
|
+
interface InflateResult {
|
|
7
|
+
readonly bytes: Uint8Array<ArrayBuffer>;
|
|
8
|
+
readonly recovered: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare function inflateTolerant(data: Uint8Array<ArrayBuffer>): InflateResult;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { DeflateLevel, InflateResult, MAX_INFLATE_OUTPUT_BYTES, deflate, inflate, inflateTolerant };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_bytes_writer = require("./writer.cjs");
|
|
3
|
+
const require_bytes_reader = require("./reader.cjs");
|
|
4
|
+
let fflate = require("fflate");
|
|
5
|
+
//#region src/bytes/flate.ts
|
|
6
|
+
const MAX_INFLATE_OUTPUT_BYTES = 536870912;
|
|
7
|
+
function deflate(data, level) {
|
|
8
|
+
return (0, fflate.zlibSync)(data, level === void 0 ? void 0 : { level });
|
|
9
|
+
}
|
|
10
|
+
function inflate(data) {
|
|
11
|
+
const out = (0, fflate.unzlibSync)(data);
|
|
12
|
+
if (out.length > 536870912) throw new Error(`inflated output exceeds the ${MAX_INFLATE_OUTPUT_BYTES}-byte limit`);
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
15
|
+
function inflateTolerant(data) {
|
|
16
|
+
try {
|
|
17
|
+
return {
|
|
18
|
+
bytes: inflate(data),
|
|
19
|
+
recovered: false
|
|
20
|
+
};
|
|
21
|
+
} catch {}
|
|
22
|
+
let offset = 0;
|
|
23
|
+
while (offset < data.length && require_bytes_reader.isAsciiWhitespace(data[offset])) offset++;
|
|
24
|
+
if (offset > 0) try {
|
|
25
|
+
return {
|
|
26
|
+
bytes: inflate(data.subarray(offset)),
|
|
27
|
+
recovered: true
|
|
28
|
+
};
|
|
29
|
+
} catch {}
|
|
30
|
+
try {
|
|
31
|
+
return {
|
|
32
|
+
bytes: (0, fflate.inflateSync)(data),
|
|
33
|
+
recovered: true
|
|
34
|
+
};
|
|
35
|
+
} catch {}
|
|
36
|
+
const chunks = [];
|
|
37
|
+
const unzlib = new fflate.Unzlib((chunk) => {
|
|
38
|
+
chunks.push(chunk);
|
|
39
|
+
});
|
|
40
|
+
try {
|
|
41
|
+
unzlib.push(data, false);
|
|
42
|
+
} catch {}
|
|
43
|
+
if (chunks.length === 0) throw new Error("unable to inflate stream: no data could be recovered");
|
|
44
|
+
return {
|
|
45
|
+
bytes: require_bytes_writer.concatBytes(chunks),
|
|
46
|
+
recovered: true
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
exports.MAX_INFLATE_OUTPUT_BYTES = MAX_INFLATE_OUTPUT_BYTES;
|
|
51
|
+
exports.deflate = deflate;
|
|
52
|
+
exports.inflate = inflate;
|
|
53
|
+
exports.inflateTolerant = inflateTolerant;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { concatBytes } from "./writer.js";
|
|
2
|
+
import { isAsciiWhitespace } from "./reader.js";
|
|
3
|
+
import { Unzlib, inflateSync, unzlibSync, zlibSync } from "fflate";
|
|
4
|
+
//#region src/bytes/flate.ts
|
|
5
|
+
const MAX_INFLATE_OUTPUT_BYTES = 536870912;
|
|
6
|
+
function deflate(data, level) {
|
|
7
|
+
return zlibSync(data, level === void 0 ? void 0 : { level });
|
|
8
|
+
}
|
|
9
|
+
function inflate(data) {
|
|
10
|
+
const out = unzlibSync(data);
|
|
11
|
+
if (out.length > 536870912) throw new Error(`inflated output exceeds the ${MAX_INFLATE_OUTPUT_BYTES}-byte limit`);
|
|
12
|
+
return out;
|
|
13
|
+
}
|
|
14
|
+
function inflateTolerant(data) {
|
|
15
|
+
try {
|
|
16
|
+
return {
|
|
17
|
+
bytes: inflate(data),
|
|
18
|
+
recovered: false
|
|
19
|
+
};
|
|
20
|
+
} catch {}
|
|
21
|
+
let offset = 0;
|
|
22
|
+
while (offset < data.length && isAsciiWhitespace(data[offset])) offset++;
|
|
23
|
+
if (offset > 0) try {
|
|
24
|
+
return {
|
|
25
|
+
bytes: inflate(data.subarray(offset)),
|
|
26
|
+
recovered: true
|
|
27
|
+
};
|
|
28
|
+
} catch {}
|
|
29
|
+
try {
|
|
30
|
+
return {
|
|
31
|
+
bytes: inflateSync(data),
|
|
32
|
+
recovered: true
|
|
33
|
+
};
|
|
34
|
+
} catch {}
|
|
35
|
+
const chunks = [];
|
|
36
|
+
const unzlib = new Unzlib((chunk) => {
|
|
37
|
+
chunks.push(chunk);
|
|
38
|
+
});
|
|
39
|
+
try {
|
|
40
|
+
unzlib.push(data, false);
|
|
41
|
+
} catch {}
|
|
42
|
+
if (chunks.length === 0) throw new Error("unable to inflate stream: no data could be recovered");
|
|
43
|
+
return {
|
|
44
|
+
bytes: concatBytes(chunks),
|
|
45
|
+
recovered: true
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { MAX_INFLATE_OUTPUT_BYTES, deflate, inflate, inflateTolerant };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/bytes/reader.d.ts
|
|
2
|
+
declare function isAsciiWhitespace(byte: number | undefined): boolean;
|
|
3
|
+
declare class ByteReader {
|
|
4
|
+
private readonly bytes;
|
|
5
|
+
private position;
|
|
6
|
+
constructor(bytes: Uint8Array<ArrayBuffer>);
|
|
7
|
+
get offset(): number;
|
|
8
|
+
get length(): number;
|
|
9
|
+
atEnd(): boolean;
|
|
10
|
+
peek(aheadBy?: number): number | undefined;
|
|
11
|
+
next(): number | undefined;
|
|
12
|
+
mark(): number;
|
|
13
|
+
reset(mark: number): void;
|
|
14
|
+
seek(offset: number): void;
|
|
15
|
+
slice(start: number, end: number): Uint8Array<ArrayBuffer>;
|
|
16
|
+
skipWhitespace(): void;
|
|
17
|
+
matchKeyword(keyword: string): boolean;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { ByteReader, isAsciiWhitespace };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/bytes/reader.d.ts
|
|
2
|
+
declare function isAsciiWhitespace(byte: number | undefined): boolean;
|
|
3
|
+
declare class ByteReader {
|
|
4
|
+
private readonly bytes;
|
|
5
|
+
private position;
|
|
6
|
+
constructor(bytes: Uint8Array<ArrayBuffer>);
|
|
7
|
+
get offset(): number;
|
|
8
|
+
get length(): number;
|
|
9
|
+
atEnd(): boolean;
|
|
10
|
+
peek(aheadBy?: number): number | undefined;
|
|
11
|
+
next(): number | undefined;
|
|
12
|
+
mark(): number;
|
|
13
|
+
reset(mark: number): void;
|
|
14
|
+
seek(offset: number): void;
|
|
15
|
+
slice(start: number, end: number): Uint8Array<ArrayBuffer>;
|
|
16
|
+
skipWhitespace(): void;
|
|
17
|
+
matchKeyword(keyword: string): boolean;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { ByteReader, isAsciiWhitespace };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/bytes/reader.ts
|
|
3
|
+
const ASCII_WHITESPACE_BYTES = /* @__PURE__ */ new Set([
|
|
4
|
+
0,
|
|
5
|
+
9,
|
|
6
|
+
10,
|
|
7
|
+
12,
|
|
8
|
+
13,
|
|
9
|
+
32
|
|
10
|
+
]);
|
|
11
|
+
function isAsciiWhitespace(byte) {
|
|
12
|
+
return byte !== void 0 && ASCII_WHITESPACE_BYTES.has(byte);
|
|
13
|
+
}
|
|
14
|
+
var ByteReader = class {
|
|
15
|
+
bytes;
|
|
16
|
+
position = 0;
|
|
17
|
+
constructor(bytes) {
|
|
18
|
+
this.bytes = bytes;
|
|
19
|
+
}
|
|
20
|
+
get offset() {
|
|
21
|
+
return this.position;
|
|
22
|
+
}
|
|
23
|
+
get length() {
|
|
24
|
+
return this.bytes.length;
|
|
25
|
+
}
|
|
26
|
+
atEnd() {
|
|
27
|
+
return this.position >= this.bytes.length;
|
|
28
|
+
}
|
|
29
|
+
peek(aheadBy = 0) {
|
|
30
|
+
return this.bytes[this.position + aheadBy];
|
|
31
|
+
}
|
|
32
|
+
next() {
|
|
33
|
+
const byte = this.bytes[this.position];
|
|
34
|
+
if (byte !== void 0) this.position++;
|
|
35
|
+
return byte;
|
|
36
|
+
}
|
|
37
|
+
mark() {
|
|
38
|
+
return this.position;
|
|
39
|
+
}
|
|
40
|
+
reset(mark) {
|
|
41
|
+
this.position = mark;
|
|
42
|
+
}
|
|
43
|
+
seek(offset) {
|
|
44
|
+
this.position = offset;
|
|
45
|
+
}
|
|
46
|
+
slice(start, end) {
|
|
47
|
+
return this.bytes.subarray(start, end);
|
|
48
|
+
}
|
|
49
|
+
skipWhitespace() {
|
|
50
|
+
while (isAsciiWhitespace(this.peek())) this.position++;
|
|
51
|
+
}
|
|
52
|
+
matchKeyword(keyword) {
|
|
53
|
+
for (let i = 0; i < keyword.length; i++) if (this.peek(i) !== keyword.charCodeAt(i)) return false;
|
|
54
|
+
this.position += keyword.length;
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
//#endregion
|
|
59
|
+
exports.ByteReader = ByteReader;
|
|
60
|
+
exports.isAsciiWhitespace = isAsciiWhitespace;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//#region src/bytes/reader.ts
|
|
2
|
+
const ASCII_WHITESPACE_BYTES = /* @__PURE__ */ new Set([
|
|
3
|
+
0,
|
|
4
|
+
9,
|
|
5
|
+
10,
|
|
6
|
+
12,
|
|
7
|
+
13,
|
|
8
|
+
32
|
|
9
|
+
]);
|
|
10
|
+
function isAsciiWhitespace(byte) {
|
|
11
|
+
return byte !== void 0 && ASCII_WHITESPACE_BYTES.has(byte);
|
|
12
|
+
}
|
|
13
|
+
var ByteReader = class {
|
|
14
|
+
bytes;
|
|
15
|
+
position = 0;
|
|
16
|
+
constructor(bytes) {
|
|
17
|
+
this.bytes = bytes;
|
|
18
|
+
}
|
|
19
|
+
get offset() {
|
|
20
|
+
return this.position;
|
|
21
|
+
}
|
|
22
|
+
get length() {
|
|
23
|
+
return this.bytes.length;
|
|
24
|
+
}
|
|
25
|
+
atEnd() {
|
|
26
|
+
return this.position >= this.bytes.length;
|
|
27
|
+
}
|
|
28
|
+
peek(aheadBy = 0) {
|
|
29
|
+
return this.bytes[this.position + aheadBy];
|
|
30
|
+
}
|
|
31
|
+
next() {
|
|
32
|
+
const byte = this.bytes[this.position];
|
|
33
|
+
if (byte !== void 0) this.position++;
|
|
34
|
+
return byte;
|
|
35
|
+
}
|
|
36
|
+
mark() {
|
|
37
|
+
return this.position;
|
|
38
|
+
}
|
|
39
|
+
reset(mark) {
|
|
40
|
+
this.position = mark;
|
|
41
|
+
}
|
|
42
|
+
seek(offset) {
|
|
43
|
+
this.position = offset;
|
|
44
|
+
}
|
|
45
|
+
slice(start, end) {
|
|
46
|
+
return this.bytes.subarray(start, end);
|
|
47
|
+
}
|
|
48
|
+
skipWhitespace() {
|
|
49
|
+
while (isAsciiWhitespace(this.peek())) this.position++;
|
|
50
|
+
}
|
|
51
|
+
matchKeyword(keyword) {
|
|
52
|
+
for (let i = 0; i < keyword.length; i++) if (this.peek(i) !== keyword.charCodeAt(i)) return false;
|
|
53
|
+
this.position += keyword.length;
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
//#endregion
|
|
58
|
+
export { ByteReader, isAsciiWhitespace };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/bytes/writer.d.ts
|
|
2
|
+
declare class ByteWriter {
|
|
3
|
+
private readonly chunks;
|
|
4
|
+
private byteLength;
|
|
5
|
+
get length(): number;
|
|
6
|
+
writeBytes(bytes: Uint8Array<ArrayBuffer>): void;
|
|
7
|
+
writeByte(byte: number): void;
|
|
8
|
+
writeAscii(text: string): void;
|
|
9
|
+
toBytes(): Uint8Array<ArrayBuffer>;
|
|
10
|
+
}
|
|
11
|
+
declare function concatBytes(chunks: readonly Uint8Array<ArrayBuffer>[]): Uint8Array<ArrayBuffer>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { ByteWriter, concatBytes };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/bytes/writer.d.ts
|
|
2
|
+
declare class ByteWriter {
|
|
3
|
+
private readonly chunks;
|
|
4
|
+
private byteLength;
|
|
5
|
+
get length(): number;
|
|
6
|
+
writeBytes(bytes: Uint8Array<ArrayBuffer>): void;
|
|
7
|
+
writeByte(byte: number): void;
|
|
8
|
+
writeAscii(text: string): void;
|
|
9
|
+
toBytes(): Uint8Array<ArrayBuffer>;
|
|
10
|
+
}
|
|
11
|
+
declare function concatBytes(chunks: readonly Uint8Array<ArrayBuffer>[]): Uint8Array<ArrayBuffer>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { ByteWriter, concatBytes };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/bytes/writer.ts
|
|
3
|
+
var ByteWriter = class {
|
|
4
|
+
chunks = [];
|
|
5
|
+
byteLength = 0;
|
|
6
|
+
get length() {
|
|
7
|
+
return this.byteLength;
|
|
8
|
+
}
|
|
9
|
+
writeBytes(bytes) {
|
|
10
|
+
if (bytes.length === 0) return;
|
|
11
|
+
this.chunks.push(bytes);
|
|
12
|
+
this.byteLength += bytes.length;
|
|
13
|
+
}
|
|
14
|
+
writeByte(byte) {
|
|
15
|
+
this.writeBytes(new Uint8Array([byte]));
|
|
16
|
+
}
|
|
17
|
+
writeAscii(text) {
|
|
18
|
+
this.writeBytes(new TextEncoder().encode(text));
|
|
19
|
+
}
|
|
20
|
+
toBytes() {
|
|
21
|
+
const out = new Uint8Array(this.byteLength);
|
|
22
|
+
let offset = 0;
|
|
23
|
+
for (const chunk of this.chunks) {
|
|
24
|
+
out.set(chunk, offset);
|
|
25
|
+
offset += chunk.length;
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
function concatBytes(chunks) {
|
|
31
|
+
const writer = new ByteWriter();
|
|
32
|
+
for (const chunk of chunks) writer.writeBytes(chunk);
|
|
33
|
+
return writer.toBytes();
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
exports.ByteWriter = ByteWriter;
|
|
37
|
+
exports.concatBytes = concatBytes;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/bytes/writer.ts
|
|
2
|
+
var ByteWriter = class {
|
|
3
|
+
chunks = [];
|
|
4
|
+
byteLength = 0;
|
|
5
|
+
get length() {
|
|
6
|
+
return this.byteLength;
|
|
7
|
+
}
|
|
8
|
+
writeBytes(bytes) {
|
|
9
|
+
if (bytes.length === 0) return;
|
|
10
|
+
this.chunks.push(bytes);
|
|
11
|
+
this.byteLength += bytes.length;
|
|
12
|
+
}
|
|
13
|
+
writeByte(byte) {
|
|
14
|
+
this.writeBytes(new Uint8Array([byte]));
|
|
15
|
+
}
|
|
16
|
+
writeAscii(text) {
|
|
17
|
+
this.writeBytes(new TextEncoder().encode(text));
|
|
18
|
+
}
|
|
19
|
+
toBytes() {
|
|
20
|
+
const out = new Uint8Array(this.byteLength);
|
|
21
|
+
let offset = 0;
|
|
22
|
+
for (const chunk of this.chunks) {
|
|
23
|
+
out.set(chunk, offset);
|
|
24
|
+
offset += chunk.length;
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
function concatBytes(chunks) {
|
|
30
|
+
const writer = new ByteWriter();
|
|
31
|
+
for (const chunk of chunks) writer.writeBytes(chunk);
|
|
32
|
+
return writer.toBytes();
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { ByteWriter, concatBytes };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/image/jpeg-info.d.ts
|
|
2
|
+
interface JpegInfo {
|
|
3
|
+
readonly width: number;
|
|
4
|
+
readonly height: number;
|
|
5
|
+
readonly components: number;
|
|
6
|
+
readonly precision: number;
|
|
7
|
+
readonly progressive: boolean;
|
|
8
|
+
readonly adobeTransform: number | undefined;
|
|
9
|
+
}
|
|
10
|
+
declare function readJpegInfo(bytes: Uint8Array<ArrayBuffer>): JpegInfo;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { JpegInfo, readJpegInfo };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/image/jpeg-info.d.ts
|
|
2
|
+
interface JpegInfo {
|
|
3
|
+
readonly width: number;
|
|
4
|
+
readonly height: number;
|
|
5
|
+
readonly components: number;
|
|
6
|
+
readonly precision: number;
|
|
7
|
+
readonly progressive: boolean;
|
|
8
|
+
readonly adobeTransform: number | undefined;
|
|
9
|
+
}
|
|
10
|
+
declare function readJpegInfo(bytes: Uint8Array<ArrayBuffer>): JpegInfo;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { JpegInfo, readJpegInfo };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/image/jpeg-info.ts
|
|
3
|
+
const SOI = 216;
|
|
4
|
+
const EOI = 217;
|
|
5
|
+
const APP14 = 238;
|
|
6
|
+
const SOF_MARKERS = /* @__PURE__ */ new Set([
|
|
7
|
+
192,
|
|
8
|
+
193,
|
|
9
|
+
194,
|
|
10
|
+
201,
|
|
11
|
+
202
|
|
12
|
+
]);
|
|
13
|
+
const PROGRESSIVE_SOF_MARKERS = /* @__PURE__ */ new Set([194, 202]);
|
|
14
|
+
const NO_PAYLOAD_MARKERS = /* @__PURE__ */ new Set([
|
|
15
|
+
1,
|
|
16
|
+
216,
|
|
17
|
+
217,
|
|
18
|
+
208,
|
|
19
|
+
209,
|
|
20
|
+
210,
|
|
21
|
+
211,
|
|
22
|
+
212,
|
|
23
|
+
213,
|
|
24
|
+
214,
|
|
25
|
+
215
|
|
26
|
+
]);
|
|
27
|
+
function requireByte(bytes, index) {
|
|
28
|
+
const value = bytes[index];
|
|
29
|
+
if (value === void 0) throw new Error("unexpected end of JPEG data");
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
function readUint16BE(bytes, offset) {
|
|
33
|
+
return requireByte(bytes, offset) << 8 | requireByte(bytes, offset + 1);
|
|
34
|
+
}
|
|
35
|
+
function readJpegInfo(bytes) {
|
|
36
|
+
if (requireByte(bytes, 0) !== 255 || requireByte(bytes, 1) !== SOI) throw new Error("not a valid JPEG file: missing SOI marker");
|
|
37
|
+
let offset = 2;
|
|
38
|
+
let adobeTransform;
|
|
39
|
+
while (offset < bytes.length) {
|
|
40
|
+
if (bytes[offset] !== 255) {
|
|
41
|
+
offset++;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
let markerOffset = offset + 1;
|
|
45
|
+
while (bytes[markerOffset] === 255) markerOffset++;
|
|
46
|
+
const marker = bytes[markerOffset];
|
|
47
|
+
if (marker === void 0) break;
|
|
48
|
+
offset = markerOffset + 1;
|
|
49
|
+
if (marker === EOI) break;
|
|
50
|
+
if (NO_PAYLOAD_MARKERS.has(marker)) continue;
|
|
51
|
+
const segmentLength = readUint16BE(bytes, offset);
|
|
52
|
+
if (marker === APP14 && segmentLength >= 14) adobeTransform = requireByte(bytes, offset + 2 + 11);
|
|
53
|
+
if (SOF_MARKERS.has(marker)) {
|
|
54
|
+
const p = offset + 2;
|
|
55
|
+
const precision = requireByte(bytes, p);
|
|
56
|
+
const height = readUint16BE(bytes, p + 1);
|
|
57
|
+
return {
|
|
58
|
+
width: readUint16BE(bytes, p + 3),
|
|
59
|
+
height,
|
|
60
|
+
components: requireByte(bytes, p + 5),
|
|
61
|
+
precision,
|
|
62
|
+
progressive: PROGRESSIVE_SOF_MARKERS.has(marker),
|
|
63
|
+
adobeTransform
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
offset += segmentLength;
|
|
67
|
+
}
|
|
68
|
+
throw new Error("no SOF marker found in JPEG file");
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
exports.readJpegInfo = readJpegInfo;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
//#region src/image/jpeg-info.ts
|
|
2
|
+
const SOI = 216;
|
|
3
|
+
const EOI = 217;
|
|
4
|
+
const APP14 = 238;
|
|
5
|
+
const SOF_MARKERS = /* @__PURE__ */ new Set([
|
|
6
|
+
192,
|
|
7
|
+
193,
|
|
8
|
+
194,
|
|
9
|
+
201,
|
|
10
|
+
202
|
|
11
|
+
]);
|
|
12
|
+
const PROGRESSIVE_SOF_MARKERS = /* @__PURE__ */ new Set([194, 202]);
|
|
13
|
+
const NO_PAYLOAD_MARKERS = /* @__PURE__ */ new Set([
|
|
14
|
+
1,
|
|
15
|
+
216,
|
|
16
|
+
217,
|
|
17
|
+
208,
|
|
18
|
+
209,
|
|
19
|
+
210,
|
|
20
|
+
211,
|
|
21
|
+
212,
|
|
22
|
+
213,
|
|
23
|
+
214,
|
|
24
|
+
215
|
|
25
|
+
]);
|
|
26
|
+
function requireByte(bytes, index) {
|
|
27
|
+
const value = bytes[index];
|
|
28
|
+
if (value === void 0) throw new Error("unexpected end of JPEG data");
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
function readUint16BE(bytes, offset) {
|
|
32
|
+
return requireByte(bytes, offset) << 8 | requireByte(bytes, offset + 1);
|
|
33
|
+
}
|
|
34
|
+
function readJpegInfo(bytes) {
|
|
35
|
+
if (requireByte(bytes, 0) !== 255 || requireByte(bytes, 1) !== SOI) throw new Error("not a valid JPEG file: missing SOI marker");
|
|
36
|
+
let offset = 2;
|
|
37
|
+
let adobeTransform;
|
|
38
|
+
while (offset < bytes.length) {
|
|
39
|
+
if (bytes[offset] !== 255) {
|
|
40
|
+
offset++;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
let markerOffset = offset + 1;
|
|
44
|
+
while (bytes[markerOffset] === 255) markerOffset++;
|
|
45
|
+
const marker = bytes[markerOffset];
|
|
46
|
+
if (marker === void 0) break;
|
|
47
|
+
offset = markerOffset + 1;
|
|
48
|
+
if (marker === EOI) break;
|
|
49
|
+
if (NO_PAYLOAD_MARKERS.has(marker)) continue;
|
|
50
|
+
const segmentLength = readUint16BE(bytes, offset);
|
|
51
|
+
if (marker === APP14 && segmentLength >= 14) adobeTransform = requireByte(bytes, offset + 2 + 11);
|
|
52
|
+
if (SOF_MARKERS.has(marker)) {
|
|
53
|
+
const p = offset + 2;
|
|
54
|
+
const precision = requireByte(bytes, p);
|
|
55
|
+
const height = readUint16BE(bytes, p + 1);
|
|
56
|
+
return {
|
|
57
|
+
width: readUint16BE(bytes, p + 3),
|
|
58
|
+
height,
|
|
59
|
+
components: requireByte(bytes, p + 5),
|
|
60
|
+
precision,
|
|
61
|
+
progressive: PROGRESSIVE_SOF_MARKERS.has(marker),
|
|
62
|
+
adobeTransform
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
offset += segmentLength;
|
|
66
|
+
}
|
|
67
|
+
throw new Error("no SOF marker found in JPEG file");
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { readJpegInfo };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/image/png-decode.d.ts
|
|
2
|
+
interface RawImage {
|
|
3
|
+
readonly width: number;
|
|
4
|
+
readonly height: number;
|
|
5
|
+
readonly channels: 1 | 3;
|
|
6
|
+
readonly data: Uint8Array<ArrayBuffer>;
|
|
7
|
+
readonly alpha?: Uint8Array<ArrayBuffer>;
|
|
8
|
+
}
|
|
9
|
+
interface PngDecodeOptions {
|
|
10
|
+
readonly onWarning?: (message: string) => void;
|
|
11
|
+
}
|
|
12
|
+
declare function decodePng(bytes: Uint8Array<ArrayBuffer>, options?: PngDecodeOptions): RawImage;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { PngDecodeOptions, RawImage, decodePng };
|