Contents

Online PDF Compression Tool โ€” Reduce PDF File Size Instantly

Fast, secure, and efficient PDF compression using Python Flask and PDFNetPython

The Online PDF Compression Tool is a powerful web-based application designed to reduce PDF file sizes efficiently while maintaining document quality. Built with modern web technologies and advanced PDF processing algorithms, this tool provides a fast, secure, and user-friendly solution for PDF optimization.

  • High Compression Ratio: Reduces PDF file sizes by up to 70% while preserving visual quality
  • Secure Processing: Files are automatically deleted from the server after 1 hour for maximum privacy
  • Fast Processing: Optimized backend processing with PDFNetPython ensures quick compression
  • Cross-Platform: Works seamlessly on all devices with a modern web browser
  • No Installation Required: Fully web-based solution accessible from anywhere

This project leverages a robust tech stack for optimal performance and security:

  • Backend: Python 3, Flask (web framework), PDFNetPython (PDF processing)
  • Frontend: HTML5, CSS3, JavaScript (ES6+)
  • Additional Tools: C, Shell scripting, Git version control
  • Deployment: Replit platform, Nix environment configuration

Experience the PDF compression tool in action:

๐Ÿš€ Launch Live Demo

Landing Page

Online PDF Compression Tool Landing Page - Clean and intuitive web interface with drag-and-drop upload zone, file size indicator, compression progress bar, and secure file handling features for fast PDF optimization using Python Flask and PDFNetPython
PDF Compressor Landing Page - Upload and Compress PDF Files Instantly

The application uses Flask’s robust file handling capabilities to manage PDF uploads securely. The HTML form’s enctype property is set to "multipart/form-data" to enable file transmission. The server-side Flask application extracts files from the request.files[] object and processes them securely.

Key Configuration Parameters:

  • app.config['UPLOAD_FOLDER']: Defines the temporary storage location for uploaded files
  • app.config['MAX_CONTENT_LENGTH']: Sets the maximum allowed file size in bytes
  • Secure filename generation using werkzeug.utils.secure_filename() to prevent path traversal attacks

Flask File Upload Implementation:

from flask import Flask, render_template, request, jsonify
from werkzeug.utils import secure_filename
import os

app = Flask(__name__)

# Configuration
app.config['UPLOAD_FOLDER'] = 'uploads/temp'
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16 MB max file size
app.config['ALLOWED_EXTENSIONS'] = {'pdf'}

def allowed_file(filename):
    """Check if uploaded file has a valid PDF extension"""
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']

@app.route('/upload')
def upload_file():
    """Render the file upload interface"""
    return render_template('upload.html')

@app.route('/uploader', methods=['GET', 'POST'])
def upload_handler():
    """Handle file upload and initiate compression"""
    if request.method == 'POST':
        # Check if file is present in request
        if 'file' not in request.files:
            return jsonify({'error': 'No file provided'}), 400

        f = request.files['file']

        # Validate file
        if f.filename == '':
            return jsonify({'error': 'No file selected'}), 400

        if not allowed_file(f.filename):
            return jsonify({'error': 'Only PDF files are allowed'}), 400

        # Save file securely
        filename = secure_filename(f.filename)
        filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        f.save(filepath)

        return jsonify({
            'message': 'File uploaded successfully',
            'filename': filename
        }), 200

if __name__ == '__main__':
    # Create upload directory if it doesn't exist
    os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
    app.run(debug=True)

The compression engine utilizes the powerful PDFNetPython library, which provides advanced PDF optimization capabilities. The compression process analyzes the PDF structure, removes redundancies, compresses streams, and optimizes embedded resources.

Compression Process Steps:

  1. Initialize PDFNet library with license key
  2. Load the input PDF document
  3. Verify document security handlers
  4. Apply Optimizer to reduce file size
  5. Save linearized PDF for optimal web viewing
  6. Validate and return compression results
import os
import sys
from PDFNetPython3.PDFNetPython import PDFDoc, Optimizer, SDFDoc, PDFNet

