Text transformieren

graphicx gilt gemeinhin als Bildpaket, doch das x im Namen steht für „erweitert“, nicht für „nur Grafik“. Seine Befehle \rotatebox, \scalebox, \resizebox und \reflectbox drehen, dehnen und spiegeln alles, was in eine Box passt – ein einzelnes Wort, eine Formel, eine ganze tabular. Die Boxmaße verhalten sich allerdings nicht wie erwartet. Gemessen ergibt ein 10pt großes Xg, mit \rotatebox{-90} nach rechts gekippt, eine Box mit Höhe 0pt und Tiefe 12,50pt: Das Ganze hängt unter der Grundlinie. Genau deshalb bricht der Zeilenabstand einer Tabelle zusammen, sobald eine Kopfzeile hochkant steht. Diese Seite führt durch die LaTeX-Befehle zum Drehen und Skalieren von Text und durch die zwei Fallen, die dabei zuschnappen: die Maße und der Treiber.

Nicht nur für Bilder: die vier Boxtransformationen in graphicx

Eine Zeile, \usepackage{graphicx}, stellt alle vier Transformationen bereit. Sie zerfallen in zwei Gruppen: die über einen Faktor gesteuerten (\scalebox, \reflectbox), die über eine Zielgröße gesteuerte (\resizebox) und \rotatebox, das über einen Winkel gesteuert wird. \scalebox{0.8}{…} heißt „das 0,8-Fache des Originals“, \resizebox{5cm}{!}{…} heißt „mach es 5 cm breit“. Welchen Befehl man wählt, hängt davon ab, ob die vorliegende Zahl ein Verhältnis oder ein Maß ist. Eine Abbildung auf die Textbreite zu bringen verlangt den zweiten, ein Wort ein wenig zu vergrößern den ersten.

BefehlWirkungForm
\rotateboxDreht den Inhalt gegen den Uhrzeigersinn\rotatebox[origin=c]{45}{...}; Grad, negativ im Uhrzeigersinn
\scaleboxSkaliert um einen Faktor\scalebox{2}[1.5]{...}; das optionale zweite Argument ist der vertikale Faktor
\reflectboxSpiegelt von links nach rechts\reflectbox{...}; intern identisch mit \scalebox{-1}[1]
\resizeboxSkaliert auf eine angegebene Endgröße\resizebox{Breite}{Höhe}{...}; ein ! in einem Feld erhält das Seitenverhältnis

\rotatebox: Grad, positiv bedeutet gegen den Uhrzeigersinn

\rotatebox{Winkel}{Inhalt} steckt den Inhalt in eine Box und dreht ihn gegen den Uhrzeigersinn um den angegebenen Winkel in Grad. Positiv dreht nach links, negativ nach rechts: \rotatebox{90}{...} stellt den Text auf, \rotatebox{-90} kippt ihn zur anderen Seite. Wer Winkel in einer anderen Einheit schreiben möchte, nutzt den optionalen Schlüssel units=, der die Zahl für eine volle Umdrehung erwartet – units=-360 ergibt Grad im Uhrzeigersinn, units=6.283185 ergibt Bogenmaß gegen den Uhrzeigersinn. Wenn das Vorzeichen immer wieder stört, verpackt man die Angabe am besten einmal in einem Makro in der Präambel.

latex
This is \rotatebox{45}{slanted text} in a line of prose.

% clockwise degrees instead of the default anticlockwise:
\rotatebox[units=-360]{90}{tipped to the right}

Nun zu den Maßen – dort scheitern die meisten. Breite, Höhe und Tiefe einer gedrehten Box werden aus dem Umriss des gedrehten Ergebnisses neu berechnet. Misst man ein 10pt großes Xg (Breite 12,50pt, Höhe 6,83pt, Tiefe 1,94pt), liefert \rotatebox{90} Breite 8,78pt, Höhe 12,50pt, Tiefe 0pt: Aus Höhe plus Tiefe wurde die neue Breite, aus der alten Breite die neue Höhe. \rotatebox{-90} ergibt dieselbe Breite, aber Höhe 0pt und Tiefe 12,50pt, die ganze Box sinkt also unter die Grundlinie. \rotatebox{45} kommt mit 15,05pt Breite und 13,67pt Höhe zurück, in beiden Richtungen größer als das Original. Drehen verändert die Zeilenhöhe – wer das weiß, wundert sich nicht mehr über den plötzlich aufgehenden Durchschuss direkt nach einer Drehung.

