25

Suppose I have a .png or .jpg file. Let's say this one:

Tux to be magnified

I would like to zoom in on the tip of Tux's beak. TikZ for example provides a very nice library that allows for zooming with a spyglass like style on TikZ pictures. How can I do the same for the above application?

  • 5
    Why not use TikZ? It works with any content, not just TikZ pictures. Take a look at How to create magnified subfigures and corresponding boxes for portions of a large image, where a similar application has been discussed. – Jake Jun 13 '12 at 13:57
  • Tried that but it didn't work. In that case there probably only is a mistake in my code, so you may just as well close this question. – Ingo Jun 13 '12 at 14:09
  • 1
    I've added an answer showing how to use the code in this case. – Jake Jun 13 '12 at 14:31
38

Also to demonstrate on a simple example:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{spy}
\begin{document}
\begin{tikzpicture}[spy using outlines={circle,yellow,magnification=5,size=1.5cm, connect spies}]
\node {\pgfimage[height=2cm]{tux}};
\spy on (0,0.4) in node [left] at (2,1.25);
\end{tikzpicture}
\begin{tikzpicture}[spy using outlines={circle,yellow,magnification=5,size=1.5cm, connect spies}]
\node {\pgfimage[interpolate=true,height=2cm]{tux}};
\spy on (0,0.4) in node [left] at (2,1.25);
\end{tikzpicture}
\end{document}

enter image description here

You can also use \includegraphics command too instead of \pgfimage inside the node.

20

To show how the code from How to create magnified subfigures and corresponding boxes for portions of a large image would be used here:

\begin{figure}[ht]\centering
\begin{tikzpicture}[
    zoomboxarray,
    zoomboxarray columns=1,
    zoomboxarray rows=1,
    connect zoomboxes,
    zoombox paths/.append style={line width=3pt}
]
    \node [image node] { \includegraphics[width=0.45\textwidth]{tux.png} };
    \zoombox[magnification=6]{0.45,0.67}
\end{tikzpicture}
\end{figure}

will produce

If you add help grid to the image node node options, you will get

which makes it easier to position the zoom point.


Here's the complete code:

\documentclass{article}
\usepackage{graphicx}
\usepackage{caption}
\usepackage{subcaption}
\usepackage{tikz}
\usepackage{pgfplots}
\usetikzlibrary{spy,calc}
\usepackage{hyperref}


\newif\ifblackandwhitecycle
\gdef\patternnumber{0}

