516

Recently I have learned how to draw simple stuff with TikZ. I really like it. Now I wonder if it is possible to draw with TikZ on a image. Instead of pasting a image in Illustrator and adding some vectors to point something in the picture I would like to do it using TikZ. Is it possible?

For example, on a picture of a computer (PNG,etc) I would like to draw some arrows and labels saying "Keyboard", "Monitor", etc.

1

8 Answers 8

559

(The first part of this answer is taken from my answer to a similar—but not identical—question.)

You can put an \includegraphics inside a TikZ node and then draw over it. The following code adds the picture so that the lower left corner is at the origin of the TikZ coordinate system.

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
    \node[anchor=south west,inner sep=0] at (0,0) {\includegraphics[width=\textwidth]{some_image.jpg}};
    \draw[red,ultra thick,rounded corners] (7.5,5.3) rectangle (9.4,6.2);
\end{tikzpicture}
\end{document}

With a picture from Wikipedia as some_image.jpg, this yields

example

There is a slight problem with this solution: whenever you choose to scale the image differently (e.g. with width=0.9\textwidth), you have to correct the coordinates for your annotations. So it might be useful to introduce coordinates relative to the picture:

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
    \node[anchor=south west,inner sep=0] (image) at (0,0) {\includegraphics[width=0.9\textwidth]{some_image.jpg}};
    \begin{scope}[x={(image.south east)},y={(image.north west)}]
        \draw[red,ultra thick,rounded corners] (0.62,0.65) rectangle (0.78,0.75);
    \end{scope}
\end{tikzpicture}
\end{document}

Then inside the scope, (0,0) is at the lower left of the picture and (1,1) is at the upper right and scaling the picture automatically scales the annotations (or more correctly, it scales their places; the line width and text size stays the same).

A small warning: If you want to draw circles in the new coordinate system, you have to use a radius with absolute lengths (e.g. [radius=1cm]). Otherwise the circle will become an ellipse (if the image is not square).

11
  • 14
    I didn't now that x={(image.south east)},y={(image.north west)} is possible! Thanks, I used \pgfsetxvec{\pgfpointanchor{image}{south east}}% \pgfsetyvec{\pgfpointanchor{image}{north west}}% so far in my implementation. Jan 24, 2011 at 8:56
  • Is there a way to make the scope square? So that only the width goes from 0 to 1?
    – Geoff
    Apr 19, 2011 at 20:36
  • 5
    @Geoff: I finally got around to implement an option for this. The code is available at the tex-sx bzr repository. To use it, download the onimage.dtx file and run pdflatex on it to obtain the onimage.sty and the documentation. (Eventually the package will be available over CTAN.)
    – Caramdir
    Jul 4, 2011 at 12:01
  • 1
    You could also define two additional commands as stated her: kogs-www.informatik.uni-hamburg.de/~meine/tikz, then the coordinates of the drawing over the image can be set in image coordinates, something I used extensively in my PhD-thesis...
    – Habi
    Jul 10, 2012 at 14:04
  • 10
    4 years later, onimage is still not on CTAN. Would you please consider uploading it? It is such a useful package!
    – AlexG
    Feb 24, 2015 at 11:32
510
+100

This is meant to be an addition to Caramdir's answer, but I cannot figure out how to insert line breaks into comments:

To make it easier to find the desired points in the new coordinate system, you can draw a labeled grid on top of the image while you're working on it:

\draw[help lines,xstep=.1,ystep=.1] (0,0) grid (1,1);
\foreach \x in {0,1,...,9} { \node [anchor=north] at (\x/10,0) {0.\x}; }
\foreach \y in {0,1,...,9} { \node [anchor=east] at (0,\y/10) {0.\y}; }

image with grid

Complete example:

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
    \node[anchor=south west,inner sep=0] (image) at (0,0) {\includegraphics[width=0.9\textwidth]{some_image.jpg}};
    \begin{scope}[x={(image.south east)},y={(image.north west)}]
        \draw[help lines,xstep=.1,ystep=.1] (0,0) grid (1,1);
        \foreach \x in {0,1,...,9} { \node [anchor=north] at (\x/10,0) {0.\x}; }
        \foreach \y in {0,1,...,9} { \node [anchor=east] at (0,\y/10) {0.\y}; }
    \end{scope}
\end{tikzpicture}
\end{document}
12
  • 28
    Very useful addition!
    – Caramdir
    Jan 23, 2011 at 18:14
  • 37
    Superb! Brilliant! May 27, 2012 at 8:43
  • 28
    By the way you can insert line beaks in the comments by using Shift+Enter. But I'm glad this isn't a comment so that I can upvote.
    – leo
    Jul 5, 2012 at 20:29
  • 3
    @leo Note that even though you see the line breaks, they won't persist once you submit the comment. Excellent technique, though (if I'm not too late to the party!) :) Apr 25, 2015 at 1:23
  • 4
    I know this is an old post but what if our picture is rectangular ? Then when we use commands such as \draw[] (0.5,0.5) circle (0.1), the circle is not a circle. How can we avoid this and make a square grid for example?
    – mwoua
    Aug 15, 2017 at 12:00
120

