Get 1000000 0FP0EXP Token to remove widget entirely!



source code
old source code

get any 0FP0EXP Token to automatically turn off or 100000 0FP0EXP Token to remove this JavaScript Mining.

Get 500000 0FP0EXP Token to remove my NFTS advertisements!

Get 400000 0FP0EXP Token to remove this donation notification!

get 300000 0FP0EXP Token to remove this paypal donation.

View My Stats

Need referral links?

get 200000 0FP0EXP Token to remove my personal ADS.

word number: 4454

Time: 2026-04-13 07:48:43 +0800

User: You said

Is it possible to build pdf compressor in html css js? What other features can we build that is as simple? How far current web technology can manipulate pdf or other documents?


Gemini: Yes, it is absolutely possible to build a PDF compressor using only HTML, CSS, and JavaScript. In fact, many modern “free online PDF tool” websites have moved to this model because it saves them money on server costs by forcing your browser to do the work.

  1. How to Build a Client-Side PDF Compressor

There are two main ways to achieve compression in the browser, each with trade-offs.

Approach A: The “Re-encoding” Method (High Compression, Lossy)

This acts like a scanner. You take the PDF, convert its pages into images, resize/compress those images (e.g., to JPEG 70% quality), and repackage them into a new PDF.

Pros: Massive file size reduction (good for scanned docs).

Cons: You lose “selectable” text (it becomes a flat image) unless you add OCR.

Tech Stack: pdf.js (to render PDF to canvas) + jsPDF (to save canvas back to PDF).

Approach B: The “Structural” Method (Low Compression, Lossless)

This cleans up the file code. It removes unused fonts, deletes hidden objects, and optimizes the internal reference table.

Pros: Keeps text selectable; quality remains perfect.

Cons: Only reduces size by 10–20% usually.

Tech Stack: pdf-lib (pure JavaScript library for modifying PDF structures).

  1. Other Simple Features You Can Build

Since the browser can now treat files as “Binary Blobs,” you can build an entire suite of tools that are often easier than compression.

Feature Difficulty Logic PDF Merger Very Easy Take two ArrayBuffers, loop through pages of Doc B, copy them to Doc A using pdf-lib. PDF Splitter Easy Load a PDF, create a new empty PDF, copy only pages 1–5 to it, and save. Image to PDF Very Easy Load a JPG/PNG into an HTML Canvas, then use jsPDF to wrap it in a PDF container. Watermark Easy Draw a semi-transparent text string or image at (x, y) coordinates on every page loop. Page Deleter Very Easy Load PDF, remove the object reference for “Page 4”, save the file. Secure/Protect Medium Use pdf-lib to rewrite the file header with standard 128-bit AES encryption and a password. Export to Sheets

  1. How Far Can Current Web Technology Go?

We are currently in the “WebAssembly (Wasm)” era, which has pushed the limits significantly.

The “Bleeding Edge” Capabilities:

Running C++ in the Browser: Developers are compiling heavy desktop libraries (like Ghostscript or QPDF) into WebAssembly. This allows the browser to perform “Server-Grade” compression (reducing image size while keeping text selectable) without ever sending the file to a backend.

OCR in the Browser: Libraries like Tesseract.js can read text from images client-side.

Microsoft Office Conversion: You can now convert .docx to PDF entirely in the browser using Wasm ports of libraries like LibreOffice, though these files are large (megabytes) to download initially.

The Hard Limits (Bottlenecks):

Memory (RAM): This is the biggest wall. A browser tab usually crashes if it tries to use more than 2GB–4GB of RAM. If a user tries to process a 500MB high-res architectural blueprint, the browser will likely crash where a native app would succeed.

Main Thread Blocking: JavaScript is single-threaded. If you try to compress a PDF on the main thread, the UI will freeze completely. You must use Web Workers to offload the math to a background thread.

File System Access: Browsers cannot “Edit” a file on your desktop directly for security reasons. You always have to “Load” the file and then “Download” the result as a new file (creating duplicates).

Recommendation for Starting

If you want to build this:

Start with pdf-lib (npm package). It is the most powerful pure-JS library for manipulation (Merge, Split, Watermark).

For compression, use pdf-lib to extract images, draw them to a standard HTML Canvas to resize them, and put them back.

Would you like a simple code snippet showing how to combine two PDFs using pdf-lib?


User: You said