origin=: Sobald die Klammern dastehen, ändert sich die Vorgabe

Das Drehzentrum wird über das optionale Argument [origin=…] gesetzt. Als Werte dienen ein oder zwei Buchstaben aus l (links), r (rechts), t (oben), b (unten), B (Grundlinie) und c (Mitte): origin=lb dreht um die linke untere Ecke, origin=c um die Boxmitte. Und hier lauert die Feinheit, die jeden verwirrt, der sie nicht kennt. Ein Blick in graphicx.sty zeigt: Fehlt das optionale Argument ganz, liegt das Zentrum bei (0,0) – linker Rand, auf der Grundlinie, also wie origin=lB; sobald aber irgendein Schlüssel geschrieben wird, springt die Vorgabe auf die Boxmitte c. Die Messung bestätigt es: \rotatebox{90}{Xg} und \rotatebox[origin=lB]{90}{Xg} stimmen mit Breite 8,78pt, Höhe 12,50pt und Tiefe 0pt exakt überein, während \rotatebox[origin=c]{45} bei denselben 45 Grad in Höhe 9,97pt und Tiefe 5,08pt zerfällt und die Grundlinie überspannt. „Ich habe nur units= ergänzt und alles hat sich verschoben“ – fast immer steckt das dahinter.

Neben origin= gibt es x= und y=, die den Drehpunkt als ausdrückliche Längen angeben. Schreibt man \rotatebox[x=1cm,y=1cm]{90}{...}, liegt das Zentrum bei (1 cm, 1 cm), gemessen von der linken unteren Ecke der Box. Das ist das Werkzeug für Feinjustierungen, die sich mit den wenigen Schlüsselwörtern nicht ausdrücken lassen.

latex
% no optional argument: the pivot is the left edge on the baseline (= origin=lB)
\rotatebox{90}{upright}

% ANY key present: the default pivot becomes the box centre (origin=c)
\rotatebox[origin=c]{180}{upside down}
\rotatebox[x=1cm,y=1cm]{90}{pivot given as a length}

Eine Tabellenüberschrift hochkant: schmaler, aber die Zeile sackt ab

Der praktischste Einsatz von \rotatebox ist, lange Spaltennamen hochkant zu stellen und so Breite zurückzugewinnen. Es funktioniert: \begin{tabular}{ll}Header&b\\ c&d\end{tabular} maß 60,42pt in der Breite, und mit \rotatebox{90}{...} um Header schrumpfte sie auf 36,50pt. Es hat allerdings seinen Preis. In derselben Messung wuchs die Tiefe der Tabelle von 9,50pt auf 20,73pt. Die Maße aus dem vorigen Abschnitt tun genau das, was sie angekündigt haben: Eine hochkant gestellte Überschrift wächst nach unten in die Zeile hinein. Unbehandelt kollidiert sie bald mit dem Text oder der Zeile darunter. Die Abhilfen sind naheliegend – den Drehpunkt mit \rotatebox[origin=c]{90}{...} verschieben, die Zelle mit \raisebox anheben oder die Höhe mit einer Stütze wie \rule{0pt}{Höhe} reservieren. Wie die Tabelle selbst aufs Papier kommt – Querformatseiten, sidewaystable, Spalten mit erklärter Breite –, gehört zu den Tabellenseiten; dort steht es.

latex
\begin{tabular}{lrr}
  % rotating the pivot to the centre keeps the row from sinking
  & \rotatebox[origin=c]{90}{Measured} & \rotatebox[origin=c]{90}{Predicted} \\
  \hline
  Sample A & 12.4 & 12.1 \\
  Sample B & 9.8  & 10.0 \\
\end{tabular}

Skalieren per Faktor und Spiegeln: \scalebox und \reflectbox