For PSTricks fans, the solution is also simple. Unlike Caramdir's and Jake's solutions which use decimal numbers for normalization, I use integer instead. I believe that using integer is better. :-)

There are three steps as follows:

  1. Specify the number of columns and rows. Higher values ease you to determine positions more accurately. Unless you are happy to redo the third step, avoid changing these values after completing the third step.
  2. Specify the scale. Scaling does not affect what you have done in the third step.
  3. Superimposing is done here. To enable the grid, change showgrid from false to top. The grid will be useful to determine positions.
\documentclass[pstricks,border=12pt]{standalone}

\def\M{4}% columns
\def\N{4}% rows
\def\scale{0.25}% scale
\def\filename{mycena_interrupta}% filename


\usepackage{graphicx}
\newsavebox\IBox
\savebox\IBox{\includegraphics[scale=\scale]{\filename}}

\addtopsstyle{gridstyle}
{
    gridcolor=yellow,
    subgridcolor=gray,
    subgriddiv=10,
    griddots=0,
    subgriddots=5,
    gridwidth=0.4pt,
    subgridwidth=0.2pt,
}

\psset
{
   xunit=0.5\dimexpr\wd\IBox/\M,
   yunit=0.5\dimexpr\ht\IBox/\N,
}

\begin{document}
\begin{pspicture}[showgrid=top](-\M,-\N)(\M,\N)
    \rput(0,0){\usebox\IBox}
    \psframe[linecolor=red,linewidth=2pt,dimen=inner,framearc=0.5](0.9,1.2)(2.2,2)
\end{pspicture}
\end{document}

When showgrid=top:

enter image description here

The final result with showgrid=false:

enter image description here

1
60

enter image description here

MWE using Asymptote graphic() label:

% igrid.tex
\documentclass{article}
\usepackage[inline]{asymptote}
\usepackage{lmodern}
\begin{document}
\begin{figure}
\begin{asy}
import graph;
import math;

defaultpen(fontsize(10pt));
real sc=2;
unitsize(sc*1bp);
real wd=200*sc;
real ht=120*sc;

// Image used from http://upload.wikimedia.org/wikipedia/commons/1/16/Mycena_interrupta.jpg
label(
  shift(wd/2,ht/2)*
  graphic("img.jpg"
  ,"width="+string(wd)+"bp"
  +",height="+string(ht)+"bp"
  +",scale="+string(sc)
  ),(0,0)
);
layer();

draw(((0,0)--(wd,ht)/sc),blue+2pt);

int ngrid=10;
int n=(int)(wd/ngrid/sc);
int m=(int)(ht/ngrid/sc);
add(scale(ngrid)*grid(n,m,yellow));

//xlimits(0,wd/sc,crop=true);
//ylimits(0,ht/sc,crop=true);
xaxis( 0,wd/sc,RightTicks(Step=ngrid));
yaxis(0,ht/sc,LeftTicks(Step=ngrid));

pair[] P={
(66,34),
(70,35),
(76,38),
(80,37),
(84,37),
(87,42),
(90,49),
(91,54),
(92,60),
(93,65),
(97,65),
(100,65),
(103,66),
(105,67),
(101,71),
(97,74),
(95,75),
(92,76),
(94,78),
(98,79),
(101,80),
(103,80),
(103,83),
(100,85),
(96,88),
(91,87),
(86,86),
(82,86),
(78,86),
(74,86),
(70,83),
(69,83),
(67,86),
(65,87),
(59,88),
(54,88),
(51,87),
(47,87),
(42,86),
(38,85),
(34,84),
(31,82),
(29,80),
(29,77),
(33,76),
(35,76),
(36,76),
(36,74),
(35,73),
(33,70),
(33,69),
(36,68),
(40,68),
(41,68),
(44,67),
(46,67),
(47,64),
(47,60),
(49,55),
(52,48),
(55,41),
(58,35),
(63,31),
};
guide g=graph(P,operator..)..cycle;
fill(g,white+opacity(0.8));
draw(g,orange+1bp);
\end{asy}
\end{figure}
\end{document}

% To process it with `latexmk`, create file `latexmkrc`:
% 
%     sub asy {return system("asy '$_[0]'");}
%     add_cus_dep("asy","eps",0,"asy");
%     add_cus_dep("asy","pdf",0,"asy");
%     add_cus_dep("asy","tex",0,"asy");
% 
% and run `latexmk -pdf igrid.tex`.
0
54

To easily get the precise relative positions (which is often quite tedious) and to generate LaTeX code automatically for such example as shown below, you could use the new web-based LaTeX Overlay Generator, which I built for such cases. This is just a small interactive tool, which helps you to find the right locations without using a manual grid-based approach.

Example

LaTeX Code

In the following the source code of a minimal working example generated by the LaTeX Overlay Generator.

\documentclass{article}

% remove "[demo]" if you want include actual image!!!
\usepackage[demo]{graphicx}