def compress_file(input_file: str, output_file: str = None) -> bool:
    """
    Compress a PDF file using PDFNetPython's advanced optimization.

    Args:
        input_file: Path to the PDF file to compress
        output_file: Path where compressed PDF will be saved.
                     If None, overwrites the input file.

    Returns:
        bool: True if compression successful, False otherwise
    """
    if not output_file:
        output_file = input_file

    try:
        # Initialize PDFNet library
        PDFNet.Initialize()

        # Open the PDF document
        doc = PDFDoc(input_file)

        # Initialize security handlers (required for protected PDFs)
        doc.InitSecurityHandler()

        # Apply optimization to reduce file size
        # This includes: stream compression, font subsetting, and object removal
        Optimizer.Optimize(doc)

        # Save optimized PDF with linearization for web viewing
        # Linearized PDFs display faster in web browsers
        doc.Save(output_file, SDFDoc.e_linearized)

        # Close document and release resources
        doc.Close()

        return True

    except Exception as e:
        print(f"Error during PDF compression: {str(e)}")
        try:
            doc.Close()
        except:
            pass
        return False

if __name__ == "__main__":
    # Command line usage: python compress_pdf.py input.pdf output.pdf
    if len(sys.argv) < 3:
        print("Usage: python compress_pdf.py <input_pdf> <output_pdf>")
        sys.exit(1)

    input_file = sys.argv[1]
    output_file = sys.argv[2]

    if not os.path.exists(input_file):
        print(f"Error: Input file '{input_file}' not found")
        sys.exit(1)

    success = compress_file(input_file, output_file)
    if success:
        original_size = os.path.getsize(input_file)
        compressed_size = os.path.getsize(output_file)
        ratio = ((original_size - compressed_size) / original_size) * 100

        print(f"โœ“ Compression successful!")
        print(f"  Original size:   {original_size / 1024:.2f} KB")
        print(f"  Compressed size: {compressed_size / 1024:.2f} KB")
        print(f"  Compression ratio: {ratio:.2f}%")
    else:
        print("โœ— Compression failed")
        sys.exit(1)

After successful compression, the client-side JavaScript handles automatic file download using modern browser APIs. The implementation uses the Fetch API to retrieve the compressed file and creates a temporary download link for seamless user experience.

Download Process:

  1. Receive compressed file metadata from server
  2. Fetch compressed PDF blob from server
  3. Create temporary object URL for download
  4. Trigger automatic download
  5. Clean up temporary resources
/**
 * Download compressed PDF file automatically
 * @param {string} filename - Name of the compressed file to download
 */
function downloadFile(filename) {
    // Validate response and filename
    if (response !== null && response.filename) {
        const fname = response.filename;
        const url = `static/resource/${fname}`;

        console.log(`Downloading file from: ${url}`);

        // Fetch compressed PDF as blob
        fetch(url)
            .then(response => {
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                return response.blob();
            })
            .then(blob => {
                // Create temporary download link
                const link = document.createElement("a");
                link.href = URL.createObjectURL(blob);
                link.download = fname;

                // Append to DOM (required for Firefox)
                document.body.appendChild(link);

                // Trigger download
                link.click();

                // Clean up: remove link and revoke object URL
                document.body.removeChild(link);
                URL.revokeObjectURL(link.href);

                console.log("โœ“ Download initiated successfully");
            })
            .catch(error => {
                console.error("โœ— Download failed:", error);
                alert("Failed to download file. Please try again.");
            });
    } else {
        console.error("โœ— Invalid response or filename");
        alert("File not ready for download. Please wait for compression to complete.");
    }
}

// Alternative: Display download progress
function downloadFileWithProgress(filename) {
    if (response !== null && response.filename) {
        const fname = response.filename;
        const url = `static/resource/${fname}`;

        fetch(url)
            .then(response => {
                const contentLength = response.headers.get('content-length');
                const total = parseInt(contentLength, 10);
                let loaded = 0;

                return new Response(
                    new ReadableStream({
                        start(controller) {
                            const reader = response.body.getReader();

                            read();
                            function read() {
                                reader.read().then(({done, value}) => {
                                    if (done) {
                                        controller.close();
                                        return;
                                    }
                                    loaded += value.byteLength;
                                    const progress = (loaded / total) * 100;
                                    console.log(`Download progress: ${progress.toFixed(2)}%`);

                                    controller.enqueue(value);
                                    read();
                                }).catch(error => {
                                    console.error(error);
                                    controller.error(error);
                                });
                            }
                        }
                    })
                );
            })
            .then(response => response.blob())
            .then(blob => {
                const link = document.createElement("a");
                link.href = URL.createObjectURL(blob);
                link.download = fname;
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
                URL.revokeObjectURL(link.href);
            })
            .catch(error => {
                console.error("Download error:", error);
            });
    }
}
  • Fork this repository;
  • Create a branch with your feature: git checkout -b my-feature;
  • Commit your changes: git commit -m "feat: my new feature";
  • Push to your branch: git push origin my-feature.