graphicx is usually taken for an image package, but the x in its name means “extended”, not “graphics only”. Its \rotatebox, \scalebox, \resizebox and \reflectbox will turn, stretch and mirror anything that fits in a box — a single word, a formula, a whole tabular. The box dimensions, however, do not behave the way you expect. Measured, a 10pt Xg tipped to the right with \rotatebox{-90} comes back as a box of height 0pt and depth 12.50pt: the whole thing hangs below the baseline. That is exactly why a table’s row spacing collapses the moment you stand a header on end. This page walks through the LaTeX commands for rotating and scaling text, along with the two traps that catch people: the dimensions, and the driver.
Not just for images: the four box transforms in graphicx
One line, \usepackage{graphicx}, gives you all four transforms. They fall into two groups: those specified by factor (\scalebox, \reflectbox), those specified by target size (\resizebox), and \rotatebox, specified by angle. \scalebox{0.8}{…} means “0.8 times the original”; \resizebox{5cm}{!}{…} means “make it 5cm wide”. Which one to reach for depends on whether the number you have is a ratio or a measurement. Fitting a figure to the text width calls for the second; nudging a word slightly larger calls for the first.
| Command | What it does | Form |
|---|---|---|
\rotatebox | Turns the content anticlockwise | \rotatebox[origin=c]{45}{...}; degrees, negative for clockwise |
\scalebox | Scales by a factor | \scalebox{2}[1.5]{...}; the optional second argument is the vertical factor |
\reflectbox | Mirrors left to right | \reflectbox{...}; internally identical to \scalebox{-1}[1] |
\resizebox | Scales to a stated finished size | \resizebox{width}{height}{...}; put ! in one slot to keep the aspect ratio |
\rotatebox: degrees, positive means anticlockwise
\rotatebox{angle}{content} puts the content in a box and turns it anticlockwise by the given angle, in degrees. Positive turns left, negative turns right: \rotatebox{90}{...} stands the text up, \rotatebox{-90} tips it the other way. If you would rather write angles in some other unit, the optional key units= takes the number that corresponds to one full turn — units=-360 gives you clockwise degrees, units=6.283185 gives you anticlockwise radians. If the sign convention keeps tripping you up, wrapping it once in a preamble macro is the easy way out.
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}Now the dimensions, which is where most people come unstuck. The width, height and depth of a rotated box are recomputed from the outline of the rotated result. Measure a 10pt Xg (width 12.50pt, height 6.83pt, depth 1.94pt) and \rotatebox{90} returns width 8.78pt, height 12.50pt, depth 0pt — the original height-plus-depth became the new width, and the original width became the new height. \rotatebox{-90} gives the same width but height 0pt and depth 12.50pt, so the entire box sinks below the baseline. \rotatebox{45} comes back 15.05pt wide and 13.67pt tall, larger than the original in both directions. Rotation changes the height of the line — know that, and the sudden gap that opens up right after you add a rotation stops being a mystery.
origin=: writing the brackets changes the default
The centre of rotation is set with the optional argument [origin=…]. Its values are one or two of l (left), r (right), t (top), b (bottom), B (baseline) and c (centre): origin=lb pivots on the bottom-left corner, origin=c on the middle of the box. And here is the wrinkle that confuses everyone who has not met it. Read graphicx.sty and you find that when the optional argument is absent, the centre is (0,0) — the left edge, on the baseline, i.e. the same as origin=lB — whereas the moment you write any key at all, the default flips to the box centre c. Measurement bears it out: \rotatebox{90}{Xg} and \rotatebox[origin=lB]{90}{Xg} agree exactly at width 8.78pt, height 12.50pt, depth 0pt, while \rotatebox[origin=c]{45} at the same 45 degrees splits into height 9.97pt and depth 5.08pt, straddling the baseline. “I only added units= and everything shifted” is almost always this.
Besides origin= there are x= and y=, which give the pivot as explicit lengths. Write \rotatebox[x=1cm,y=1cm]{90}{...} and the centre sits at (1cm, 1cm) measured from the box’s bottom-left corner. That is the tool for the fine adjustments the handful of keywords cannot express.
% 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}Standing a table header on end: narrower, but the row sinks
The most practical use of \rotatebox is to stand long column names on end and win back width. It works: \begin{tabular}{ll}Header&b\\ c&d\end{tabular} measured 60.42pt wide, and rotating Header with \rotatebox{90}{...} brought it down to 36.50pt. There is a price, though. In the same measurement the table’s depth grew from 9.50pt to 20.73pt. The dimensions from the previous section are doing exactly what they said they would: a header stood on end grows downward into the row. Left alone, it starts to collide with the text or the row beneath. The fixes are straightforward — move the pivot with \rotatebox[origin=c]{90}{...}, lift the cell with \raisebox, or reserve the height with a strut such as \rule{0pt}{height}. Getting the table itself onto the page — landscape pages, sidewaystable, columns with declared widths — is the tables pages’ business; see those.
\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}Scaling by a factor and mirroring: \scalebox and \reflectbox
\scalebox{factor}{content} scales both directions equally and so preserves the shape. \scalebox{2}{...} doubles, \scalebox{0.5}{...} halves. To stretch the two directions differently, pass a vertical factor as the optional second argument: \scalebox{horizontal}[vertical]{content}. Measured, \scalebox{2} doubled width, height and depth alike, while \scalebox{1}[2] left the width at 12.50pt and doubled only height and depth. That is how you condense or flatten type — but remember that the stroke weights of the typeface distort along with it, so use it sparingly in running text.
A factor may also be negative, which flips along that axis. \scalebox{-1}[1]{...} is horizontal factor −1 and vertical factor 1 — a left-right mirror. That case is common enough to have its own shorthand, and in graphics.sty \reflectbox is defined as exactly \Gscale@box-1[1]. The measurement agrees: both boxes come out 12.50pt wide, 6.83pt high and 1.94pt deep. \reflectbox is simply an alias for \scalebox{-1}[1]. Mirror half of the palindrome “Able was I ere I saw Elba” and the behaviour of the command becomes obvious at a glance.
\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}Scaling to a target size: \resizebox and the starred \resizebox*
\resizebox{width}{height}{content} scales the content to a stated finished size. Put an exclamation mark ! in one slot and that dimension takes whatever factor the other one implies — the aspect ratio is preserved. \resizebox{\textwidth}{!}{...} is the form you will see most. Inside the dimension arguments you may use \width, \height, \totalheight and \depth, which stand for the content’s own size. Measured, \resizebox{2\width}{!}{Xg} came out identical to \scalebox{2}{Xg} down to the last digit: 25.00pt wide, 13.67pt high, 3.89pt deep.
A point that slips past most people: the height argument of \resizebox is the height, not height-plus-depth. Measure \resizebox{!}{1cm}{Xg} and the height is 28.46pt — near enough 1cm — but a further 8.10pt of depth hangs below it, so the box as a whole exceeds 1cm. When you mean the total height, use the starred \resizebox*. Measured, \resizebox*{!}{1cm}{Xg} gave height 22.15pt and depth 6.30pt, adding to 28.45pt, exactly 1cm. If something you “shrank to 1cm” is still poking out of its line, suspect the missing star.
% 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 = 1cmThe commonest use of \resizebox is to shrink an over-wide table until it fits the text. Wrap the whole tabular in \resizebox{\textwidth}{!}{...} and the width will always come out right. It is a double-edged sword, though, because the type inside the table shrinks with it: a hard reduction leaves letters smaller than the body text — sometimes hard to read — and out of step with their surroundings. Re-specifying a font size for the table afterwards does nothing, since the whole box is scaled at the end anyway. Exactly how much a table shrinks, and how alarmingly a too-narrow table blows up when handed to the same command, is measured in detail on the wide-tables page. The proper first move is to make the table itself fit — adjust column widths, drop columns — and to treat \resizebox as a last resort.
When nothing rotates: a driver that does not match
\rotatebox does not make TeX draw rotated letters. TeX only embeds an instruction — “turn what follows by this angle” — into the output file, and the actual turning is done by the driver downstream. So naming the wrong driver makes the rotation vanish with no error and no warning. Here is the measurement. Compile a document that says \usepackage[dvips]{graphicx} with pdfLaTeX and it finishes cleanly, zero errors — yet the content stream of the resulting PDF contains not a single cm transformation matrix. The text simply sits there straight. Remove the driver option from the same document and the log reports Package graphics Info: Driver file: pdftex.def, while the PDF gains .70709 .70709 -.70709 .70709 0 0 cm — the cosine and sine of 45 degrees.
The conclusion is simple: do not name a driver. pdfLaTeX, XeLaTeX and LuaLaTeX are all detected automatically by graphicx, so writing [dvips] or [pdftex] by hand is precisely how you manufacture a mismatch. The DVI route is the exception. Under latex, graphicx defaults to the dvips driver and the DVI ends up carrying raw PostScript (ps: gsave currentpoint currentpoint translate 45 neg rotate …). dvipdfmx understands enough of those PostScript specials that it does in fact rotate, but the clean path is to say \usepackage[dvipdfmx]{graphicx} explicitly, after which the DVI carries a PDF-flavoured instruction instead: pdf:btrans rotate 45. What a DVI actually hands to its driver is discussed at length on the page about DVI-to-PDF conversion.
adjustbox and max width=: shrink only, never enlarge
The graphicx commands are spare and powerful, but combining them nests deeply. adjustbox, loaded with \usepackage{adjustbox}, is the higher-level alternative that folds them into a single \includegraphics-style key-value interface. \adjustbox{angle=45,scale=0.8}{…} sets rotation (angle=), factor (scale=), target size (width=/height=) and mirroring (reflect) at once, and a matching adjustbox environment exists too. Measured, the box from \adjustbox{angle=45}{Xg} matched \rotatebox{45}{Xg} to the last decimal, so the machinery underneath is the same. What differs is the ease of writing — and the notion of an upper bound, described next.
The really useful key is max width=\textwidth (and max totalheight= and friends). The previous section’s \resizebox{\textwidth}{!}{...} will happily enlarge content that is narrower than the text, whereas max width= is built to shrink only on overflow and to leave anything that already fits alone. Measured: a small one-column tabular 17.00pt wide came through max width=\textwidth still 17.00pt, while handing the same table to \resizebox{\textwidth}{!} stretched it to a full 345.00pt. So if you apply \resizebox to every table out of \includegraphics habit, it is the narrow ones that turn into monsters. Make “shrink when needed, never enlarge” the default — in practice that is the setting that causes the fewest accidents.
\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}%
}