\scalebox{Faktor}{Inhalt} skaliert beide Richtungen gleich und erhält damit die Form. \scalebox{2}{...} verdoppelt, \scalebox{0.5}{...} halbiert. Sollen die Richtungen unterschiedlich gedehnt werden, übergibt man einen vertikalen Faktor als optionales zweites Argument: \scalebox{horizontal}[vertikal]{Inhalt}. Gemessen verdoppelte \scalebox{2} Breite, Höhe und Tiefe gleichermaßen, während \scalebox{1}[2] die Breite bei 12,50pt beließ und nur Höhe und Tiefe verdoppelte. So lässt sich Schrift schmal oder flach machen – doch die Strichstärken der Schrift verzerren sich mit, weshalb man das im Fließtext sparsam einsetzt.

Ein Faktor darf auch negativ sein, was entlang dieser Achse spiegelt. \scalebox{-1}[1]{...} bedeutet horizontaler Faktor −1 und vertikaler Faktor 1, also eine Links-rechts-Spiegelung. Dieser Fall kommt oft genug vor, um eine eigene Kurzform zu haben: In graphics.sty ist \reflectbox als genau \Gscale@box-1[1] definiert. Die Messung bestätigt es – beide Boxen sind 12,50pt breit, 6,83pt hoch und 1,94pt tief. \reflectbox ist also schlicht ein Alias für \scalebox{-1}[1]. Spiegelt man die Hälfte des Palindroms „Able was I ere I saw Elba“, wird das Verhalten des Befehls auf einen Blick klar.

latex
\scalebox{2}{bigger}\quad\scalebox{0.5}{smaller}\quad\scalebox{1}[2]{stretched}

% \reflectbox is literally \scalebox{-1}[1]
Able was I \reflectbox{Able was I}

Auf eine Zielgröße skalieren: \resizebox und das gesternte \resizebox*

\resizebox{Breite}{Höhe}{Inhalt} skaliert den Inhalt auf eine angegebene Endgröße. Ein Ausrufezeichen ! in einem der Felder übernimmt für diese Richtung den Faktor der anderen – das Seitenverhältnis bleibt erhalten. \resizebox{\textwidth}{!}{...} ist die verbreitetste Form. In den Maßargumenten dürfen \width, \height, \totalheight und \depth stehen, die die ursprüngliche Größe des Inhalts bezeichnen. Gemessen fiel \resizebox{2\width}{!}{Xg} bis auf die letzte Stelle mit \scalebox{2}{Xg} zusammen: 25,00pt breit, 13,67pt hoch, 3,89pt tief.

Ein Punkt, der den meisten entgeht: Das Höhenargument von \resizebox meint die Höhe, nicht Höhe plus Tiefe. Misst man \resizebox{!}{1cm}{Xg}, beträgt die Höhe 28,46pt – also nahezu 1 cm –, doch darunter hängen weitere 8,10pt Tiefe, sodass die Box insgesamt über 1 cm hinausgeht. Ist die Gesamthöhe gemeint, nimmt man das gesternte \resizebox*. Gemessen ergab \resizebox*{!}{1cm}{Xg} eine Höhe von 22,15pt und eine Tiefe von 6,30pt, zusammen 28,45pt – genau 1 cm. Wenn etwas, das „auf 1 cm verkleinert“ wurde, immer noch aus der Zeile ragt, ist der fehlende Stern der Verdächtige.

latex
% twice the original width, aspect ratio kept
\resizebox{2\width}{!}{double width}

% height only vs. height+depth
\resizebox{!}{1cm}{Tall}      % height = 1cm, depth hangs below
\resizebox*{!}{1cm}{Tall}     % height + depth = 1cm

Die häufigste Verwendung von \resizebox ist, eine zu breite Tabelle so weit zu verkleinern, bis sie in den Satzspiegel passt. Man umschließt die ganze tabular mit \resizebox{\textwidth}{!}{...}, und die Breite stimmt garantiert. Es ist jedoch ein zweischneidiges Schwert, denn die Schrift in der Tabelle schrumpft mit: Bei starker Verkleinerung werden die Buchstaben kleiner als der Fließtext, manchmal schwer lesbar, und passen nicht mehr zur Umgebung. Eine nachträgliche Schriftgrößenangabe für die Tabelle bringt nichts, weil am Ende ohnehin die ganze Box skaliert wird. Wie stark eine Tabelle schrumpft und wie beunruhigend eine zu schmale Tabelle von demselben Befehl aufgeblasen wird, ist auf der Seite zu breiten Tabellen mit Messwerten behandelt. Der richtige erste Schritt ist, die Tabelle selbst passend zu machen – Spaltenbreiten anpassen, Spalten streichen – und \resizebox als letzte Möglichkeit zu betrachten.

