t_fischer: (Default)
Thomas Fischer ([personal profile] t_fischer) wrote2010-09-07 05:58 pm
Entry tags:

More on LaTeX Beamer: Linking images to an enlarged version

If you have read my previous posting on LaTeX Beamer, you may remember that there were two example slides taken from a lecture of mine. Most slides for this lecture have a similar layout, consisting of a three-column table with fixed column widths. For photos to be shown in the right column, details become beyond recognition if the image or photo has a landscape-like aspect ratio or is scaled down by a large factor.

To circumvent this problem I came up with the idea of showing the small photo in full-screen size once clicked on; another click brings the viewer back to the original view. In terms of LaTeX, Beamer and PDF this means adding a new slide containing only the up-scaled photo and creating click-sensitive hyper-references (a.k.a. links) in both directions between the small image on the regular slide and the big-photo-only slide. As the big-photo-only slide should not interfere with the presentation if you do not click on the small photo, those special slides have to be appended at the very end of your presentation.

Thus, to solve the problem stated above, three subproblems have to be solved:

  1. Automatically creating a new slide at the end of your presentation
  2. Showing the photo in full-screen size
  3. Adding clickable links to jump between the regular slide and the big-photo-only slide

Of course, it should be as flexible and simple for the user as possible, so that it can be included in existing slide sets if necessary.

More Details

The process of creating slides for photos requires to scan through the document and memorize which photos to link to. This "memorization" is implemented in a LaTeX-like way by writing to a special .aux file using \newwrite and related commands. At the beginning, the file is opened for writing:

\newcounter{linkimagecounter}
\setcounter{linkimagecounter}{0}

\AtBeginDocument{%
% open file linkimage.aux for writing images' filenames to it
\newwrite\linkimageoutputstream
\immediate\openout\linkimageoutputstream=linkimage.aux
}

The .aux file only stores image filenames. The links are later generated using the linkimagecounter counter, so that the first link always points to the first file etc.

Whenever there is an image to link, the user uses the \linkimage command:

% use this command to link some content to a large picture at the end of your slides
\newcommand{\linkimage}[2]{%
% create link anchor where link from document's end points to
\hypertarget{linkimagerefbackward\arabic{linkimagecounter}}{%
% create link pointing forward to link source in frames at document's end
\hyperlink{linkimagerefforward\arabic{linkimagecounter}}{%
#1%
}} % close both hypertarget and hyperlink
\immediate\write\linkimageoutputstream{#2}
% step counter
\addtocounter{linkimagecounter}{1}
}

This command takes two arguments: First, the object which is the link source. This can be for example an \includegraphics, a \copyrightbox, or a \beamerbutton command. The second argument is the image's filename; no includegraphics statement should be used here, as this will be called automatically when generating the big-photo-only slides.
Example:
\linkimage{\copyrightbox{\includegraphics[height=3em]{photo2}}{Thomas Fischer}}{photo2}
\linkimage{\beamerbutton{Show Photo}}{photo2}

Finally, at the end of your slide set after the slide with "questions now, please", you have to call \flushlinkimages which will insert all big-photo-only slides.

% call this command at the very end of your presentation (even after "Now questions, please" slide)
\newcommand{\flushlinkimages}{%
% internal counter for loop over all linked images
\newcounter{linkimagetotal}
\setcounter{linkimagetotal}{\value{linkimagecounter}}
\setcounter{linkimagecounter}{0}

% close auxiliary file linkimage.aux and re-open it again for reading
\immediate\closeout\linkimageoutputstream
\newread\linkimageinputstream
\immediate\openin\linkimageinputstream=linkimage.aux

% loop over all linked images ...
\whiledo{\value{linkimagecounter}<\value{linkimagetotal}}{%
% read one line (one image filename) at a time (and strip new line character at end)
\endlinechar=-1\immediate\read\linkimageinputstream to \linkimagefilename
% create a new frame per image, center content
\begin{frame}\begin{center}
% create link pointing backward to link source in main document
\hyperlink{linkimagerefbackward\arabic{linkimagecounter}}{%
% create link anchor where link from main document points to
\hypertarget{linkimagerefforward\arabic{linkimagecounter}}{%
\includegraphics[width=\linewidth,height=0.75\paperheight,keepaspectratio]{\linkimagefilename}%
}% hypertarget
}% hyperlink
\end{center}\end{frame}
% step counter
\addtocounter{linkimagecounter}{1}
} % whiledo
% close file
\immediate\closein\linkimageinputstream
}

In above code, first some counters are initialized. As you remember, we use counters to match images and hyper-references. Next we close our .aux file (still open for writing) and open it for reading. This makes a single LaTeX run sufficient to generate the extra slides, as the .aux file is written and read in one pass.

The interesting part is the loop, going through all photos. In each iteration, one filename is read from the .aux file and a simple frame environment is created holding an \includegraphics command maximizing the photo while keeping its aspect ratio. You may have to adjust the height parameter for your personal Beamer theme. Hyper-references (\hyperlink and \hypertarget) are generated as well, corresponding the commands created in the original \linkimage call.

As a clarification: All the LaTeX code above should be placed in a class or style file to be included in your presentation. Within your presentation, you should only use \linkimage and \flushlinkimages, everything else happens automatically.

I would be interested in hearing from you if you see ways to make it more efficient, simpler, or more flexible.

Some improvements

(Anonymous) 2016-05-25 11:44 am (UTC)(link)
Month ago i tried to put this on your Wordpress site (and to send it to you by e-mail), but I did not succeed. I hope this time it will reach you (and potential users) unmodified by the CMS of the website.
---------------------------------------------------------------------------------------------

A very very useful package! I only tried to eliminate some aspects that I had found disturbing:

1) For frames containing more slides, one new frame is created for each
SLIDE (including the slides where the smal picture is hidden). This
creates too many useless pages (annoying especialy when printing).
2) The optional caption does not allow formatting, math mode etc.
3) The area of the small image is active as hyperlink even on slides
where the image itself is hidden. This may be undesirable.