Yes please but pdf compression is first priority, then other simple features.


Gemini: Here is the implementation strategy. I have separated this into your two requests: Compression (using the “Resample” method) and Merging (the simplest structural feature).

Part 1: The PDF Compressor

Since browsers cannot easily “re-distill” a PDF like Adobe Acrobat does, the standard web approach is the “Resample Method.”

How it works:

Read the PDF.

Render each page onto an HTML (effectively taking a picture of it).

Export that canvas as a JPEG with low quality (e.g., 0.5).

Generate a brand new PDF with these compressed images.

The Trade-off: You get massive file size reduction, but the text becomes “flattened” (not selectable), similar to a scanned document.

The Code: You will need two libraries: pdf.js (by Mozilla) to read the file, and jsPDF to build the new one.

HTML

Part 2: The PDF Merger (Simpler Feature)

Merging is much cleaner code because we don’t need to render images. We just shuffle data around. We use pdf-lib for this.

How it works: It loads two existing PDFs, copies the pages from the second one, and pastes them into the first one.

HTML

Key Differences in Difficulty

Compression is computationally heavy. If the user uploads a 50-page PDF, the browser might freeze while rendering those 50 canvases. In a real app, you must use a Web Worker to run that loop in the background so the UI doesn’t crash.

Merging is lightweight. It happens almost instantly because it’s just copying bytes, not processing pixels.

Summary of Libraries

pdf.js: Best for reading PDFs and converting them to images (viewers, compressors).

jsPDF: Best for creating simple PDFs from scratch (generating invoices, reports).

pdf-lib: Best for modifying existing PDFs (merging, splitting, rotating, watermarking).

Would you like me to show you how to move that heavy compression logic into a Web Worker so the browser doesn’t freeze?


User: You said

First I would like to split the pages for the features and below the interface for merge pdf is missing:


<html>

<head>

<title>PDF Merge Tools</title>

<script src="../lib/pdf-3.11.174.js"></script>

<script src="../lib/jspdf-4.0.0.umd.js"></script>

<script src="../lib/pdf-lib-1.17.1.js"></script>

</head>

<body>




<script>

async function mergePDFs(file1, file2) {

const { PDFDocument } = PDFLib;




// 1. Load both documents

const pdf1Bytes = await file1.arrayBuffer();

const pdf2Bytes = await file2.arrayBuffer();




const pdf1 = await PDFDocument.load(pdf1Bytes);

const pdf2 = await PDFDocument.load(pdf2Bytes);




// 2. Copy all pages from PDF 2

const copiedPages = await pdf1.copyPages(pdf2, pdf2.getPageIndices());




// 3. Add them to PDF 1

copiedPages.forEach((page) => pdf1.addPage(page));




// 4. Save

const mergedPdfBytes = await pdf1.save();

// (Helper function to trigger download would go here)

downloadBlob(mergedPdfBytes, "merged.pdf");

}

</script>

</body>

</html>

Second you probably notice above I am planning to use the following libraries:

pdf-3.11.174.js: https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.js

jspdf-4.0.0.umd.js: https://unpkg.com/jspdf@4.0.0/dist/jspdf.umd.js

pdf-lib-1.17.1.js: https://unpkg.com/pdf-lib@1.17.1/dist/pdf-lib.js


Gemini: This is a great approach. Splitting the tools into separate HTML pages (e.g., merge.html, compress.html) keeps the logic clean and prevents memory leaks from unused libraries.

Here is the complete merge.html file.

I have updated the code to support selecting multiple files at once (instead of just two), which is standard for merging tools. I also added the missing downloadBlob helper function so the file actually saves to the user’s computer.

merge.html HTML <!DOCTYPE html>

PDF Merger

Merge PDF Files

Select multiple PDFs to combine them into one file.

No files selected.

Key Changes I Made for You:

Multiple File Support: Changed the input logic to accept an array of files (files[…]). The loop now iterates through every file you select and appends them sequentially.

PDFDocument.create(): Instead of loading File 1 and adding File 2 to it, I created a fresh, empty PDF. This is safer because it prevents any metadata or corruption from the first file affecting the whole document.

The downloadBlob function: This handles the browser-specific logic of turning a binary array into a clickable download link.

Note on Libraries

