0

I have to create certificates in Latex the format of which is already available with me. In this certificate, only the name of the participant changes and every other thing remains the same (including format, border, colors etc).

The list of participants is available in the form of a text file (participant.txt). This file contains one participant in each line.

How can I generate certificates automatically using latex.

My roadmap is as follows: - I will create a copy of TEX file; search for a specific line that contains the participant name, in this line I will replace the old participant by new_participant (by reading the participant.txt file) and compile the code. The same needs to be done for all the participants.

How to go on with this implementation ? Any help.

Upendra01
  • 170
  • you don't say if you want one pdf with a certificate per page, or one pdf per certificate. In the first case you don't need to copy the tex file or use any external tools just a single latex run would do. – David Carlisle May 24 '19 at 06:40
  • I implemented the “one output file for all participants” case. Can someone tell whether the fact that I had to use \endlinechar=-1 with \ior_map_inline:Nn is an expl3 bug or the result of a misderstanding of mine? Thanks! (I can make this a new question if you think it's appropriate.) – frougon May 24 '19 at 07:06
  • Concerning the \endlinechar=-1, egreg replied below my answer (I had put the question there first). – frougon May 24 '19 at 07:20
  • I would use a certificate template with %s for name and printf the actual names in there with a shell. At least bash has printf as a built-in. – Oleg Lobachev May 24 '19 at 22:51
  • You may check this : https://www.youtube.com/watch?v=C43BZWtjrEw – Debashish May 21 '20 at 16:08

1 Answers1

3

Here is a solution that creates one output file for all participants. You don't have to use any scripting for this, just one LaTeX run is enough. You may want to insert \newpage or \clearpage in the definition of \printCertificate if you wish to start a new page for each participant.

\documentclass{article}
% I use these encodings in order to properly typeset “René Descartes”, which
% is in my participant.txt file. Use encodings appropriate for your situation,
% of course.
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{xparse}

\ExplSyntaxOn

\msg_new:nnn { upsmakeparticlist } { file-not-found }
             { File~'\exp_not:n {#1}'~not~found. }

\cs_new_protected:Npn \ups_call_user_callback:Nn #1#2
  {
    % Call the user callback (#1) with contents obtained from the file (#2).
    #1 {#2}
  }

\cs_generate_variant:Nn \ups_call_user_callback:Nn { Nx }

\ior_new:N \g_ups_stream_ior

% #1: macro taking one argument (the participant name)
% #2: file containing one participant per line (blank lines are ignored)
\cs_new_protected:Npn \ups_list_participants:Nn #1#2
  {
    \ior_open:NnF \g_ups_stream_ior {#2}
      { \msg_error:nnn { upsmakeparticlist } { file-not-found } {#2} }

    \ior_map_inline:Nn \g_ups_stream_ior
      {
        \tl_if_eq:nnF {##1} { \par } % ignore blank lines
          {
            % Calling \ups_call_user_callback:Nx will *not* trigger expansion
            % of user-provided contents from ##1, so this should be safe to use
            % (see the documentation of \tl_trim_spaces:n).
            \ups_call_user_callback:Nx #1 { \tl_trim_spaces:n {##1} }
          }
      }

    \ior_close:N \g_ups_stream_ior
  }

% #1: macro taking one argument (the participant name)
% #2: file containing one participant per line (blank lines are ignored). Must
% be readable by TeX; for instance, it can live in the same directory as the
% .tex document or be somewhere in TEXINPUTS.
\NewDocumentCommand \participantlist { m m }
  {
    \ups_list_participants:Nn #1 {#2}
  }

\ExplSyntaxOff

% Will be our callback function that is called for each participant
\newcommand*{\printCertificate}[1]{%
  This is the certificate of #1, etc.\par
}

\begin{document}
\participantlist{\printCertificate}{participant.txt}
\end{document}

Input file participant.txt (may be in TEXINPUTS; for instance, can be in the same directory as the .tex file):

Isaac Newton
Pierre de Fermat
Karl Friedrich Gauss
Henri Lebesgue
William Rowan Hamilton
Georg Ferdinand Ludwig Philipp Cantor
René Descartes

Output:

Screenshot

frougon
  • 24,283
  • 1
  • 32
  • 55
  • 1
    I believe it's a stranded sentence. I'd prefer #1 { \tl_trim_spaces:n { ##1 } } to setting \endlinechar=-1. – egreg May 24 '19 at 07:12
  • @egreg Thanks, I've applied your suggestion and will report a bug unless Someone of the LaTeX3 team tells me he is already on it. :-) – frougon May 24 '19 at 07:19
  • 1
    See https://github.com/latex3/latex3/issues/369; there is a difference between \ior_map_inline:Nn and \ior_str_map_inline:Nn: the former does not ignore the \endlinechar, the latter does. – egreg May 24 '19 at 07:22
  • @egreg Hmmm, this issue is supposedly closed since 2017, but I see it on interface3.pdf from Debian unstable, which is supposed to have TeX Live “20190227“ (texlive-latex-recommended-doc version 2018.20190227-2). Maybe the (documentation) bug was never closed? – frougon May 24 '19 at 07:29
  • @egreg And what do you think about \exp_args:Nx #1 { \tl_trim_spaces:n {##1} }, in order to ensure the user callback doesn't even see the \tl_trim_spaces:n call (\tl_trim_spaces:n is fully expandable, so should be safe inside x argument)? – frougon May 24 '19 at 07:36
  • Replying to myself: this could cause problems if participant.txt were to contain (formatting, etc.) commands that are not expandable (which wasn't specified in the question). In order to be on the safe side, the answer doesn't use this \exp_args:Nx anymore. :-) – frougon May 24 '19 at 07:58
  • 1
    \tl_trim_spaces:n returns its argument (after removing explicit leading and trailing spaces) surrounded by \exp_not:n, so it's safe in x expansion. – egreg May 24 '19 at 08:24
  • @egreg Ah... interesting. So, using \exp_args:Nx would make the thing no less safe but a tiny bit faster in case the user callback \printCertificate uses its argument several times[1], right? [1] Not very likely here, but let's think in general terms. – frougon May 24 '19 at 08:32
  • thanks @frougon. Almost done... – Upendra01 May 24 '19 at 09:09
  • @UpendraPratapSingh Is there something you are missing in my solution? The discussion is about a LaTeX3 documentation bug and a tiny optimization, but the code should already do what you need, unless I missed something. – frougon May 24 '19 at 09:22
  • 1
    @frougon Use variants: \exp_args:<specs> should be the exception, rather than the rule. – egreg May 24 '19 at 10:51
  • @egreg Code updated, thanks! – frougon May 24 '19 at 11:14