compress-pdf-lib 1.0.3 → 1.0.4
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/package.json +1 -1
- package/src/compress.js +42 -20
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compress-pdf-lib",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Client-side PDF compression: pdf.js render + mozjpeg (WASM) encoding via a parallel worker pool + pdf-lib rebuild. No server, no UI. Ships as raw ESM source for Vite-based apps (React + Vite, Astro).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/compress.js
CHANGED
|
@@ -276,8 +276,8 @@ function jpegResultToBytes(item) {
|
|
|
276
276
|
* ---- PDF filter name plumbing --------------------------------------------
|
|
277
277
|
*/
|
|
278
278
|
|
|
279
|
-
function filterNamesOf(dict) {
|
|
280
|
-
const filter = dict.get(PDFName.of("Filter"));
|
|
279
|
+
function filterNamesOf(context, dict) {
|
|
280
|
+
const filter = context.lookup(dict.get(PDFName.of("Filter")));
|
|
281
281
|
|
|
282
282
|
if (!filter) return [];
|
|
283
283
|
|
|
@@ -286,19 +286,15 @@ function filterNamesOf(dict) {
|
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
if (filter instanceof PDFArray) {
|
|
289
|
-
return filter.asArray().map((f) =>
|
|
289
|
+
return filter.asArray().map((f) => {
|
|
290
|
+
const resolved = context.lookup(f);
|
|
291
|
+
return resolved instanceof PDFName ? resolved.asString().replace(/^\//, "") : "";
|
|
292
|
+
}).filter(Boolean);
|
|
290
293
|
}
|
|
291
294
|
|
|
292
295
|
return [];
|
|
293
296
|
}
|
|
294
297
|
|
|
295
|
-
const IMAGE_CODEC_FILTERS = new Set([
|
|
296
|
-
"DCTDecode",
|
|
297
|
-
"JPXDecode",
|
|
298
|
-
"CCITTFaxDecode",
|
|
299
|
-
"JBIG2Decode",
|
|
300
|
-
]);
|
|
301
|
-
|
|
302
298
|
/*
|
|
303
299
|
* ---- ColorSpace resolution --------------------------------------------
|
|
304
300
|
* Returns { kind, components, palette?, paletteComponents? }
|
|
@@ -518,11 +514,12 @@ async function decodeImageXObject(context, ref) {
|
|
|
518
514
|
// values — recompressing would break it, so skip these entirely.
|
|
519
515
|
if (dict.get(PDFName.of("Mask"))) return null;
|
|
520
516
|
|
|
521
|
-
const filterNames = filterNamesOf(dict);
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
517
|
+
const filterNames = filterNamesOf(context, dict);
|
|
518
|
+
|
|
519
|
+
// Skip explicitly unhandled compression formats natively
|
|
520
|
+
const unsupported = filterNames.find(f => f === "JPXDecode" || f === "CCITTFaxDecode" || f === "JBIG2Decode");
|
|
521
|
+
if (unsupported) {
|
|
522
|
+
return { unsupported: true, reason: unsupported };
|
|
526
523
|
}
|
|
527
524
|
|
|
528
525
|
const width = dict.get(PDFName.of("Width"))?.asNumber?.();
|
|
@@ -535,10 +532,35 @@ async function decodeImageXObject(context, ref) {
|
|
|
535
532
|
let bitmap;
|
|
536
533
|
let hasAlpha = false;
|
|
537
534
|
|
|
538
|
-
if (
|
|
539
|
-
//
|
|
540
|
-
//
|
|
541
|
-
|
|
535
|
+
if (filterNames.includes("DCTDecode")) {
|
|
536
|
+
// pdf-lib's decodePDFRawStream throws on DCTDecode because it natively lacks a
|
|
537
|
+
// mechanism to decode JPEGs to raw samples. We must extract the bytes dynamically
|
|
538
|
+
// whilst bypassing the "DCTDecode" step inside its pipeline filter.
|
|
539
|
+
let jpegBytes;
|
|
540
|
+
const originalFilterVal = dict.get(PDFName.of("Filter"));
|
|
541
|
+
const filterObj = context.lookup(originalFilterVal);
|
|
542
|
+
|
|
543
|
+
if (filterNames.length > 1 && filterObj instanceof PDFArray) {
|
|
544
|
+
const filtered = filterObj.asArray().filter((f) => {
|
|
545
|
+
const resolved = context.lookup(f);
|
|
546
|
+
return resolved instanceof PDFName && resolved.asString() !== "/DCTDecode";
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
if (filtered.length === 0) {
|
|
550
|
+
jpegBytes = stream.contents;
|
|
551
|
+
} else {
|
|
552
|
+
dict.set(PDFName.of("Filter"), context.obj(filtered));
|
|
553
|
+
try {
|
|
554
|
+
jpegBytes = decodePDFRawStream(stream).decode();
|
|
555
|
+
} finally {
|
|
556
|
+
dict.set(PDFName.of("Filter"), originalFilterVal);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
} else {
|
|
560
|
+
// It's just a raw DCTDecode stream (most common).
|
|
561
|
+
jpegBytes = stream.contents;
|
|
562
|
+
}
|
|
563
|
+
|
|
542
564
|
const blob = new Blob([jpegBytes], { type: "image/jpeg" });
|
|
543
565
|
bitmap = await createImageBitmap(blob);
|
|
544
566
|
} else {
|
|
@@ -1217,4 +1239,4 @@ export async function rasterizePDF(input, options = {}) {
|
|
|
1217
1239
|
|
|
1218
1240
|
pool.destroy();
|
|
1219
1241
|
}
|
|
1220
|
-
}
|
|
1242
|
+
}
|