The modified version below, as far as I tried, eliminates these problems.

1) The modified version creates only one new frame for each "linkimaged"
image file, except if the user wants to use the same image with and
without the caption or with different captions. In this case, one new
frame is created for each <caption><filename> combination.
2) It allows using macros and math mode in the caption.
3) The \linkimage command (exactly its \hyperlink component) is made
aware of overlay specifications. So the command can be used like
\linkimage<2->[<caption>]{<text>}{<filename>}. The overlay specification
doesn't influence the appearance of the <text> (one never knows what the
user puts in it), so you have to use for instance \onslide for this. The
\linkimage overlay specification determines only on which slides the
area is clickable as the hyperlink.
4) Two typos corrected: linkimage.sty (the "t" missing) and optional
caption (the second "p" missing)

To achieve this:
-- The forward links are named after the <caption><filename> combination
instead of using the counter. (The <caption> part is there to
distinguish different uses of the same image file, like with different
captions.)
-- At the same time, a macro \<caption><filename> is linked (using \let)
to a "reference macro". The \linkimage command always checks whether the
\<caption><filename> macro is defined and writes the new item to the
.aux file (and steps the counter) only if the check fails. The reference
macro is defined as an error message, since it should be never executed.
-- The backward links (and targets) are suspended. Instead, I used the
\Acrobatmenu{GoBack} command (defined in the hyperref package) jumping
simply back to the page we came from (without any target needed in it).
-- The eTeX primitive \detokenize is used to enable the <caption>
parameter to be used in the link names, macro names and .aux file items.
-- \linkimage is defined using the Beamer version of \newcommand.

I have found the .sty file months (or years?) ago somewhere, don't know any more where. My attempts to re-find it failed. So I include the complete linkimage.sty with my modifications marked and the original version commented out.

Regards
Tomáš Kučera, Prague

linkimage.sty%%
%
% linkimage is a LaTeX package to link small images within a Beamer
% presentation to a full-screen variant of the same image at the
% slide set's end.
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
% of this license or (at your option) any later version.
% The latest version of this license is in
% http://www.latex-project.org/lppl.txt
% and version 1.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is
% Thomas Fischer <fischer@unix-ag.uni-kl.de>
%
% This work consists of the files linkimage.sty, linkimage-example.tex
% and linkimage-manual.tex.
%
%%

\NeedsTeXFormat{LaTeX2e}

\ProvidesPackage{linkimage}[2012/07/29 LinkImage]

\RequirePackage{graphicx}
\RequirePackage{hyperref}
\RequirePackage{ifthen}

% counter to build references between linked images
\newcounter{linkimagecounter}
\setcounter{linkimagecounter}{0}

% variable for image height (used when "flushing" images)
\newlength{\imageheight}

\AtBeginDocument{%
% open file linkimage.aux for writing images' filenames to it
\newwrite\linkimageoutputstream
\immediate\openout\linkimageoutputstream=linkimage.aux
}