\pgfkeys{/tikz/.cd,
    zoombox paths/.style={
        draw=orange,
        very thick
    },
    black and white/.is choice,
    black and white/.default=static,
    black and white/static/.style={ 
        draw=white,   
        zoombox paths/.append style={
            draw=white,
            postaction={
                draw=black,
                loosely dashed
            }
        }
    },
    black and white/static/.code={
        \gdef\patternnumber{1}
    },
    black and white/cycle/.code={
        \blackandwhitecycletrue
        \gdef\patternnumber{1}
    },
    black and white pattern/.is choice,
    black and white pattern/0/.style={},
    black and white pattern/1/.style={    
            draw=white,
            postaction={
                draw=black,
                dash pattern=on 2pt off 2pt
            }
    },
    black and white pattern/2/.style={    
            draw=white,
            postaction={
                draw=black,
                dash pattern=on 4pt off 4pt
            }
    },
    black and white pattern/3/.style={    
            draw=white,
            postaction={
                draw=black,
                dash pattern=on 4pt off 4pt on 1pt off 4pt
            }
    },
    black and white pattern/4/.style={    
            draw=white,
            postaction={
                draw=black,
                dash pattern=on 4pt off 2pt on 2 pt off 2pt on 2 pt off 2pt
            }
    },
    zoomboxarray inner gap/.initial=5pt,
    zoomboxarray columns/.initial=2,
    zoomboxarray rows/.initial=2,
    subfigurename/.initial={},
    figurename/.initial={zoombox},
    zoomboxarray/.style={
        execute at begin picture={
            \begin{scope}[
                spy using outlines={%
                    zoombox paths,
                    width=\imagewidth / \pgfkeysvalueof{/tikz/zoomboxarray columns} - (\pgfkeysvalueof{/tikz/zoomboxarray columns} - 1) / \pgfkeysvalueof{/tikz/zoomboxarray columns} * \pgfkeysvalueof{/tikz/zoomboxarray inner gap} -\pgflinewidth,
                    height=\imageheight / \pgfkeysvalueof{/tikz/zoomboxarray rows} - (\pgfkeysvalueof{/tikz/zoomboxarray rows} - 1) / \pgfkeysvalueof{/tikz/zoomboxarray rows} * \pgfkeysvalueof{/tikz/zoomboxarray inner gap}-\pgflinewidth,
                    magnification=3,
                    every spy on node/.style={
                        zoombox paths
                    },
                    every spy in node/.style={
                        zoombox paths
                    }
                }
            ]
        },
        execute at end picture={
            \end{scope}
            \node at (image.north) [anchor=north,inner sep=0pt] {\subcaptionbox{\label{\pgfkeysvalueof{/tikz/figurename}-image}}{\phantomimage}};
            \node at (zoomboxes container.north) [anchor=north,inner sep=0pt] {\subcaptionbox{\label{\pgfkeysvalueof{/tikz/figurename}-zoom}}{\phantomimage}};
     \gdef\patternnumber{0}
        },
        spymargin/.initial=0.5em,
        zoomboxes xshift/.initial=1,
        zoomboxes right/.code=\pgfkeys{/tikz/zoomboxes xshift=1},
        zoomboxes left/.code=\pgfkeys{/tikz/zoomboxes xshift=-1},
        zoomboxes yshift/.initial=0,
        zoomboxes above/.code={
            \pgfkeys{/tikz/zoomboxes yshift=1},
            \pgfkeys{/tikz/zoomboxes xshift=0}
        },
        zoomboxes below/.code={
            \pgfkeys{/tikz/zoomboxes yshift=-1},
            \pgfkeys{/tikz/zoomboxes xshift=0}
        },
        caption margin/.initial=4ex,
    },
    adjust caption spacing/.code={},
    image container/.style={
        inner sep=0pt,
        at=(image.north),
        anchor=north,
        adjust caption spacing
    },
    zoomboxes container/.style={
        inner sep=0pt,
        at=(image.north),
        anchor=north,
        name=zoomboxes container,
        xshift=\pgfkeysvalueof{/tikz/zoomboxes xshift}*(\imagewidth+\pgfkeysvalueof{/tikz/spymargin}),
        yshift=\pgfkeysvalueof{/tikz/zoomboxes yshift}*(\imageheight+\pgfkeysvalueof{/tikz/spymargin}+\pgfkeysvalueof{/tikz/caption margin}),
        adjust caption spacing
    },
    calculate dimensions/.code={
        \pgfpointdiff{\pgfpointanchor{image}{south west} }{\pgfpointanchor{image}{north east} }
        \pgfgetlastxy{\imagewidth}{\imageheight}
        \global\let\imagewidth=\imagewidth
        \global\let\imageheight=\imageheight
        \gdef\columncount{1}
        \gdef\rowcount{1}
        \gdef\zoomboxcount{1}
    },
    image node/.style={
        inner sep=0pt,
        name=image,
        anchor=south west,
        append after command={
            [calculate dimensions]
            node [image container,subfigurename=\pgfkeysvalueof{/tikz/figurename}-image] {\phantomimage}
            node [zoomboxes container,subfigurename=\pgfkeysvalueof{/tikz/figurename}-zoom] {\phantomimage}
        }
    },
    color code/.style={
        zoombox paths/.append style={draw=#1}
    },
    connect zoomboxes/.style={
    spy connection path={\draw[draw=none,zoombox paths] (tikzspyonnode) -- (tikzspyinnode);}
    },
    help grid code/.code={
        \begin{scope}[
                x={(image.south east)},
                y={(image.north west)},
                font=\footnotesize,
                help lines,
                overlay
            ]
            \foreach \x in {0,1,...,9} { 
                \draw(\x/10,0) -- (\x/10,1);
                \node [anchor=north] at (\x/10,0) {0.\x};
            }
            \foreach \y in {0,1,...,9} {
                \draw(0,\y/10) -- (1,\y/10);                        \node [anchor=east] at (0,\y/10) {0.\y};
            }
        \end{scope}    
    },
    help grid/.style={
        append after command={
            [help grid code]
        }
    },
}

\newcommand\phantomimage{%
    \phantom{%
        \rule{\imagewidth}{\imageheight}%
    }%
}
\newcommand\zoombox[2][]{
    \begin{scope}[zoombox paths]
        \pgfmathsetmacro\xpos{
            (\columncount-1)*(\imagewidth / \pgfkeysvalueof{/tikz/zoomboxarray columns} + \pgfkeysvalueof{/tikz/zoomboxarray inner gap} / \pgfkeysvalueof{/tikz/zoomboxarray columns} ) + \pgflinewidth
        }
        \pgfmathsetmacro\ypos{
            (\rowcount-1)*( \imageheight / \pgfkeysvalueof{/tikz/zoomboxarray rows} + \pgfkeysvalueof{/tikz/zoomboxarray inner gap} / \pgfkeysvalueof{/tikz/zoomboxarray rows} ) + 0.5*\pgflinewidth
        }
        \edef\dospy{\noexpand\spy [
            #1,
            zoombox paths/.append style={
                black and white pattern=\patternnumber
            },
            every spy on node/.append style={#1},
            x=\imagewidth,
            y=\imageheight
        ] on (#2) in node [anchor=north west] at ($(zoomboxes container.north west)+(\xpos pt,-\ypos pt)$);}
        \dospy
        \pgfmathtruncatemacro\pgfmathresult{ifthenelse(\columncount==\pgfkeysvalueof{/tikz/zoomboxarray columns},\rowcount+1,\rowcount)}
        \global\let\rowcount=\pgfmathresult
        \pgfmathtruncatemacro\pgfmathresult{ifthenelse(\columncount==\pgfkeysvalueof{/tikz/zoomboxarray columns},1,\columncount+1)}
        \global\let\columncount=\pgfmathresult
        \ifblackandwhitecycle
            \pgfmathtruncatemacro{\newpatternnumber}{\patternnumber+1}
            \global\edef\patternnumber{\newpatternnumber}
        \fi
    \end{scope}
}


\begin{document}

\begin{figure}[ht]\centering
\begin{tikzpicture}[
    zoomboxarray,
    zoomboxarray columns=1,
    zoomboxarray rows=1,
    connect zoomboxes,
    zoombox paths/.append style={line width=3pt}
]
    \node [image node] { \includegraphics[width=0.45\textwidth]{tux.png} };
    \zoombox[magnification=6]{0.45,0.67}
\end{tikzpicture}
\end{figure}

\end{document}
  • 3
    Time for a library already, eh? :) – percusse Jun 13 '12 at 14:43
  • 3
    @percusse: Hehe, yes, it definitely is. I'm starting a PhD in a couple of weeks - judging from Martin Scharrer's example, that's the time to write packages. – Jake Jun 13 '12 at 14:44
  • 1
    Hahaha, so true. I have mixed feelings. Wow,congrats! and oh no, why? at the same time. All the best! – percusse Jun 13 '12 at 14:47
  • 1
    How is the library coming along ;-)? – Ingo Jan 8 '14 at 11:02
5

You can "zoom out" some part of an image by clipping the other material away and then scale the remainder:

\documentclass{article}
\usepackage{graphicx}
\begin{document}

\includegraphics[clip,viewport=85 195 160 240,width=4cm]{tux}

\end{document}

Here viewport is used to specify the lower-left and upper-right corner of the area (in bp by default). You can also use the trim key to trim material from the left, bottom, right and top away. You need to figure out the values by trial and error or measure them. The scaling can be done using width, height or scale.

Also, the adjustbox package and its additional keys can be helpful here. Then you can use e.g. .4\width to clip away 40% of the left etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.