Skip to content

Extract images from PDF files in C#

Since 1.1View as Markdown

Find the images on a page, where they land and at what resolution, and save them as files.

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}");
}
}

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,770
640x400, DCTDecode, 288 dpi, at 72,22
PdfPageImageMeaning
Width, HeightSize in samples
BitsPerComponent1, 2, 4, 8 or 16 (1 for a mask, 8 for a JPEG)
EncodingDCTDecode, JPXDecode, JBIG2Decode or CCITTFaxDecode, or null for plain samples
BoundsThe smallest rectangle around the image on the page, in points from the bottom left, before /Rotate
TransformThe matrix that maps the image’s unit square to the page
HorizontalResolution, VerticalResolutionDots per inch, as drawn
IsInline, IsMaskAn inline image (BI … EI), a stencil mask
Dictionary, StreamThe image dictionary and XObject, for anything else

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 Encoding is null.

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.

InputDecoded
Raw samples1 to 16 bits per component
JPEGInverse DCT, upsampling and color conversion as libjpeg does them, within two steps per sample
JPEG 2000JP2 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 faxGroup 3 one and two dimensional, Group 4, bit exact with libtiff
JBIG2Generic, refinement, text and halftone regions, with JBIG2Globals
Color spacesDeviceGray, 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.

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.

  • 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.

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.