Procurei por muito tempo uma solução para o meu problema, mas esse problema não parecia se adequar bem ao "google-eez"!
Aqui está o meu problema: tenho uma apresentação do Beamer que apresento a vários clientes. Como gosto de personalizar a apresentação para se adequar à organização de cada cliente, tenho vários "pedaços" de código, com cerca de 10 linhas cada, em meu arquivo pai Beamer .tex que extraem logotipos, definem cores, exibem nomes de organizações - todas as coisas que servem para "personalizar" a apresentação a um determinado cliente. A apresentação de cada cliente separada, é claro, exige que outro pedaço de código de 10 linhas seja inserido no documento .tex pai. Como você pode imaginar, depois de um tempo esses "pedaços de personalização" servem para confundir o documento .tex pai.
O que eu gostaria de fazer é criar arquivos de "dados" separados, um para cada cliente, que contenham os detalhes exclusivos de cada cliente (ou, se possível, armazenartodosditos dados do cliente, detodosclientes, em umsolteiroarquivo). Então, gostaria de poder, usando uma única linha no documento .tex pai, extrair os dados de personalização dos arquivos de dados adequados.
O texto em itálico foi adicionado pelo OP em 16 de fevereiro de 2016: Tenha em mente que meu desejo é ser capaz de gerar, sob demanda, uma apresentação personalizada apenas alguns dias antes de entregá-la.
Algo como:
\documentclass{beamer}
\usepackage{xcolor}
\newcommand{\nameoforg}{1st line from FileA.data}% Name of organization
\newcommand{\mainRGB}{2nd line from FileA.data}% Title color code
\newcommand{\backRGB}{3rd line from FileA.data}% Background color code
\newcommand{\clientlogowidth}{4th line from FileA.data}% Logo width
\newcommand{\clientlogo}{5th line from FileA.data}% Logo file name
\definecolor{mainslidecolor}{RGB}{\mainRGB}
\definecolor{backslidecolor}{RGB}{\backRGB}
\begin{document}
\title[\nameoforg]{Presentation Title}
\titlegraphic{\includegraphics[width=\clientlogowidth]{\clientlogo}}
\begin{frame}
this is boring
\end{frame}
\end{document}
ArquivoA.txt, é claro, é um dos arquivos de "dados" (ou, talvez, oúnicotal arquivo, se isso for possível) que abordei acima.
Algumas de minhas pesquisas pareciam indicar que o catchfile
pacote era a resposta para meus problemas, mas não consegui entender a documentação do pacote.
Como posso fazer isso? E é possível combinar todos os meus arquivos de "dados" em um arquivo (o que eu realmente gostaria de fazer) ou é melhor mantê-los separados, um para cada cliente?
Responder1
Mencionei isso originalmente em um comentário e fui solicitado a postar isso como resposta.
Outra maneira muito simples de fazer isso sem outros pacotes é apenas ter as \newcommand
declarações em seu próprio .tex
arquivo e usar um \input
para carregá-las. Ou seja, tenha:
% Name of organization
\newcommand{\nameoforg}{Organization A}
% Title color code
\newcommand{\mainRGB}{255,0,0}
% Background color code
\newcommand{\backRGB}{255,255,255}
% Logo width
\newcommand{\clientlogowidth}{6cm}
% Logo file name
\newcommand{\clientlogo}{example-image-a}
dentro clientA.tex
e da mesma forma para outros clientes. Isso pode então ser carregado com um simples \input{clientA.tex}
:
\documentclass{beamer}
\usepackage{mwe}
\input{clientA.tex}
\definecolor{mainslidecolor}{RGB}{\mainRGB}
\definecolor{backslidecolor}{RGB}{\backRGB}
\title[\nameoforg]{Presentation Title}
\titlegraphic{\includegraphics[width=\clientlogowidth]{\clientlogo}}
\begin{document}
\begin{frame}
\maketitle
\end{frame}
\begin{frame}
Hello, World!
\end{frame}
\end{document}
Como outros mostraram, isso pode ser estendido com um script para produzir slides em massa, embora o Digger pareça exigir apenas a criação de um conjunto de slides por vez.
Responder2
Eu usaria um script de shell para fazer isso e definiria o nome do arquivo \input
para cada cliente no script e depois o passaria para o pdflatex
comando (ou qualquer mecanismo que você esteja usando).
Aqui está um exemplo. Para cada cliente, crie um .tex
arquivo contendo as definições relevantes para esse cliente. Aqui estão três arquivos de exemplo:
clienteA.tex
\newcommand\clientname{Client A}
\newcommand\clienttheme{EastLansing}
clienteB.tex
\newcommand\clientname{Client B}
\newcommand\clienttheme{Madrid}
clienteC.tex
\newcommand\clientname{Client C}
\newcommand\clienttheme{Bergen}
A primeira linha do seu client-presentation.tex
arquivo (antes de \documentclass
) conterá a linha:
\InputIfFileExists{\clientfile}{}{\typeout{\detokenize{\clientfile}\ not found!}}
Arquivo de apresentação
\InputIfFileExists{\clientfile}{}{\typeout{\detokenize{\clientfile}\ not found!}}
\documentclass{beamer}
\usetheme{\clienttheme}
\title{My Presentation}
\author{Prepared for:\\\clientname}
\date{}
\begin{document}
\begin{frame}[plain]
\maketitle
\end{frame}
\begin{frame}
\begin{block}{This is a block}
\begin{itemize}
\item An item
\end{itemize}
\end{block}
\end{frame}
\end{document}
Então, na linha de comando, definimos \clientfile
e passamos para pdflatex
. Esta é a aparência de um único arquivo:
pdflatex "\def\clientfile{clientA}\input{client-presentation}"
Isso criará client-presentation.pdf
com comandos definidos em clientA.tex
.
Script de shell de uso único
Agora podemos criar um script de shell simples que pega um nome base de arquivo do cliente e um nome base de arquivo de apresentação e então produz um documento para esse cliente. Como é possível que o documento precise de mais de uma compilação para resolver referências etc., eu costumava latexmk
fazer a compilação. Isso garantirá, na maioria dos casos, que o documento seja compilado corretamente.
#!/bin/sh
#Usage: first argument = client file base name, second = latex document base
latexmk -pdf -silent \
-jobname="$1_$2" \
-pdflatex="pdflatex --file-line-error --shell-escape --synctex=1 %O '\def\clientfile{$1}\input{%S}'" $2.tex
Script de shell para automação
Agora podemos automatizar a produção de vários arquivos de clientes de uma só vez, se necessário.
#!/bin/sh
#Usage: pass the basename of the presentation file as an argument
for f in client*.tex; do
basefile=$(basename "$f")
if [ "${basefile%.*}" != "$1" ]
then
latexmk -pdf \
-jobname="${basefile%.*}_$1" \
-pdflatex="pdflatex --file-line-error --shell-escape --synctex=1 %O '\def\clientfile{${basefile%.*}}\input{%S}'" $1.tex
fi
done
Este script de shell usa o nome base do arquivo de apresentação como argumento e gera PDFs separados para cada clientX.tex
arquivo no diretório atual.
Exemplo de saída:
Responder3
Você pode considerar uma abordagem de interface de valor-chave. Isso é menos frágil, pois as chaves podem ser especificadas em qualquer ordem, em vez de estarem em linhas específicas.
Além disso, os pacotes de valores-chave permitem que padrões sejam especificados, se determinados dados estiverem faltando para clientes específicos ou para fornecer compatibilidade com versões anteriores se você adicionar mais chaves no futuro. Com alguns pacotes de valores-chave, você pode marcar certas chaves comoobrigatórioou todos os tipos de outras coisas. Basicamente, adiciona muita flexibilidade.
Aqui está um exemplo básico da abordagem. VerUma grande lista de todos os pacotes keyvalpara descrição dos pacotes e artigo do TUGboatImplementando entrada de valor-chave: uma introdução porJosé WrighteChristian Feuersängerpara uma introdução às ideias e possibilidades das interfaces de valor-chave.
\RequirePackage{filecontents}
\begin{filecontents*}{clientA.data}
\diggersetup{
orgname = First Organization,
mainRGB = {1,0,0},
backRGB = {0,0,1},
clientlogowidth = 1in,
clientlogo = example-image-a,
}
\end{filecontents*}
\begin{filecontents*}{clientB.data}
\diggersetup{
orgname = Second Organization,
mainRGB = {1,1,0},
backRGB = {0,1,0},
clientlogowidth = 1.5in,
clientlogo = example-image-b,
}
\end{filecontents*}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass{beamer}
\usetheme{Boadilla}
\usepackage{lmodern} % no font substitution warnings
\usepackage{graphicx}
\usepackage{keyval} % or your favorite key-value package of the month
\makeatletter
\newlength\clientlogowidth
\define@key{digger}{orgname}{\def\nameoforg{#1}}
\define@key{digger}{mainRGB}{\definecolor{mainslidecolor}{RGB}{#1}}
\define@key{digger}{backRGB}{\definecolor{backslidecolor}{RGB}{#1}}
\define@key{digger}{clientlogo}{\def\clientlogo{#1}}
\define@key{digger}{clientlogowidth}{\setlength\clientlogowidth{#1}}
\setkeys{digger}{ % default key settings
orgname = No Name!,
mainRGB = {1,1,1},
backRGB = {1,0,1},
clientlogo = example-image,
clientlogowidth = 1in,
}
\newcommand{\diggersetup}[1]{\setkeys{digger}{#1}}
\makeatother
%-------------------------------------
\input{clientA.data}
%\input{clientB.data}
%-------------------------------------
\begin{document}
\title[\nameoforg]{Presentation Title}
\titlegraphic{\includegraphics[width=\clientlogowidth]{\clientlogo}}
\begin{frame}
\titlepage
\end{frame}
\begin{frame}
this is boring
\end{frame}
\end{document}
Responder4
Aqui está um exemplo simples de como você pode usar textmerg
. Supondo que você saiba quais variáveis deseja em cada caso, você poderia fazer um arquivo individual para cada empresa e depois “mesclar” com o seu documento. Então, dado este arquivo (chamado, digamos, textmerg-example.dat
)
FooCo Inc.
rose
whale
serif
4cm
example-image
Você então configura seu arquivo beamer assim:
\documentclass{beamer}%
\usepackage{mwe}% to get "example-image" named in .dat file
\usepackage{textmerg}
% the "Fields" are read and assigned in the order of the .dat file
\Fields{
\nameoforg
\myinnertheme
\myoutertheme
\myfonttheme
\clientlogowidth
\clientlogo
}
% Load the specific options
\Merge{textmerg-example.dat}{}% <-- note the second argument is empty because we are looping anything.
\usecolortheme{\myinnertheme}
\usecolortheme{\myoutertheme}
\usefonttheme{\myfonttheme}
\title[\nameoforg]{Presentation Title}
\titlegraphic{\includegraphics[width=\clientlogowidth]{\clientlogo}}
\begin{document}
\maketitle
\begin{frame}
\frametitle{Some Frame Title}
\nameoforg: This is boring\ldots
\end{frame}
\end{document}
Obviamente, você vai querer pensar com bastante cuidado sobre quais coisas você pode querer mudar a cada vez.
EditarSe quiser produzir muitos arquivos ao mesmo tempo usando um conjunto diferente de variáveis, você pode modificar o exemplo acima. Vamos pegar dois .dat
arquivos: 1-textmerg.dat
e 2-textmerg.dat
:
FooCo Inc.
rose
whale
serif
4cm
example-image
e
SOME COMPANY
orchid
seahorse
default
7cm
example-image
Em seguida, modificamos o arquivo beamer acima desta forma:
% main.tex
\documentclass{beamer}%
\usepackage{mwe}% to get "example-image" named in .dat file
\usepackage{textmerg}
% the "Fields" are read and assigned in the order of the .dat file
\Fields{
\nameoforg
\myinnertheme
\myoutertheme
\myfonttheme
\clientlogowidth
\clientlogo
}
% Hack: we don't want to loop the file, so we leave the second argument empty
\providecommand{\tmdatanum}{1}% set a default input file
\Merge{\tmdatanum-textmerg.dat}{}
\usecolortheme{\myinnertheme}
\usecolortheme{\myoutertheme}
\usefonttheme{\myfonttheme}
\title[\nameoforg]{Presentation Title}
\titlegraphic{\includegraphics[width=\clientlogowidth]{\clientlogo}}
\begin{document}
\maketitle
\begin{frame}
\frametitle{Some Frame Title}
\nameoforg: This is boring\ldots
I have used \textbf{\myinnertheme\ \& \myoutertheme} as the inner and outer themes, with this as the client logo: \texttt{\clientlogo}.
\end{frame}
\end{document}
Agora, para produzir todos os diferentes PDFs de uma só vez, poderíamos usar algo como:
for num in {1..2} ; do pdflatex -jobname=$num-beamer "\def\tmdatanum{$num}\input{main.tex}" ; done
Isso seleciona (inclusive) os arquivos que começam no intervalo "entre" 1 e 2, atribui a eles um nome correspondente 1-
ou 2-beamer
para a saída, define o comando \tmdatanum
que é usado em nosso comando sem loop \Merge
e, em seguida, insere o arquivo principal do projeto , main.tex
. O resultado deve ser dois arquivos separados com as configurações nomeadas nos dois .dat
arquivos diferentes.
Alternativamente, um script de shell (chamado, digamos, mergit
) poderia ser construído ao longo destas linhas:
#!/bin/bash
#
# Usage: mergit [FILE] [Highest input file num]
#
MASTERFILE=$1
ENDNUMBER=$2
#
for ((num=1;num<=ENDNUMBER;num++))
do
pdflatex -jobname=$num-beamer "\def\tmdatanum{$num}\input{$MASTERFILE.tex}"
done
Assim, mergit main 2
criaria seus dois PDFs como na linha acima.