\usepackage{tikz}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% LaTeX Overlay Generator - Annotated Figures v0.0.1
% Created with http://ff.cx/latex-overlay-generator/
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%\annotatedFigureBoxCustom{bottom-left}{top-right}{label}{label-position}{box-color}{label-color}{border-color}{text-color}
\newcommand*\annotatedFigureBoxCustom[8]{\draw[#5,thick,rounded corners] (#1) rectangle (#2);\node at (#4) [fill=#6,thick,shape=circle,draw=#7,inner sep=2pt,font=\sffamily,text=#8] {\textbf{#3}};}
%\annotatedFigureBox{bottom-left}{top-right}{label}{label-position}
\newcommand*\annotatedFigureBox[4]{\annotatedFigureBoxCustom{#1}{#2}{#3}{#4}{white}{white}{black}{black}}
\newcommand*\annotatedFigureText[4]{\node[draw=none, anchor=south west, text=#2, inner sep=0, text width=#3\linewidth,font=\sffamily] at (#1){#4};}
\newenvironment {annotatedFigure}[1]{\centering\begin{tikzpicture}
    \node[anchor=south west,inner sep=0] (image) at (0,0) { #1};\begin{scope}[x={(image.south east)},y={(image.north west)}]}{\end{scope}\end{tikzpicture}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}

    \begin{figure}[h!t]

        \begin{annotatedFigure}
            {\includegraphics[width=1.0\linewidth]{black-demo.png}}
            \annotatedFigureBox{0.084,0.614}{0.394,0.804}{A}{0.084,0.614}%bl
            \annotatedFigureBox{0.222,0.284}{0.3743,0.4934}{B}{0.3743,0.4934}%tr
            \annotatedFigureBox{0.555,0.784}{0.6815,0.874}{C}{0.555,0.784}%bl
            \annotatedFigureBox{0.557,0.322}{0.8985,0.5269}{D}{0.8985,0.5269}%tr
        \end{annotatedFigure}

        \caption{\textbf{Lorum Ipsum Overview} -- Lorem ipsum dolor amet (A), consetetur (B) elitr, sed diam (C) nonumy eirmod invidunt ut labore (D).}
        \label{fig:teaser}

    \end{figure}

\end{document}
54

In meantime there is a new package callouts

In the annotate-environment you define the image width and an annotation scale. If you scale both with the same factor, then you can change the size of the image without loosing the correct relative positions.

Example:

\documentclass[11pt]{scrartcl} % use larger type; default would be 10pt
\usepackage[wby]{callouts}

\begin{document}
  % pic-source: http://upload.wikimedia.org/wikipedia/commons/1/16/Mycena_interrupta.jpg
  \begin{annotate}{\includegraphics[width=1\textwidth]{Mycena_interrupta}}{1}
    % \helpgrid
    \note{0,0}{Center}
    \callout{4,3}{Mushrom}{3,2}
    \arrow{-3,-2.4}{-4.5,-3}
    %And raw tikz
    \draw[very thick,red] (-4,4) rectangle (-3,3);
  \end{annotate}
\end{document}

enter image description here

2
  • 1
    Great package! Simple and to the point. Sep 20, 2017 at 13:16
  • 1
    I'm wondering why this answer has attracted way less attention as it should, cause this solution is just super straightforward :)
    – Prelude
    Oct 31, 2017 at 19:32
21

For simple tasks, such a heavy weapon like tikz is not always necessary. If only simple shapes or text should be added a picture environment is more then enough:

\documentclass{article}

\usepackage{graphicx}

\begin{document}
bla

\begin{picture}(1,0.55038404)%
  \put(0,0){\includegraphics[width=.4\textwidth]{17D2J}}%
  \put(150,50){x axis}%
\end{picture}%

\end{document}

enter image description here

(Example based on https://tex.stackexchange.com/a/347168/36296)

An overview of available shapes inside the picture environment can be found at http://www.weinelt.de/latex/picture.html (unfortunately I only found it in German, does anyone know an English version? Or another overview?)

17

Since 2019, we have the tikz-imagelabels package. I think it has been bundled in TeX Live 2019 onwards.

This package does what the question asks entirely using the standard tikz macros.

Example (taken from the documentation) below. Image source.

    \documentclass{standalone}
     \usepackage{tikz-imagelabels}

     \begin{document}
     \begin{annotationimage}{width=6cm}{pleiades.jpg}
       \draw[annotation left = {Atlas at 0.3}] to (0.11,0.4);
       \draw[annotation left = {Pleione at 0.55}] to (0.11,0.49);
       \draw[annotation left = {Alcyone at 0.8}] to (0.39,0.45);
       \draw[annotation below = {Merope at 0.5}] to (0.58,0.28);
       \draw[annotation right = {Electra at 0.3}] to (0.84,0.45);
       \draw[annotation right = {Caleano at 0.75}] to (0.85,0.64);
       \draw[annotation above = {Maia at 0.4}] to (0.67,0.72);
       \draw[annotation above = {Taygeta at 0.9}] to (0.78,0.82);
       \draw[image label = {M45 at south east}];
     \end{annotationimage}
     \end{document}

Output of tikz-imagelabels example

2
  • 3
    Please extend your answer with an example of use of this package
    – Zarko
    Jan 17, 2021 at 7:40
  • @Zarko, There you go - example added.
    – prash
    Jan 18, 2021 at 4:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .