Skip to content

Bildextraktion

PDF Oxide extrahiert Bilder aus PDF-Seiten, indem es den Content Stream parst, XObject-Verweise über Do-Operatoren auflöst, rekursiv in verschachtelte Form-XObjects absteigt und Inline-Bilder dekodiert. Verwenden Sie extract_images(), um Bildobjekte im Arbeitsspeicher zu erhalten, oder extract_images_to_files(), um sie direkt als PNG- oder JPEG-Dateien auf die Platte zu speichern.

Seit v0.3.5 verarbeitet die Bildextraktion den vollständigen Content Stream der Seite, statt nur das XObject-Dictionary zu durchsuchen. Dadurch werden über Do-Operatoren platzierte Bilder, verschachtelte Form-XObjects mit Zyklenerkennung und mit BI/ID/EI-Sequenzen eingebettete Inline-Bilder korrekt verarbeitet.

Farbraumunterstützung

Extrahierte Bilder werden dekodiert und in ihrem ursprünglichen Farbraum geliefert — ohne verlustbehaftete Hin- und Rückkonvertierung:

  • DeviceRGB / DeviceGray / DeviceCMYK — unverändert zurückgegeben.
  • Indexed (1, 2, 4, 8 Bit pro Komponente) — Palette über resolve_indexed_palette aufgelöst und über expand_indexed_to_rgb expandiert. Unterstützt Indexed-Paletten auf Basis der Farbräume RGB, Grayscale und CMYK. Zuvor wurden bei vielen realen PDFs Invalid RGB image dimensions-Fehler ausgegeben.
  • CalRGB / CalGray / ICCBased — beim Dekodieren in RGB umgewandelt.

Die Palettenexpansion ist gegen bösartige Eingaben abgesichert: mit einem checked_mul-Überlaufschutz und einer Speicherobergrenze von 256 MiB; abgeschnittene Streams werden sauber abgelehnt, statt unsinnige Pixel zu erzeugen.

Toleranz gegenüber fehlerhaften Bildern

Bilder mit fehlenden /ColorSpace-Einträgen, Nullabmessungen oder ungültigen Streams werden mit einer Warnung übersprungen — sie führen nicht mehr zum Absturz des Seitenrenderings. Dieselbe Toleranz gilt für fehlerhafte Bilder, die in Form-XObjects verschachtelt sind.

Schnellbeispiel

Python

from pdf_oxide import PdfDocument

doc = PdfDocument("report.pdf")
images = doc.extract_image_bytes(0)
for img in images:
    print(f"{img['width']}x{img['height']}")

Node.js

const { PdfDocument } = require("pdf-oxide");

const doc = new PdfDocument("report.pdf");
const images = doc.getEmbeddedImages(0);
for (const img of images) {
    console.log(`${img.width}x${img.height}`);
}

Go

import pdfoxide "github.com/yfedoseev/pdf_oxide/go"

doc, _ := pdfoxide.Open("report.pdf")
defer doc.Close()
images, _ := doc.Images(0)
for _, img := range images {
    fmt.Printf("%dx%d\n", img.Width, img.Height)
}

C#

using PdfOxide.Core;

using var doc = PdfDocument.Open("report.pdf");
var images = doc.ExtractImages(0);
foreach (var img in images)
{
    Console.WriteLine($"{img.Width}x{img.Height}");
}

WASM

const doc = new WasmPdfDocument(bytes);
const images = doc.extractImages(0);
for (const img of images) {
    console.log(`${img.width}x${img.height}`);
}

Rust

use pdf_oxide::PdfDocument;

let mut doc = PdfDocument::open("report.pdf")?;
let images = doc.extract_images(0)?;
for img in &images {
    println!("{}x{} {:?}", img.width(), img.height(), img.color_space());
}

API-Referenz

extract_images(page_index) -> Vec<PdfImage>

Extrahiert alle Bilder einer Seite. Parst den Content Stream der Seite, um Folgendes zu finden:

  1. XObject-Bilder, die über Do-Operatoren referenziert werden
  2. Form-XObjects, die verschachtelte Bilder enthalten (rekursiv, mit Zyklenerkennung)
  3. Inline-Bilder, die mit BI/ID/EI-Sequenzen eingebettet sind

Das Tracking der CTM (Current Transformation Matrix) liefert die Bounding-Box für jedes Bild.

Parameter Typ Beschreibung
page_index int / usize Nullbasierter Seitenindex

Rückgabe: Ein Vektor aus PdfImage-Objekten.

PdfImage-Felder und -Methoden

Methode / Feld Typ Beschreibung
width() u32 Bildbreite in Pixeln
height() u32 Bildhöhe in Pixeln
color_space() &ColorSpace Farbraum (DeviceRGB, DeviceGray, DeviceCMYK usw.)
bits_per_component() u8 Bits pro Farbkomponente (typischerweise 8)
data() &ImageData Rohe Bilddaten (JPEG-Bytes oder Rohpixel)
bbox() Option<&Rect> Bounding-Box im PDF-Benutzerkoordinatenraum (falls die CTM verfolgt wurde)
save_as_png(path) Result<()> Bild als PNG-Datei speichern
save_as_jpeg(path) Result<()> Bild als JPEG-Datei speichern
to_png_bytes() Result<Vec<u8>> Als PNG-Bytes im Arbeitsspeicher kodieren
to_jpeg_bytes() Result<Vec<u8>> Als JPEG-Bytes im Arbeitsspeicher kodieren

