„unoconv“ für einfache Dokumentkonvertierung
Wenn Ihre Anwendung weiterhin auf unoconv angewiesen ist, prüfen Sie zunächst die Python/UNO-Umgebung und konvertieren Sie ein Dokument mit bekanntem Inhalt. Diese Anleitung behandelt einen bestehenden Debian-12-Worker, ein DOCX-Batch-Skript und die nötigen PDF-Prüfungen, bevor Sie dessen Ausgabe akzeptieren.
Unoconv ist veraltet, und sein Repository ist archiviert. Nutzen Sie für neue Implementierungen unoserver. Diese Anleitung dient zur Pflege eines bestehenden unoconv-Ablaufs, während Sie die Migration planen.
Einführung in „unoconv“ und seine Open-Source-Funktionen
Unoconv ist ein Open-Source-Kommandozeilenwerkzeug, das LibreOffice über dessen UNO-Bindings aufruft. LibreOffice stellt die Import- und Exportfilter bereit. Die Installation eines Python-Skripts allein ermöglicht keine Dokumentkonvertierung. Auch Schriftarten beeinflussen das resultierende Layout.
„unoconv“ auf Ihrem System einrichten und installieren
Voraussetzungen
Verwenden Sie einen dedizierten Legacy-Worker mit einer bereits eingerichteten Umgebung und festgelegten
Versionen. Der getestete Worker nutzte Debian 12 Bookworm, das Python 3.11.2 der Distribution,
das passende python3-uno, unoconv 0.7 aus dem Debian-Paket 0.7-2,
LibreOffice Writer 7.4.7.2 und Liberation Sans aus fonts-liberation2.
Diese Versionen wurden für die Wartung bestehender Systeme getestet. Diese Seite empfiehlt nicht,
für eine neue Anwendung einen alten Stack zu installieren.
Der Worker benötigt ein beschreibbares LibreOffice-Benutzerprofil und ein beschreibbares temporäres
Verzeichnis. Führen Sie jeweils nur einen Batch aus, ohne dass eine LibreOffice-Desktop-Sitzung oder
ein gemeinsam genutzter Listener dieses Profil verwendet. Nutzen Sie für die erste Konvertierung
bekannte, vertrauenswürdige DOCX- und ODT-Dokumente. Installieren Sie die Schriftarten Ihrer tatsächlichen
Dokumente, bevor Sie die Seitenaufteilung beurteilen. Die folgenden Prüfkommandos benötigen
poppler-utils von Poppler auf dem Rechner, auf dem Sie die PDFs prüfen.
Das kann der Worker oder ein anderer Rechner mit Zugriff auf dieselben Ausgabedateien sein.
Installation unter Linux (Ubuntu/Debian)
Das Bookworm-Paket von Debian stellt diese ältere
unoconv-Version bereit. Behalten Sie die Python- und UNO-Pakete der Distribution zusammen.
Die folgende Prüfung setzt voraus, dass python3 außerhalb einer virtuellen
Umgebung auf /usr/bin/python3 verweist. Sie prüft jeden Befehl einzeln und stellt vor
der Konvertierung sicher, dass dieser Interpreter UNO importieren kann:
(
for tool in python3 unoconv libreoffice fc-match; do
command -v "$tool" >/dev/null || { printf 'Missing %s\n' "$tool" >&2; exit 1; }
done
python3 -c 'import uno, unohelper; print(uno.__file__)' &&
python3 --version &&
unoconv --version &&
libreoffice --version &&
fc-match -f '%{family}\n' 'Liberation Sans'
)
Auf dem getesteten Worker stammte UNO aus /usr/lib/python3/dist-packages/uno.py. Brechen Sie ab, wenn der
Import fehlschlägt oder die gemeldeten Versionen vom verifizierten Image Ihrer Bereitstellung
abweichen. Dies ist eine Prüfung eines bestehenden Workers, keine Installationsanleitung für
aktuelle Ubuntu- oder Debian-Versionen.
Prüfen Sie auch die PDF-Werkzeuge auf dem Rechner, auf dem Sie die Ausgabe untersuchen werden. Die Prüfungen hier wurden mit Poppler 26.08.0 durchgeführt:
(
for tool in pdfinfo pdftotext pdftoppm; do
command -v "$tool" >/dev/null || { printf 'Missing %s\n' "$tool" >&2; exit 1; }
done
pdfinfo -v
)
Installation unter macOS
Homebrew führt unoconv als deaktiviert. Die Installation von LibreOffice allein stellt keine funktionierende Kombination aus unoconv und Python sicher. Diese Anleitung verifiziert keine macOS-Installation. Nutzen Sie beim Wechsel von einem älteren macOS-Worker die Installationsanleitung des gepflegten Nachfolgers.
Installation unter Windows
Native Windows- und WSL-Installationen liegen außerhalb des getesteten Umfangs dieser Anleitung. WSL stellt nicht selbst das passende Python, die UNO-Bindings, Schriftarten oder LibreOffice-Filter bereit. Betrachten Sie einen Wechsel zu WSL nicht als Lösung für eine unverifizierte Umgebung.
Schritt für Schritt: Dokumente von docx in PDF konvertieren
Legen Sie ein bekanntes DOCX-Dokument unter document.docx und ein bekanntes
ODT-Dokument unter notes.odt in einem Arbeitsverzeichnis ab.
Notieren Sie die erwarteten Seitenzahlen, Überschriften, Schlussabsätze sowie Tabellen oder Grafiken.
Diese direkten Befehle schreiben document.pdf und notes.pdf
neben die Eingabedateien und können bestehende PDFs ersetzen. Nutzen Sie daher ein Verzeichnis,
in dem diese Zieldateien noch nicht existieren:
unoconv -f pdf ./document.docx &&
unoconv -f pdf ./notes.odt
Prüfen Sie das DOCX-Ergebnis mit diesen Befehlen. Sie schreiben document.txt und
nummerierte PNG-Dateien wie document-page-1.png. Eine erneute Prüfung ersetzt diese
Prüfdateien:
pdfinfo -box ./document.pdf &&
pdftotext -layout ./document.pdf ./document.txt &&
pdftoppm -cropbox -r 96 -png ./document.pdf ./document-page
Vergleichen Sie die Seitenzahl und den extrahierten Text mit dem Quelldokument, einschließlich des
letzten Absatzes jeder Seite. Öffnen Sie jedes gerenderte PNG und prüfen Sie Tabellen, Grafiken,
Ränder und Seitenumbrüche. Das Rendern der CropBox zeigt die sichtbare Seite, sodass Inhalte außerhalb
dieses Bereichs ein Problem mit abgeschnittenen Inhalten nicht verdecken können. Wiederholen Sie
die Prüfung für notes.pdf mit notes.txt und dem Präfix
notes-page. Eine nicht leere Datei, eine PDF-Signatur oder ein erfolgreich
abgeschlossener Befehl beweist nicht, dass das richtige Dokument vollständig konvertiert wurde.
Dokumentkonvertierung mit Skripten automatisieren
Speichern Sie dies als convert_documents.py, um auf dieser funktionierenden Installation
einen sequenziellen DOCX-Batch auszuführen. Das Skript wählt reguläre Dateien mit der Endung
.docx unabhängig von der Groß- und Kleinschreibung aus, überspringt
Verzeichnisse und symbolische Links und erfordert ein neues Ausgabeverzeichnis. Seine einfache
Archivprüfung erkennt sowohl die Transitional- als auch die Strict-OOXML-Namespaces für das
Hauptdokument. Sie ist kein vollständiger OOXML-Schemavalidator.
import os
from pathlib import Path
import posixpath
import subprocess
import sys
from tempfile import TemporaryDirectory
from urllib.parse import unquote
from xml.etree import ElementTree
from zipfile import BadZipFile, ZipFile
import zlib
def check_docx(path):
relationship_types = {
'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument',
'http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument',
}
document_tags = {
'{http://schemas.openxmlformats.org/wordprocessingml/2006/main}document',
'{http://purl.oclc.org/ooxml/wordprocessingml/main}document',
}
with ZipFile(path) as archive:
if archive.testzip() is not None:
raise ValueError('Damaged DOCX member')
relationships = ElementTree.fromstring(archive.read('_rels/.rels'))
main_parts = [item for item in relationships
if item.get('Type') in relationship_types
and item.get('TargetMode', 'Internal') == 'Internal']
if len(main_parts) != 1:
raise ValueError('Missing main document relationship')
part = posixpath.normpath(unquote(main_parts[0].get('Target', '')).lstrip('/'))
types = ElementTree.fromstring(archive.read('[Content_Types].xml'))
content_type = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml'
if not any(item.get('PartName') == '/' + part
and item.get('ContentType') == content_type for item in types):
raise ValueError('Not a DOCX main part')
if ElementTree.fromstring(archive.read(part)).tag not in document_tags:
raise ValueError('Not a Word document')
def convert_documents(input_dir, output_dir):
source = Path(input_dir).resolve(strict=True)
files = sorted(path for path in source.iterdir()
if not path.is_symlink() and path.is_file()
and path.suffix.lower() == '.docx')
if not files:
print('No DOCX files found', file=sys.stderr)
return 1
output = Path(output_dir).absolute()
output.mkdir(mode=0o700)
failures = 0
for path in files:
try:
check_docx(path)
with TemporaryDirectory(prefix='.conversion-', dir=output) as temporary:
candidate = Path(temporary) / 'result.pdf'
subprocess.run(
['unoconv', '-f', 'pdf', '-o', str(candidate), str(path)],
check=True, timeout=120,
)
if not candidate.is_file() or candidate.stat().st_size == 0:
raise ValueError('No nonempty PDF was produced')
# Hard-link publication fails instead of replacing a destination that appeared.
os.link(candidate, output / (path.stem + '.pdf'))
print(f'Converted {path.name}')
except (OSError, ValueError, KeyError, BadZipFile, ElementTree.ParseError,
zlib.error, NotImplementedError, RuntimeError, subprocess.SubprocessError):
failures += 1
print(f'Conversion failed: {path.name}', file=sys.stderr)
return 1 if failures else 0
if __name__ == '__main__':
if len(sys.argv) != 3:
sys.exit('Usage: python3 convert_documents.py <input-directory> <new-output-directory>')
try:
sys.exit(convert_documents(sys.argv[1], sys.argv[2]))
except (OSError, ValueError):
sys.exit('Cannot prepare conversion directories; use an existing input and a new output directory')
Führen Sie es aus, wenn Ihre DOCX-Dateien in docs liegen und das Verzeichnis
new-pdfs noch nicht existiert:
python3 convert_documents.py docs new-pdfs
Das Skript versucht nach einem Fehler auch die nachfolgenden Dateien zu konvertieren und gibt Status 1 zurück, wenn eine Datei fehlschlägt. Es meldet den betroffenen Dateinamen, entfernt temporäre Kandidaten und erhält bestehende Zieldateien, auch bei Kollisionen durch gleiche Basisnamen. Erfolgreich erstellte PDFs bleiben verfügbar, wenn eine andere Datei fehlschlägt. Prüfen Sie sie vor der Verwendung mit den oben beschriebenen Text- und Rendering-Prüfungen. Die Bereitstellung bedeutet lediglich, dass der Konverter erfolgreich zurückgekehrt ist und einen nicht leeren Kandidaten produziert hat.
Behalten Sie für einen erneuten Versuch die bereits bereitgestellten PDFs und nutzen Sie ein weiteres neues Ausgabeverzeichnis. Eine leere Auswahl gibt Status 1 zurück, ohne das Ausgabeverzeichnis zu erstellen. Das Zeitlimit von 120 Sekunden begrenzt jeden Client-Prozess. Es garantiert nicht, dass LibreOffice seine Arbeit beendet hat. Ein unterbrochener Worker kann Staging-Verzeichnisse hinterlassen. Prüfen Sie daher vor einem erneuten Versuch den Speicher, der diesem Worker zugeordnet ist. Dieses Skript ist für einen vertrauenswürdigen lokalen Batch gedacht, nicht für einen Endpunkt für nicht vertrauenswürdige Uploads. Ein solcher Worker benötigt eine eigene Prozessüberwachung, Ressourcenlimits und Dateisystemisolierung.
Häufige Probleme beheben
Konflikte zwischen Python-Versionen
Wenn die UNO-Importprüfung fehlschlägt, prüfen Sie, welches Python ausgeführt wird und ob es zur installierten UNO-Bridge passt. Das Projekt dokumentiert diese Interpreter-Anforderung. Eine beliebige virtuelle Umgebung reicht nicht aus: Eine standardmäßige venv blendet das UNO-Modul der Distribution aus. Allein ein Wechsel der Python-Version installiert keine passende Bridge.
Kompatibilität der LibreOffice-Version
Das getestete unoconv aus Debian gibt unter Python 3.11 eine Warnung zum veralteten Modul
distutils aus. Auch nach erfolgreicher Konvertierung müssen Sie die tatsächlichen
PDFs prüfen. Behalten Sie die verifizierte Kombination aus Python, UNO und LibreOffice in Ihrem
Legacy-Image bei. Wenn die Konvertierung eines Dokuments fehlschlägt, versuchen Sie, dasselbe Dokument
in LibreOffice zu öffnen und zu exportieren. So können Sie ein Import- oder Exportproblem von einem
Problem im unoconv-Client unterscheiden.
Hinweise zur Bereitstellung in Containern
Ein Container muss für seinen Konvertierungsbenutzer beschreibbare Profil-, Cache-, Daten-, Laufzeit-
und temporäre Verzeichnisse bereitstellen. Erstellen Sie diese Verzeichnisse vor dem Start von
LibreOffice, wenn Sie XDG_CONFIG_HOME, XDG_CACHE_HOME,
XDG_DATA_HOME oder XDG_RUNTIME_DIR setzen. Ein fehlendes beschreibbares
Profil kann den Start schon vor der Dokumentkonvertierung verhindern. Führen Sie Jobs sequenziell aus
und stoppen Sie den gesamten zugehörigen Worker, wenn ein Client sein Zeitlimit überschreitet.
Das Beenden allein des Clients beweist nicht, dass die Umgebung bereinigt wurde.
Moderne Alternativen im Vergleich
| Bereitstellung | Wahl |
|---|---|
| Bestehender Legacy-Worker mit festgelegten Versionen | unoconv weiter pflegen und dabei repräsentative Dokumente testen. |
| Neue Bereitstellung | unoserver verwenden. |
Unoserver (empfohlen)
Unoserver trennt einen dauerhaft laufenden LibreOffice-Worker von seinem Konvertierungsclient. Der Server benötigt weiterhin einen Python-Interpreter, der UNO importieren kann. Diese Abhängigkeit entfällt dadurch nicht. Folgen Sie der Installationsanleitung für unoserver und lesen Sie anschließend Dokumentkonvertierung mit Rust für die gepflegte Integration. Die Tests auf dieser Seite decken unoconv ab, nicht diesen separaten Serverablauf.
LibreOffice-Kommandozeile
Für eine einmalige Konvertierung bietet LibreOffice auch eine
Exportoption für die Kommandozeile.
Auf dem getesteten Debian-Worker schreibt dieser Befehl document.pdf in das aktuelle
Verzeichnis:
libreoffice --headless --convert-to pdf ./document.docx
Verwenden Sie eine Zieldatei, die noch nicht existiert, und führen Sie dieselbe PDF-Prüfung durch. LibreOffice kann eine bestehende PDF-Datei ersetzen, und ein Exit-Status allein gibt keinen Aufschluss über den resultierenden Inhalt. Dieser Weg umgeht den unoconv-Client, nutzt aber weiterhin die Filter und Schriftarten von LibreOffice.
Cloudbasierte Lösungen
Wenn Sie eine API-Schnittstelle bevorzugen, statt einen Office-Worker zu betreiben, evaluieren Sie den Dienst zur Dokumentkonvertierung von Transloadit mit Ihren repräsentativen Dokumenten. Dies ist eine separate Integration. Die lokalen Befehle oben testen keinen gehosteten Dienst.
