Client-side

PDF TO IMAGE

Convert document pages into ZIP-packaged PNG or JPG files using 100% local, high-fidelity browser rendering.

🖼️
Drag & drop a PDF file here, or click to browse
Supports single .pdf file

About PDF to Image Converter

Render and export every page of your PDF document as high-resolution PNG or JPG image files. The converter handles rendering entirely within your browser using the pdf.js rendering engine and bundles all pages into a single download-ready ZIP archive.

This is ideal for sharing document pages on social media, inserting pages into presentations, or referencing files when PDF viewers are not available. Zero uploads mean your files are completely safe.

Developer Reference

Core Algorithm & Standalone Script

Standalone, zero-dependency JavaScript implementation powering this tool. Free to inspect, copy, and build upon.

// Set up PDF.js worker
    pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';

    let currentFile = null;
    let currentPdfDoc = null;
    let fileNameStr = '';

    const uploadZone = document.getElementById('uploadZone');
    const fileInput = document.getElementById('fileInput');
    const configPanel = document.getElementById('configPanel');
    const fileNameEl = document.getElementById('fileName');
    const pageCountEl = document.getElementById('pageCount');
    const formatSelect = document.getElementById('formatSelect');
    const scaleSelect = document.getElementById('scaleSelect');
    const convertBtn = document.getElementById('convertBtn');
    const loadingContainer = document.getElementById('loadingContainer');
    const progressText = document.getElementById('progressText');
    const progressBar = document.getElementById('progressBar');
    const resultContainer = document.getElementById('resultContainer');
    const resultInfo = document.getElementById('resultInfo');
    const downloadBtn = document.getElementById('downloadBtn');

    // Drag and drop event listeners
    ['dragenter', 'dragover'].forEach(eventName => {
      uploadZone.addEventListener(eventName, e => {
        e.preventDefault();
        uploadZone.classList.add('dragover');
      }, false);
    });

    ['dragleave', 'drop'].forEach(eventName => {
      uploadZone.addEventListener(eventName, e => {
        e.preventDefault();
        uploadZone.classList.remove('dragover');
      }, false);
    });

    uploadZone.addEventListener('drop', e => {
      const dt = e.dataTransfer;
      const files = dt.files;
      if (files.length > 0) handleFile(files[0]);
    });

    fileInput.addEventListener('change', e => {
      if (e.target.files.length > 0) handleFile(e.target.files[0]);
    });

    async function handleFile(file) {
      if (file.type !== 'application/pdf') return;
      currentFile = file;
      fileNameStr = file.name;

      try {
        const fileReader = new FileReader();
        fileReader.onload = async function() {
          const typedarray = new Uint8Array(this.result);
          currentPdfDoc = await pdfjsLib.getDocument(typedarray).promise;

          fileNameEl.textContent = file.name;
          pageCountEl.textContent = `${currentPdfDoc.numPages} page${currentPdfDoc.numPages > 1 ? 's' : ''}`;
          
          configPanel.classList.remove('hidden');
          resultContainer.classList.add('hidden');
        };
        fileReader.readAsArrayBuffer(file);
      } catch (err) {
        console.error(err);
        alert('Could not read PDF file.');
      }
    }

    function formatBytes(bytes, decimals = 2) {
      if (bytes === 0) return '0 Bytes';
      const k = 1024;
      const dm = decimals < 0 ? 0 : decimals;
      const sizes = ['Bytes', 'KB', 'MB', 'GB'];
      const i = Math.floor(Math.log(bytes) / Math.log(k));
      return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
    }

    convertBtn.addEventListener('click', async () => {
      if (!currentPdfDoc) return;

      configPanel.classList.add('hidden');
      loadingContainer.classList.remove('hidden');
      resultContainer.classList.add('hidden');

      const format = formatSelect.value;
      const scale = parseFloat(scaleSelect.value);
      const totalPages = currentPdfDoc.numPages;
      const zip = new JSZip();

      try {
        for (let pageNum = 1; pageNum <= totalPages; pageNum++) {
          progressText.textContent = `Rendering page ${pageNum} of ${totalPages}...`;
          const percentage = Math.round((pageNum - 1) / totalPages * 100);
          progressBar.style.width = `${percentage}%`;

          const page = await currentPdfDoc.getPage(pageNum);
          const viewport = page.getViewport({ scale: scale });

          // Render page to canvas
          const canvas = document.createElement('canvas');
          const context = canvas.getContext('2d');
          canvas.height = viewport.height;
          canvas.width = viewport.width;

          const renderContext = {
            canvasContext: context,
            viewport: viewport
          };
          await page.render(renderContext).promise;

          // Convert canvas content to blob
          const mimeType = format === 'png' ? 'image/png' : 'image/jpeg';
          const ext = format === 'png' ? 'png' : 'jpg';
          const imgDataUrl = canvas.toDataURL(mimeType, 0.9);
          
          // Get byte array from data url
          const response = await fetch(imgDataUrl);
          const imageBlob = await response.blob();

          // Add to ZIP file
          const nameWithoutExt = fileNameStr.replace(/\.[^/.]+$/, "");
          const fileNum = String(pageNum).padStart(3, '0');
          zip.file(`${nameWithoutExt}_page_${fileNum}.${ext}`, imageBlob);
        }

        progressBar.style.width = '100%';
        progressText.textContent = 'Creating ZIP file...';

        const zipBlob = await zip.generateAsync({ type: 'blob' });
        const zipUrl = URL.createObjectURL(zipBlob);

        downloadBtn.href = zipUrl;
        const nameWithoutExt = fileNameStr.replace(/\.[^/.]+$/, "");
        downloadBtn.download = `${nameWithoutExt}_images.zip`;
        resultInfo.textContent = `Successfully rendered ${totalPages} page(s). Total ZIP file size: ${formatBytes(zipBlob.size)}.`;

        loadingContainer.classList.add('hidden');
        resultContainer.classList.remove('hidden');
      } catch (err) {
        console.error(err);
        alert('An error occurred while converting PDF to images: ' + err.message);
        loadingContainer.classList.add('hidden');
        configPanel.classList.remove('hidden');
      }
    });