Tell me more ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have a set of pictures in my working directory and I want to make a PDF report using these images. I want to include all of them, but the number of the pictures changes in each case. I would like to make a "for" loop to insert each picture one after the other sequentially. Can anyone can help me? At the moment the code I have is the following:

\begin{figure}[h!]
\begin{centering}
\includegraphics[width=10cm,height=10cm]{Figure1.png}
\caption[Sèries temporals de vent i direccions]{Sèries temporals velocitat de vent i     direccions. filtratge de pics i glaçades de velocitat.}
\label{Serie}
\end{centering}

\end{figure}

I would like to do it for every .png image in the directory. Thanks for your questions: I'm using Windows 7 and the files names follow the pattern Figura1.png, Figura2.png and so forth. So which of these possibilities would fit best?

share|improve this question
I don't know of an (easy) way that can traverse a directory from within LaTeX and apply a certain command for each file. There is PerlTeX, wich might be the easiest-to-use candidate for this job within LaTeX. However, PerlTeX is as far as I know not installed by default (in common LaTeX distros such as TexLive or MikTeX), and if you use PerlTex, you have to invoke LaTeX with some special flags. If you, however, do it "outside" from LaTeX, i.e. you set up a script that generates that very part of your document automatically, than you have to run this script and afterwards you can call LaTeX. – phimuemue Apr 26 '12 at 10:59
Are you on Windows, or Unix (Mac/Linux)? Are the files named in a systematic format? If the files have a controlled naming format you could consider using How to iterate through the name of files in a folder – Peter Grill Apr 26 '12 at 16:37

migrated from stackoverflow.com Apr 26 '12 at 16:30

5 Answers

