Generate PDF Thumbnails for Document Previews with Go

Every document management system needs thumbnails. Users expect to see a visual preview before clicking on a file, whether it's a contract, invoice, or report. Without thumbnails, you're stuck showing generic PDF icons.

Generating PDF thumbnails locally requires heavy libraries like ImageMagick or Poppler. These add deployment complexity and consume server resources. For a Go backend, there's no clean native solution.

The simpler approach: convert PDF pages to images via API. Send the PDF URL, get back image URLs. No dependencies, no memory spikes, just clean HTTP calls.

Quick Example

Here's how to generate a thumbnail from the first page of a PDF:
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

func main() {
    apiToken := "YOUR_API_TOKEN"
    apiURL := "https://apdf.io/api/pdf/file/to-image"

    payload := map[string]interface{}{
        "file":       "https://pdfobject.com/pdf/sample.pdf",
        "image_type": "jpeg",
        "pages":      "1",
        "dpi":        150,
    }

    jsonData, _ := json.Marshal(payload)

    req, _ := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonData))
    req.Header.Set("Authorization", "Bearer "+apiToken)
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Accept", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer resp.Body.Close()

    var result []map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&result)

    fmt.Printf("Thumbnail URL: %s\n", result[0]["file"])
}

The API returns an array of images, one per page. For a thumbnail, we only request page 1.

Real-World Scenario: Document Library API

You're building a document library for a SaaS app. When users upload PDFs, you need to generate thumbnails to display in the file browser. Here's a complete Go service that handles this:

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "time"
)

const (
    apiToken = "YOUR_API_TOKEN"
    apiURL   = "https://apdf.io/api/pdf/file/to-image"
)

type ThumbnailResult struct {
    Page       string `json:"page"`
    File       string `json:"file"`
    Expiration string `json:"expiration"`
}

type ThumbnailRequest struct {
    DocumentID string
    PDFURL     string
}

func generateThumbnail(pdfURL string) (*ThumbnailResult, error) {
    payload := map[string]interface{}{
        "file":       pdfURL,
        "image_type": "jpeg",
        "pages":      "1",
        "dpi":        100, // Lower DPI for faster thumbnails
    }

    jsonData, _ := json.Marshal(payload)

    req, _ := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonData))
    req.Header.Set("Authorization", "Bearer "+apiToken)
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Accept", "application/json")

    client := &http.Client{Timeout: 30 * time.Second}
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    var results []ThumbnailResult
    if err := json.NewDecoder(resp.Body).Decode(&results); err != nil {
        return nil, err
    }

    if len(results) == 0 {
        return nil, fmt.Errorf("no thumbnail generated")
    }

    return &results[0], nil
}

func main() {
    // Documents that need thumbnails
    documents := []ThumbnailRequest{
        {DocumentID: "doc-001", PDFURL: "https://pdfobject.com/pdf/sample.pdf"},
        {DocumentID: "doc-002", PDFURL: "https://ontheline.trincoll.edu/images/bookdown/sample-local-pdf.pdf"},
    }

    for _, doc := range documents {
        fmt.Printf("Generating thumbnail for %s...\n", doc.DocumentID)

        result, err := generateThumbnail(doc.PDFURL)
        if err != nil {
            fmt.Printf("  Error: %v\n", err)
            continue
        }

        fmt.Printf("  Thumbnail: %s\n", result.File)

        // In production: download and store this image in your storage
        // The URL expires after 1 hour
    }
}

Note: The thumbnail URLs are valid for 1 hour. Download and store them in your own storage (S3, local disk) for permanent use.

Choosing the Right Settings

The API offers several parameters to tune your thumbnails:

  • image_type: Use jpeg for photos/scans (smaller files), png for sharp text/diagrams
  • dpi: 72-100 for small thumbnails, 150 for medium previews, 300 for full-quality
  • pages: Use 1 for a single thumbnail, or 1-3 for a multi-page preview
// High-quality preview (e.g., document viewer)
payload := map[string]interface{}{
    "file":       pdfURL,
    "image_type": "png",
    "dpi":        200,
    "pages":      "1",
}

// Fast, small thumbnail (e.g., file browser grid)
payload := map[string]interface{}{
    "file":       pdfURL,
    "image_type": "jpeg",
    "dpi":        72,
    "pages":      "1",
}

// Multi-page preview carousel
payload := map[string]interface{}{
    "file":       pdfURL,
    "image_type": "jpeg",
    "dpi":        150,
    "pages":      "1-5",
}

Next Steps

Once you have thumbnails working, consider these enhancements:

  • Extract first page: Use the Extract Pages endpoint to create a single-page preview PDF.
  • Compress before converting: For large PDFs, use the Compress endpoint first to speed up thumbnail generation.
Ready to build?
Get Started for Free