Seitenrendering
Rendern Sie PDF-Seiten mithilfe eines reinen Rust-Rendering-Engines, der auf tiny-skia aufbaut, in Rasterbilder (PNG oder JPEG). Externe Abhängigkeiten wie Poppler oder MuPDF sind nicht erforderlich.
Schrift-Fallback-Kette
Beim Rendern werden Glyphen benötigt. Wenn ein PDF eine nicht eingebettete Schrift (ArialMT, TimesNewRomanPSMT usw.) referenziert, die auf dem Host nicht installiert ist, durchläuft PDF Oxide eine Fallback-Kette bekannter Open-Source-Schriften:
- DejaVu Sans / DejaVu Serif / DejaVu Sans Mono
- Noto Sans / Noto Serif
- FreeSans / FreeSerif
Wenn der Fallback greift, wird eine Warnung mit dem Namen der fehlenden Schrift sowie ein umsetzbarer Hinweis protokolliert: Auf Linux installieren Sie liberation-fonts, dejavu-fonts oder noto-fonts; in minimalen Containern fügen Sie eines dieser Pakete zu Ihrem Dockerfile hinzu.
Hinweise zur Performance
- Die Systemschrift-Datenbank wird auf Prozessebene gecacht — nachfolgende Rendervorgänge verwenden den geparsten Index wieder.
- Mehrzeichige Glyph-Cluster akkumulieren Breiten korrekt (behebt fehlende Ligaturen bei lateinischen/arabischen Subset-CID-Schriften).
- Fehlerhafte Bilder (fehlende
/ColorSpace, ungültige Abmessungen) werden mit einer Warnung übersprungen, anstatt die Seite zum Absturz zu bringen.
Schnellbeispiel
Rust
use pdf_oxide::PdfDocument;
use pdf_oxide::rendering::{render_page, RenderOptions};
let mut doc = PdfDocument::open("document.pdf")?;
// Render first page as PNG at 150 DPI (default)
let image = render_page(&mut doc, 0, &RenderOptions::default())?;
image.save("page1.png")?;
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("document.pdf")
# Render first page as PNG at 150 DPI
png_bytes = doc.render_page(0, dpi=150)
with open("page1.png", "wb") as f:
f.write(png_bytes)
# Render as JPEG
jpeg_bytes = doc.render_page(0, dpi=150, format="jpeg")
with open("page1.jpg", "wb") as f:
f.write(jpeg_bytes)
Node.js
const { PdfDocument } = require("pdf-oxide");
const fs = require("node:fs");
const doc = new PdfDocument("document.pdf");
// Render first page as PNG
const pngBytes = doc.renderPage(0, "png");
fs.writeFileSync("page1.png", Buffer.from(pngBytes));
// Render as JPEG
const jpegBytes = doc.renderPage(0, "jpeg");
fs.writeFileSync("page1.jpg", Buffer.from(jpegBytes));
doc.close();
Go
import pdfoxide "github.com/yfedoseev/pdf_oxide/go"
doc, _ := pdfoxide.Open("document.pdf")
defer doc.Close()
// Render first page as PNG (format 0 = PNG, 1 = JPEG)
png, _ := doc.RenderPage(0, 0)
os.WriteFile("page1.png", png.Data, 0644)
// Render as JPEG
jpeg, _ := doc.RenderPage(0, 1)
os.WriteFile("page1.jpg", jpeg.Data, 0644)
C#
using PdfOxide.Core;
using var doc = PdfDocument.Open("document.pdf");
// Render first page as PNG (format 0 = PNG, 1 = JPEG)
var pngBytes = doc.RenderPage(0, 0);
File.WriteAllBytes("page1.png", pngBytes);
// Render as JPEG
var jpegBytes = doc.RenderPage(0, 1);
File.WriteAllBytes("page1.jpg", jpegBytes);
Java
import fyi.oxide.pdf.PdfDocument;
import java.nio.file.*;
try (PdfDocument doc = PdfDocument.open(Path.of("document.pdf"))) {
// Render first page as PNG at 150 DPI
byte[] png = doc.render(0, 150);
Files.write(Path.of("page1.png"), png);
}
Kotlin
import fyi.oxide.pdf.PdfDocument
import java.nio.file.*
PdfDocument.open(Path.of("document.pdf")).use { doc ->
// Render first page as PNG at 150 DPI
val png = doc.render(0, 150)
Files.write(Path.of("page1.png"), png)
}
Scala
import fyi.oxide.pdf.PdfDocument
import scala.util.Using
import java.nio.file.{Files, Paths}
Using.resource(PdfDocument.open("document.pdf")) { doc =>
// Render first page as PNG at 150 DPI
val png = doc.render(0, 150)
Files.write(Paths.get("page1.png"), png)
}
Clojure
(require '[pdf-oxide.core :as pdf])
(require '[clojure.java.io :as io])
(with-open [doc (pdf/open "document.pdf")]
;; Render first page as PNG at 150 DPI
(with-open [out (io/output-stream "page1.png")]
(.write out (pdf/render doc 0 150))))
Ruby
require 'pdf_oxide'
PdfOxide::PdfDocument.open('document.pdf') do |doc|
# Render first page as PNG at 150 DPI
File.binwrite('page1.png', doc.render(0, dpi: 150))
# Render as JPEG (format 1)
jpeg = doc.render_with_layers(0, dpi: 150, format: 1)
File.binwrite('page1.jpg', jpeg)
end
C++
#include <pdf_oxide/pdf_oxide.hpp>
auto doc = pdf_oxide::Document::open("document.pdf");
// Render first page as PNG (format 0 = PNG, 1 = JPEG)
doc.render_page(0, 0).save("page1.png");
// Render as JPEG
doc.render_page(0, 1).save("page1.jpg");
Swift
import PdfOxide
let doc = try Document.open("document.pdf")
// Render first page as PNG (format 0 = PNG, 1 = JPEG)
try doc.renderPage(0, format: 0).save("page1.png")
// Render as JPEG
try doc.renderPage(0, format: 1).save("page1.jpg")
Dart
import 'package:pdf_oxide/pdf_oxide.dart';
final doc = PdfDocument.open('document.pdf');
// Render first page as PNG (format 0 = PNG, 1 = JPEG)
doc.renderPage(0, 0).save('page1.png');
// Render as JPEG
doc.renderPage(0, 1).save('page1.jpg');
R
library(pdfoxide)
doc <- pdf_open("document.pdf")
# Render first page as PNG (format 0 = PNG, 1 = JPEG)
img <- pdf_render_page(doc, 0, format = 0L)
pdf_rendered_image_save(img, "page1.png")
# Render as JPEG
jpg <- pdf_render_page(doc, 0, format = 1L)
pdf_rendered_image_save(jpg, "page1.jpg")
Julia
using PdfOxide
doc = open_document("document.pdf")
# Render first page as PNG (format 0 = PNG, 1 = JPEG)
img = render_page(doc, 0, 0)
save(img, "page1.png")
# Render as JPEG
jpg = render_page(doc, 0, 1)
save(jpg, "page1.jpg")
Zig
const pdf_oxide = @import("pdf_oxide");
const a = std.heap.page_allocator;
var doc = try pdf_oxide.Document.open("document.pdf");
// Render first page as PNG (format 0 = PNG, 1 = JPEG)
var png = try doc.renderPage(a, 0, 0);
defer png.deinit();
try png.save("page1.png");
// Render as JPEG
var jpg = try doc.renderPage(a, 0, 1);
defer jpg.deinit();
try jpg.save("page1.jpg");
Objective-C
#import "POXPdfOxide.h"
NSError *err = nil;
POXDocument *doc = [POXDocument openPath:@"document.pdf" error:&err];
// Render first page as PNG (format 0 = PNG, 1 = JPEG)
POXRenderedImage *png = [doc renderPage:0 format:0 error:&err];
[png saveToPath:@"page1.png" error:&err];
// Render as JPEG
POXRenderedImage *jpg = [doc renderPage:0 format:1 error:&err];
[jpg saveToPath:@"page1.jpg" error:&err];
Elixir
{:ok, doc} = PdfOxide.open("document.pdf")
# Render first page as PNG (format 0 = PNG, 1 = JPEG)
{:ok, png} = PdfOxide.render_page(doc, 0, 0)
PdfOxide.save(png, "page1.png")
# Render as JPEG
{:ok, jpg} = PdfOxide.render_page(doc, 0, 1)
PdfOxide.save(jpg, "page1.jpg")
WASM
import { WasmPdfDocument } from "pdf-oxide-wasm";
const doc = new WasmPdfDocument(bytes);
// Render first page as PNG at 150 DPI
const pngBytes = doc.renderPage(0, 150);
// Save in Node.js
import { writeFileSync } from "fs";
writeFileSync("page1.png", Buffer.from(pngBytes));
doc.free();
Feature aktivieren
Das Seitenrendering erfordert das Feature-Flag rendering:
[dependencies]
pdf_oxide = { version = "0.3", features = ["rendering"] }
Dadurch werden tiny-skia (2D-Rendering), fontdb (Schriftladen) und rustybuzz (Textformung) eingebunden.
Rendering-Optionen
Konfigurieren Sie das Rendering über RenderOptions:
use pdf_oxide::rendering::{RenderOptions, ImageFormat};
// Default: 150 DPI, PNG, white background, render annotations
let opts = RenderOptions::default();
// High-quality rendering at 300 DPI
let opts = RenderOptions::with_dpi(300);
// JPEG output with 90% quality
let opts = RenderOptions::with_dpi(300).as_jpeg(90);
// Transparent background (PNG only)
let opts = RenderOptions::default().with_transparent_background();
RenderOptions-Felder
| Feld | Typ | Standard | Beschreibung |
|---|---|---|---|
dpi |
u32 |
150 |
Auflösung in Punkten pro Zoll |
format |
ImageFormat |
Png |
Ausgabeformat (Png oder Jpeg) |
background |
Option<[f32; 4]> |
Weiß [1,1,1,1] |
RGBA-Hintergrundfarbe (0.0–1.0 pro Kanal) |
render_annotations |
bool |
true |
Ob Annotationen gerendert werden sollen |
jpeg_quality |
u8 |
85 |
JPEG-Qualität 1–100 (bei PNG ignoriert) |
Builder-Methoden
| Methode | Beschreibung |
|---|---|
RenderOptions::with_dpi(dpi) |
Optionen mit benutzerdefiniertem DPI erstellen |
.with_transparent_background() |
Hintergrund auf transparent setzen (nur PNG) |
.as_jpeg(quality) |
Auf JPEG-Ausgabe mit angegebener Qualität umschalten |
ImageFormat
| Variante | Beschreibung |
|---|---|
Png |
Verlustfreie Komprimierung, unterstützt Transparenz |
Jpeg |
Verlustbehaftete Komprimierung, kleinere Dateigröße, keine Transparenz |
RenderedImage
Die Funktion render_page() gibt ein RenderedImage zurück:
pub struct RenderedImage {
pub data: Vec<u8>, // Encoded image bytes
pub width: u32, // Width in pixels
pub height: u32, // Height in pixels
pub format: ImageFormat, // PNG or JPEG
}
Methoden
| Methode | Gibt zurück | Beschreibung |
|---|---|---|
save(path) |
Result<()> |
Bild in Datei schreiben |
as_bytes() |
&[u8] |
Rohe Bildbytes abrufen |
Erweiterte Rendering-Varianten
Über den codierten PNG/JPEG-Pfad hinaus bietet PDF Oxide drei niedrigstufige Rendering-Einstiegspunkte: einen rohen Pixelpuffer (ohne PNG/JPEG-Codierung), eine erweiterte Optionsvariante mit Filterung nach Gruppen optionaler Inhalte (OCG) sowie eine günstige Rendering-Zeitschätzung.
Wie erhalte ich einen rohen RGBA-Pixelpuffer statt PNG/JPEG?
Verwenden Sie den Raw-Rendering-Pfad, wenn Sie Pixel direkt an eine GPU-Textur, eine Bildbibliothek oder einen Compositor übergeben möchten, ohne für PNG/JPEG-Codierung zu bezahlen. Der Puffer ist vorgemultiplyiertes RGBA8888, zeilenweise, mit Ursprung oben links: len == width * height * 4.
Rust
use pdf_oxide::PdfDocument;
use pdf_oxide::rendering::{render_page, RenderOptions};
let mut doc = PdfDocument::open("document.pdf")?;
// `.as_raw()` switches the encoder off — `image.data` is the raw RGBA buffer.
let opts = RenderOptions::with_dpi(150).as_raw();
let image = render_page(&mut doc, 0, &opts)?;
assert_eq!(image.data.len(), (image.width * image.height * 4) as usize);
println!("Raw RGBA buffer: {}×{}, {} bytes", image.width, image.height, image.data.len());
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("document.pdf")
# render_pixmap returns a RenderedPixmap (raw RGBA8888, no encoding)
pixmap = doc.render_pixmap(0, dpi=150)
assert len(pixmap.data) == pixmap.width * pixmap.height * 4
print(f"Raw RGBA buffer: {pixmap.width}x{pixmap.height}, {len(pixmap.data)} bytes")
Swift
import PdfOxide
let doc = try PdfDocument(path: "document.pdf")
// renderPageRaw returns the RenderedImage plus the pixel dimensions
let (image, width, height) = try doc.renderPageRaw(0, dpi: 150)
print("Raw RGBA buffer: \(width)x\(height), \(image.data.count) bytes")
C++
#include <pdf_oxide/pdf_oxide.hpp>
auto doc = pdf_oxide::Document::open("document.pdf");
// render_page_raw writes the pixel dimensions into out_width/out_height;
// the raw RGBA buffer is the returned image's data().
int width = 0, height = 0;
auto image = doc.render_page_raw(0, /*dpi=*/150, width, height);
// data().size() == width * height * 4
printf("Raw RGBA buffer: %dx%d, %zu bytes\n", width, height, image.data().size());
Dart
import 'package:pdf_oxide/pdf_oxide.dart';
final doc = PdfDocument.open('document.pdf');
// renderPageRaw returns a RenderedImage holding the raw RGBA8888 buffer
final image = doc.renderPageRaw(0, 150);
assert(image.data.length == image.width * image.height * 4);
print('Raw RGBA buffer: ${image.width}x${image.height}, ${image.data.length} bytes');
R
library(pdfoxide)
doc <- pdf_open("document.pdf")
# pdf_render_page_raw returns a rendered-image with the raw RGBA8888 buffer
img <- pdf_render_page_raw(doc, 0, dpi = 150L)
stopifnot(length(img$data) == img$width * img$height * 4)
cat(sprintf("Raw RGBA buffer: %dx%d, %d bytes\n", img$width, img$height, length(img$data)))
Julia
using PdfOxide
doc = open_document("document.pdf")
# render_page_raw returns a RenderedImage holding the raw RGBA8888 buffer
img = render_page_raw(doc, 0, 150)
@assert length(img.data) == img.width * img.height * 4
println("Raw RGBA buffer: $(img.width)x$(img.height), $(length(img.data)) bytes")
Zig
const pdf_oxide = @import("pdf_oxide");
const a = std.heap.page_allocator;
var doc = try pdf_oxide.Document.open("document.pdf");
// renderPageRaw returns a RenderedImage whose `data` is the raw RGBA8888 buffer
var image = try doc.renderPageRaw(a, 0, 150);
defer image.deinit();
std.debug.assert(image.data.len == @as(usize, @intCast(image.width * image.height * 4)));
std.debug.print("Raw RGBA buffer: {d}x{d}, {d} bytes\n", .{ image.width, image.height, image.data.len });
Objective-C
#import "POXPdfOxide.h"
NSError *err = nil;
POXDocument *doc = [POXDocument openPath:@"document.pdf" error:&err];
// renderPageRaw writes the pixel dimensions into outWidth/outHeight
int32_t width = 0, height = 0;
POXRenderedImage *image = [doc renderPageRaw:0 dpi:150 outWidth:&width outHeight:&height error:&err];
// image.data.length == width * height * 4
NSLog(@"Raw RGBA buffer: %dx%d, %lu bytes", width, height, (unsigned long)image.data.length);
Elixir
{:ok, doc} = PdfOxide.open("document.pdf")
# render_page_raw returns a RenderedImage whose data holds the raw RGBA8888 buffer
{:ok, image} = PdfOxide.render_page_raw(doc, 0, 150)
true = byte_size(image.data) == image.width * image.height * 4
IO.puts("Raw RGBA buffer: #{image.width}x#{image.height}, #{byte_size(image.data)} bytes")
Das C-ABI stellt dies als pdf_render_page_raw(doc, page_index, dpi, *out_width, *out_height, *error_code) bereit; rufen Sie die Pixel-Bytes mit pdf_get_rendered_image_data ab und geben Sie das Handle mit pdf_rendered_image_free frei.
Wie blende ich optionale Inhalts-Layer (OCG) beim Rendering aus?
render_page_with_options_ex ist die vollständige Rendering-Optionsfläche plus eine Liste von /Names optionaler Inhaltsgruppen (OCG), die unterdrückt werden sollen. Übergeben Sie die Namen der Layer, die Sie ausblenden möchten (z. B. einen „Confidential"-Wasserzeichen-Layer oder einen „Construction lines"-CAD-Layer). OCMD-Referenzen, die auf eine der genannten OCGs aufgelöst werden, werden ebenfalls berücksichtigt, gemäß ISO 32000-1 §8.11.2.
Rust
use pdf_oxide::PdfDocument;
use pdf_oxide::rendering::{render_page, RenderOptions};
let mut doc = PdfDocument::open("layered.pdf")?;
let mut opts = RenderOptions::with_dpi(200);
// Suppress these optional-content groups by /Name
opts.excluded_layers = ["Watermark", "Draft Notes"].into_iter().map(String::from).collect();
let image = render_page(&mut doc, 0, &opts)?;
image.save("page_no_watermark.png")?;
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("layered.pdf")
# render_page takes excluded_layers — the OCG /Name strings to hide
png = doc.render_page(0, dpi=200, excluded_layers=["Watermark", "Draft Notes"])
with open("page_no_watermark.png", "wb") as f:
f.write(png)
Swift
import PdfOxide
let doc = try PdfDocument(path: "layered.pdf")
// dpi 200, PNG (format 0), excluded OCG names
let image = try doc.renderPageWithOptionsEx(
0, dpi: 200, format: 0,
excludedLayers: ["Watermark", "Draft Notes"]
)
try image.save("page_no_watermark.png")
C++
#include <pdf_oxide/pdf_oxide.hpp>
auto doc = pdf_oxide::Document::open("layered.pdf");
// dpi 200, PNG (format 0), white bg, render annotations, then OCG /Names to suppress
auto image = doc.render_page_with_options_ex(
0, /*dpi=*/200, /*format=*/0,
1.0f, 1.0f, 1.0f, 1.0f, /*transparent=*/false, /*render_annotations=*/true,
/*jpeg_quality=*/85, {"Watermark", "Draft Notes"});
image.save("page_no_watermark.png");
Ruby
require 'pdf_oxide'
PdfOxide::PdfDocument.open('layered.pdf') do |doc|
# render_with_layers takes excluded_layers — the OCG /Name strings to hide
png = doc.render_with_layers(0, dpi: 200, excluded_layers: ["Watermark", "Draft Notes"])
File.binwrite('page_no_watermark.png', png)
end
Dart
import 'package:pdf_oxide/pdf_oxide.dart';
final doc = PdfDocument.open('layered.pdf');
// renderPageWithOptionsEx takes excludedLayers — the OCG /Name strings to hide
final image = doc.renderPageWithOptionsEx(
0,
dpi: 200,
format: 0,
excludedLayers: ["Watermark", "Draft Notes"],
);
image.save('page_no_watermark.png');
R
library(pdfoxide)
doc <- pdf_open("layered.pdf")
# excluded_layers is a character vector of OCG /Names to suppress
img <- pdf_render_page_with_options_ex(
doc, 0, dpi = 200L, format = 0L,
excluded_layers = c("Watermark", "Draft Notes")
)
pdf_rendered_image_save(img, "page_no_watermark.png")
Julia
using PdfOxide
doc = open_document("layered.pdf")
# excluded_layers is a vector of OCG /Name strings to suppress
img = render_page_with_options_ex(
doc, 0, 200, 0, 1.0, 1.0, 1.0, 1.0, 0, 1, 85,
["Watermark", "Draft Notes"],
)
save(img, "page_no_watermark.png")
Zig
const pdf_oxide = @import("pdf_oxide");
const a = std.heap.page_allocator;
var doc = try pdf_oxide.Document.open("layered.pdf");
// excluded_layers are the OCG /Names to suppress
const layers = [_][*:0]const u8{ "Watermark", "Draft Notes" };
var image = try doc.renderPageWithOptionsEx(
a, 0, 200, 0, 1.0, 1.0, 1.0, 1.0, false, true, 85, &layers,
);
defer image.deinit();
try image.save("page_no_watermark.png");
Objective-C
#import "POXPdfOxide.h"
NSError *err = nil;
POXDocument *doc = [POXDocument openPath:@"layered.pdf" error:&err];
// excludedLayers are the OCG /Names to suppress
POXRenderedImage *image = [doc renderPageWithOptionsEx:0
dpi:200
format:0
bgR:1.0 bgG:1.0 bgB:1.0 bgA:1.0
transparentBackground:0
renderAnnotations:1
jpegQuality:85
excludedLayers:@[@"Watermark", @"Draft Notes"]
error:&err];
[image saveToPath:@"page_no_watermark.png" error:&err];
Elixir
{:ok, doc} = PdfOxide.open("layered.pdf")
# render_page_with_options_ex takes the OCG /Name strings to hide
{:ok, image} =
PdfOxide.render_page_with_options_ex(doc, 0, ["Watermark", "Draft Notes"], dpi: 200)
PdfOxide.save(image, "page_no_watermark.png")
Die C-ABI-Signatur lautet pdf_render_page_with_options_ex(doc, page_index, dpi, format, bg_r, bg_g, bg_b, bg_a, transparent_background, render_annotations, jpeg_quality, excluded_layers, excluded_layers_count, *error_code). Übergeben Sie einen Null-Zeiger für excluded_layers (oder einen Zähler von null), um die Filterung zu deaktivieren — dies entspricht dem einfachen pdf_render_page_with_options.
Wie schätze ich die Rendering-Kosten vor dem Rendern ab?
estimate_render_time gibt eine günstige, implementierungsdefinierte Kostenzahl für eine Seite zurück, damit ein Stapelauftrag Arbeit priorisieren oder einplanen kann, ohne tatsächlich zu rastern. Diese Funktion ist heute über das C-ABI und den Swift-Wrapper verfügbar; das Rust-Crate und die Python-/Go-/Node-Bindungen stellen sie nicht als idiomatische Methode bereit.
Swift
import PdfOxide
let doc = try PdfDocument(path: "document.pdf")
// Implementation-defined cost units — useful for relative comparisons
let cost = try doc.estimateRenderTime(0)
print("Estimated render cost for page 0: \(cost)")
C-ABI: int32_t pdf_estimate_render_time(const void *doc, int32_t page_index, int32_t *error_code).
Abdeckung erweiterter Varianten
| Methode | C-ABI | Rust | Python | Swift |
|---|---|---|---|---|
| Roher RGBA-Puffer | pdf_render_page_raw |
RenderOptions::as_raw() + render_page |
render_pixmap(page, dpi) |
renderPageRaw(_:dpi:) |
| Optionen + OCG-Filter | pdf_render_page_with_options_ex |
RenderOptions.excluded_layers + render_page |
render_page(..., excluded_layers=[...]) |
renderPageWithOptionsEx(...) |
| Rendering-Zeitschätzung | pdf_estimate_render_time |
— | — | estimateRenderTime(_:) |
Python-API
doc.render_page(page, dpi=None, format=None)
Rendert eine Seite in Bild-Bytes.
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
page |
int |
erforderlich | Nullbasierter Seitenindex |
dpi |
int |
72 |
Punkte pro Zoll |
format |
str |
"png" |
Ausgabeformat: "png" oder "jpeg" |
Gibt zurück: bytes — codierte Bilddaten (PNG oder JPEG)
# PNG at default DPI
png = doc.render_page(0)
# High-quality PNG
png = doc.render_page(0, dpi=300)
# JPEG with default quality
jpeg = doc.render_page(0, format="jpeg")
# High-DPI JPEG
jpeg = doc.render_page(0, dpi=300, format="jpeg")
JavaScript-API
doc.renderPage(pageIndex, dpi?)
Rendert eine Seite in PNG-Bytes.
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
pageIndex |
number |
erforderlich | Nullbasierter Seitenindex |
dpi |
number |
150 |
Punkte pro Zoll |
Gibt zurück: Uint8Array — PNG-Bilddaten
const pngBytes = doc.renderPage(0); // 150 DPI default
const hiRes = doc.renderPage(0, 300); // 300 DPI
Häufige Anwendungsfälle
Alle Seiten rendern
use pdf_oxide::PdfDocument;
use pdf_oxide::rendering::{render_page, RenderOptions};
let mut doc = PdfDocument::open("document.pdf")?;
let opts = RenderOptions::with_dpi(200);
for page in 0..doc.page_count()? {
let image = render_page(&mut doc, page, &opts)?;
image.save(format!("page_{}.png", page + 1))?;
}
Python
from pdf_oxide import PdfDocument
from pathlib import Path
doc = PdfDocument("document.pdf")
for i in range(doc.page_count()):
png_bytes = doc.render_page(i, dpi=200)
Path(f"page_{i + 1}.png").write_bytes(png_bytes)
Node.js
const doc = new PdfDocument("document.pdf");
for (let i = 0; i < doc.pageCount(); i++) {
const pngBytes = doc.renderPage(i, "png");
fs.writeFileSync(`page_${i + 1}.png`, Buffer.from(pngBytes));
}
doc.close();
Go
doc, _ := pdfoxide.Open("document.pdf")
defer doc.Close()
pages, _ := doc.PageCount()
for i := 0; i < pages; i++ {
img, _ := doc.RenderPage(i, 0)
os.WriteFile(fmt.Sprintf("page_%d.png", i+1), img.Data, 0644)
}
C#
using var doc = PdfDocument.Open("document.pdf");
for (int i = 0; i < doc.PageCount; i++)
{
var pngBytes = doc.RenderPage(i, 0);
File.WriteAllBytes($"page_{i + 1}.png", pngBytes);
}
Java
try (PdfDocument doc = PdfDocument.open(Path.of("document.pdf"))) {
for (int i = 0; i < doc.pageCount(); i++) {
byte[] png = doc.render(i, 200);
Files.write(Path.of("page_" + (i + 1) + ".png"), png);
}
}
Kotlin
PdfDocument.open(Path.of("document.pdf")).use { doc ->
for (i in 0 until doc.pageCount()) {
val png = doc.render(i, 200)
Files.write(Path.of("page_${i + 1}.png"), png)
}
}
Scala
Using.resource(PdfDocument.open("document.pdf")) { doc =>
for (i <- 0 until doc.pageCount()) {
val png = doc.render(i, 200)
Files.write(Paths.get(s"page_${i + 1}.png"), png)
}
}
Clojure
(with-open [doc (pdf/open "document.pdf")]
(doseq [i (range (pdf/page-count doc))]
(with-open [out (io/output-stream (str "page_" (inc i) ".png"))]
(.write out (pdf/render doc i 200)))))
Ruby
PdfOxide::PdfDocument.open('document.pdf') do |doc|
(0...doc.page_count).each do |i|
File.binwrite("page_#{i + 1}.png", doc.render(i, dpi: 200))
end
end
C++
auto doc = pdf_oxide::Document::open("document.pdf");
for (int i = 0; i < doc.page_count(); i++) {
doc.render_page_with_options(i, /*dpi=*/200, /*format=*/0,
1.0f, 1.0f, 1.0f, 1.0f, false, true, 85)
.save("page_" + std::to_string(i + 1) + ".png");
}
Swift
let doc = try Document.open("document.pdf")
for i in 0..<(try doc.pageCount()) {
let image = try doc.renderPageWithOptions(i, dpi: 200)
try image.save("page_\(i + 1).png")
}
Dart
final doc = PdfDocument.open('document.pdf');
for (var i = 0; i < doc.pageCount; i++) {
doc.renderPageWithOptions(i, dpi: 200).save('page_${i + 1}.png');
}
R
doc <- pdf_open("document.pdf")
for (i in seq_len(pdf_page_count(doc)) - 1L) {
img <- pdf_render_page_with_options(doc, i, dpi = 200L)
pdf_rendered_image_save(img, sprintf("page_%d.png", i + 1))
}
Julia
doc = open_document("document.pdf")
for i in 0:(page_count(doc) - 1)
img = render_page_with_options(doc, i, 200, 0, 1.0, 1.0, 1.0, 1.0, 0, 1, 85)
save(img, "page_$(i + 1).png")
end
Zig
var doc = try pdf_oxide.Document.open("document.pdf");
var i: i32 = 0;
const pages = try doc.pageCount();
while (i < pages) : (i += 1) {
var image = try doc.renderPageWithOptions(a, i, 200, 0, 1.0, 1.0, 1.0, 1.0, false, true, 85);
defer image.deinit();
var buf: [64]u8 = undefined;
const name = try std.fmt.bufPrintZ(&buf, "page_{d}.png", .{i + 1});
try image.save(name);
}
Objective-C
POXDocument *doc = [POXDocument openPath:@"document.pdf" error:&err];
for (NSInteger i = 0; i < [doc pageCountError:&err]; i++) {
POXRenderedImage *image = [doc renderPageWithOptions:i dpi:200 format:0
bgR:1.0 bgG:1.0 bgB:1.0 bgA:1.0
transparentBackground:0 renderAnnotations:1
jpegQuality:85 error:&err];
[image saveToPath:[NSString stringWithFormat:@"page_%ld.png", (long)(i + 1)] error:&err];
}
Elixir
{:ok, doc} = PdfOxide.open("document.pdf")
{:ok, n} = PdfOxide.page_count(doc)
for i <- 0..(n - 1) do
{:ok, image} = PdfOxide.render_page_with_options(doc, i, dpi: 200)
PdfOxide.save(image, "page_#{i + 1}.png")
end
Vorschaubilder erzeugen
use pdf_oxide::rendering::{render_page, RenderOptions};
// Low DPI for fast thumbnail generation
let opts = RenderOptions::with_dpi(72).as_jpeg(75);
let thumb = render_page(&mut doc, 0, &opts)?;
thumb.save("thumbnail.jpg")?;
println!("Thumbnail: {}×{} ({} bytes)", thumb.width, thumb.height, thumb.data.len());
Python
doc = PdfDocument("document.pdf")
thumb = doc.render_page(0, dpi=72, format="jpeg")
Path("thumbnail.jpg").write_bytes(thumb)
Node.js
const doc = new PdfDocument("document.pdf");
const thumb = doc.renderPage(0, "jpeg");
fs.writeFileSync("thumbnail.jpg", Buffer.from(thumb));
doc.close();
Go
doc, _ := pdfoxide.Open("document.pdf")
defer doc.Close()
// RenderThumbnail returns a 72-DPI thumbnail (format 1 = JPEG)
thumb, _ := doc.RenderThumbnail(0, 72, 1)
os.WriteFile("thumbnail.jpg", thumb.Data, 0644)
C#
using var doc = PdfDocument.Open("document.pdf");
// RenderThumbnail returns a 72-DPI thumbnail (format 1 = JPEG)
var thumb = doc.RenderThumbnail(0, 1);
File.WriteAllBytes("thumbnail.jpg", thumb);
Java
try (PdfDocument doc = PdfDocument.open(Path.of("document.pdf"))) {
// Low DPI for fast thumbnail generation (PNG)
byte[] thumb = doc.render(0, 72);
Files.write(Path.of("thumbnail.png"), thumb);
}
Kotlin
PdfDocument.open(Path.of("document.pdf")).use { doc ->
// Low DPI for fast thumbnail generation (PNG)
Files.write(Path.of("thumbnail.png"), doc.render(0, 72))
}
Scala
Using.resource(PdfDocument.open("document.pdf")) { doc =>
// Low DPI for fast thumbnail generation (PNG)
Files.write(Paths.get("thumbnail.png"), doc.render(0, 72))
}
Clojure
(with-open [doc (pdf/open "document.pdf")]
;; Low DPI for fast thumbnail generation (PNG)
(with-open [out (io/output-stream "thumbnail.png")]
(.write out (pdf/render doc 0 72))))
Ruby
PdfOxide::PdfDocument.open('document.pdf') do |doc|
# Low DPI + JPEG (format 1) for fast thumbnail generation
thumb = doc.render_with_layers(0, dpi: 72, format: 1)
File.binwrite('thumbnail.jpg', thumb)
end
C++
auto doc = pdf_oxide::Document::open("document.pdf");
// render_page_thumbnail fits the page within `size` px (format 1 = JPEG)
doc.render_page_thumbnail(0, /*size=*/256, /*format=*/1).save("thumbnail.jpg");
Swift
let doc = try Document.open("document.pdf")
// renderPageThumbnail fits the page within `size` px (format 1 = JPEG)
try doc.renderPageThumbnail(0, size: 256, format: 1).save("thumbnail.jpg")
Dart
final doc = PdfDocument.open('document.pdf');
// renderPageThumbnail fits the page within `size` px (format 1 = JPEG)
doc.renderPageThumbnail(0, 256, 1).save('thumbnail.jpg');
R
doc <- pdf_open("document.pdf")
# pdf_render_page_thumbnail fits the page within `size` px (format 1 = JPEG)
thumb <- pdf_render_page_thumbnail(doc, 0, size = 256L, format = 1L)
pdf_rendered_image_save(thumb, "thumbnail.jpg")
Julia
doc = open_document("document.pdf")
# render_page_thumbnail fits the page within `size` px (format 1 = JPEG)
thumb = render_page_thumbnail(doc, 0, 256, 1)
save(thumb, "thumbnail.jpg")
Zig
var doc = try pdf_oxide.Document.open("document.pdf");
// renderPageThumbnail fits the page within `size` px (format 1 = JPEG)
var thumb = try doc.renderPageThumbnail(a, 0, 256, 1);
defer thumb.deinit();
try thumb.save("thumbnail.jpg");
Objective-C
POXDocument *doc = [POXDocument openPath:@"document.pdf" error:&err];
// renderPageThumbnail fits the page within `size` px (format 1 = JPEG)
POXRenderedImage *thumb = [doc renderPageThumbnail:0 size:256 format:1 error:&err];
[thumb saveToPath:@"thumbnail.jpg" error:&err];
Elixir
{:ok, doc} = PdfOxide.open("document.pdf")
# render_page_thumbnail fits the page within `size` px (format 1 = JPEG)
{:ok, thumb} = PdfOxide.render_page_thumbnail(doc, 0, 256, 1)
PdfOxide.save(thumb, "thumbnail.jpg")
Transparenter Hintergrund für Compositing
let opts = RenderOptions::with_dpi(150).with_transparent_background();
let image = render_page(&mut doc, 0, &opts)?;
image.save("page_transparent.png")?;
Benutzerdefinierte Hintergrundfarbe
let opts = RenderOptions {
dpi: 150,
background: Some([0.95, 0.95, 0.95, 1.0]), // Light gray
..RenderOptions::default()
};
let image = render_page(&mut doc, 0, &opts)?;
Hochqualitative Druckausgabe
// 300 DPI for print-quality output
let opts = RenderOptions::with_dpi(300);
let image = render_page(&mut doc, 0, &opts)?;
image.save("print_quality.png")?;
println!("Image size: {}×{}", image.width, image.height);
PDF in Bilder umwandeln (Flatten)
Konvertiert ein gesamtes PDF in ein flaches bildbasiertes PDF. Jede Seite wird als Rasterbild mit dem angegebenen DPI gerendert und dann zu einem neuen PDF zusammengefügt. Dabei werden alle Annotationen, Formularfelder, Overlays und Schriften dauerhaft eingebrannt.
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("document.pdf")
flattened = doc.flatten_to_images(dpi=150)
with open("flattened.pdf", "wb") as f:
f.write(flattened)
WASM
import { WasmPdfDocument } from "pdf-oxide-wasm";
import { writeFileSync } from "fs";
const doc = new WasmPdfDocument(bytes);
const flattened = doc.flattenToImages(150);
writeFileSync("flattened.pdf", Buffer.from(flattened));
doc.free();
Rust
use pdf_oxide::PdfDocument;
use pdf_oxide::rendering::flatten_to_images;
let mut doc = PdfDocument::open("document.pdf")?;
let flattened = flatten_to_images(&mut doc, 150)?;
std::fs::write("flattened.pdf", flattened)?;
Parameter
| Parameter | Python | JavaScript | Rust | Standard | Beschreibung |
|---|---|---|---|---|---|
| DPI | dpi |
dpi |
dpi |
150 | Renderauflösung für jede Seite |
Gibt zurück: PDF-Datei-Bytes — ein neues PDF, bei dem jede Seite ein ganzseitiges Bild ist.
Anwendungsfälle
- Schwärzung (Redaction) — nach dem Schwärzen abflachen, um versteckte Inhalte dauerhaft zu entfernen
- Archivierung — einen visuellen Schnappschuss erstellen, der in jedem Viewer identisch aussieht
- Einheitliches Rendering — Schrift- und Layoutunterschiede zwischen PDF-Viewern eliminieren
- Druckvorbereitung — komplexe Overlays für zuverlässigen Druck abflachen
- Formulareinreichung — ausgefüllte Formularfeldwerte einbrennen
Mit hoher Qualität abflachen
# 300 DPI for print-quality flattening
flattened = doc.flatten_to_images(dpi=300)
with open("print_ready.pdf", "wb") as f:
f.write(flattened)
Rendering-Pipeline
Der Renderer von PDF Oxide verarbeitet den Seiteninhalts-Stream der Reihe nach:
- Abmessungen — Pixelgröße aus Seitenabmessungen und DPI berechnen (72 Punkte = 1 Zoll)
- Hintergrund — Pixmap mit konfigurierter Hintergrundfarbe erstellen
- Transformation — Koordinatentransformation anwenden (PDF-Ursprung unten links → Bildursprung oben links)
- Inhalts-Stream — Alle PDF-Operatoren parsen und ausführen:
- Pfade — Linien, Kurven, Rechtecke mit Füllung/Kontur
- Text — Positionierter Text mit Schriftauswahl und Zeichenabstand
- Bilder — Eingebettete Rasterbilder (DeviceGray, DeviceRGB, DeviceCMYK)
- Grafikzustand — Transparenz, Mischmodi, Clipping, Linienstile
- Codierung — Als PNG oder JPEG ausgeben
Unterstützte PDF-Operatoren
| Kategorie | Operatoren |
|---|---|
| Grafikzustand | q Q (speichern/wiederherstellen), cm (Transformationsmatrix) |
| Farbe | rg RG g G k K (RGB, Graustufen, CMYK) |
| Pfadkonstruktion | m l c v y re h (bewegen, Linie, Kurve, Rechteck, schließen) |
| Pfadzeichnung | S s f F f* B B* b b* n (Kontur, Füllung, beides) |
| Clipping | W W* (Nicht-Null- und Gerade-Ungerade-Wicklung) |
| Text | BT ET Td TD Tm Tf Tj TJ ' " |
| Bilder | Do (XObjects: Bilder und Formular-XObjects) |
| Erweiterter Zustand | gs (Transparenz ca/CA, Mischmodi BM) |
Häufig gestellte Fragen
In welchem Format liegt der rohe Render-Puffer vor?
Vorgemultiplyiertes RGBA8888, zeilenweise, Ursprung oben links. Die Länge beträgt exakt width * height * 4 Bytes — kein PNG/JPEG-Header, keine Komprimierung. Verwenden Sie diesen, wenn Sie Pixel in eine GPU-Textur oder eine externe Bild-Pipeline einspeisen. In Rust rufen Sie RenderOptions::with_dpi(dpi).as_raw() auf, in Python doc.render_pixmap(page, dpi=...) und in Swift doc.renderPageRaw(page, dpi:).
Kann ich beim Rendern ein Wasserzeichen oder einen anderen Layer ausblenden?
Ja. Übergeben Sie die /Names der optionalen Inhaltsgruppen (OCG), die Sie unterdrücken möchten: render_page(0, excluded_layers=["Watermark"]) in Python, RenderOptions.excluded_layers in Rust oder renderPageWithOptionsEx(... excludedLayers:) in Swift. Der Renderer löst auch OCMD-Referenzen auf diese Gruppen auf.
Warum ist estimate_render_time in Python nicht verfügbar?
In v0.3.69 ist es auf das C-ABI und den Swift-Wrapper beschränkt — das Rust-Crate und die Python-/Go-/Node-Bindungen stellen es nicht bereit. Verwenden Sie die Swift-Methode estimateRenderTime(_:) oder die C-Funktion pdf_estimate_render_time direkt.
Wie schnell ist das Rendering? Der Texterextraktionskern von PDF Oxide läuft auf dem Benchmark-Korpus mit einem Mittelwert von 0,8 ms und einer Erfolgsrate von 100 %; das Rendering verwendet denselben reinen Rust-Parser mit einem prozessweiten Schrift-Cache, sodass wiederholte Rendervorgänge keine erneute Analyse der System-Schriftdatenbank erfordern.
Verwandte Seiten
- Textextraktion — Textinhalt aus Seiten extrahieren
- Bildextraktion — Eingebettete Bilder aus PDFs extrahieren
- OCR gescannter PDFs — OCR verwendet intern das Rendering
- Aus Bildern erstellen — Bilder zurück in PDF konvertieren