If your system is a Unix one, the following set of macros will do, but they require that the file is compiled with pdflatex -shell-escape:

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[catalan]{babel}
\usepackage{graphicx}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\figureloop}{m}
 {
  \group_begin:
  \etex_everyeof:D { \exp_not:N }
  \tex_endlinechar:D \c_minus_one
  \seq_gset_split:Nnx \g_figloop_names_seq { , }
    { \tex_input:D |"ls ~ -m ~ #1*.png" ~}
  \group_end:
  \seq_map_inline:Nn \g_figloop_names_seq { \dofigureloop { ##1 } }
 }
\cs_generate_variant:Nn \seq_gset_split:Nnn {Nnx}
\seq_new:N \g_figloop_names_seq
\ExplSyntaxOff

\NewDocumentCommand \dofigureloop {m}
 {
  \begin{figure}
  \centering
  \includegraphics[width=10cm,height=10cm]{#1}
  \caption[Sèries temporals de vent i direccions]
          {Sèries temporals velocitat de vent i direccions. Filtratge de pics i glaçades de velocitat.}
  \label{Serie-#1}
  \end{figure}
 }

\begin{document}

\figureloop{figure}

\end{document}

The argument to \figureloop is the common part in the names of your figures. It might be generalized to different extensions.

The \tex_input:D |"ls~-m~#1*.png"~ bit loads the output of the ls command sent via shell-escape to the operating system. This output is stored in a sequence that is then split. Then a mapping function is called on the sequence, its argument is exactly a file name and the macro called just typesets the necessary figure environment. A label in the form Serie-<filename> is also generated.

With a different shell command this may be adapted also to Windows systems.

share|improve this answer

Using the wonderful python.sty package (see github) and some embedded python code, this is very easy:

\documentclass{article}

\usepackage{python}
\usepackage{graphicx}

\begin{document}

\begin{python}
import os
directory = "."
extension = ".png"
files = [file for file in os.listdir(directory) if file.lower().endswith(extension)]

for file in files:
   print r"\begin{figure}[!ht]"
   print r"\centering"
   print r"\includegraphics[width=10cm,height=10cm]{%s}" % file
   print r"\caption{File %s}" % file
   print r"\label{Serie}"
   print r"\end{figure}"
\end{python}

\end{document}

Notice that you need to compile with the --enable-write18 option in order to run the python code.

share|improve this answer
1  
It might be simpler to generate the code with python (or whatever softaware or language you used to generate the figures) using a similar syntax and copy and paste it. I often do it with R and MATLAB. – Alfred M. Apr 26 '12 at 19:05
Does it runs under Windows 7 too? Could you explain me this sentence please? files = [file for file in os.listdir(directory) if file.lower().endswith(extension)] – Jonel_R Apr 28 '12 at 9:23
@Jonel_R: the line files = [file for file in os.listdir(directory) if file.lower().endswith(extension)] first constructs the list os.listdir(directory) and then filters it by the condition file.lower().endswith(extension). – Yori Apr 28 '12 at 19:02
@Jonel_R: Yes, from now on, the github version of python.sty should work on Windows too. – Yori Apr 29 '12 at 3:16
I am haviong real problems using python. See stackoverflow.com/questions/10385232/python-in-latex pleae. – Jonel_R Apr 30 '12 at 15:17
show 3 more comments

Edit:

I want to expand my first answer with an easy to understand approach based on LaTeX3 (pdflatex). Because it follows the same principle like the LuaLaTeX answer I gave (see for explanation), I don't want to separate it from my original answer. So one can compare the two solutions and see how easy it is to use some basics of LaTeX3. As in the LuaLaTeX solution one is independent from external scripting languages, shell commands and specific operating systems.

\documentclass{article}
\usepackage{expl3}
\usepackage{graphicx}

\ExplSyntaxOn

% new bool for the loop condition
\bool_new:N \runWhileLoop    
% new integer for the filename counter
\int_new:N \counter

% create a new latex command
% #1 filename base
% #2 file extension
\newcommand{\figureLoop}[2]
{   
    % set the condition to 'true'
    \bool_set_true:N \runWhileLoop        
    % set the counter to '0'
    \int_zero:N \counter

    % run the loop until '\runWhileLoop' is set to 'false' 
    \bool_while_do:Nn {\runWhileLoop}
    { 
        % increment the counter   
        \int_incr:N \counter            
        % merge the given arguments to a filename
        \edef\fileName{#1\int_use:N\counter#2}

        % check if the file exists
        \file_if_exist:nTF {\fileName}
        {            
            % file exists
            \begin{figure}
                \centering
                \includegraphics[width=5cm]{\fileName}
                \caption{Filename:~\fileName}
                \label{fig:\fileName}
            \end{figure}
        }{
            % there is no file with the given name
            % break the loop
            \bool_set_false:N \runWhileLoop
        }    
    }
}

\ExplSyntaxOff

\begin{document}
\figureLoop{figure}{.jpg}
\figureLoop{image}{.png}
\end{document}

Original:

I think this is a good job for LuaLaTeX. You are independent of the operating system and any external scripts. In this example there is a lua function which concatenates a filename, checks if the file exists and put the picture to the 'figure' environment. You don't have to know how many files are in the folder and you can reuse the given function with different (base)filenames and extensions.

It is good practice to write the lua functions in a separate file with the extension .lua. For this MWE I use the filecontents environment to do so.

\documentclass{book}
\usepackage{graphicx}
\usepackage{filecontents}

%create a lua script file
\begin{filecontents*}{luaFunctions.lua}
function PrintImages(name, extension)

    local i = 1
    local filename = ""

    while true do    
        --concatenate the filename
        filename = name..i..extension
        i = i + 1

        if FileExists(filename) then
            tex.print(string.format("\\begin{figure}[h!]"))
            tex.print(string.format("\\begin{centering}"))

            tex.print(string.format("\\includegraphics[width=15cm, height=10cm]{"..filename.."}"))
            tex.print(string.format("\\caption{"..filename.."}"))
            tex.print(string.format("\\label{fig:"..filename.."}"))

            tex.print(string.format("\\end{centering}"))
            tex.print(string.format("\\end{figure}"))
        else
            --if the file doesn't exists break the while loop
            break
        end        
    end
end

--checks if a file exists
function FileExists(fileName)
    -- try to open the file
    local file = io.open(fileName, "r")

    -- if the file exists close the file and return true
    if file ~= nil then
        io.close(file)
        return true
    else
        return false
    end
end
\end{filecontents*}

% read the external lua file to declare the functions,
% but without execute the Lua commands and functions
\directlua{dofile("luaFunctions.lua")}

% latex commands to execute the lua functions
\def\printImages#1#2{\directlua{PrintImages("#1", "#2")}}

\begin{document}
%choose what type of images you want to print
\printImages{figure}{.jpg}
\printImages{image}{.png}
\end{document}
share|improve this answer

I am using TeXLive 2011 on Windows 7. The following solution has been tested on the production and works without problem. If you use different operating system then my answer might not work. There are 3 steps as follows:

Step 1 : Create a batch file

The batch file has a job to create a temporary plain text file that contains the list of file names (in your context, the PNG file names).

Let MakeFileList.bat be the name of the batch file. It contains the following codes:

rem %1 represents the path relative to the main input file. 

set curdir=%CD%

cd %1

dir /b *.png > %curdir%\FileList.temp

For simplicity (to avoid editing PATH system variable), save the batch in the same directory in which your TeX input file is saved.

Step 2 : Create the TeX input file

Now you write the TeX input file as follows.

\documentclass{article}

\usepackage{graphicx}


\newread\reader

\makeatletter
\newcommand\Import[2][1]{%
\immediate\write18{MakeFileList #2}%
    \openin\reader=FileList.temp\relax
    \loop
        \read\reader to \x
        \unless\ifeof\reader
            \filename@parse{\x}
            \begin{figure}
                    \centering
                \includegraphics[scale=#1]{#2\filename@base}
                \caption{\filename@base}
                \label{fig:\filename@base}
            \end{figure}
    \repeat
    \closein\reader}
\makeatother


\begin{document}

\Import[0.5]{Images/}

\end{document}

The code above will execute the batch, the batch prepares the list of PNG file names, the remaining codes iterate the list and sandwiches each image with figure.

\Import takes 2 arguments. The first argument, which is optional, is used to scale the imported graphics. The second mandatory argument represents a path.

Step 3: Compile with -shell-escape enabled

Let inputfile.tex be the name of TeX input file. Compile the input file with pdflatex -shell-escape inputfile.tex.

share|improve this answer
If there are spaces in the PNG file name, please enclose \filename@base with a pair of double quotes, i.e., \includegraphics[scale=#1]{#3"\filename@base"}. – mozartstraße Apr 27 '12 at 17:36
If you are lazy to follow the 3 steps above, unpack the complete, working archive here. No virus added! – mozartstraße Apr 27 '12 at 17:41

Suppose your pictures are all following certain naming convention (here I used pic1.png up to pic4.png), the lipsumpackage is just for the dummy text:

\documentclass[parskip]{scrartcl}
\usepackage[margin=10mm,a6paper]{geometry}
\usepackage{tikz}
\usepackage{lipsum}

\begin{document}

\foreach \x in {1,2,3,4}
{ \lipsum[\x]
    \includegraphics[scale=1]{pic\x.png}
    \clearpage
}

\end{document}

Alternatively, you can specify tuples of variable to iterate over. The following does the same:

\foreach \x/\picname in {4/pic1.png,8/pic2.png,15/pic3.png,16/pic4.png}
{ \lipsum[\x]
    \begin{figure}[htb]
        \includegraphics[scale=1]{\picname}
        \caption{The very nice picture \x}
    \end{figure}
    \clearpage
}

And the output being:

enter image description here

share|improve this answer
Just another solution with the same constraint. – mozartstraße Apr 28 '12 at 12:00

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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