Scale (resize) large images (graphics) that exceed page margins

Background

A large number of screen captures have been scaled 300% at 288dpi. They appear correctly when embedded in OpenOffice, but not LyX.

Problem

Images that do not extend beyond the margins (small images) appear perfectly. Images that are too big extend beyond the margins.

Attempt #1

\setkeys{Gin}{width=1.0\textwidth}


However, that code scales the smaller images to also fit the width, which is undesirable. (The smaller images become distorted.)

Attempt #2

Didn't attempt this, but it looks useful.

% Redefine includgraphics for avoiding images larger than the screen size
% If the size is not specified.
\let\py@Oldincludegraphics\includegraphics

\newbox\image@box%
\newdimen\image@width%
\renewcommand\includegraphics[2][\@empty]{%
\ifx#1\@empty%
\setbox\image@box=\hbox{\py@Oldincludegraphics{#2}}%
\image@width\wd\image@box%
\ifdim \image@width>\linewidth%
\setbox\image@box=\hbox{\py@Oldincludegraphics[width=\linewidth]{#2}}%
\box\image@box%
\else%
\py@Oldincludegraphics{#2}%
\fi%
\else%
\py@Oldincludegraphics[#1]{#2}%
\fi%
}


Attempt #3

% Resize figures that are too wide for the page
\let\oldincludegraphics\includegraphics
\renewcommand\includegraphics[2][]{%
\makeatletter%
\def\maxwidth{\ifdim\Ginnatwidth>\linewidth\linewidth%
\else\Ginnatwidth\fi}%
\makeatother%
\oldincludegraphics[width=\maxwidth]{#2}%


Packages

Using graphicx.

Other package suggestions are welcome.

Question

Without adding LaTeX code to every image that exceeds the margins, what can be done to resize just those images that are too big?

Example

The following image is an example of many, many images that must be scaled back to fit the page width:

Related

-
Please reconsider accepting Martin's answer. It offers the desired functionality in a nice package and then some. – krlmlr Jun 21 '12 at 8:10

Using the adjustbox package with the export option which extends graphicx with several new keys you can now simply use the max width key which scales the image down to that width if it is larger but doesn't scale it at all if it is smaller the equal to it. There are also the related keys max height, max size (for both width and height) as well as min width, min height and min size.

In your case simply use the following code:

\includegraphics[max width=\linewidth]{<image file name>}


Note that you can't set max width etc. in a global way using \setkeys{Gin}{max width=...}. It is implemented in a different way as width. However, I'm planning to add a possibility for this as well.

-
Exactly what I was looking for. Once more -- thank you for packaging this! – krlmlr Jun 21 '12 at 8:08

Solution

1. Define a macro that calculates whether the image is wider than \linewidth.
2. If the image is too wide then assign a value of \linewidth to the macro.
3. Otherwise, assign the value of the graphic input's natural width (\Gin@nat@width).
4. Redefine \includegraphics to leverage the new macro definition.
\usepackage{graphicx}

% Determine if the image is too wide for the page.
\makeatletter
\def\ScaleIfNeeded{%
\ifdim\Gin@nat@width>\linewidth
\linewidth
\else
\Gin@nat@width
\fi
}
\makeatother

% Resize figures that are too wide for the page.
\let\oldincludegraphics\includegraphics
\renewcommand\includegraphics[2][]{%
\oldincludegraphics[width=\ScaleIfNeeded]{#2}
}


Source

-
Ah! Guten.Ich fühle mich gut. That is basically the solution that I proposed in my comment below. I just didn't think of using the renewcommand structure as above. Danke. – bev Nov 28 '10 at 9:10
This does have the effect of ignoring any optional arguments that are passed to \includegraphics. – TH. Nov 28 '10 at 11:38
Good answer, but you don't need to redefine \includegraphics but you can set the default width using \setkeys{Gin}{width=\ScaleIfNeeded} in the preamble. And if you redefine it please pass the optional argument along! – Martin Scharrer Mar 2 '11 at 14:28
Thanks for the idea. I added a max width option to \includegraphics over the adjustbox package now (CTAN release pending). Here it can be used as \includegraphics[max width=\linewidth]{image}. – Martin Scharrer Jul 4 '11 at 11:24
i assume the (broken) link to l2picfaq would give us the same thing as at ctan:info/l2picfaq/german -- anyone know? – wasteofspace Oct 27 '11 at 19:24

I don't use Lyx, but many people in my lab do, and come to me with all sorts of problems created by Lyx. All of the Lyx-created problems I've seen can only be fixed by editing the latex code manually. YMMV.

This should fix it (you'll need

\usepackage{ifthen}

\ifthenelse{\lengthtest{Gin > \textwidth}}
{\setkeys{Gin}{width=1.0\textwidth}}{\relax}

-
A few errors: Missing number, treated as zero. Illegal unit of measure. Missing = inserted for \ifdem. Thanks for the effort! – Dave Jarvis Nov 28 '10 at 2:35
@Dave - (sigh) you're right, Dave. Teach me to wing it without checking. For some reason, at the time it seemed simple. I've just spend an hour looking into it deeper, and all I can say is that I'm sorry that I wasted your time. On the plus side, I know the graphicx and graphics package much better than 60 mins ago. The problem, as I see it now, it that the internal variable \Gin@nat@width is set by subtracting the the \Gin@llx from \Gin@urx. So it seems a simple matter to compare that the \textwidth using \lengthtest, but, this has to be done after \includegraphics is called --> – bev Nov 28 '10 at 4:39
-->**cont** . So I tried \ifthenelse{1=1}{\def\blah{[width=3in]}{\def\blah{[width=5in]}} then \expandafter\includegraphics\blah{mypic} just to see whether I could put a cs into the space where the optional keyval pairs go. So that worked, but now I'm stuck :-) . What I really want to do is \def\blah{\makeatletter\ifthenelse{\lengthtest{\Gin@nat@width > \textwidth}\makeatother}{[width=\textwidth]}{[]}} but this fails. Anyway, I feel like I owe you a little more time, so unless somebody sets me straight, hang in there. – bev Nov 28 '10 at 4:47
See my solution: it works. :-) – Dave Jarvis Nov 28 '10 at 4:54

Here is another solution, based on the original attempt #2 (from sphinx.sty). What I needed was to only resize images that were too big, in all the others that could fit I wanted to keep the original arguments to \includegraphics.

\makeatletter
\newbox\image@box%
\newdimen\image@width%
\newcommand\IncludeGraphics[2][\@empty]{%
\setbox\image@box=\hbox{\includegraphics[#1]{#2}}%
\image@width\wd\image@box%
\ifdim \image@width>\linewidth%
\setbox\image@box=\hbox{\includegraphics[width=\linewidth]{#2}}%
\box\image@box%
\else%
\includegraphics[#1]{#2}%
\fi%
}


I can now do:

\IncludeGraphics[scale=.7]{myimage}


And in case the myimage scaled down to 70% is still wider than current line it will be scaled down even more to fit the \linewidth otherwise it will stay scaled down to only 70%.

Please note, that this will create a new command \IncludeGraphics rather than modify the \includegraohics. If you want to use \includegraphics instead then you need to add

\let\oldincludegraphics\includegraphics



-