% use this command to link some content to a large picture at the end of your slides
% example:
% \linkimage{\copyrightbox{\includegraphics[height=3em]{photo2}}{Thomas Fischer}}{photo2}
% \linkimage[optional caption]{\beamerbutton{Show Photo}}{photo2}
%%%-------- modified ------ To make \linkimage aware of overlay specification. ------
%\newcommand{\linkimage}[3][]{%
\newcommand<>{\linkimage}[3][]{%
%%%-------- end of modified ------------------------------------------------------------------
%%%-------- added ------ The reference macro defined as an error message (it should be never executed). -------
\ifx\lnkmgmakro\undefined\gdef\lnkmgmakro{\errmessage{linkimage package: Something is wrong -- the \string\lnkmgmakro \space is not intended to be executed!}}\fi
%%%-------- end of added ------------------------------------------------------------------
%%%-------- cancelled ------ Not needed, there is no hypertarget in the modified version. ---
% create link anchor where link from document's end points to
%\hypertarget{linkimagerefbackward\arabic{linkimagecounter}}{%
%%%-------- end of cancelled ------------------------------------------------------------------
% create link pointing forward to link source in frames at document's end
%%%-------- modified ------ Hyperlink named after the <caption><filename> instead of the counter. The #4 is for overlay-specification awareness.
%\hyperlink{linkimagerefforward\arabic{linkimagecounter}}{%
\hyperlink#4{\detokenize{#1}#3}{%
%%%-------- end of modified ------------------------------------------------------------------
#2%
%%%-------- modified ------ No hypertarget closure as there is no hypertarget in the modified version.
%}} % close both hypertarget and hyperlink
} % close hyperlink
%%%-------- end of modified ------------------------------------------------------------------
%%%-------- added ------ Write new item to the .aux file and step the counter only if the <capture><filename> combination is used for the first time.
\expandafter\expandafter\expandafter\ifx\expandafter\expandafter\csname\detokenize{#1}#3\endcsname\relax
\global\expandafter\expandafter\expandafter\let\expandafter\expandafter\csname\detokenize{#1}#3\endcsname=\lnkmgmakro
%%%-------- end of added ------------------------------------------------------------------
\immediate\write\linkimageoutputstream{#3}%
% write caption for target's beamer frame
%%%-------- modified ------ The <caption> tokens receive the catergory 12.
%\immediate\write\linkimageoutputstream{#1}%
\immediate\write\linkimageoutputstream{\detokenize{#1}}%
%%%-------- end of modified ------------------------------------------------------------------
% step counter
\addtocounter{linkimagecounter}{1}%
%%%-------- added ------ The end of the \ifx conditional
\fi%
%%%-------- end of added ------------------------------------------------------------------
}

% call this command at the very end of your presentation (even after "Now questions, please" slide)
\newcommand{\flushlinkimages}{%
% remove decorations to make more space on slides
\setbeamertemplate{headline}{}\setbeamertemplate{footline}{}
% internal counter for loop over all linked images
\newcounter{linkimagetotal}
\setcounter{linkimagetotal}{\value{linkimagecounter}}
\setcounter{linkimagecounter}{0}

% close auxiliary file linkimage.aux and re-open it again for reading
\immediate\closeout\linkimageoutputstream
\newread\linkimageinputstream
\immediate\openin\linkimageinputstream=linkimage.aux

% loop over all linked images ...
\whiledo{\value{linkimagecounter}<\value{linkimagetotal}}{%
% read one line (one image filename) at a time (and strip new line character at end)
\endlinechar=-1\immediate\read\linkimageinputstream to \linkimagefilename
% read ocaption for target's beamer frame
\endlinechar=-1\immediate\read\linkimageinputstream to \linkimagecaption
% create a new frame per image, center content
\begin{frame}%
\ifthenelse{\equal{\linkimagecaption}{}}{}{\frametitle{\linkimagecaption}}%
\centering
% create link pointing backward to link source in main document
%%%-------- cancelled ------ No hyperlink needed, since no target has been created on the referring page.
%\hyperlink{linkimagerefbackward\arabic{linkimagecounter}}{%
%%%-------- end of cancelled ------------------------------------------------------------------
%%%-------- added ------ Instead, this "relative hyperlink" (defined in hyperref) is used.
\Acrobatmenu{GoBack}{%
%%%-------- end of added ------------------------------------------------------------------
% create link anchor where link from main document points to
%%%-------- modified ------ Hypertarget named after the <caption><filename> instead of the counter.
%\hypertarget{linkimagerefforward\arabic{linkimagecounter}}{%%old version
\hypertarget{\expandafter\detokenize\expandafter{\linkimagecaption}\linkimagefilename}{%%new version
%%%-------- end of modified ------------------------------------------------------------------
% base height for image shall be text body's height
\setlength{\imageheight}{\textheight}
% if page has to have a title, substract estimated title height from max image height
\ifthenelse{\equal{\linkimagecaption}{}}{}{\addtolength{\imageheight}{-3em}}
\includegraphics[width=\linewidth,height=\imageheight,keepaspectratio]{\linkimagefilename}%
}% hypertarget
}% hyperlink

\end{frame}
% step counter
\addtocounter{linkimagecounter}{1}
} % whiledo
% close file
\immediate\closein\linkimageinputstream
}