How Are Images Stored in a PDF? XObjects, Filters and Masks
8 min read
When you open a PDF, how is the photo you see stored inside the file? The answer is more complex than it first appears: the image data, color information, transparency mask and placement information are all stored in separate places. This article explains PDF's image storage architecture and how it plays out in extraction.
Image XObject: the basic structure
In a PDF an image is stored as an object called an Image XObject. That object consists of a dictionary and a data stream:
<< /Type /XObject
/Subtype /Image
/Width 2400
/Height 1800
/ColorSpace /DeviceRGB
/BitsPerComponent 8
/Filter /DCTDecode
/Length 458392
>>
stream
...(JPEG data)...
endstream
What the keys mean:
| Key | Meaning |
|---|---|
| /Width, /Height | Dimensions in pixels |
| /ColorSpace | The color space (DeviceRGB, DeviceCMYK, DeviceGray, Indexed) |
| /BitsPerComponent | Bits per channel (usually 8) |
| /Filter | How the data is encoded |
| /SMask | A reference to a transparency mask object, if present |
| /Decode | Whether the color values should be inverted |
The critical point: this dictionary doesn't say where the image is on the page. Position and scale information lives in the page content stream:
q
400 0 0 300 100 500 cm % scale and position matrix
/Im1 Do % draw image Im1
Q
That matrix means "draw this image 400 points wide, 300 points tall, at position (100,500)."
That separation explains raw extraction's behavior: extraction takes the image object, not its placement on the page. An image that appears rotated, cropped or scaled down on the page comes out in its original state during extraction.
Filters: how the data is encoded
The /Filter key says which compression the data in the stream was encoded with. The most common ones:
/DCTDecode — JPEG compression. The data in the stream is a genuine JPEG file. That's a smart design choice in PDF: rather than decoding and recompressing a JPEG when adding it, it stores it as it is. The result: the file stays small and there's no extra quality loss.
In raw extraction you can save that data directly as .jpg — no conversion needed.
/FlateDecode — lossless zlib/deflate compression. Decompressing the stream yields a raw pixel array. During extraction that data has to be wrapped in a usable format (usually PNG) — because a raw pixel array on its own isn't an image file.
/JPXDecode — JPEG 2000. Rare but used in some scanning systems. Can be extracted directly as .jp2, though many programs can't open that format.
/CCITTFaxDecode — fax compression, for black-and-white scanned documents. Very efficient; an A4 page scan can take a few tens of kilobytes. Wrapping it in TIFF is common during extraction.
/JBIG2Decode — advanced black-and-white compression. More efficient than CCITT but with less widespread support.
/LZWDecode — an older lossless compression, also used in TIFF and GIF.
An extraction tool's output format depends on this filter: DCTDecode → JPEG, FlateDecode → PNG, CCITTFaxDecode → TIFF. That's why files in different formats can come out of the same PDF.
Color spaces and extraction problems
The /ColorSpace key determines how the image's color is interpreted:
/DeviceRGB — standard screen colors. Extracts without trouble.
/DeviceGray — grayscale. No trouble.
/DeviceCMYK — print colors. This is where the trouble starts: many viewers and browsers can't open CMYK JPEGs properly or show the colors inverted. Some CMYK JPEGs also use Adobe's inverted encoding convention and are marked with a /Decode [1 0 1 0 1 0 1 0] array — that information is in the image object, not in the extracted JPEG file. The result: the extracted file can look like a negative.
/Indexed — palette-based color. The image data contains palette indices and the actual colors are stored in a separate palette array. If the palette isn't applied during extraction, the image comes out in meaningless colors.
/ICCBased — an embedded color profile. For correct color, the profile has to be transferred too.
That's why some images can look "wrong" in color after raw extraction. It isn't an error; it's the consequence of the color interpretation information living outside the image file.
Transparency: the SMask mechanism
In PDF, an image's transparency isn't embedded in the image itself. It's stored in a separate soft mask object:
/SMask 15 0 R
Object 15 is a grayscale image with the same dimensions as the main image. Each pixel's value indicates the opacity at that point: 0 is fully transparent, 255 fully opaque.
In raw extraction these two objects are found separately and come out as separate files. The result:
- The main image comes out opaque, without the transparency information. A background that looked transparent in the PDF can now appear black or white.
- The mask file on its own looks like a black-and-white silhouette. It isn't a corrupted file; it's the mask itself.
To recover the transparency you have to combine the two in an image editor: open the main image, apply the mask as an alpha channel, save as PNG.
There's also a /Mask key — used for binary (1-bit) stencil masks or color key masking. It works differently from SMask but creates a similar separation problem.
Why images get split up
A common situation in raw extraction: there's one photo on the page but ten separate strip files come out.
The reason is the PDF producer's memory management. Rather than processing a very large image in one piece, it reads and writes it in horizontal strips. Each strip becomes a separate Image XObject.
They look continuous on the page because the content stream places each strip at exactly the adjacent position:
q 612 80 0 0 0 712 cm /Im1 Do Q
q 612 80 0 0 0 632 cm /Im2 Do Q
q 612 80 0 0 0 552 cm /Im3 Do Q
This behavior shows up especially in scanner software and in the PDF output of some office programs.
To combine them you have to bring the pieces together side by side in an editor. You can guess the ordering from the numbers in the file names, but it isn't guaranteed; matching them visually is more reliable.
The concept of effective resolution
An image's "resolution" in a PDF isn't a fixed property. It's calculated from the ratio of two values:
Effective DPI = pixel width / physical width on the page (inches)
A 2400-pixel image drawn 8 inches wide on the page is 300 DPI. Fit the same image into 4 inches and it becomes 600 DPI.
That explains why raw extraction sometimes yields surprisingly high-quality images: a photo that looks small on the page can be very high resolution in the original. When the PDF was produced the image wasn't downscaled, it was just placed into a small area.
The reverse is also true: if the PDF has been through a compression pass, the images may genuinely have been reduced to low resolution and raw extraction gives you that low resolution. Lost pixels don't come back.
Invisible images
Raw extraction sometimes gives you images you never saw on the page. The reasons:
- Areas outside a clipping path. Only part of an image may be shown; the object carries all of it.
- Covered images. An element drawn later may have hidden the one beneath.
- Elements placed off the page. Content outside the MediaBox stays in the file.
- Unused objects. After an edit, images no longer referenced by any page can remain in the file.
That last item matters for privacy: putting something over an image isn't enough to "delete" it from a PDF; the object stays in the file and raw extraction finds it.
Why vector graphics can't be extracted
Raw extraction only finds Image XObject objects. Logos, diagrams and charts in a PDF are usually vector — defined by drawing commands in the page content stream, not as a separate object.
To "extract" a vector logo you need a different approach: convert the page to SVG and isolate the logo there.
A simple test for the distinction: zoom way in on the element in the PDF. If it pixelates it's raster (extractable); if it stays sharp it's vector (not extractable).
In summary
Every image in a PDF is an Image XObject object with its own dictionary and data stream, while position and scale information lives in the page content stream. That separation is why raw extraction gives you the original image rather than the version on the page. The data is stored either as a genuine JPEG (DCTDecode) or as raw pixels (FlateDecode) depending on the filter — the extraction format depends on that. Because transparency sits in a separate SMask object, it's lost in extraction and comes out as two files. And because some producers split large images into strips, a single photo can come out as many files. Vector graphics are outside this mechanism entirely; those need SVG conversion.
Frequently Asked Questions
Is a JPEG inside a PDF really stored as a JPEG?
Yes, images encoded with the DCTDecode filter are genuine JPEG data and can be used directly as .jpg when extracted from the file. That's a smart design choice in PDF: instead of decoding and recompressing a JPEG, it stores it as it is, so the file stays small and there's no extra quality loss. Images stored with FlateDecode, on the other hand, are raw pixel data and have to be wrapped in a format like PNG during extraction.
How is an image's resolution determined in a PDF?
It's calculated from the ratio between the image object's own pixel dimensions (Width/Height) and the physical area it occupies on the page. If an image 2400 pixels wide is drawn 8 inches wide on the page, the effective resolution is 300 DPI. Fit the same image into 4 inches and it becomes 600 DPI. So an image's 'resolution' in a PDF isn't a fixed property but a result that depends on the placement scale.
Why are some images split into horizontal strips?
Usually for memory efficiency. Scanner software and some PDF producers process very large images strip by strip rather than loading the whole thing into memory, and they write them to the file that way too. They look continuous on the page because the strips are placed at exactly adjacent positions. Raw extraction finds each strip as a separate object and gives it as a separate file.
What is an SMask, and why does it come out as a separate file?
An SMask (soft mask) is a separate grayscale image carrying an image's transparency information. It specifies how transparent each pixel is with a value between 0 and 255. Because transparency in PDF is stored in that separate object rather than embedded in the image itself, raw extraction gives the two as separate files and the transparency is lost. To recover it, you have to combine them in an editor.
Try this out right away with PDF'ten Görsel Çıkar (Ham).
Try PDF'ten Görsel Çıkar (Ham)