ColorSpace-Varianten

Variante Beschreibung
DeviceRGB 3-Kanal-RGB
DeviceGray Einkanal-Graustufen
DeviceCMYK 4-Kanal-CMYK
Indexed Palettenbasierte Farbe
ICCBased ICC-profilbasierte Farbe
CalGray Kalibrierte Graustufen
CalRGB Kalibriertes RGB
Lab CIE-Lab*-Farbe

ImageData-Varianten

Variante Beschreibung
Jpeg(Vec<u8>) JPEG-komprimierte Daten (DCT-Pass-Through)
Raw { pixels, format } Dekodierte Pixeldaten mit PixelFormat (RGB, Gray, CMYK, RGBA)

Rust

let mut doc = PdfDocument::open("report.pdf")?;
let images = doc.extract_images(0)?;

for (i, image) in images.iter().enumerate() {
    println!(
        "Image {}: {}x{} {:?} {}bpc",
        i, image.width(), image.height(),
        image.color_space(), image.bits_per_component(),
    );

    if let Some(bbox) = image.bbox() {
        println!("  Position: ({:.1}, {:.1})", bbox.x, bbox.y);
    }

    image.save_as_png(&format!("output/image_{}.png", i))?;
}

extract_images_to_files(page_index, output_dir, prefix, start_index) -> Vec<ExtractedImageRef>

Extrahiert Bilder aus einer Seite und speichert sie direkt in Dateien. JPEG-Bilder werden in ihrem Originalformat gespeichert (kein Verlust durch erneutes Kodieren); andere Bilder werden als PNG gespeichert.

Parameter Typ Standard Beschreibung
page_index usize Nullbasierter Seitenindex
output_dir impl AsRef<Path> Verzeichnis zum Speichern der Bilder (wird angelegt, falls nicht vorhanden)
prefix Option<&str> "img" Dateinamenpräfix
start_index Option<usize> 1 Startindex für die Dateinamen

Rückgabe: Ein Vektor aus ExtractedImageRef, der die gespeicherten Dateien beschreibt.

ExtractedImageRef-Felder

Feld Typ Beschreibung
filename String Gespeicherter Dateiname (z. B. "img_001.png")
format ImageFormat Png oder Jpeg
width u32 Bildbreite in Pixeln
height u32 Bildhöhe in Pixeln

Rust

let mut doc = PdfDocument::open("report.pdf")?;
let refs = doc.extract_images_to_files(0, "output/images", Some("fig"), Some(1))?;

for img_ref in &refs {
    println!("Saved: {} ({}x{}, {:?})", img_ref.filename, img_ref.width, img_ref.height, img_ref.format);
}

Erweiterte Beispiele

Alle Bilder aus allen Seiten extrahieren

use pdf_oxide::PdfDocument;
use std::path::Path;

let mut doc = PdfDocument::open("book.pdf")?;
let page_count = doc.page_count()?;
let mut total = 0;

for page in 0..page_count {
    let refs = doc.extract_images_to_files(
        page,
        "output/images",
        Some(&format!("page{}", page + 1)),
        Some(1),
    )?;
    total += refs.len();
    println!("Page {}: {} images", page + 1, refs.len());
}
println!("Total: {} images extracted", total);

Bild-Bytes im Arbeitsspeicher abrufen (ohne Festplatten-I/O)

let mut doc = PdfDocument::open("report.pdf")?;
let images = doc.extract_images(0)?;

for image in &images {
    let png_bytes = image.to_png_bytes()?;
    println!("PNG size: {} bytes", png_bytes.len());

    // Use png_bytes with an HTTP response, database, etc.
}

Bilder nach Größe filtern

let mut doc = PdfDocument::open("report.pdf")?;
let images = doc.extract_images(0)?;

// Only keep images larger than 100x100 pixels
let large_images: Vec<_> = images.iter()
    .filter(|img| img.width() > 100 && img.height() > 100)
    .collect();

println!("{} large images on page 1", large_images.len());
for img in &large_images {
    println!("  {}x{} {:?}", img.width(), img.height(), img.color_space());
}

JPEG-Pass-Through von neu kodierten Bildern unterscheiden

use pdf_oxide::extractors::ImageData;

let mut doc = PdfDocument::open("report.pdf")?;
let images = doc.extract_images(0)?;

for (i, image) in images.iter().enumerate() {
    match image.data() {
        ImageData::Jpeg(bytes) => {
            // Original JPEG data -- save directly for zero quality loss
            std::fs::write(format!("image_{}.jpg", i), bytes)?;
            println!("Image {}: JPEG pass-through ({} bytes)", i, bytes.len());
        }
        ImageData::Raw { pixels, format } => {
            // Raw pixels -- must encode to a file format
            image.save_as_png(&format!("image_{}.png", i))?;
            println!("Image {}: raw {:?} ({}x{})", i, format, image.width(), image.height());
        }
    }
}

Verwandte Seiten