PageSourceSearch

https://catenapdf.vercel.app/workers/compress.worker.js

js catenapdf.vercel.app collected 2026-10-03 06:23:01 UTC 4,006 bytes, 132 lines download raw bytes

1/**
2 * Compress PDF Worker
3 * Uses coherentpdf for advanced PDF compression
4 */
5
6self.importScripts('../coherentpdf.browser.min.js');
7
8/**
9 * Compress PDF with coherentpdf
10 * @param {ArrayBuffer} pdfData - PDF file data
11 * @param {Object} options - Compression options
12 * @param {string} options.quality - Compression quality: 'low', 'medium', 'high', 'maximum'
13 * @param {boolean} options.removeMetadata - Whether to remove metadata
14 */
15function compressPdfInWorker(pdfData, options) {
16  try {
17    const uint8Array = new Uint8Array(pdfData);
18    let pdf;
19    
20    try {
21      pdf = coherentpdf.fromMemory(uint8Array, '');
22    } catch (error) {
23      if (error.message && error.message.includes('encrypt')) {
24        self.postMessage({
25          status: 'error',
26          message: 'The PDF file is encrypted. Please decrypt it first.',
27        });
28        return;
29      }
30      throw error;
31    }
32
33    self.postMessage({ status: 'progress', progress: 20 });
34
35    // Remove metadata if requested
36    if (options.removeMetadata) {
37      try {
38        coherentpdf.setTitle(pdf, '');
39        coherentpdf.setAuthor(pdf, '');
40        coherentpdf.setSubject(pdf, '');
41        coherentpdf.setKeywords(pdf, '');
42        coherentpdf.setCreator(pdf, '');
43        coherentpdf.setProducer(pdf, '');
44      } catch (e) {
45        // Ignore metadata errors
46      }
47    }
48
49    self.postMessage({ status: 'progress', progress: 40 });
50
51    // Apply compression based on quality level
52    // For all quality levels except 'maximum', we apply compression
53    if (options.quality !== 'maximum') {
54      // Compress all uncompressed streams using Flate
55      coherentpdf.compress(pdf);
56    }
57
58    self.postMessage({ status: 'progress', progress: 60 });
59
60    // Squeeze/optimize the PDF structure for better compression
61    // This removes duplicate objects, optimizes cross-references, etc.
62    if (options.quality === 'low' || options.quality === 'medium') {
63      coherentpdf.squeezeInMemory(pdf);
64    }
65
66    self.postMessage({ status: 'progress', progress: 80 });
67
68    // Output with object stream settings based on quality
69    let outputBytes;
70    
71    if (options.quality === 'low') {
72      // Maximum compression: generate and compress object streams
73      outputBytes = coherentpdf.toMemoryExt(
74        pdf,
75        false, // linearize
76        false, // make_id
77        false, // preserve_objstm
78        true,  // generate_objstm - create new object streams
79        true   // compress_objstm - compress object streams
80      );
81    } else if (options.quality === 'medium') {
82      // Balanced: generate object streams with compression
83      outputBytes = coherentpdf.toMemoryExt(
84        pdf,
85        false, // linearize
86        false, // make_id
87        true,  // preserve_objstm
88        true,  // generate_objstm
89        true   // compress_objstm
90      );
91    } else if (options.quality === 'high') {
92      // Less compression: preserve existing, compress new
93      outputBytes = coherentpdf.toMemoryExt(
94        pdf,
95        false, // linearize
96        false, // make_id
97        true,  // preserve_objstm
98        false, // generate_objstm
99        true   // compress_objstm
100      );
101    } else {
102      // Maximum quality (minimal compression): just output normally
103      outputBytes = coherentpdf.toMemory(pdf, false, false);
104    }
105
106    // Note: pdf is invalid after toMemoryExt, no need to delete
107
108    self.postMessage({ status: 'progress', progress: 100 });
109
110    const outputBuffer = outputBytes.buffer;
111    self.postMessage(
112      {
113        status: 'success',
114        pdfBytes: outputBuffer,
115        originalSize: pdfData.byteLength,
116        compressedSize: outputBytes.length,
117      },
118      [outputBuffer]
119    );
120  } catch (error) {
121    self.postMessage({
122      status: 'error',
123      message: error instanceof Error ? error.message : 'Unknown error during compression.',
124    });
125  }
126}
127
128self.onmessage = (e) => {
129  if (e.data.command === 'compress') {
130    compressPdfInWorker(e.data.pdfData, e.data.options);
131  }
132};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.