All posts
Tutorial7 min read

Extract every image from a PDF at full quality (pdfimages, pypdf, PDFBox)

Pull embedded images out of a PDF at original resolution — pdfimages for batch, pypdf in Python, PdfPig and PDFBox on .NET and Java — plus scanned pages, masks, and when to render instead.

By · Updated

PDFs embed images as separate objects inside the file. "Extracting" them really means dumping those objects to disk in their original format. That's good news — there's no quality loss when you do it right, because you're getting the bytes that were embedded, not a re-render.

One image, no install

Acrobat: right-click the image → Copy Image, paste into any image editor, save. Preview on macOS: select the image with the rectangular selection tool, copy, paste into Preview's File → New from Clipboard. Both are fine for one or two images. Both lose quality if the embedded image was higher-resolution than your screen.

Every image, full quality: pdfimages

Comes with the poppler-utils package. The right tool for batch:

pdfimages -all report.pdf out/img # writes out/img-001.jpg, out/img-002.png, etc.

-all writes each image in its native format (JPEG stays JPEG, PNG stays PNG). -j writes JPEGs and converts everything else; -png forces PNG output. -list inspects without writing — useful to see how many images and at what resolution before extracting.

Look before you extract

pdfimages -list report.pdf prints one row per image — page, width, height, colour space, bits per component, encoding, and size on disk — without writing a single file. Run it first. It answers the two questions that decide the rest of the job: how many images are actually in here, and are they the resolution you need? An image that lists at 96×72 is a thumbnail placeholder, and no extraction method will give you more pixels than the file contains.

Scanned PDFs are one image per page

If the PDF came from a scanner or a phone scanning app, there are no embedded figures — every page is a single full-page raster. pdfimages dumps one large image per page, which is correct but rarely what someone asking for "the images" wants. If you need the pictures inside a scanned page, you have to detect and crop them out of the page raster. If you need the words, that is OCR, not image extraction.

Extracting an object vs rendering the page

Extraction pulls the embedded bytes out untouched: original format, original resolution, no rendering step. Rendering rasterises the whole page at a DPI you choose (pdftoppm -r 300, or pdf2image in Python) and gives you a picture of the page rather than of the objects on it. Use extraction when you want the asset. Use rendering when you want what the reader sees — a logo drawn from vector paths, a chart with its axes, anything where the visible result was never a single embedded file.

Python: pypdf

from pypdf import PdfReader reader = PdfReader("report.pdf") for page_num, page in enumerate(reader.pages, 1): for img in page.images: with open(f"page_{page_num}_{img.name}", "wb") as f: f.write(img.data)

page.images iterates every embedded image in original format. Faster than pdfimages for tight integration with the rest of a Python pipeline.

C#: PdfPig or iText

PdfPig (MIT) for read access:

using var doc = PdfDocument.Open("report.pdf"); foreach (var page in doc.GetPages()) foreach (var img in page.GetImages()) File.WriteAllBytes($"img_{img.Name}.png", img.RawBytes.ToArray());

iText 7 covers the same ground with finer control over color spaces and JBIG2 (mind the AGPL license).

Java: PDFBox

PDFBox's PDFStreamEngine plus a custom processor extracts images during page rendering — the canonical Java pattern. Apache-licensed, mature, handles every PDF image encoding including JBIG2 and JPEG2000 if you add the optional jai-imageio-jpeg2000 dependency.

Quality and quirks

  • PDFs sometimes split a single visible image into many small tiles. pdfimages will dump them as separate files; merging requires positional metadata.
  • Some images are stored with a separate stencil mask (alpha channel as a second object). pdfimages flags these — use -all and check for paired images with similar timestamps.
  • JBIG2-encoded images won't open in most image viewers. Re-encode with pdfimages -png if you need portability.
  • Vector graphics (logos drawn with PDF path operators, not embedded as raster) aren't "images" in this sense — pdfimages skips them. For those, render the page region to PNG with a tool like pdf2image.

Image plus surrounding text

If the goal is each image alongside its caption or the prose around it (figure cataloging in scientific papers, or building a multimodal training set), pdfimages alone isn't enough — you need positional info to pair images with nearby text spans. pdfplumber's page.images returns bounding boxes you can intersect with text spans — the pairing is code you write, but pdfplumber hands you both halves of it. ExtractFox picks up after that: once the figure is cropped out, drop the crop into the image data extractor to read what is inside it.

Related reading

Stop reading, start extracting

Drop a PDF or image into ExtractFox and get structured data back in seconds.

Try a free extraction →