You listed jspdf-4.0.0.umd.js. Just a heads up—Standard jspdf is currently at version 2.5.1. If 4.0.0 is a specific fork or a beta version you have, that is fine! But if you run into “jspdf is not defined” errors, ensure that file path is correct or revert to the standard 2.5.1 CDN/file.

Would you like the compress.html code next, using the image-resampling method we discussed?


User: You said

I will pause about both compress and merge feature. I have an urgent feature that I have to build. Help me write a pdf to image such as jpg png and for initial simplicity, you may choose one format.


Gemini: Here is the PDF to Image (JPG) converter.

This is simpler than compression because we don’t need to rebuild a PDF; we just need to render the pages to a canvas and save them as images. We only need pdf.js for this.

pdf-to-image.html HTML <!DOCTYPE html>

PDF to JPG Converter

PDF to JPG Converter

Critical Note on the “Worker”

pdf.js is unique; it requires a second file called the Worker to handle the heavy math without freezing your screen.

In the script above, I added this line:

JavaScript pdfjsLib.GlobalWorkerOptions.workerSrc = ‘https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js’;

If you have downloaded the library files locally (e.g. into your ../lib/ folder), you should change that URL to point to your local worker file (e.g., ../lib/pdf.worker-3.11.174.js) so it works offline.


User: You said

It works:


<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>PDF to JPG Converter</title>

<script src="../lib/pdf-3.11.174.js"></script>




<style>

body { font-family: sans-serif; max-width: 900px; margin: 2rem auto; padding: 0 1rem; }

