Extract images from PDF files in C#
Find the images on a page, where they land and at what resolution, and save them as files.
Short answer
Section titled “Short answer”page.GetImages() lists the images a page draws, in drawing order, with their placement.
Save a JPEG as stored with GetEncodedData(), or call Decode() to get 8 bit gray or RGB pixels
and save them with SavePng.
int n = 0;foreach (PdfPageImage image in images){ n++; if (image.Encoding == "DCTDecode") { File.WriteAllBytes($"image-{n}.jpg", image.GetEncodedData()); // the JPEG as stored } else if (image.Decode() is PdfBitmap bitmap) { bitmap.SavePng($"image-{n}.png"); // 8 bit gray or RGB pixels Console.WriteLine($"image-{n}.png: {bitmap.Format}, {bitmap.Width}x{bitmap.Height}"); }}What a page draws
Section titled “What a page draws”GetImages() walks the page content: image XObjects, inside form XObjects too, and inline
images. The same XObject drawn twice appears twice, once per placement.
PdfDocument doc = PdfDocument.Open("manual.pdf");IReadOnlyList<PdfPageImage> images = doc.Pages[0].GetImages();foreach (PdfPageImage image in images){ Console.WriteLine( $"{image.Width}x{image.Height}, {image.Encoding ?? "raw samples"}, " + $"{image.HorizontalResolution:0} dpi, at {image.Bounds.Left:0},{image.Bounds.Bottom:0}");}300x100, raw samples, 225 dpi, at 72,770640x400, DCTDecode, 288 dpi, at 72,22PdfPageImage | Meaning |
|---|---|
Width, Height | Size in samples |
BitsPerComponent | 1, 2, 4, 8 or 16 (1 for a mask, 8 for a JPEG) |
Encoding | DCTDecode, JPXDecode, JBIG2Decode or CCITTFaxDecode, or null for plain samples |
Bounds | The smallest rectangle around the image on the page, in points from the bottom left, before /Rotate |
Transform | The matrix that maps the image’s unit square to the page |
HorizontalResolution, VerticalResolution | Dots per inch, as drawn |
IsInline, IsMask | An inline image (BI … EI), a stencil mask |
Dictionary, Stream | The image dictionary and XObject, for anything else |
Encoded data
Section titled “Encoded data”GetEncodedData() returns the data with general compression such as Flate undone:
- a JPEG file for
DCTDecode, as stored, with no re-encoding, - a JPEG 2000 codestream for
JPXDecode, - the raw samples when
Encodingis null.
Decoded pixels
Section titled “Decoded pixels”Decode() returns a PdfBitmap: rows top to bottom, Format Gray8 or Rgb24, with Width,
Height, Stride and Pixels. SavePng(path), SavePng(stream) and ToPng() write it as PNG.
It returns null for an unknown encoding or a color space it does not support.
| Input | Decoded |
|---|---|
| Raw samples | 1 to 16 bits per component |
| JPEG | Inverse DCT, upsampling and color conversion as libjpeg does them, within two steps per sample |
| JPEG 2000 | JP2 files and raw codestreams (ITU-T T.800 part 1): every progression order, precincts, layers, tiles, ROI, the 5/3 and 9/7 wavelets, RCT and ICT, 1 to 16 bit components, JP2 palettes and channel definitions. Lossless images decode bit exact, lossy ones within one step of OpenJPEG |
| CCITT fax | Group 3 one and two dimensional, Group 4, bit exact with libtiff |
| JBIG2 | Generic, refinement, text and halftone regions, with JBIG2Globals |
| Color spaces | DeviceGray, DeviceRGB, DeviceCMYK, CalGray, CalRGB, ICCBased, Indexed, Lab, Separation and DeviceN |
The Decode array is applied, and stencil masks come back black where they paint. For a JPEG 2000 image, the color space in the image dictionary wins; without one, the JP2 header’s applies, as ISO 32000-1, 7.4.9 says.
Damaged and hostile files
Section titled “Damaged and hostile files”Decoding is bounded by the image’s size and the document’s decode limit. Damaged or oversized
data raises PdfFormatException; damaged page content is read as far as it goes.
Limits
Section titled “Limits”- Soft masks and transparency are not applied: an image with an alpha channel decodes without it, and neither is a JPEG 2000 image’s own alpha (SMaskInData).
- JPEG 2000 ICC profiles count only for their number of components, and HTJ2K (JPEG 2000 part 15) and part 2 extensions are not supported.
- Separation and DeviceN colors other than a Type 2 tint transform are approximated as gray.
- Rendering whole pages to images is out of scope.
Related
Section titled “Related”- Extract text
- OCR: decoded scans feed the recognizer
- Images: place images on pages
- API: PdfPageImage, PdfBitmap, PdfPage
Questions
- Are JPEG images re-encoded when extracted?
- No. GetEncodedData returns a DCTDecode image as the JPEG file stored in the PDF, byte for byte once general compression is undone.
- Which image encodings can be decoded to pixels?
- Raw samples of 1 to 16 bits, JPEG, JPEG 2000, CCITT fax (Group 3 and 4) and JBIG2.