Skip to content

Видобування зображень

PDF Oxide видобуває зображення зі сторінок PDF, розбираючи потік вмісту, розв’язуючи посилання на XObject через оператори Do, рекурсивно обходячи вкладені Form XObject та декодуючи вбудовані зображення. Використовуйте extract_images(), щоб отримати об’єкти зображень у пам’яті, або extract_images_to_files(), щоб зберегти їх безпосередньо на диск як файли PNG чи JPEG.

Починаючи з v0.3.5, видобування зображень обробляє повний потік вмісту сторінки, а не лише сканує словник XObject. Це коректно обробляє зображення, розміщені через оператори Do, вкладені Form XObject із виявленням циклів та вбудовані зображення, закодовані послідовностями BI/ID/EI.

Підтримка колірних просторів

Видобуті зображення декодуються та повертаються в їхньому оригінальному колірному просторі — без втрат на перекодуванні:

  • DeviceRGB / DeviceGray / DeviceCMYK — повертаються як є.
  • Indexed (1, 2, 4, 8 біт на компонент) — палітра розв’язується через resolve_indexed_palette та розгортається через expand_indexed_to_rgb. Підтримує палітри Indexed на основі базових колірних просторів RGB, Grayscale та CMYK. Раніше видавали помилки Invalid RGB image dimensions на багатьох реальних PDF.
  • CalRGB / CalGray / ICCBased — конвертуються в RGB під час декодування.

Розгортання палітри захищене від зловмисних вхідних даних за допомогою захисту від переповнення checked_mul та обмеження на виділення 256 МіБ; обрізані потоки відхиляються коректно замість генерування сміттєвих пікселів.

Толерантність до пошкоджених зображень

Зображення з відсутніми записами /ColorSpace, нульовими розмірами або недійсними потоками пропускаються з попередженням — вони більше не аварійно завершують відмальовування сторінки. Така сама толерантність застосовується до пошкоджених зображень, вкладених у Form XObject.

Швидкий приклад

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

extract_images(page_index) -> Vec<PdfImage>

Видобути всі зображення зі сторінки. Розбирає потік вмісту сторінки, щоб знайти:

  1. Зображення XObject, на які посилаються через оператори Do
  2. Form XObject, що містять вкладені зображення (рекурсивно, з виявленням циклів)
  3. Вбудовані зображення, закодовані послідовностями BI/ID/EI

Відстеження CTM (Current Transformation Matrix) надає обмежувальні рамки для кожного зображення.

Параметр Тип Опис
page_index int / usize Індекс сторінки з нуля

Повертає: вектор об’єктів PdfImage.

Поля та методи PdfImage

Метод / Поле Тип Опис
width() u32 Ширина зображення у пікселях
height() u32 Висота зображення у пікселях
color_space() &ColorSpace Колірний простір (DeviceRGB, DeviceGray, DeviceCMYK тощо)
bits_per_component() u8 Біт на колірний компонент (зазвичай 8)
data() &ImageData Сирі дані зображення (байти JPEG або сирі пікселі)
bbox() Option<&Rect> Обмежувальна рамка в користувацькому просторі PDF (якщо CTM відстежувалася)
save_as_png(path) Result<()> Зберегти зображення як файл PNG
save_as_jpeg(path) Result<()> Зберегти зображення як файл JPEG
to_png_bytes() Result<Vec<u8>> Закодувати як байти PNG у пам’яті
to_jpeg_bytes() Result<Vec<u8>> Закодувати як байти JPEG у пам’яті

Варіанти ColorSpace

Варіант Опис
DeviceRGB 3-канальний RGB
DeviceGray Одноканальні відтінки сірого
DeviceCMYK 4-канальний CMYK
Indexed Колір на основі палітри
ICCBased Колір на основі профілю ICC
CalGray Каліброване сіре
CalRGB Каліброване RGB
Lab Колір CIE Lab*

Варіанти ImageData

Варіант Опис
Jpeg(Vec<u8>) Стиснуті дані JPEG (DCT pass-through)
Raw { pixels, format } Декодовані піксельні дані з 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>

Видобути зображення зі сторінки та зберегти їх безпосередньо у файли. Зображення JPEG зберігаються у їхньому оригінальному форматі (без втрат на перекодуванні); інші зображення зберігаються як PNG.

Параметр Тип За замовчуванням Опис
page_index usize Індекс сторінки з нуля
output_dir impl AsRef<Path> Каталог для збереження зображень (створюється за відсутності)
prefix Option<&str> "img" Префікс імені файлу
start_index Option<usize> 1 Початковий індекс для імен файлів

Повертає: вектор ExtractedImageRef, що описує збережені файли.

Поля ExtractedImageRef

Поле Тип Опис
filename String Збережене ім’я файлу (наприклад, "img_001.png")
format ImageFormat Png або Jpeg
width u32 Ширина зображення у пікселях
height u32 Висота зображення у пікселях

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

Розширені приклади

Видобування всіх зображень з усіх сторінок

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

Отримання байтів зображення в пам’яті (без дискового вводу-виводу)

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

Фільтрування зображень за розміром

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 та перекодованих зображень

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

Пов’язані сторінки