.container { border: 1px solid #ccc; padding: 2rem; border-radius: 8px; }

.controls { margin-bottom: 2rem; padding-bottom: 1rem; border-bottom: 1px solid #eee; }

/* Grid to show the resulting images */

.image-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 20px; }

.image-card { border: 1px solid #ddd; padding: 10px; border-radius: 4px; text-align: center; background: #f9f9f9; }

.image-card img { max-width: 100%; height: auto; border: 1px solid #ccc; margin-bottom: 10px; }

button { padding: 8px 16px; cursor: pointer; background-color: #28a745; color: white; border: none; border-radius: 4px; }

button:hover { background-color: #218838; }

.download-btn { background-color: #007bff; font-size: 0.9rem; width: 100%; }

.download-btn:hover { background-color: #0069d9; }

</style>

</head>

<body>




<div class="container">

<h2>PDF to JPG Converter</h2>

<div class="controls">

<input type="file" id="fileInput" accept=".pdf" />

<button onclick="convertPdfToImages()">Convert to JPG</button>

<p id="status"></p>

</div>




<div id="output" class="image-grid">

</div>

</div>




<script>

// IMPORTANT: Set the worker source.

// If you have the worker file locally, point to it here.

// Otherwise, this CDN link usually works as a fallback for standard versions.

pdfjsLib.GlobalWorkerOptions.workerSrc = '../lib/pdf.worker-3.11.174.js';




async function convertPdfToImages() {

const fileInput = document.getElementById('fileInput');

const outputDiv = document.getElementById('output');

const status = document.getElementById('status');

if (!fileInput.files[0]) return alert("Please select a PDF first");




try {

outputDiv.innerHTML = ''; // Clear previous results

status.innerText = "Processing...";




// 1. Load the PDF

const file = fileInput.files[0];

const arrayBuffer = await file.arrayBuffer();

const pdf = await pdfjsLib.getDocument(arrayBuffer).promise;




status.innerText = `Found ${pdf.numPages} pages. Converting...`;




// 2. Loop through each page

for (let i = 1; i <= pdf.numPages; i++) {

const page = await pdf.getPage(i);

// Set scale (1.5 = 150% size for better quality, 1.0 = standard)

const viewport = page.getViewport({ scale: 1.5 });




// Create a canvas to render the page

const canvas = document.createElement('canvas');

const ctx = canvas.getContext('2d');

canvas.width = viewport.width;

canvas.height = viewport.height;




// Render page to canvas

await page.render({ canvasContext: ctx, viewport: viewport }).promise;




// 3. Convert Canvas to JPG Image (0.8 is 80% quality)

const imgData = canvas.toDataURL('image/jpeg', 0.8);




// 4. Create UI Elements to display it

createImageCard(imgData, i, outputDiv);

}




status.innerText = "Conversion Complete!";




} catch (error) {

console.error(error);

status.innerText = "Error: " + error.message;

}

}




function createImageCard(dataUrl, pageNum, container) {

const div = document.createElement('div');

div.className = 'image-card';




// The Image Preview

const img = document.createElement('img');

img.src = dataUrl;

// The Download Button

const btn = document.createElement('button');

btn.className = 'download-btn';

btn.innerText = `Download Page ${pageNum}`;

btn.onclick = () => {

const link = document.createElement('a');

link.href = dataUrl;

link.download = `page-${pageNum}.jpg`;

link.click();

};




div.appendChild(img);

div.appendChild(btn);

container.appendChild(div);

}

</script>




</body>

</html>

Is it possible to make the downloaded images name initially the same as the uploaded pdf filename?


Gemini: Yes, that is a great user experience improvement. We can easily grab the name property from the uploaded file object and strip off the .pdf extension.

Here is the updated logic. I have modified the JavaScript to capture the filename and pass it down to the download button.

Updated JavaScript Logic

Replace the

HTML

async function convertPdfToImages() {
    const fileInput = document.getElementById('fileInput');
    const outputDiv = document.getElementById('output');
    const status = document.getElementById('status');
    
    if (!fileInput.files[0]) return alert("Please select a PDF first");

    try {
        outputDiv.innerHTML = ''; 
        status.innerText = "Processing...";

        const file = fileInput.files[0];
        
        // --- CHANGE 1: Get the original filename without extension ---
        // "My Report.pdf" -> "My Report"
        const originalName = file.name.replace(/\.[^/.]+$/, ""); 
        
        const arrayBuffer = await file.arrayBuffer();
        const pdf = await pdfjsLib.getDocument(arrayBuffer).promise;

        status.innerText = `Found ${pdf.numPages} pages. Converting...`;

        for (let i = 1; i <= pdf.numPages; i++) {
            const page = await pdf.getPage(i);
            
            // Scale 1.5 gives good quality. Increase to 2.0 for higher res.
            const viewport = page.getViewport({ scale: 1.5 });

            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d');
            canvas.width = viewport.width;
            canvas.height = viewport.height;

            await page.render({ canvasContext: ctx, viewport: viewport }).promise;

            // 0.8 = 80% JPG quality
            const imgData = canvas.toDataURL('image/jpeg', 0.8);

            // --- CHANGE 2: Pass the original filename to the helper ---
            createImageCard(imgData, i, outputDiv, originalName);
        }

        status.innerText = "Conversion Complete!";

    } catch (error) {
        console.error(error);
        status.innerText = "Error: " + error.message;
    }
}

// --- CHANGE 3: Accept 'fileName' as a new argument ---
function createImageCard(dataUrl, pageNum, container, fileName) {
    const div = document.createElement('div');
    div.className = 'image-card';

    const img = document.createElement('img');
    img.src = dataUrl;
    
    const btn = document.createElement('button');
    btn.className = 'download-btn';
    btn.innerText = `Download Page ${pageNum}`;
    
    btn.onclick = () => {
        const link = document.createElement('a');
        link.href = dataUrl;
        
        // --- CHANGE 4: Use the dynamic filename ---
        // Result: "My Report-page-1.jpg"
        link.download = `${fileName}-page-${pageNum}.jpg`;
        
        link.click();
    };

    div.appendChild(img);
    div.appendChild(btn);
    container.appendChild(div);
} </script>

What Changed?

file.name.replace(…): We use a regular expression to cleanly strip the last extension (everything after the last dot).

Passing the name: The createImageCard function now requires a 4th parameter (fileName) so it knows what to name the file when the user clicks download.

Result: If you upload Contract_Final.pdf, the button for page 1 will now download Contract_Final-page-1.jpg instead of just page-1.jpg.

Would you like to add a “Download All as Zip” button? It’s a very common feature for PDF-to-Image converters so the user doesn’t have to click 20 times for a 20-page document.


User: You said

Both pdf2jpg and merge works. Now we fix the problem with compress:


<html>

<head>

<title>PDF Compress Tools</title>

<script src="../lib/pdf-3.11.174.js"></script>

<script src="../lib/jspdf-4.0.0.umd.js"></script>

<script src="../lib/pdf-lib-1.17.1.js"></script>

</head>

<body>

<input type="file" id="upload" accept=".pdf" />

<button onclick="compressPDF()">Compress & Download</button>




<script>

async function compressPDF() {

const file = document.getElementById('upload').files[0];

if (!file) return alert("Please select a PDF!");




// 1. Load the PDF using pdf.js

const arrayBuffer = await file.arrayBuffer();

const pdf = await pdfjsLib.getDocument(arrayBuffer).promise;

// Initialize jsPDF (The builder)

const { jsPDF } = window.jspdf;

const newPdf = new jsPDF();




// 2. Loop through every page

for (let i = 1; i <= pdf.numPages; i++) {

const page = await pdf.getPage(i);

// Determine scale (lower scale = smaller file but blurrier)

const viewport = page.getViewport({ scale: 1 });

// Create a temporary canvas to render the page

const canvas = document.createElement('canvas');

const ctx = canvas.getContext('2d');

canvas.width = viewport.width;

canvas.height = viewport.height;




// Render page to canvas

await page.render({ canvasContext: ctx, viewport: viewport }).promise;




// 3. Compress: Convert canvas to JPEG with 0.5 quality (50%)

const imgData = canvas.toDataURL('image/jpeg', 0.5);




// 4. Add image to the new PDF

if (i > 1) newPdf.addPage();

const pdfWidth = newPdf.internal.pageSize.getWidth();

const pdfHeight = newPdf.internal.pageSize.getHeight();

newPdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight);

}




// 5. Save

newPdf.save("compressed.pdf");

}

</script>

</body>

</html>

Console:


pdf-3.11.174.js:5524 Deprecated API usage: No "GlobalWorkerOptions.workerSrc" specified.

pdf-3.11.174.js:381 Warning: Setting up fake worker.

pdf-3.11.174.js:5524 Deprecated API usage: No "GlobalWorkerOptions.workerSrc" specified.

pdf-3.11.174.js:5520  GET file:///home/fajarpurnama/Documents/vscode-default-directory/webapp/pdf/lib/pdf-3.11.174.worker.js net::ERR_FILE_NOT_FOUND

(anonymous) @ pdf-3.11.174.js:5520

loadScript @ pdf-3.11.174.js:5508

loader @ pdf-3.11.174.js:1985

get _setupFakeWorkerGlobal @ pdf-3.11.174.js:1988

_setupFakeWorker @ pdf-3.11.174.js:1910

_initialize @ pdf-3.11.174.js:1903

PDFWorker @ pdf-3.11.174.js:1814

getDocument @ pdf-3.11.174.js:970

compressPDF @ index.html:19

await in compressPDF

onclick @ index.html:10

pdf-3.11.174.js:1927 Uncaught (in promise) Error: Setting up fake worker failed: "Cannot load script at: file:///home/fajarpurnama/Documents/vscode-default-directory/webapp/pdf/lib/pdf-3.11.174.worker.js".

(anonymous) @ pdf-3.11.174.js:1927

Promise.catch

_setupFakeWorker @ pdf-3.11.174.js:1926

_initialize @ pdf-3.11.174.js:1903

PDFWorker @ pdf-3.11.174.js:1814

getDocument @ pdf-3.11.174.js:970

compressPDF @ index.html:19

await in compressPDF

onclick @ index.html:10


Gemini: The error Deprecated API usage: No “GlobalWorkerOptions.workerSrc” specified confirms that pdf.js cannot find the helper file needed to process the PDF.

It worked in your PDF to JPG tool because we added the workerSrc line there, but it is missing in this Compress tool.

Here is the fixed code. I have also upgraded the logic to respect the original page size (instead of squashing everything into A4) and included the worker path.

compress.html HTML <!DOCTYPE html>

PDF Compress Tool

PDF Compressor


Key Changes Explained

Added pdfjsLib.GlobalWorkerOptions.workerSrc: This points to the file ../lib/pdf.worker-3.11.174.js. Without this, pdf.js does not know how to start the background process.

Dynamic Page Sizing:

Old Code: new jsPDF() defaults to A4 size. If your original PDF was a small receipt or a large slide deck, it would be stretched or squished to fit A4.

New Code: new jsPDF({ unit: ‘pt’, format: [w, h] }). This reads the width/height of your original PDF page and creates the new page with the exact same dimensions.

Scale Adjustment: I set scale: 1.5 in the viewport.

scale: 1.0 is very blurry (low res).

scale: 1.5 or 2.0 is sharper but creates larger files.

To compress more aggressively: Change scale: 1.5 to 1.0 OR change the JPEG quality 0.5 to 0.3.