Nichts dreht sich: ein Treiber, der nicht passt

\rotatebox lässt TeX die Buchstaben nicht selbst gedreht zeichnen. TeX bettet lediglich eine Anweisung in die Ausgabedatei ein – „drehe das Folgende um diesen Winkel“ –, und gedreht wird tatsächlich vom nachgelagerten Treiber. Deshalb verschwindet die Drehung bei falsch benanntem Treiber ohne Fehler und ohne Warnung. Hier die Messung: Ein Dokument mit \usepackage[dvips]{graphicx}, mit pdfLaTeX übersetzt, läuft sauber durch, null Fehler – doch der Inhaltsstrom des entstandenen PDF enthält keine einzige Transformationsmatrix cm. Der Text steht schlicht gerade da. Entfernt man die Treiberoption aus demselben Dokument, meldet das Log Package graphics Info: Driver file: pdftex.def, und im PDF erscheint .70709 .70709 -.70709 .70709 0 0 cm – Kosinus und Sinus von 45 Grad.

Der Schluss ist einfach: keinen Treiber angeben. pdfLaTeX, XeLaTeX und LuaLaTeX erkennt graphicx von selbst; [dvips] oder [pdftex] von Hand zu schreiben ist genau die Art, wie man ein Missverhältnis herstellt. Ausnahme ist der DVI-Weg: Unter latex verwendet graphicx standardmäßig den Treiber dvips, und im DVI landet rohes PostScript (ps: gsave currentpoint currentpoint translate 45 neg rotate …). dvipdfmx versteht von diesen PostScript-Specials genug, um tatsächlich zu drehen, doch der saubere Weg ist die ausdrückliche Angabe \usepackage[dvipdfmx]{graphicx}; dann trägt das DVI stattdessen eine PDF-nahe Anweisung: pdf:btrans rotate 45. Was ein DVI seinem Treiber überhaupt übergibt, behandelt ausführlich die Seite zur DVI-nach-PDF-Umwandlung.

adjustbox und max width=: nur verkleinern, nie vergrößern

Die graphicx-Befehle sind schlicht und mächtig, doch kombiniert verschachteln sie sich tief. adjustbox, geladen mit \usepackage{adjustbox}, ist die höherwertige Alternative, die sie in eine einzige Schlüssel-Wert-Schnittstelle nach Art von \includegraphics bündelt. \adjustbox{angle=45,scale=0.8}{…} setzt Drehung (angle=), Faktor (scale=), Zielgröße (width=/height=) und Spiegelung (reflect) auf einmal; eine gleichnamige Umgebung adjustbox gibt es ebenfalls. Gemessen stimmte die Box aus \adjustbox{angle=45}{Xg} bis auf die letzte Stelle mit \rotatebox{45}{Xg} überein – darunter arbeitet also dieselbe Mechanik. Der Unterschied liegt in der Schreibweise und in der gleich beschriebenen Idee einer Obergrenze.

Wirklich nützlich ist der Schlüssel max width=\textwidth (und max totalheight= und Ähnliche). Das \resizebox{\textwidth}{!}{...} aus dem vorigen Abschnitt vergrößert bereitwillig Inhalte, die schmaler als der Text sind; max width= dagegen verkleinert nur bei Überlauf und lässt alles Passende unangetastet. Gemessen: Eine kleine einspaltige tabular von 17,00pt Breite kam durch max width=\textwidth weiterhin mit 17,00pt heraus, während dieselbe Tabelle über \resizebox{\textwidth}{!} auf volle 345,00pt gedehnt wurde. Wer also aus \includegraphics-Gewohnheit jede Tabelle in \resizebox steckt, verwandelt gerade die schmalen in Ungetüme. Man mache „nur bei Bedarf verkleinern, nie vergrößern“ zur Voreinstellung – in der Praxis passieren damit die wenigsten Unfälle.

latex
\usepackage{adjustbox}
% ...
\adjustbox{angle=45,scale=0.8}{rotate and scale in one go}

% shrinks only when the content overflows; leaves narrow tables alone
\adjustbox{max width=\textwidth}{%
  \begin{tabular}{lrr} ... \end{tabular}%
}