From 94ac70b92400e4b95d43d570ad53a713c036118b Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Tue, 26 Jan 2021 03:01:06 +0000 Subject: CTAN sync 202101260301 --- support/ltximg/README.md | 50 +- support/ltximg/doc/ltximg-doc.pdf | Bin 242217 -> 0 bytes support/ltximg/doc/ltximg-doc.tex | 2094 ----------------------- support/ltximg/ltximg-doc.pdf | Bin 0 -> 316588 bytes support/ltximg/ltximg-doc.tex | 2132 ++++++++++++++++++++++++ support/ltximg/ltximg.1 | 279 ++++ support/ltximg/ltximg.man1.pdf | Bin 0 -> 27866 bytes support/ltximg/ltximg.pl | 3284 +++++++++++++++++++++++++++++++++++++ support/ltximg/script/ltximg.pl | 3009 --------------------------------- 9 files changed, 5719 insertions(+), 5129 deletions(-) delete mode 100644 support/ltximg/doc/ltximg-doc.pdf delete mode 100644 support/ltximg/doc/ltximg-doc.tex create mode 100644 support/ltximg/ltximg-doc.pdf create mode 100644 support/ltximg/ltximg-doc.tex create mode 100644 support/ltximg/ltximg.1 create mode 100644 support/ltximg/ltximg.man1.pdf create mode 100644 support/ltximg/ltximg.pl delete mode 100644 support/ltximg/script/ltximg.pl (limited to 'support/ltximg') diff --git a/support/ltximg/README.md b/support/ltximg/README.md index c5dc89cd92..955b3b7598 100644 --- a/support/ltximg/README.md +++ b/support/ltximg/README.md @@ -1,6 +1,6 @@ -## LTXimg – LaTeX environments to image format and standalone files +## LTXimg – LaTeX environments to image and standalone files -Release v1.9 \[2020-08-22\] +Release v2.0 \[2021-01-24\] ## Description @@ -42,7 +42,7 @@ and saved in the `./images` directory using `pdflatex` and `preview` package to ``` [default] -h, --help Display command line help and exit [off] --v, --version Display current version (1.8) and exit [off] +-v, --version Display current version (2.0) and exit [off] -V, --verbose Verbose printing information [off] -l, --log Write .log file with debug information [off] -t, --tif Create .tif files using ghostscript [gs] @@ -55,19 +55,19 @@ and saved in the `./images` directory using `pdflatex` and `preview` package to -g, --gray Gray scale for images using ghostscript [off] -f, --force Capture "\psset" and "\tikzset" to extract [off] -n, --noprew Create images files without "preview" package [off] --r , --runs +-r , --runs= Set the number of times the compiler will run on the input file for environment extraction [1] --d , --dpi +-d , --dpi= Dots per inch resolution for images [150] --m , --margins +-m , --margins= Set margins in bp for pdfcrop [0] --o , --output +-o , --output= Create output file [off] ---imgdir Set name of directory to save images/files [images] ---prefix Set prefix append to each generated files [fig] ---myverb Add "\macroname" to verbatim inline search [myverb] ---clean (doc|pst|tkz|all|off) +--imgdir= Set name of directory to save images/files [images] +--prefix= Set prefix append to each generated files [fig] +--myverb= Add "\macroname" to verbatim inline search [myverb] +--clean=doc|pst|tkz|all|off Removes specific block text in output file [doc] --zip Compress files generated in .zip [off] --tar Compress files generated in .tar.gz [off] @@ -89,11 +89,11 @@ and saved in the `./images` directory using `pdflatex` and `preview` package to --norun Run script, but no create images files [off] --nopdf Don't create a ".pdf" image files [off] --nocrop Don't run pdfcrop [off] ---extrenv Add new environments to extract [empty] ---skipenv Skip some default environments to extract [empty] ---verbenv Add new verbatim environments [empty] ---writenv Add new verbatim write environments [empty] ---deltenv Delete environments in output file [empty] +--extrenv= Add new environments to extract [empty] +--skipenv= Skip some default environments to extract [empty] +--verbenv= Add new verbatim environments [empty] +--writenv= Add new verbatim write environments [empty] +--deltenv= Delete environments in output file [empty] ``` ## Example @@ -118,10 +118,16 @@ $ texdoc ltximg For recreation all documentation use: ``` -$ arara ltximg-doc.dtx -H +$ arara ltximg-doc.tex -H ``` -## Licence +## Author + +Pablo González L, ``. + +## Copyright and Licence + +Copyright 2013 - 2020 Pablo González L ``. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, @@ -130,11 +136,3 @@ or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -## Author - -Written by Pablo González L ``. - -## Copyright - -Copyright 2013 - 2020 by Pablo González L. diff --git a/support/ltximg/doc/ltximg-doc.pdf b/support/ltximg/doc/ltximg-doc.pdf deleted file mode 100644 index d11504ff8e..0000000000 Binary files a/support/ltximg/doc/ltximg-doc.pdf and /dev/null differ diff --git a/support/ltximg/doc/ltximg-doc.tex b/support/ltximg/doc/ltximg-doc.tex deleted file mode 100644 index 8c625bf24b..0000000000 --- a/support/ltximg/doc/ltximg-doc.tex +++ /dev/null @@ -1,2094 +0,0 @@ -% arara: lualatex -% arara: lualatex -% arara: clean: { extensions: [ aux, log, out, ilg, ind, idx, toc, hd, fls ] } -\documentclass{ltxdoc} -\usepackage[top=0.5in, bottom=0.3in, left=1.4in, right=0.7in,footskip=0.2in,headheight=1cm,headsep=0.27cm]{geometry} -\usepackage{unicode-math} % -\setmathfont[Scale = 0.95]{Latin Modern Math} -\setmainfont[ - Numbers = OldStyle, - Ligatures = TeX, - Scale = 0.95, - UprightFont = *-Regular, - ItalicFont = *-Italic, - BoldFont = *-Bold, - BoldItalicFont = *-BoldItalic, - SmallCapsFeatures = {Letters=SmallCaps}, - Extension =.otf]{LibertinusSerif} -\setsansfont[ - Numbers = OldStyle, - Ligatures = TeX, - Scale = 0.95, - UprightFont = *-Regular, - ItalicFont = *-Italic, - BoldFont = *-Bold, - SmallCapsFeatures = {Letters=SmallCaps}, - Extension = .otf]{LibertinusSans} -\setmonofont[ - Numbers = OldStyle, - Scale = 0.80, - UprightFont = *-Regular, - ItalicFont = *-RegularIt, - BoldFont = *-Semibold, - BoldItalicFont = *-SemiboldIt, - RawFeature = {+zero,+ss06}, - FontFace = {m}{sc}{LinBiolinum_R.otf}, - Extension = .otf]{SourceCodePro} % source code font -\newfontfamily\lmmitalic{lmmono10-italic.otf}[ - Scale = 0.95,% - Extension = .otf,% - ItalicFont = lmmono10-italic,% - SmallCapsFont = lmmonocaps10-oblique,% - SlantedFont = lmmonoslant10-regular, - ] -\newfontfamily\fetamontotf{ffmw10.otf}[ - Scale = 0.95,% - RawFeature = {+latn,+rand,+kern,+size},% - FontFace = {bx}{n}{ffmw10.otf}, - ] -\newfontfamily\libertinusinitials{LibertinusSerifInitials-Regular.otf} -% The character of visible space is now taken from Latin Modern Mono -% to prevent fonts in T1. The original definition for xetex/luatex is -% \def\verbvisiblespace{\usefont{OT1}{cmtt}{m}{n}\asciispace} -\def\verbvisiblespace{{\fontfamily{lmtt}\selectfont\char"2423}} -\usepackage{fontawesome5} -\usepackage{hologo} % LaTeX logos -\usepackage{enumitem,lastpage,microtype,titletoc} % custom -\usepackage[svgnames]{xcolor} % -\usepackage[sf,bf,compact,medium]{titlesec} % section styles -\usepackage[topmarks,extramarks]{titleps} % pagestyles -\settitlemarks*{section,subsection} -\usepackage{adjustbox,multicol,hyperref,xparse,listings,accsupp} -\usepackage{csquotes} -\usepackage{hyperxmp,imakeidx}% -% Hyperref number in index -\newcommand{\HP}[1]{\emph{\hyperpage{#1}}\normalsize} -\def\SortIndex#1#2{\index{#1\actualchar#2|HP}} -\indexsetup{level=\section,firstpagestyle=myheader} -\makeindex[options=-q -s gind.ist,columnsep=15pt,title={Index of Documentation}] %noautomatic -%\makeindex[noautomatic,columnsep=15pt,title={Index of Documentation}] % - -% parindent -\setlength{\parindent}{0pt} - -% Colors for options -\definecolor{optcolor}{rgb}{0.281,0.275,0.485} -\definecolor{pkgcolor}{rgb}{0,0.5,0.5} -\definecolor{araracolor}{rgb}{0, 0.72, 0.28} -\definecolor{linkcolor}{rgb}{0.04,0.38,0.04} -\definecolor{rulecolor}{rgb}{0.96,0.96,0.96} - -% Only for arara... I like arara :) -\usepackage[scale=0.85]{comfortaa} -\newcommand{\araratext}[1]{{\small\normalfont\comfortaa\color{araracolor}\bfseries#1}} -\newcommand*\arara{\araratext{ar\kern-.03emar\kern-.03ema}} - -% Identification -\def\myscript{ltximg} -\def\fileversion{1.9} -\def\filedate{2020-08-22} - -% Logo with fetamont and libertuns font -\ExplSyntaxOn -\NewDocumentCommand{\pkglogo}{} - { - \group_begin: - \libertinusinitials% - \textcolor{red}{L}\hspace{-3.0pt}% - \raisebox{-0.2em}{\small \textcolor{green}{T}}% - \hspace{-2.9pt}\textcolor{blue}{X}% - \hspace{-1pt} - \fetamontotf{\textcolor{gray}{img}} - \group_end: - } -\ExplSyntaxOff - -% Logo with libertuns and fetamont font (box) -\newsavebox{\logobox} -\savebox{\logobox}{% - \normalsize% - {\libertinusinitials% - \textcolor{red}{L}\hspace{-3.0pt}% - \raisebox{-0.2em}{\small \textcolor{green}{T}}% - \hspace{-2.9pt}\textcolor{blue}{X}}% - \hspace{-1pt}\fetamontotf{\textcolor{gray}{img}}% -}% -\makeatletter -\newcommand{\LTXimg}{% - \settoheight{\@tempdima}{L}% - \resizebox{!}{\@tempdima}{\usebox{\logobox}}% -} -\makeatother - -% email https://tex.stackexchange.com/a/663 -\catcode`\_=11\relax% -\newcommand\email[1]{\_email #1\q_nil}% -\def\_email#1@#2\q_nil{% - \href{mailto:#1@#2}{{\emailfont #1\emailampersat #2}}% -}% -\newcommand\emailfont{\sffamily}% -\newcommand\emailampersat{{\color{pkgcolor}\footnotesize@}}% -\catcode`\_=8\relax% % - -% Config hyperref -\hypersetup{ - linkcolor = linkcolor,% - citecolor = magenta,% - urlcolor = magenta,% - colorlinks = true,% - linktoc = all, - pdftitle = {.:: ltximg v\fileversion{} [\filedate] --- LaTeX environments to image format and standalone files ::.},% - pdfauthor = {Pablo Gonz\'{a}lez Luengo},% - pdfsubject = {Documentation for version \fileversion},% - pdfcopyright = {\textcopyright 2013 - 2020 by Pablo González Luengo}, - pdfcontacturl = {https://github.com/pablgonz/ltximg}, - pdfkeywords = {extract, conversion, images, TikZ, PStricks, standalone files}, - pdfstartview = {FitH},% - bookmarksopenlevel = 2,% -} - -% Configuration titleps and titlesec -\renewpagestyle{plain}[\color{optcolor}\small\sffamily]{% -\setfoot{\rlap{\hskip\dimexpr-\oddsidemargin-1in\relax% - \parbox{1.93\paperwidth}{\hfil\thepage\,/\,\pageref{LastPage}}}}% - {}% - {}% -} -\newpagestyle{myheader}[\color{optcolor}\small\sffamily]{% -\renewcommand\makeheadrule{% -\rlap{\hskip\dimexpr-\oddsidemargin-1in\relax - \color{rulecolor}\rule[0.3cm]{\paperwidth}{0.7cm}}\hss -} -\setfoot{\rlap{\hskip\dimexpr-\oddsidemargin-1in\relax% - \parbox{1.93\paperwidth}{\hfil\thepage\,/\,\pageref{LastPage}}}}% - {\parbox{\textwidth}{\raggedright \textcolor{gray}{\raisebox{-1pt}{\textcopyright}{}2013 -- 2020 by Pablo González}}}% - {}% -\sethead{\llap{\raisebox{0.55cm}{\parbox{\dimexpr\oddsidemargin+1in\relax}{\makebox[0pt][l]{\hspace{15pt}\pkglogo\space\fileversion}}}}} - {\raisebox{0.55cm}{\parbox{\textwidth}{\hspace*{-\oddsidemargin}\centering\small\S.\firstextramarks{section}\thesection\space\sectiontitle}}}% - {}% -} - -% Table of contents -\titlecontents{section}[0mm]{}% - {\bfseries\contentspush{\makebox[5mm][l]{\thecontentslabel\hfill}}}% - {\hspace*{-5mm}}% numberless - {\hspace{0.25em}\titlerule*[6pt]{.}\contentspage}% - -\titlecontents{subsection}[5mm]{}% - {\contentspush{\makebox[6mm][l]{\thecontentslabel\hfill}}} - {\hspace*{-11mm}}% numberless - {\hspace{0.25em}\titlerule*[6pt]{.}\contentspage}% - -\titlecontents{subsubsection}[11mm]{}% - {\contentspush{\makebox[8mm][l]{\thecontentslabel\hfill}}} - {\hspace*{-19mm}}% numberless - {\hspace{0.25em}\titlerule*[6pt]{.}\contentspage}% - -\makeatletter -\renewcommand\tableofcontents{% -\begingroup% -\section*{\contentsname\quad{\color{optcolor}\leaders\hrule height 5pt depth -4.4pt\hfill}% - \@mkboth{% - \MakeUppercase\contentsname}{\MakeUppercase\contentsname}}% -\vspace*{-14pt} -\setlength{\columnsep}{10pt}% - \begin{multicols}{2}% - \@starttoc{toc}% -\end{multicols}% -\vspace*{-3pt}{\color{optcolor}\hrule height 0.6pt}% -\vspace*{5pt} -\endgroup -} -\makeatother - -% Custom thanks -\makeatletter -\renewcommand*{\@fnsymbol}[1]{\ensuremath{\ifcase#1\or \textcolor{pkgcolor}{*} -\or \textcolor{pkgcolor}{\dagger} \or \ddagger\or \mathsection -\or \mathparagraph\or \|\or **\or \dagger\dagger -\or \ddagger\ddagger \else\@ctrerr\fi}} -\makeatother - -% Custom \meta[...]{...}, \marg[...]{...} and \oarg[...]{...} for color -\ExplSyntaxOn -\RenewDocumentCommand{\meta}{O{}m} - { - \ltximg_meta_generic:Nnn \ltximg_meta:n { #1 } { #2 } - } -\RenewDocumentCommand{\marg}{O{}m} - { - \ltximg_meta_generic:Nnn \ltximg_marg:n { #1 } { #2 } - } -\RenewDocumentCommand{\oarg}{O{}m} - { - \ltximg_meta_generic:Nnn \ltximg_oarg:n { #1 } { #2 } - } -%^^A Variables and keys -\tl_new:N \l_ltximg_meta_font_tl - -\keys_define:nn { ltximg/meta } - { - type .choice:, - type / tt .code:n = \tl_set:Nn \l_ltximg_meta_font_tl { \ttfamily }, - type / rm .code:n = \tl_set:Nn \l_ltximg_meta_font_tl { \rmfamily }, - type .initial:n = rm, - cf .tl_set:N = \l_ltximg_meta_color_tl, - cf .initial:n = optcolor, - ac .tl_set:N = \l_ltximg_meta_anglecolor_tl, - ac .initial:n = lightgray, - sbc .tl_set:N = \l_ltximg_meta_brackcolor_tl, - sbc .initial:n = gray, - cbc .tl_set:N = \l_ltximg_meta_bracecolor_tl, - cbc .initial:n = gray, - } -%^^A Internal commands -\cs_new_protected:Npn \ltximg_meta_generic:Nnn #1 #2 #3 - { - \group_begin: - \keys_set:nn { ltximg/meta } { #2 } - \color{ \l_ltximg_meta_color_tl } - \l_ltximg_meta_font_tl - #1 { #3 } % #1 is \ltximg_meta:n, \ltximg_marg:n or \ltximg_oarg:n - \group_end: - } -\cs_new_protected:Npn \ltximg_meta:n #1 - { - \ltximg_meta_angle:n { \textlangle } - \ltximg_meta_meta:n { #1 } - \ltximg_meta_angle:n { \textrangle } - } -\cs_new_protected:Npn \ltximg_marg:n #1 - { - \ltximg_meta_brace:n { \textbraceleft } - \ltximg_meta:n { #1 } - \ltximg_meta_brace:n { \textbraceright } - } -\cs_new_protected:Npn \ltximg_oarg:n #1 - { - \ltximg_meta_brack:n { [ } - \ltximg_meta:n { #1 } - \ltximg_meta_brack:n { ] } - } -\cs_new_protected:Npn \ltximg_meta_meta:n #1 - { - \textnormal{\textit{#1}} - } -\cs_new_protected:Npn \ltximg_meta_angle:n #1 - { - \group_begin: - \fontfamily{lmr}\selectfont - \textcolor{\l_ltximg_meta_anglecolor_tl}{#1} - \group_end: - } -\cs_new_protected:Npn \ltximg_meta_brace:n #1 - { - \group_begin: - \color{\l_ltximg_meta_bracecolor_tl} - #1 - \group_end: - } -\cs_new_protected:Npn \ltximg_meta_brack:n #1 - { - \textcolor{\l_ltximg_meta_brackcolor_tl}{#1} - } - -% \ltximg for body document -\NewDocumentCommand{\ltximg}{} - { - \normalsize\texttt{\bfseries\textcolor{pkgcolor}{ltximg}} - } - -% \prgname{sm} : #1 index compiler, #2 index programs: -\NewDocumentCommand{\prgname}{sm} - { - \IfBooleanTF{#1} - { - \textcolor{ForestGreen}{\texttt{#2}} - \SortIndex{compiler}{Compiler>\small\texttt{#2}} - } - { - \textcolor{ForestGreen}{\texttt{#2}} - \SortIndex{programs}{Programs>\small\texttt{#2}} - } - } - -% \prgopt{sm} : #1 compiler opt, #2 program opt: -\NewDocumentCommand{\prgopt}{sm} - { - \IfBooleanTF{#1} - { - \mbox{\textcolor{gray}{\texttt{-{}#2}}} - \SortIndex{compiler ~ options}{Compiler ~ options>\small\texttt{-{}#2}} - } - { - \mbox{\textcolor{gray}{\texttt{-{}#2}}} - \SortIndex{#2}{\small\texttt{-{}#2} (program ~ option)}% - } - } - -% \scriptname*{m} -\NewDocumentCommand{\scriptname}{m} - { - \textcolor{ForestGreen}{\texttt{#1}} - \SortIndex{scripts}{Scripts>\small\texttt{#1}} - } - -% \scriptopt{m} -\NewDocumentCommand{\scriptopt}{m} - { - \mbox{\texttt{#1}} - \SortIndex{script ~ option}{Script ~ options>\small\texttt{#1}} - } - -% \myclass{m} -\NewDocumentCommand{\myclass}{ m } - { - \mbox{\textsf{\textcolor{SlateBlue}{#1}}} - \SortIndex{document}{Document ~ class>\small\texttt{#1}} - \SortIndex{#1}{\texttt{#1} ~ (class)} - } - -% \pkgname{m} -\NewDocumentCommand{\pkgname}{ m } - { - \textsf{\textcolor{SlateBlue}{#1}} - \SortIndex{packages}{Packages>\small\texttt{#1}} - \SortIndex{#1}{\texttt{#1} ~ (package)} - } - -% \pkgopt{m} -\NewDocumentCommand{\pkgopt}{ m } - { - \textsf{\textcolor{gray}{#1}} - \SortIndex{package ~ options}{Package ~ options>\small\texttt{#1}} - \SortIndex{#1}{\texttt{#1} ~ (package ~ option)} - } - -% \env{m} -\NewDocumentCommand{\env}{ m } - { - \textcolor{pkgcolor}{\texttt{#1}} - \SortIndex{environment}{Environments>\small\texttt{#1}} - } - -% \LVenv{m} -\NewDocumentCommand{\LVenv}{ m } - { - \textcolor{pkgcolor}{\texttt{#1}} - \SortIndex{environment ~ verbatim}{Environments ~ verbatim>\small\texttt{#1}} - } - -% \LWenv{m} -\NewDocumentCommand{\LWenv}{ m } - { - \textcolor{pkgcolor}{\texttt{#1}} - \SortIndex{environment ~ verbatim ~ write}{Environments ~ verbatim ~ write>\small\texttt{#1}} - } - -% \ics{sm} -\NewDocumentCommand{\ics}{sm} - { - \IfBooleanTF{#1} - { - \tl_set:Nn \l_tmpa_tl { #2 } - \regex_replace_once:nnN { (\*) } { \c{textcolor}\cB\{MediumOrchid\cE\}\cB\{\1\cE\} } \l_tmpa_tl - \textcolor{blue!75}{\ttfamily\textbackslash{\tl_use:N \l_tmpa_tl}} - } - { - \textcolor{blue!75}{\ttfamily{\textbackslash#2}} - } - \SortIndex{#2}{\texttt{\small\textbackslash#2}} - } - -% file extention -\NewDocumentCommand{\fext}{m} - { - \mbox{\textcolor{OrangeRed}{\texttt{.#1}}} - \SortIndex{file ~ extention}{File ~ extentions >\small\texttt{.#1}} - } - -% File -\NewDocumentCommand{\Fext}{m m} - { - \mbox{\textcolor{OrangeRed}{\texttt{#1}\fext{#2}}} - \SortIndex{file}{File >\small\texttt{#1.#2}} - } - - -% image format/extention -\NewDocumentCommand{\iext}{m} - { - \textcolor{optcolor}{\texttt{#1}} - \SortIndex{Image ~ format}{Image ~ formats>\small\texttt{#1}} - } - -% \sysydir{m} -\NewDocumentCommand{\sysdir}{m} - { - \mbox{\textcolor{OrangeRed}{\texttt{#1}}} - } - -% \sysfile{m} ...only for color in some examples -\NewDocumentCommand{\sysfile}{m} - { - \mbox{\textcolor{OrangeRed}{\texttt{#1}}} - } - -% \OSsystem{m} ...only for color in some examples -\NewDocumentCommand{\OSsystem}{m} - { - \mbox{\textcolor{OrangeRed}{\texttt{#1}}} - \SortIndex{Operating ~ system}{Operating ~ system>\small\texttt{#1}} - } - -% \cmdopt[short]{long} -\NewDocumentCommand{\cmdopt}{om} - { - \IfNoValueTF{#1} - { - \textcolor{optcolor}{\texttt{-\/-#2}} - } - { - \textcolor{optcolor}{\texttt{-{}#1}}, - \textcolor{optcolor}{\texttt{-\/-#2}} - } - \SortIndex{options}{\textsf{\myscript}\ options ~ in ~ command ~ line>\small\texttt{-\/-#2}} - } - -\ExplSyntaxOff -% \DescribeIF{m}, #1 image format -\newsavebox{\marginIF} -\NewDocumentCommand{\DescribeIF}{ m } - {% - \begin{lrbox}{\marginIF}% - \begin{minipage}[t]{\marginparwidth}% - \raggedleft\ttfamily\bfseries% - \textcolor{optcolor}{#1} - \end{minipage}% - \end{lrbox}% - \SortIndex{Image format}{Image formats>\small\texttt{#1}} - \leavevmode% - \marginpar{\usebox{\marginIF}}% - \ignorespaces% - }% - -% \myenv{environ} for margin -\NewDocumentCommand{\myenv}{m} - { - \begin{minipage}[t]{\marginparwidth}% - \raggedleft\ttfamily\small% - {\textcolor{gray}{\textbackslash begin\{}}{\bfseries\textcolor{pkgcolor}{#1}}\textcolor{gray}{\}}\par% - \meta[ac=lightgray,cf=gray]{env content}\par% - {\textcolor{gray}{\textbackslash end\{}}{\bfseries\textcolor{pkgcolor}{#1}}\textcolor{gray}{\}}% - \end{minipage}% - \SortIndex{Environment}{Environments suport by default>\small\texttt{#1}}% - } - -% \mytag{dtxtag} for margin -\NewDocumentCommand{\mytag}{m} - {% - \begin{minipage}[t]{\marginparwidth}% - \raggedleft\ttfamily\small% - \textcolor{gray}{\%<*}{\bfseries\textcolor{pkgcolor}{#1}}\textcolor{gray}{>}\par% - \meta[ac=lightgray,cf=gray]{content}\par% - \textcolor{gray}{\%}% - \end{minipage}% - \SortIndex{docstrip}{Docstrip tag>\small\texttt{#1}}% - }% - -% \DescribeTE{sm}, #1 tag, #2 env -\newsavebox{\marginenvtag} -\NewDocumentCommand{\DescribeTE}{sm}{% -\begin{lrbox}{\marginenvtag}% - \begin{minipage}[t]{\marginparwidth}% - \raggedleft - \IfBooleanTF{#1}{\mytag{#2}}{\myenv{#2}} - \end{minipage}% -\end{lrbox}% - \leavevmode% - \marginpar{\usebox{\marginenvtag}}% - \ignorespaces% -}% - -% DescribeOptFile*{options}{example}[!] -\newsavebox{\optinfile} -\NewDocumentCommand{\DescribeOptFile}{s m m O{\hphantom{!}}}{ -\begin{lrbox}{\optinfile}% - \begin{minipage}[t]{\marginparwidth}% - \raggedleft\ttfamily\bfseries% - \textcolor{gray}{\%}\textcolor{optcolor}{{#4}\myscript}\textcolor{gray}{\texttt{:}}% - \end{minipage}% -\end{lrbox}% -\leavevmode% -\lapbox[0pt]{-\marginparwidth-0.5\marginparsep}{\usebox{\optinfile}}% -\textcolor{optcolor}{\bfseries\texttt{{#2}}}% -\textcolor{gray}{\texttt{:}}\space% -\marg[type=tt,cbc=gray,ac=lightgray,cf=optcolor!85]{#3}% -\vspace*{2pt}\par% -\IfBooleanF{#1} - {% - \SortIndex{options}{\textsf{\myscript}\ options in input file>\small\texttt{#2}}% - }% -} - -% \DescribeCmd[...]{...}{...}{...} -\newsavebox{\optcmdline} -\NewDocumentCommand{\DescribeCmd}{ o m m m } - { - \begin{lrbox}{\optcmdline}% - \begin{minipage}[t]{\marginparwidth}% - \ttfamily\bfseries\raggedleft% - \IfNoValueTF{#1} - {\textcolor{optcolor}{-\/-#2}} - {\textcolor{optcolor}{-{#1}}\textcolor{gray}{,} \textcolor{optcolor}{-\/-#2}}% - \end{minipage}% - \SortIndex{options}{\textsf{\myscript}\ options in command line>\small\texttt{-\/-#2}}% - \end{lrbox}% - \leavevmode% - \marginpar{\usebox{\optcmdline}}% - \ignorespaces - \meta[ac=lightgray,cf=gray]{#3} - \hfill\textcolor{gray}{\textsf{(default: {#4})}}% - \vspace*{2pt}\par% -} - -% don't copy numbers in code example for listings -\newcommand*{\noaccsupp}[1]{\BeginAccSupp{ActualText={}}#1\EndAccSupp{}} - -% Create a language for documentation -\lstdefinelanguage{ltximg-doc}{ - texcsstyle=*,% - escapechar=`,% - showstringspaces=false,% - extendedchars=true, % - stringstyle = {\color{red}},% - alsoletter={\-,.},% -% comments - morecomment=[l]{\%},% - commentstyle=\lmmitalic\color{lightgray},% -% Important words 1 - keywordstyle=[1]{\color{NavyBlue}},% - keywords=[1]{PassOptionsToPackage,AtBeginDocument,documentclass,usepackage,section},% -% Important words 2 (macros) - keywordstyle=[2]{\color{blue!75}},% - keywords=[2]{graphicspath,RequirePackage,renewcommand,includegraphics,coordinate,draw,approx,% - PreviewBbAdjust,setlength,parindent,usetikzlibrary,tikzexternalize,psset,tikzset,PrependGraphicsExtensions,% - DefineShortVerb,lstMakeShortInline,MakeSpecialShortVerb,UndefineShortVerb,verb,myverb,macro,put,line},% -% Important words 3, options in input file - keywordstyle=[3]{\color{optcolor!85}},% - keywords=[3]{extrenv,deltenv,skipenv,options,arara,extensions,luatex,env,norun,% - clean,pst,tkz,eps,pdf,xetex,latex,luatex,dvips,png,latexmk,svg,srcenv,noprew,imgdir,prefix,output},% -% Important words 4, environments and tags - keywordstyle=[4]{\color{pkgcolor}},% - keywords=[4]{ltximg,noltximg,remove,pspicture,endpspicture,overlay,remember,% - description,filecontents,PSTexample,pgfpicture, endpgfpicture, tikzpicture, endtikzpicture, % - psgraph, endpsgraph,nopreview,postscript,picture},% -% Important words 5, directory - keywordstyle=[5]{\color{OrangeRed}},% - keywords=[5]{images,pics},% -% Important words 6, begin, end and other - keywordstyle=[6]{\color{gray}},% replace this color - keywords=[6]{begin,end,-recorder,doc,active,inactive,tightpage,BEGIN,END,% - -shell-escape,osf,--output-format,--exact-bbox,-o,dvi},% -% Important words 7, reserved for arara - keywordstyle=[7]{\color{araracolor}},% - keywords=[7]{lualatex,dvisvgm,halt,xelatex},% -% Important words 8, pkg and others load in examples - keywordstyle=[8]{\color{SlateBlue}},% - keywords=[8]{graphicx,grfext,tikz,article,document,preview,libertinus,calc,tikzmark,pst-pdf},% -% Important words 9, files used in examples - keywordstyle=[10]{\color{OrangeRed}},% - keywords=[10]{file.tex,test-fig-1981.tex,test-fig-1981.pdf,test-fig-1,test-fig-2,test-out,test-in.ltx,% - test-fig-1981.tex,test-out.tex,file-in.tex,file-out,test.tex,test-fig-all.dvi,test-fig-1.svg,test-fig-all.tex},% -}[keywords,tex,comments,strings]% end languaje - -% \begin{examplecode}[opts]...\end{examplecode} -\lstnewenvironment{examplecode}[1][]{% -\lstset{ - language=ltximg-doc,% - stringstyle = {\color{red}},% - basicstyle=\ttfamily\small,% - numbersep=1em,% - numberstyle=\tiny\color{gray}\noaccsupp,% - rulecolor=\color{gray!50},% - framesep=\fboxsep,% - framerule=\fboxrule,% - xleftmargin=\dimexpr\fboxsep+\fboxrule\relax,% - xrightmargin=\dimexpr\fboxsep+\fboxrule\relax,% -% literateee - literate=*{\{}{{\bfseries\textcolor{gray}{\{}}}{1} - {\}}{{\bfseries\textcolor{gray}{\}}}}{1} - {[}{{\textcolor{gray}{[}}}{1} - {]}{{\textcolor{gray}{]}}}{1} - {\*}{{\bfseries\textcolor{MediumOrchid}{*}}}{1} - {:}{{\textcolor{gray}{:}}}{1} - {,}{{\textcolor{gray}{,}}}{1} - {=}{{\textcolor{gray}{=}}}{1} - {/}{{\textcolor{OrangeRed}{/}}}{1} - {scale=1}{{\textcolor{gray}{scale=1}}}{7} - {\%\ ltximg}{{\textcolor{gray}{\%}\space\textcolor{optcolor}{ltximg}}}{8} - {\%\ arara}{{\textcolor{gray}{\%}\space\textcolor{araracolor}{arara}}}{7} - {\%<*remove>}{{\textcolor{gray}{\%<*}\textcolor{pkgcolor}{remove}\textcolor{gray}{>}}}{10} - {\%}{{\textcolor{gray}{\%}}}{10} - {\%<*ltximg>}{{\textcolor{gray}{\%<*}\textcolor{pkgcolor}{ltximg}\textcolor{gray}{>}}}{10} - {\%}{{\textcolor{gray}{\%}}}{10} - {\%<*noltximg>}{{\textcolor{gray}{\%<*}\textcolor{pkgcolor}{noltximg}\textcolor{gray}{>}}}{12} - {\%}{{\textcolor{gray}{\%}}}{12},% - #1,% - }% close lstset -}% -{}% close examplecode - -% \begin{examplecmd}...\end{examplecmd} -\lstnewenvironment{examplecmd}{% -\lstset{ - language=ltximg-doc,% - basicstyle=\ttfamily\small,% - frame=single,% - alsoletter={\-,.,\-\-},% - rulecolor=\color{gray!50},% - framesep=\fboxsep,% - framerule=\fboxrule,% - xleftmargin=\dimexpr\fboxsep+\fboxrule\relax,% - xrightmargin=\dimexpr\fboxsep+\fboxrule\relax,% - keywordstyle=[20]{\color{gray}},% replace this color - keywords=[20]{-recorder,-shell-escape,--latex,-s,-o,--arara,--log,% - -no-shell-escape,-interaction,nonstopmode,--norun,--luatex,--latexmk,% - --svg,--png,--nopdf,--margins},% -% Reserved words (cmd line options) - deletekeywords=[4]{ltximg},% - classoffset=7,% - keywordstyle=\bfseries\color{pkgcolor},% - morekeywords={ltximg},% -% % Reserved words (cmd line options) - classoffset=8,% - keywordstyle={\color{ForestGreen}},% - morekeywords={gs,pdftoppm,pdftocairo,pdftops,cd,perl,pdfcrop},% -% Only for command line options - classoffset=5,% - keywordstyle=\color{blue},% - keywords={user,machine},% - literate=*{[}{{\textcolor{darkgray}{[}}}{1} - {]}{{\textcolor{darkgray}{]}}}{1} - {=}{{\textcolor{gray}{=}}}{1} - {@}{{\textcolor{blue}{@}}}{1} - {\$}{{\textcolor{blue}{\$}}}{1} - {:}{{\textcolor{blue}{:}}}{1} - {§}{{\textcolor{red}{\$}}}{1} - {~}{{\textcolor{blue}{\bfseries\textasciitilde}}}{1}% - }% close lstset -}% -{}% close examplecmd - -% \lstinline[style=inline]|...| -\lstdefinestyle{inline} - { - language=ltximg-doc,% - basicstyle=\ttfamily\color{gray},% - escapechar=`,% - upquote=true,% - deletekeywords=[8]{preview},% - morekeywords =[4]{preview},% - literate=*{\%}{{\bfseries\textcolor{gray}{\%}}}{1} - {\*}{{\bfseries\textcolor{MediumOrchid}{*}}}{1} - } - -% set default style -\lstset{style=inline} - -\begin{document} - -\title{% - {\fetamontotf latex environments }\\[3pt]% - \scalebox{3.4}{\LTXimg}\\[2pt]% - {\fetamontotf\addfontfeature{LetterSpace=12.0} to image format}\\% - \Large - v\fileversion{} --- \filedate\thanks{% - This file describes a documentation for version \fileversion, last revised \filedate.}\\[25pt]% - \author{% - \large% - \raisebox{-1pt}{\textcopyright}{}2013--2020 by Pablo González L% - \thanks{E-mail: \textcolor{optcolor}{\textsf{\guillemotleft}}\email{pablgonz@yahoo.com}\textcolor{optcolor}{\textsf{\guillemotright}}} - }% -\small -\textsc{ctan}: \url{https://www.ctan.org/pkg/ltximg}\\ -\textcolor{gray}{\scriptsize\faIcon[regular]{github}}\,\,\,\url{https://github.com/pablgonz/ltximg} -\vspace*{-2cm} -}% -\date{} -\maketitle - -\begin{abstract} -\ltximg{} is a \prgname{perl} \emph{script} that automates the process of -extracting and converting environments provided by \pkgname{TikZ}, % -\pkgname{PStricks} and other packages from \meta[cf=optcolor]{input file} to image -formats and standalone files using \prgname{ghostscript} and % -\prgname{poppler-utils}. Generates a file with only extracted environments -and another with all extracted environments converted to \ics{includegraphics}. -\end{abstract} - -\tableofcontents -\setlength{\parskip}{3pt} - -\section{License} - -This program is free software; you can redistribute it and/or modify -it under the terms of the \href{https://www.gnu.org/licenses/gpl-3.0.html}{GNU General Public License} as published by -the \href{https://www.fsf.org/}{Free Software Foundation}; either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \href{https://www.gnu.org/licenses/gpl-3.0.html}{GNU General Public License} -for more details. - -\section{Motivation and Acknowledgments} - -The original idea was to extend the functionality of the \scriptname{pst2pdf}\cite{pst2pdf} -script to work with \env{tikzpicture} and other environments. The \pkgname{TikZ}\cite{tikz} package -allows to \emph{externalize} the environments, but, the idea was to be able to extend this -to \emph{any type} of environment covering three central points: - -\begin{enumerate}[font=\small,noitemsep,leftmargin=*,nosep] - -\item Generate a separate image files for environments. - -\item Generate a standalone files with only the extracted environments. - -\item Generate a file replacing the environments by \ics{includegraphics}. -\end{enumerate} - -From the side of \hologo{TeX} there are some packages that cover several of these -points such as the \pkgname{preview}\cite{preview}, \pkgname{xcomment}\cite{xcomment}, \pkgname{extract}\cite{extract} -and \pkgname{cachepic}\cite{cachepic} packages among others, but none covered all points. - -In the network there are some solutions in \texttt{bash} that were able to -extract and convert environments, but in general they presented problems -when the document contained \emph{\enquote{verbatim style}} code or were only -available for \OSsystem{Linux}. - -\thispagestyle{plain} - -\newpage - -\pagestyle{myheader} - -Analysed the situation the best thing was to create a new \emph{\enquote{script}} that -was able to cover the three points and was multi platform, the union of all -these ideas is born \ltximg. - -This script would not be possible without the great work of Herbert Voß -author of \scriptname{pst2pdf}\footnote{\url{https://ctan.org/pkg/pst2pdf}} -and Heiko Oberdiek author of \scriptname{pdfcrop}\footnote{\url{https://ctan.org/pkg/pdfcrop}}. -Several parts of the code have been taken and adapted from both scripts. - -\section{Requirements for operation} -\label{sec:requirements} - -For the complete operation of \ltximg{} you need to have a modern % -\hologo{TeX} distribution such as \hologo{TeX} Live or \hologo{MiKTeX}, have -a version equal to or greater than \liningnums{5.28} of \prgname{perl}, a -version equal to or greater than \liningnums{9.24} of \prgname{ghostscript}, a -version equal to or greater than \liningnums{1.40} of \scriptname{pdfcrop} -and have a version equal to or greater than \liningnums{0.52} of % -\prgname{poppler-utils}. The distribution of \hologo{TeX} Live 2020 for \OSsystem{Windows} includes % -\ltximg{} and all requirements, \hologo{MiKTeX} users must install the -appropriate software for full operation. - -The script auto detects the \prgname{ghostscript}, but not \prgname{poppler-utils}. -You should keep this in mind if you are using the script directly and not -the version provided in your \hologo{TeX} distribution. - -The script has been tested on \OSsystem{Windows} (v10) and % -\OSsystem{Linux} (fedora 32) using \prgname{ghostscript} % -\liningnums{v9.52}, \prgname{poppler-utils} \liningnums{v0.84}, \prgname{perl} \liningnums{v5.30} -and the standard classes offers by \hologo{LaTeX}: \myclass{book}, -\myclass{report}, \myclass{article} and \myclass{letter}. The \pkgname{preview}\cite{preview} and -\pkgname{pst-pdf}\cite{pst-pdf} packages are required to process the \meta{input file} and if -an \meta{output file} is generated, the \pkgname{graphicx}\cite{graphicx} and \pkgname{grfext}\cite{grfext} -packages will be needed. - -\section{How it works} -\label{sec:howtowork} - -It is important to have a general idea of how the \emph{\enquote{extraction and conversion}} -process works and the requirements that must be fulfilled so -that everything works correctly, for this we must be clear about some -concepts related to how to work with the \meta[cf=optcolor]{input file}, the \meta{verbatim content} -and the \meta{steps process}. - -\subsection{The input file} -\label{sec:inputfile} - -The \meta[cf=optcolor]{input file} must comply with \emph{certain characteristics} in order to -be processed, the content at the beginning and at the end of the \meta{input -file} is treated in a special way, before \lstinline|\documentclass| and after -\lstinline|\end{document}| can go any type of content, internally the script will -\emph{\enquote{split}} the \meta[cf=optcolor]{input file} at this points. - -If the \meta[cf=optcolor]{input file} contains files using \ics{input}\marg[type=tt]{file} or -\ics{include}\marg[type=tt]{file} these will not be processed, from the side of -the \emph{script} they only represent lines within the file, if you want -them to be processed it is better to use the \scriptname{latexpand}\footnote{\url{https://www.ctan.org/pkg/latexpand}} -first and then process the file. - -Like \ics{input}\marg[type=tt]{file} or \ics{include}\marg[type=tt]{file}, blank lines, vertical spaces and tab -characters are treated literally, for the \emph{script} the \meta[cf=optcolor]{input file} -is just a set of characters, as if it was a simple text file. It is -advisable to format the source code \meta[cf=optcolor]{input file} using utilities such -as \prgname{chktex}\footnote{\url{https://www.ctan.org/pkg/chktex}} and -\scriptname{latexindent}\footnote{\url{https://www.ctan.org/pkg/latexindent}}, especially if you want to -extract the source code of the environments. - -Both \ics{thispagestyle}\marg[type=tt]{style} and \ics{pagestyle}\marg[type=tt]{style} -are treated in a special way by the script, if they do not appear in the -preamble then \ics{pagestyle}\marg[type=tt]{empty} will be added and if they are present -and \marg[type=tt]{style} is different from \marg[type=tt]{empty} this -will be replaced by \marg[type=tt]{empty}. - -This is necessary for the image creation process, it does not affect the \meta{output file}, but -it does affect the \emph{standalone} files. For the script the process of dividing the \meta{input file} into four -parts and then processing them: - -\begin{examplecode}[numbers=left,frame=single] -% Part One: Everything before \documentclass -\documentclass{article} -% Part two: Everything between \documentclass and \begin{document} -\begin{document} -% Part three: : Everything between \begin{document} and \end{document} -\end{document} -% Part Four: Everything after \end{document} -\end{examplecode} - -If for some reason you have an environment \LWenv{filecontens} before \lstinline|\documentclass| or -in the preamble of the \meta{input file} that contains a \emph{sub-document} or \emph{environment} -you want to extract, the script will ignore them. Similarly, the content after \lstinline|\end{document}| -is ignored in the extraction process. - -\newpage - -\subsection{Verbatim contents} -\label{sec:verbatim} - -One of the greatest capabilities of this script is to \emph{\enquote{skip}} -the complications that \meta{verbatim content} produces with the extraction -of environments using tools outside the \enquote{\hologo{TeX} world}\footnote{Only \hologo{TeX} can -understand \hologo{TeX}, all other languages and programs are just lines in a file.}. -In order to \emph{\enquote{skip}} the complications, the \meta{verbatim content} is classified into -three types: - -\begin{itemize}[nosep] - \item Verbatim in line. - \item Verbatim standard. - \item Verbatim write. -\end{itemize} - -\subsection*{Verbatim in line} -\label{sec:verbatim:inline} - -The small pieces of code written using a \emph{\enquote{verbatim macro}} -are considered \meta{verbatim in line}, such as \lstinline+\verb|+\meta{code}\lstinline+|+ -or \lstinline+\verb*|+\meta{code}\lstinline+|+ or \lstinline+\macro+\marg[type=tt]{code} or -\lstinline+\macro+\oarg[type=tt]{opts}\marg[type=tt]{code}. - -Most \emph{\enquote{verbatim macro}} provide by packages \pkgname{minted}\cite{minted}, % -\pkgname{fancyvrb}\cite{fancyvrb} and \pkgname{listings}\cite{listings} have been tested and are fully -supported. They are automatically detected the \emph{verbatim macro} (including \texttt{\small\bfseries\textcolor{MediumOrchid}{*}} argument) generates by -\ics{newmint} and \ics{newmintinline} and the following list: - -\vspace*{-10pt} -\begin{multicols}{3} -\begin{itemize}[font=\sffamily\small,partopsep=5pt,parsep=5pt,nosep,leftmargin=*] -\small -\item \ics{mint} -\item \ics{spverb} -\item \ics{qverb} -\item \ics{fverb} -\item \ics{verb} -\item \ics{Verb} -\item \ics{lstinline} -\item \ics{pyginline} -\item \ics{pygment} -\item \ics{Scontents} -\item \ics{tcboxverb} -\item \ics{mintinline} -\end{itemize} -\end{multicols} - -Some packages define abbreviated versions for \emph{\enquote{verbatim macro}} as % -\ics{DefineShortVerb}, \ics{lstMakeShortInline} and % -\ics{MakeSpecialShortVerb}, will be detected automatically if are declared -explicitly in \meta[cf=optcolor]{input file}. - -The following consideration should be kept in mind for some packages that -use abbreviations for verbatim macros, such as \pkgname{shortvrb}\cite{doc} or % -\pkgname{doc}\cite{doc} for example in which there is no explicit \lstinline+\macro+ in the -document by means of which the abbreviated form can be detected, for -automatic detection need to find \ics{DefineShortVerb} explicitly to process -it correctly. The solution is quite simple, just add in \meta[cf=optcolor]{input file}: - -\begin{examplecode} -\UndefineShortVerb{\|} -\DefineShortVerb{\|} -\end{examplecode} - -depending on the package you are using. If your \emph{\enquote{verbatim macro}} is not -supported by default or can not detect, use the options described in \ref% -{sec:optline} and \ref{sec:optfile}. - -\subsection*{Verbatim standard} -\label{sec:verbatim:std} - -These are the \emph{\enquote{classic}} environments for \emph{\enquote{writing code}} are considered % -\meta{verbatim standard}, such as \LVenv{verbatim} and \LVenv{lstlisting} -environments. The following list (including \texttt{\small\bfseries\textcolor{MediumOrchid}{*}} argument) -is considered as \meta{verbatim standard} environments: - -\begin{multicols}{4} -\begin{itemize}[font=\sffamily\small, noitemsep,leftmargin=*] -\small -\item \LVenv{Example} -\item \LVenv{CenterExample} -\item \LVenv{SideBySideExample} -\item \LVenv{PCenterExample} -\item \LVenv{PSideBySideExample} -\item \LVenv{verbatim} -\item \LVenv{Verbatim} -\item \LVenv{BVerbatim} -\item \LVenv{LVerbatim} -\item \LVenv{SaveVerbatim} -\item \LVenv{PSTcode} -\item \LVenv{LTXexample} -\item \LVenv{tcblisting} -\item \LVenv{spverbatim} -\item \LVenv{minted} -\item \LVenv{listing} -\item \LVenv{lstlisting} -\item \LVenv{alltt} -\item \LVenv{comment} -\item \LVenv{chklisting} -\item \LVenv{verbatimtab} -\item \LVenv{listingcont} -\item \LVenv{boxedverbatim} -\item \LVenv{demo} -\item \LVenv{sourcecode} -\item \LVenv{xcomment} -\item \LVenv{pygmented} -\item \LVenv{pyglist} -\item \LVenv{program} -\item \LVenv{programl} -\item \LVenv{programL} -\item \LVenv{programs} -\item \LVenv{programf} -\item \LVenv{programsc} -\item \LVenv{programt} -\end{itemize} -\end{multicols} - -They are automatically detected \meta{verbatim standard} environments -(including \texttt{\small\bfseries\textcolor{MediumOrchid}{*}} argument) -generates by commands: - -\begin{multicols}{2} -\begin{itemize}[font=\sffamily\small,noitemsep,leftmargin=*] -\small -\item \ics{DefineVerbatimEnvironment} -\item \ics{NewListingEnvironment} -\item \ics{DeclareTCBListing} -\item \ics{ProvideTCBListing} -\item \ics{lstnewenvironment} -\item \ics{newtabverbatim} -\item \ics{specialcomment} -\item \ics{includecomment} -\item \ics{newtcblisting} -\item \ics{NewTCBListing} -\item \ics{newverbatim} -\item \ics{NewProgram} -\item \ics{newminted} -\end{itemize} -\end{multicols} - -If any of the \meta{verbatim standard} environments is not supported by -default or can not detected, you can use the options described in \ref% -{sec:optline} and \ref{sec:optfile}. - -\subsection*{Verbatim write} -\label{sec:verbatim:write} - -Some environments have the ability to write \emph{\enquote{external files}} -or \emph{\enquote{store content}} in memory, these environments are -considered \meta{verbatim write}, such as \LWenv{scontents}, \LWenv{filecontents} -or \LWenv{VerbatimOut} environments. The following list is considered (including \texttt{\small\bfseries\textcolor{MediumOrchid}{*}} argument) as % -\meta{verbatim write} environments: - -\begin{multicols}{4} -\begin{itemize}[font=\sffamily\small, noitemsep,leftmargin=*] -\ttfamily\small -\item \LWenv{scontents} -\item \LWenv{filecontents} -\item \LWenv{tcboutputlisting} -\item \LWenv{tcbexternal} -\item \LWenv{tcbwritetmp} -\item \LWenv{extcolorbox} -\item \LWenv{extikzpicture} -\item \LWenv{VerbatimOut} -\item \LWenv{verbatimwrite} -\item \LWenv{filecontentsdef} -\item \LWenv{filecontentshere} -\item \LWenv{filecontentsdefmacro} -\item \LWenv{filecontentsdefstarred} -\item \LWenv{filecontentsgdef} -\item \LWenv{filecontentsdefmacro} -\item \LWenv{filecontentsgdefmacro} -\end{itemize} -\end{multicols} - -They are automatically detected \meta{verbatim write} -(including \texttt{\small\bfseries\textcolor{MediumOrchid}{*}} argument) environments generates -by commands: - -\begin{itemize}[font=\sffamily\small, noitemsep,leftmargin=*] -\small -\item \ics{renewtcbexternalizetcolorbox} -\item \ics{renewtcbexternalizeenvironment} -\item \ics{newtcbexternalizeenvironment} -\item \ics{newtcbexternalizetcolorbox} -\item \ics{newenvsc} -\end{itemize} - -If any of the \meta{verbatim write} environments is not supported by default -or can not detected, you can use the options described in \ref{sec:optline} -and \ref{sec:optfile}. - -\subsection{Steps process} -\label{sec:steps:process} - -For creation of the image formats, extraction of source code of environments and creation of an -\meta[cf=optcolor]{output file}, \ltximg{} need a various steps. Let's assume that the % -\meta[cf=optcolor]{input file} is \sysfile{test.tex}, \meta[cf=optcolor]{output file} is % -\sysfile{test-out.tex}, the working directory are \enquote{\sysdir{./}}, the -directory for images are \sysdir{./images}, the temporary -directory is \sysdir{/tmp} and we want to generate images in \iext{pdf} -format and \meta{standalone} files for all environments extracted. - -We will use the following code as \sysfile{test.tex}: - -\begin{examplecode}[numbers=left,frame=single] -% Some commented lines at begin file -\documentclass{article} -\usepackage{tikz} -\begin{document} -Some text -\begin{tikzpicture} - Some code -\end{tikzpicture} -Always use \verb|\begin{tikzpicture}| and \verb|\end{tikzpicture}| to open -and close environment -\begin{tikzpicture} - Some code -\end{tikzpicture} -Some text -\begin{verbatim} -\begin{tikzpicture} - Some code -\end{tikzpicture} -\end{verbatim} -Some text -\end{document} -Some lines that will be ignored by the script -\end{examplecode} - -\subsection*{Validating Options} - -The first step is read and validated \oarg[type=tt,cf=optcolor,sbc=gray,ac=lightgray]{options} from the command -line and \sysfile{test.tex}, verifying that \sysfile{test.tex} contains \emph{some} environment to extract, -check the name and extension of \sysfile{test-out.tex}, check the directory \sysdir{./images} if it doesn't exist create it -and create a temporary directory \sysdir{/tmp/hG45uVklv9}. - -The entire \sysfile{test.tex} file is loaded into memory and \emph{\enquote{split}} to start the extraction process. - -\newpage - -\subsection*{Comment and ignore} -In the second step, once the file \sysfile{test.tex} is loaded and divided in memory, -proceeds (in general terms) as follows: - -\begin{quotation} -Search the words \lstinline|\begin{| and \lstinline|\end{| in verbatim standard, verbatim write, verbatim in line and -commented lines, if it finds them, converts to \lstinline|\BEGIN{| and \lstinline|\END{|, then places all code to -extract inside the \lstinline|\begin{preview}| \ldots \lstinline|\end{preview}|. -\end{quotation} - -At this point \emph{\enquote{all}} the code you want to extract is inside \lstinline|\begin{preview}|\ldots\lstinline|\end{preview}|. - -\subsection*{Creating files and extracting} - -In the third step, the script generate \meta{standalone} files: \sysfile{test-fig-1.tex}, -\sysfile{test-fig-2.tex}, \dots{} and saved in \sysdir{./images} then proceed in two ways -according to the \oarg[type=tt,cf=optcolor,sbc=gray,ac=lightgray]{options} -passed to generate a temporary file with a random number (1981 for example): - -\begin{enumerate}[leftmargin=*] -\item If script is call \emph{without} \cmdopt{noprew} options, the following lines -will be added at the beginning of the \sysfile{test.tex} (in memory): - -\begin{examplecode} -\PassOptionsToPackage{inactive}{pst-pdf}% -\AtBeginDocument{% -\RequirePackage[inactive]{pst-pdf}% -\RequirePackage[active,tightpage]{preview}% -\renewcommand\PreviewBbAdjust{-60pt -60pt 60pt 60pt}}% -% rest of input file -\end{examplecode} - -The different parts of the file read in memory are joined and save in a temporary -file \sysfile{test-fig-1981.tex} in \enquote{\sysdir{./}}. This file will contain all the environments -for extraction between \lstinline|\begin{preview}|\ldots\lstinline|\end{preview}| along with the rest of the document. -If the document contains images, these must be in the formats supported by the \emph{engine} selected to process the \meta{input file}. - -\item If script is call \emph{with} \cmdopt{noprew} options, the \lstinline|\begin{preview}|\ldots\lstinline|\end{preview}| -lines are only used as delimiters for extracting the content \emph{without} using the package \pkgname{preview}, the following lines -will be added at the beginning of the \sysfile{test.tex} (in memory): - -\begin{examplecode} -\PassOptionsToPackage{inactive}{pst-pdf}% -\AtBeginDocument{% -\RequirePackage[inactive]{pst-pdf}}% -% only environments extracted -\end{examplecode} - -Then it is joined with all extracted environments separated by \ics{newpage} and saved -in a temporary file \sysfile{test-fig-1981.tex} in \enquote{\sysdir{./}}. - -\end{enumerate} - -If \cmdopt{norun} is passed, the temporary file \sysfile{test-fig-1981.tex} -is renamed to \sysfile{test-fig-all.tex} and moved to \sysdir{./images}. - -\subsection*{Generate image formats} - -In the fourth step, the script generating the file \sysfile{test-fig-1981.pdf} with all code extracted and croping, running: -\begin{examplecmd} -[user@machine ~:]§ `\small\meta[type=tt,cf=ForestGreen,ac=lightgray]{compiler}` -no-shell-escape -interaction=nonstopmode -recorder test-fig-1981.tex -[user@machine ~:]§ pdfcrop --margins `\small\textcolor{gray}{0}` test-fig-1981.pdf test-fig-1981.pdf -\end{examplecmd} -Now move \sysfile{test-fig-1981.pdf} to \sysdir{/tmp/hG45uVklv9} and rename to \sysfile{test-fig-all.pdf}, -generate image files \sysfile{test-fig-1.pdf} and \sysfile{test-fig-2.pdf} and copy to \sysdir{./images}, if the -image files exist, they will be rewritten each time you run the script. The file \sysfile{test-fig-1981.tex} is -moved to the \sysdir{./images} and rename to \sysfile{test-fig-all.tex}. - -Note the options passed to \meta[type=tt,cf=ForestGreen,ac=lightgray]{compiler} always use \prgopt*{no-shell-escape} -and \prgopt*{recorder}, to generate the \fext{fls} file which is used to delete temporary files and directories after -the process is completed. The \cmdopt{shell} option activates \prgopt*{shell-escape} for compatibility with packages -such as \pkgname{minted} or others. - -\subsection*{Create output file} - -In the fifth step, the script apply the option \cmdopt{clean}, remove all content betwen \lstinline|%<*remove> ... %| -and try to detect whether the \pkgname{graphicx} package and the \ics{graphicspath} command are in the preamble of the \meta[cf=optcolor]{output file} (in memory). -If it is not possible to find it, it will read the \fext{log} file generated by the temporary file with only preamble. -Once the detection is complete, the package \pkgname{grfext} and \ics*{PrependGraphicsExtensions*} will be added at the end of the preamble: - -\begin{examplecode}[numbers=left] -\usepackage{graphicx} -\graphicspath{{images/}} -\usepackage{grfext} -\PrependGraphicsExtensions*{.pdf} -\end{examplecode} - -Now converting all extracted code to \ics{includegraphics} and save \sysfile{test-out.tex} -in \enquote{\sysdir{./}}, then proceed to run: - -\begin{examplecmd} -[user@machine ~:]§ `\small\meta[type=tt,cf=ForestGreen,ac=lightgray]{compiler}` -recorder -shell-escape test-out.tex -\end{examplecmd} - -generating the file \sysfile{test-out.pdf}. - -\subsection*{Clean temporary files and dirs} - -In the sixth step, the script read the files \sysfile{test-fig-1981.fls} -and \sysfile{test-out.fls}, extract the information from the -temporary files and dirs generated in the process in \enquote{\sysdir{./}} and then -delete them together with the directory \sysdir{/tmp/hG45uVklv9}. - -Finally the output file \sysfile{test-out.tex} looks like this: - -\begin{examplecode}[numbers=left] -% some commented lines at begin document -\documentclass{article} -\usepackage{tikz} -\graphicspath{{images/}} -\usepackage{grfext} -\PrependGraphicsExtensions*{.pdf} -\begin{document} -Some text -\includegraphics[scale=1]{test-fig-1} -Always use \verb|\begin{tikzpicture}| and \verb|\end{tikzpicture}| to open -and close environment -\includegraphics[scale=1]{test-fig-2} -Some text -\begin{verbatim} -\begin{tikzpicture} - Some code -\end{tikzpicture} -\end{verbatim} -Some text -\end{document} -\end{examplecode} - -\section{Extract content} -\label{sec:extract} - -The script provides two ways to \meta{extract} content from \meta[cf=optcolor]{input file}, -using \meta[type=rm,cf=optcolor,ac=gray]{environments} and \meta[type=rm,cf=optcolor,ac=gray]{docstrip tags}. -Some environment (including \texttt{\small\bfseries\textcolor{MediumOrchid}{*}} argument) -are supported by default. If environments are nested, the outermost one will be extracted. - -\subsection{Default environments} -\label{sec:extract:env} - -\DescribeTE{preview} -Environment provide by \pkgname{preview}\cite{preview} package. If any \env{preview} environments -found in the \meta[cf=optcolor]{input file} will be extracted and converted these. Internally -the script converts all environments to extract in \env{preview} environments. -Is better comment this package in preamble unless the option \cmdopt[n]{noprew}{} is -used. This environment is reserved for the internal process of extraction and conversion, it -cannot be passed as an argument to the option \cmdopt{skipenv}. - -\vspace{0.25\baselineskip} - -\DescribeTE{postscript} -Environment provide by \pkgname{pst-pdf}\cite{pst-pdf}, \pkgname{auto-pst-pdf}\cite{auto-pst-pdf} -and \pkgname{auto-pst-pdf-lua}\cite{auto-pst-pdf-lua} packages. Since the \pkgname{pst-pdf}, \pkgname{auto-pst-pdf} -and \pkgname{auto-pst-pdf-lua} packages internally use the \pkgname{preview} package, is better comment this in preamble. -Only the \emph{content} of this environment is extracted and \emph{\enquote{not}} the environment itself when using the -\cmdopt{srcenv}{} or \cmdopt{subenv}{} options. - -\vspace{0.25\baselineskip} - -\DescribeTE{PSTexample} -Environment provide by \pkgname{pst-exa}\cite{pst-exa} packages. The script automatically detects the -\lstinline|\begin{PSTexample}| \lstinline|...\end{PSTexample}| -environments and processes them as separately compiled files. The user should have loaded the -package with the [\pkgopt{swpl}] or [\pkgopt{tcb}] option and run the script -using \cmdopt{latex}{} or \cmdopt{xetex}. This environment is reserved for the internal process of extraction and conversion, it -cannot be passed as an argument to the option \cmdopt{skipenv}{}. - -\vspace{0.25\baselineskip} - -\DescribeTE{pspicture} -Environment provide by \pkgname{PStricks}\cite{pstricks} package. The plain \hologo{TeX} -syntax \lstinline|\pspicture ... \endpspicture| its converted to \hologo{LaTeX} syntax -\lstinline|\begin{pspicture} ... \end{pspicture}| if not within the \env{PSTexample} or \env{postscript} environments. - -\vspace{0.75\baselineskip} - -\DescribeTE{psgraph} -Environment provide by \pkgname{pst-plot}\cite{pst-plot} package. The plain \hologo{TeX} syntax \lstinline|\psgraph ... \endpsgraph| -its converted to \hologo{LaTeX} syntax \lstinline|\begin{psgraph} ... \end{psgraph}| if -not within the \env{PSTexample} or \env{postscript} environments. - -\newpage - -\DescribeTE{tikzpicture} -Environment provide by \pkgname{TikZ}\cite{tikz} package. The plain \hologo{TeX} syntax \lstinline|\tikzpicture ... \tikzpicture| -its converted to \hologo{LaTeX} syntax \lstinline|\begin{tikzpicture} ... \end{tikzpicture}| -but no a short syntax \lstinline|\tikz ... ;|. - -\vspace{0.75\baselineskip} - -\DescribeTE{pgfpicture} -Environment provide by \pkgname{pgf}\cite{tikz} package. Since the script uses a -\emph{\enquote{recursive regular expression}} to extract environments, no presents problems -if present \env{pgfinterruptpicture}. - -If you need to extract other environments you can use one of the options described -in \ref{sec:optline} or \ref{sec:optfile}. - -\subsection{Extract with docstrip tags} -\label{sec:extract:tag} - -\DescribeTE*{ltximg} -All content included between \lstinline|%<*ltximg> ... %| is extracted. -The tags can \emph{not} be nested and should be at the beginning of the line and in separate lines. -Internally the script converts all this tags to \env{preview} environments. - -\begin{examplecode}[frame=single] -% no space before open tag %<* -%<*ltximg> -code to extract -% -% no space before close tag % ... %| are ignored and no extract. -The tags can \emph{not} be nested and should be at the beginning of the line and in separate lines. -Internally the script converts all this tags to \env{nopreview} environments. - -\begin{examplecode}[frame=single] -% no space before open tag %<* -%<*noltximg> -no extract this -% -% no space before close tag % ... %| are deleted in the \meta[cf=optcolor]{output file}. -The tags can \emph{not} be nested and should be at the beginning of the line and in separate lines. - -\begin{examplecode}[frame=single] -% no space before open tag %<* -%<*remove> -lines removed in output file -% -% no space before close tag % ... %|. Like this: - -\begin{examplecode}[numbers=left] -%<*remove> -% ltximg: options: { png, srcenv, xetex } -% ltximg: extrenv: { description } -% -\end{examplecode} - -\subsection*{Passing options from input file} - -Adding the following lines to the beginning of the file \sysfile{file-in.tex}: - -\begin{examplecode}[numbers=left] -% ltximg: options: { luatex, output = file-out, imgdir = pics, prefix = env } -% ltximg: skipenv: { tikzpicture } -% ltximg: deltenv: { filecontents } -\end{examplecode} -and run: -\begin{examplecmd} -[user@machine~:]§ ltximg file-in.tex -\end{examplecmd} - -Create a \sysdir{./pics} directory (if it does not exist) with all extracted environments, -except \env{tikzpicture}, converted to image formats (\iext{pdf}) in individual files, -an output file \meta[ac=LightSlateGrey,cf=OrangeRed]{file-out.tex} with all extracted environments -converted to \ics{includegraphics} and environment \LWenv{filecontents} removed, -a single file \meta[ac=LightSlateGrey,cf=OrangeRed]{file-in-env-all.ltx} with \emph{only} the extracted environments -using \prgname*{lualatex} and \pkgname{preview} package for process \meta[ac=LightSlateGrey,cf=OrangeRed]{file-in.tex} -and \meta[ac=LightSlateGrey,cf=OrangeRed]{file-out.tex}. - -\section{The way of \texttt{arara}} -\label{sec:arara} -By design, the script only runs \emph{\enquote{one or more compilation}} on top -of the \meta[cf=optcolor]{input file}, but, sometimes you need to process in a specific mode the \meta[cf=optcolor]{input file} -or needs to be processed with something other than \hologo{LaTeX}, \hologo{XeLaTeX}, \hologo{pdfLaTeX} or \hologo{LuaLaTeX} engine. -This is where \arara\cite{arara} comes in, this \emph{\enquote{great little tool}}, -is able to have complete control over the compilation of the \meta[cf=optcolor]{input file}, we just -have to keep a few considerations in mind: - -\begin{enumerate}[font=\small, nosep, noitemsep,leftmargin=*] -\item Read the documentation (this always comes first). -\item Add \lstinline|{ options: [-recorder] }| to \enquote{rule} for clean temporary files. -\item Avoiding the use of \lstinline|: clean: { extensions: [...] }|. -\item Don't set \lstinline|-jobname| and \lstinline|-output-directory| in any \enquote{rule}. -\end{enumerate} - -When the \cmdopt{arara} option is passed to the script, the line that runs in the system is: - -\begin{examplecmd} -[user@machine~:]§ `\small\prgname{arara}` --log file.tex -\end{examplecmd} - -If you have several \enquote{rules} within the file they will all be executed, to avoid this we must add: - -\begin{examplecode}[numbers=left] -% arara: halt -\end{examplecode} - -After the last \enquote{rule} you have at the beginning of the file. With all these considerations -in mind it is possible to extract and convert environments -from \emph{any file}. - -For example, by adding these lines at the beginning of the file: - -\begin{examplecode}[numbers=left] -% arara: lualatex: { options: [-recorder] } -% arara: lualatex: { options: [-recorder] } -%<*remove> -% ltximg: options: { arara, output = file-out, prefix = tkz} -% -\end{examplecode} - -and run: - -\begin{examplecmd} -[user@machine~:]§ ltximg test.tex -\end{examplecmd} - -Create a \sysdir{./images} directory (if it does not exist) with all extracted -environments converted to image format (\iext{pdf}) in individual files, -an output file \meta[ac=LightSlateGrey,cf=OrangeRed]{file-out.tex} with all exatracted environments -converted to \ics{includegraphics}, a single file \meta[ac=LightSlateGrey,cf=OrangeRed]{test-tkz-all.tex} -with only the extracted environments using \pkgname{preview} package and \prgname*{lualatex} \emph{\enquote{two times}} -for process \meta[ac=LightSlateGrey,cf=OrangeRed]{test.tex} and \meta[ac=LightSlateGrey,cf=OrangeRed]{file-out.tex}. - -Remember that the \meta[cf=optcolor]{input file} and \meta[cf=optcolor]{output file} -will be compiled using the same \enquote{rule}. One \emph{trick} to get around this situation is to use: - -\begin{examplecode}[numbers=left] -%<*remove> -% arara: lualatex: { options: [-recorder] } -% arara: lualatex: { options: [-recorder] } -% arara: halt -% ltximg: options: { arara, output = file-out, prefix = tkz} -% -% arara: xelatex: { options: [-recorder] } -% arara: xelatex: { options: [-recorder] } -\end{examplecode} - -The content betwen \lstinline|%<*remove> ... %| are remove from output file -before compiling. Thus, the output file \meta[ac=LightSlateGrey,cf=OrangeRed]{file-out.tex} will be -compiled using \prgname*{xelatex} \emph{\enquote{two times}}. - -As a final consideration, \ltximg{} passes options to the \pkgname{preview} package and -the \scriptname{pdfcrop} script according to the engine used. When using \cmdopt{arara} it -will \emph{\enquote{try}} to detect the used engine by means of a regular expression, if the -detection fails the default values will be used. - -This does not affect the process of creating \meta{standalone} files and can be prevented by using \cmdopt{noprew} -or \cmdopt{nocrop} at the cost of not having the images cropped. - -In this way we can \meta{compile} and \meta{convert} any document as long as the conditions -of the \meta[cf=optcolor]{input file} are met and the correct \enquote{rule} are used. - -\newpage - -\section{Example usign \texttt{latexmk}} - -If you are a user of \scriptname{latexmk}, another great utility that automates the compilation process, you must keep -in mind that this will run only in the \meta{output file}. Consider the following example -adapted from \href{https://tex.stackexchange.com/a/209059}{How to get tikzmark to work} and -\href{https://tex.stackexchange.com/a/114847}{Draw an aircraft with Tikz} -to generate an image in \iext{svg}, \iext{png} and \iext{pdf} format from environment \env{picture} using \prgname*{lualatex} and \scriptname{latexmk}. - -\begin{examplecode}[numbers=left] -%<*remove> -% ltximg: extrenv: {picture} -% ltximg: skipenv: {tikzpicture} -% -\documentclass{article} -\usepackage{tikz} -\usetikzlibrary{calc,tikzmark} -\setlength{\parindent}{0pt} -\begin{document} -\section{How to get Tikzmark to work} -By taking logarithms of both sides: - -\[ - t = \frac{30\cdot\ln(3/22)}{\ln(15/22)} - \tikzmark{calculator}\approx\tikzmark{otherside} - 156 -\] -\begin{tikzpicture}[overlay,remember picture] - \coordinate (target) at ($(pic cs:calculator)!1/2!(pic cs:otherside) - (0,.5ex)$); - \draw[arrows=->] (target) ++(0,-2ex) node [anchor=north] {use calculator} -- (target); -\end{tikzpicture} - -\section{Draw an aircraft with Tikz} -The best airplane ever drawn by David Carlise. No TikZ used, just the -classic and perhaps forgotten \verb|\begin{picture} ... \end{picture}|. - -\begin{picture}(200,100) - \put(30,40){\line(1,0){150}} \put(30,40){\line(0,1){60}} - \put(30,100){\line(1,0){20}} \put(50,100){\line(1,-4){10}} - \put(60,60){\line(1,0){100}} \put(160,60){\line(1,-1){20}} - \put(100,50){\line(0,-1){80}} \put(130,50){\line(0,-1){80}} - \put(100,-30){\line(1,0){30}} \put(100,61){\line(0,1){49}} - \put(130,61){\line(0,1){49}} \put(100,110){\line(1,0){30}} -\end{picture} -\end{document} -\end{examplecode} - -We now run: - -\begin{examplecmd} -[user@machine~:]§ ltximg --luatex --latexmk --svg --png -o file-out file-in.tex -\end{examplecmd} - -Create a \sysdir{./images} directory (if it does not exist) with all \env{picture} environments, -except \env{tikzpicture}, converted to image formats (\iext{svg}, \iext{png}, \iext{pdf}), -an output file \meta[ac=LightSlateGrey,cf=OrangeRed]{file-out.tex} with all \env{picture} environments -converted to \ics{includegraphics}, a single file \meta[ac=LightSlateGrey,cf=OrangeRed]{file-in-fig-all.ltx} with -only environments \env{picture} extracted using \prgname*{lualatex} and \pkgname{preview} package for process -\meta[ac=LightSlateGrey,cf=OrangeRed]{file-in.tex} and \scriptname{latexmk} for \emph{full} process -\meta[ac=LightSlateGrey,cf=OrangeRed]{file-out.tex}. - -\section{Note for \texttt{dvisvgm} users} -\label{sec:dvisvgm} - -By design, the image format \iext{svg} is created using \prgname{pdftocairo} over the -generated \iext{pdf} file, but, if you want to have a good \iext{svg} files that preserve our \emph{typographic} fonts it is best to -use \prgname{dvisvgm}\footnote{\url{https://ctan.org/pkg/dvisvgm}}. The best results of \prgname{dvisvgm}\cite{dvisvgm} are obtained when processing the file in \fext{dvi} or \fext{xdv} -format, there are two possible ways to do this: - -\begin{enumerate}[font=\small, nosep, noitemsep,leftmargin=*] -\item Execute the script using \cmdopt{subenv}{} and \cmdopt{norun}{} to generate \meta{standalone} files, move to \sysdir{./images} -and generate \fext{dvi} or \fext{xdv} files, then runing: - -\begin{examplecmd} -[user@machine~:]§ for i in *.tex; do `\meta[type=tt,cf=ForestGreen,ac=lightgray]{compiler} \oarg[type=tt,cf=gray,sbc=optcolor,ac=gray]{options}` §i;done -[user@machine~:]§ for i in *.dvi; do `\small\prgname{dvisvgm} \oarg[type=tt,cf=gray,sbc=optcolor,ac=gray]{options}` §i;done -\end{examplecmd} - -\item Execute the script using \cmdopt{norun}{}, move to \sysdir{./images} and generate \fext{dvi} or \fext{xdv} file, then runing: - -\begin{examplecmd} -[user@machine~:]§ `\meta[type=tt,cf=ForestGreen,ac=lightgray]{compiler} \oarg[type=tt,cf=gray,sbc=optcolor,ac=gray]{options}` test-fig-all.tex -[user@machine~:]§ `\small\prgname{dvisvgm} \oarg[type=tt,cf=gray,sbc=optcolor,ac=gray]{options}` test-fig-all.dvi -\end{examplecmd} - -\end{enumerate} - -\section{Final notes} - -The process and operations required to generate the various types of \meta{image -formats} or \meta{standalone} files have been described throughout the documentation, -but, as discussed in section \ref{sec:arara}, sometimes the requirements are a \emph{little -different}. - -This is the best way to extend the capabilities of the \ltximg{}. Although -many tasks can be \emph{automated}, in the end only the user knows what -the document contains and how it should be generated. - -Finding the correct \emph{\enquote{regular expressions}} and writing a \emph{\enquote{good documentation}} -would be the great mission (which does not end yet). - -\section{Change history} -\label{sec:change:history} - -The most recent publicly released of \ltximg{} is available at -\textsc{ctan}: \url{https://www.ctan.org/pkg/ltximg}. Historical and -developmental versions are available at \textcolor{gray}{\scriptsize\faIcon[regular]{github}} -\url{https://github.com/pablgonz/ltximg}. - -While general feedback via email is welcomed, specific bugs or feature -requests should be reported through the issue -tracker: \url{https://github.com/pablgonz/ltximg/issues}. - -This is a short list of some of the notable changes in the history of the \ltximg{} along with the -versions, both development (devp) and public (ctan). - -\setlist[itemize,1]{label=\textendash,wide=0.5em,nosep,noitemsep,leftmargin=10pt} -% length for change history -\newlength\descrwidth -\settowidth{\descrwidth}{\textsf{v1.4.5, (ctan), 2013-01-23}} -\begin{description}[font=\small\sffamily,wide=0pt,style=multiline,leftmargin=\descrwidth,nosep,noitemsep] -\item [v\fileversion\ (ctan), \filedate] - \begin{itemize} - \item Fix \texttt{graphicx} detection. - \item Fix typos in documentation. - \item Add more contents to \texttt{.log} file. - \end{itemize} -\item [v1.8 (ctan), 2020-08-18] - \begin{itemize} - \item It is now possible to extract any environment. - \item Add \texttt{--log}, \texttt{--runs}, \texttt{--latexmk} and \texttt{--dvilua} options. - \item All calls to the system are captured. - \item Re-write source code acording to \texttt{Perl} v5.3x. - \item Review of documentation. - \end{itemize} -\item [v1.7 (ctan), 2019-08-24] - \begin{itemize} - \item Add \texttt{scontents} environment support. - \item Add \texttt{filecontentsdefmacro} environment support. - \item Fix regex in source code. - \item Update documentation. - \end{itemize} -\item [v1.6 (ctan), 2019-07-13] - \begin{itemize} - \item Add \texttt{--zip} and \texttt{--tar} options. - \item Add new \texttt{Verb} from \texttt{fvextra}. - \item Fix and update source code and documentation. - \end{itemize} -\item [v1.5 (ctan), 2018-04-12] - \begin{itemize} - \item Use \texttt{GitHub} to control version. - \item Rewrite and optimize most part of source code and options. - \item Change \texttt{pdf2svg} for \texttt{pdftocairo}. - \item Complete support for \texttt{pst-exa} package. - \item Escape characters in regex according to \texttt{Perl} v5.2x. - \end{itemize} -\item [v1.4 (devp), 2016-11-29] - \begin{itemize} - \item Remove and rewrite code for regex and system call. - \item Add \texttt{--arara} compiler, clean and comment code. - \item Add \texttt{--dvips} and \texttt{--dvipdfm(x)} for creation images. - \item Add \texttt{bmp}, \texttt{tiff} image format. - \end{itemize} -\item [v1.3 (devp), 2016-08-14] - \begin{itemize} - \item Rewrite some part of code (norun, nocrop, clean). - \item Suport \texttt{minted} and \texttt{tcolorbox} package. - \item Escape some characters in regex according to \texttt{Perl} v5.2x. - \item All options read from command line and input file. - \item Use \texttt{/tmp} dir for work process. - \end{itemize} -\item [v1.2 (ctan), 2015-04-22] - \begin{itemize} - \item Remove unused modules. - \item Add more image format. - \item Fix regex. - \end{itemize} -\item [v1.1 (ctan), 2015-04-21] - \begin{itemize} - \item Change \texttt{mogrify} to \texttt{gs} for image formats. - \item Create output file. - \item Rewrite source code and fix regex. - \item Change format date to iso format. - \end{itemize} -\item [v1.0 (ctan), 2013-12-01] - \begin{itemize} - \item First public release. - \end{itemize} -\end{description} - -\newpage - -\let\stdsection\section -\def\section*#1{\stdsection{#1}} -\begin{thebibliography}{9} - -\bibitem{preview} \textsc{Kastrup, David}. \enquote{The \textsf{preview} -package for \hologo{LaTeX}}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/preview}, 2017. - -\bibitem{tikz} \textsc{Tantau, Till}. \enquote{The \textsf{TikZ} and \textsf{PGF} -Packages}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/pgf}, 2020. - -\bibitem{pstricks} \textsc{Van Zandt, Timothy}. \enquote{\textsf{PSTricks} - -\textsf{PostScript} macros for generic \hologo{TeX}}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/pstricks-base}, 2007. - -\bibitem{pst-plot} \textsc{Van Zandt, Timothy}. \enquote{\textsf{pst-plot} – -Plot data using \textsf{PSTricks}}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/pst-plot}, 2019. - -\bibitem{pst-pdf} \textsc{Niepraschk, Rolf}. \enquote{The \textsf{pst-pdf} -Packages}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/pst-pdf}, 2019. - -\bibitem{auto-pst-pdf} \textsc{Robertson, Will}. \enquote{The \textsf{auto-pst-pdf} -Packages}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/auto-pst-pdf}, 2009. - -\bibitem{auto-pst-pdf-lua} \textsc{Voß, Herbert}. \enquote{\textsf{auto-pst-pdf-lua} - Using -\hologo{LuaLaTeX} with \textsf{PSTricks}}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/auto-pst-pdf-lua}, 2018. - -\bibitem{pst-exa} \textsc{Voß, Herbert}. \enquote{\textsf{pst-exa} - Typeset -\textsf{PSTricks} examples, with \hologo{pdfTeX}}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/pst-exa}, 2017. - -\bibitem{pst2pdf} \textsc{Voß, Herbert}. \enquote{\textsf{pst2pdf} - A script -to compile \textsf{PSTricks} documents via \hologo{pdfTeX}}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/pst2pdf}, 2017. - -\bibitem{graphicx} \textsc{The \hologo{LaTeX3} Project}. \enquote{\textsf{graphics} – Enhanced -support for graphics}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/graphicx}, 2017. - -\bibitem{grfext} \textsc{Oberdiek, Heiko}. \enquote{The \textsf{grfext} -package}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/grfext}, 2019. - -\bibitem{xcomment} \textsc{Van Zandt, Timothy}. \enquote{The \textsf{xcomment} -package}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/xcomment}, 2010. - -\bibitem{extract} \textsc{Adriaens, Hendri}. \enquote{The \textsf{extract} -package}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/extract}, 2019. - -\bibitem{cachepic} \textsc{Trzeciak, Tomasz M}. \enquote{The \textsf{cachepic} -package}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/cachepic}, 2009. - -\bibitem{doc} \textsc{Mittelbach, Frank}. \enquote{The \textsf{doc} and \textsf{shortvrb} -Packages}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/doc}, 2020. - -\bibitem{fancyvrb} \textsc{Van Zandt, Timothy}. \enquote{The \textsf{fancyvrb} -package - Fancy Verbatims in \hologo{LaTeX}}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/fancyvrb}, 2020. - -\bibitem{listings} \textsc{Hoffmann, Jobst}. \enquote{The \textsf{listings} -package}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/listings}, 2020. - -\bibitem{minted} \textsc{Poore, Geoffrey M}. \enquote{The \textsf{minted} -package - Highlighted source code in \hologo{LaTeX}}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/minted}, 2017. - -\bibitem{arara} \textsc{The Island of \hologo{TeX}}. \enquote{\textsf{arara} - The -cool \hologo{TeX} automation tool}. Available from -\textsc{ctan}, \url{https://www.ctan.org/pkg/arara}, 2020. - -\bibitem{dvisvgm} \textsc{Gieseking, Martin}. \enquote{\textsf{dvisvgm} - A -fast \textsf{DVI} to \textsf{SVG} converter}. Available from -\textsc{ctan}, \url{https://ctan.org/pkg/dvisvgm}, 2020. - -\end{thebibliography} -\let\section\stdsection - -\addtocontents{toc}{\protect\setcounter{tocdepth}{2}} -\cleardoublepage -\phantomsection -\indexprologue{ -The italic numbers denote the pages where the corresponding entry is -described.} - -\printindex -\end{document} diff --git a/support/ltximg/ltximg-doc.pdf b/support/ltximg/ltximg-doc.pdf new file mode 100644 index 0000000000..0a6f44fe49 Binary files /dev/null and b/support/ltximg/ltximg-doc.pdf differ diff --git a/support/ltximg/ltximg-doc.tex b/support/ltximg/ltximg-doc.tex new file mode 100644 index 0000000000..3d41f5c6cb --- /dev/null +++ b/support/ltximg/ltximg-doc.tex @@ -0,0 +1,2132 @@ +% arara: lualatex +% arara: lualatex +% arara: clean: { extensions: [ aux, log, out, ilg, ind, idx, toc, hd, fls ] } +\documentclass{ltxdoc} +\usepackage[top=0.5in, bottom=0.3in, left=1.4in, right=0.7in,footskip=0.2in,headheight=1cm,headsep=0.27cm]{geometry} +\usepackage{unicode-math} % +\setmathfont[Scale = 0.95]{Latin Modern Math} +\setmainfont[ + Numbers = OldStyle, + Ligatures = TeX, + Scale = 0.95, + UprightFont = *-Regular, + ItalicFont = *-Italic, + BoldFont = *-Bold, + BoldItalicFont = *-BoldItalic, + SmallCapsFeatures = {Letters=SmallCaps}, + Extension =.otf]{LibertinusSerif} +\setsansfont[ + Numbers = OldStyle, + Ligatures = TeX, + Scale = 0.95, + UprightFont = *-Regular, + ItalicFont = *-Italic, + BoldFont = *-Bold, + SmallCapsFeatures = {Letters=SmallCaps}, + Extension = .otf]{LibertinusSans} +\setmonofont[ + Numbers = OldStyle, + Scale = 0.80, + UprightFont = *-Regular, + ItalicFont = *-RegularIt, + BoldFont = *-Semibold, + BoldItalicFont = *-SemiboldIt, + RawFeature = {+zero,+ss06}, + FontFace = {m}{sc}{LinBiolinum_R.otf}, + Extension = .otf]{SourceCodePro} % source code font +\newfontfamily\lmmitalic{lmmono10-italic.otf}[ + Scale = 0.95,% + Extension = .otf,% + ItalicFont = lmmono10-italic,% + SmallCapsFont = lmmonocaps10-oblique,% + SlantedFont = lmmonoslant10-regular, + ] +\newfontfamily\fetamontotf{ffmw10.otf}[ + Scale = 0.95,% + RawFeature = {+latn,+rand,+kern,+size},% + FontFace = {bx}{n}{ffmw10.otf}, + ] +\newfontfamily\libertinusinitials{LibertinusSerifInitials-Regular.otf} +% The character of visible space is now taken from Latin Modern Mono +% to prevent fonts in T1. The original definition for xetex/luatex is +% \def\verbvisiblespace{\usefont{OT1}{cmtt}{m}{n}\asciispace} +\def\verbvisiblespace{{\fontfamily{lmtt}\selectfont\char"2423}} +\usepackage{fontawesome5} +\usepackage{hologo} % LaTeX logos +\usepackage{enumitem,lastpage,microtype,titletoc} % custom +\usepackage[svgnames]{xcolor} % +\usepackage[sf,bf,compact,medium]{titlesec} % section styles +\usepackage[topmarks,extramarks]{titleps} % pagestyles +\settitlemarks*{section,subsection} +\usepackage{adjustbox,multicol,hyperref,xparse,listings,accsupp} +\usepackage{csquotes} +\usepackage{hyperxmp,imakeidx}% +% Hyperref number in index +\newcommand{\HP}[1]{\emph{\hyperpage{#1}}\normalsize} +\def\SortIndex#1#2{\index{#1\actualchar#2|HP}} +\indexsetup{level=\section,firstpagestyle=myheader} +\makeindex[options=-q -s gind.ist,columnsep=15pt,title={Index of Documentation}] %noautomatic +%\makeindex[noautomatic,columnsep=15pt,title={Index of Documentation}] % + +% parindent +\setlength{\parindent}{0pt} + +% Colors for options +\definecolor{optcolor}{rgb}{0.281,0.275,0.485} +\definecolor{pkgcolor}{rgb}{0,0.5,0.5} +\definecolor{araracolor}{rgb}{0, 0.72, 0.28} +\definecolor{linkcolor}{rgb}{0.04,0.38,0.04} +\definecolor{rulecolor}{rgb}{0.96,0.96,0.96} + +% Only for arara... I like arara :) +\usepackage[scale=0.85]{comfortaa} +\newcommand{\araratext}[1]{{\small\normalfont\comfortaa\color{araracolor}\bfseries#1}} +\newcommand*\arara{\araratext{ar\kern-.03emar\kern-.03ema}} + +% Identification +\def\myscript{ltximg} +\def\fileversion{2.0} +\def\filedate{2021-01-24} + +% Logo with fetamont and libertuns font +\ExplSyntaxOn +\NewDocumentCommand{\pkglogo}{} + { + \group_begin: + \libertinusinitials% + \textcolor{red}{L}\hspace{-3.0pt}% + \raisebox{-0.2em}{\small \textcolor{green}{T}}% + \hspace{-2.9pt}\textcolor{blue}{X}% + \hspace{-1pt} + \fetamontotf{\textcolor{gray}{img}} + \group_end: + } +\ExplSyntaxOff + +% Logo with libertuns and fetamont font (box) +\newsavebox{\logobox} +\savebox{\logobox}{% + \normalsize% + {\libertinusinitials% + \textcolor{red}{L}\hspace{-3.0pt}% + \raisebox{-0.2em}{\small \textcolor{green}{T}}% + \hspace{-2.9pt}\textcolor{blue}{X}}% + \hspace{-1pt}\fetamontotf{\textcolor{gray}{img}}% +}% +\makeatletter +\newcommand{\LTXimg}{% + \settoheight{\@tempdima}{L}% + \resizebox{!}{\@tempdima}{\usebox{\logobox}}% +} +\makeatother + +% email https://tex.stackexchange.com/a/663 +\catcode`\_=11\relax% +\newcommand\email[1]{\_email #1\q_nil}% +\def\_email#1@#2\q_nil{% + \href{mailto:#1@#2}{{\emailfont #1\emailampersat #2}}% +}% +\newcommand\emailfont{\sffamily}% +\newcommand\emailampersat{{\color{pkgcolor}\footnotesize@}}% +\catcode`\_=8\relax% % + +% Config hyperref +\hypersetup{ + linkcolor = linkcolor,% + citecolor = magenta,% + urlcolor = magenta,% + colorlinks = true,% + linktoc = all, + pdftitle = {.:: ltximg v\fileversion{} [\filedate] --- LaTeX environments to image and standalone files ::.},% + pdfauthor = {Pablo Gonz\'{a}lez Luengo},% + pdfsubject = {Documentation for version \fileversion},% + pdfcopyright = {\textcopyright 2013 - 2021 by Pablo González Luengo}, + pdfcontacturl = {https://github.com/pablgonz/ltximg}, + pdfkeywords = {extract, conversion, images, TikZ, PStricks, standalone files}, + pdfstartview = {FitH},% + bookmarksopenlevel = 2,% +} + +% Configuration titleps and titlesec +\renewpagestyle{plain}[\color{optcolor}\small\sffamily]{% +\setfoot{\rlap{\hskip\dimexpr-\oddsidemargin-1in\relax% + \parbox{1.93\paperwidth}{\hfil\thepage\,/\,\pageref{LastPage}}}}% + {}% + {}% +} +\newpagestyle{myheader}[\color{optcolor}\small\sffamily]{% +\renewcommand\makeheadrule{% +\rlap{\hskip\dimexpr-\oddsidemargin-1in\relax + \color{rulecolor}\rule[0.3cm]{\paperwidth}{0.7cm}}\hss +} +\setfoot{\rlap{\hskip\dimexpr-\oddsidemargin-1in\relax% + \parbox{1.93\paperwidth}{\hfil\thepage\,/\,\pageref{LastPage}}}}% + {\parbox{\textwidth}{\raggedright \textcolor{gray}{\raisebox{-1pt}{\textcopyright}{}2013 -- 2021 by Pablo González}}}% + {}% +\sethead{\llap{\raisebox{0.55cm}{\parbox{\dimexpr\oddsidemargin+1in\relax}{\makebox[0pt][l]{\hspace{15pt}\pkglogo\space\fileversion}}}}} + {\raisebox{0.55cm}{\parbox{\textwidth}{\hspace*{-\oddsidemargin}\centering\small\S.\firstextramarks{section}\thesection\space\sectiontitle}}}% + {}% +} + +% Table of contents +\titlecontents{section}[0mm]{}% + {\bfseries\contentspush{\makebox[5mm][l]{\thecontentslabel\hfill}}}% + {\hspace*{-5mm}}% numberless + {\hspace{0.25em}\titlerule*[6pt]{.}\contentspage}% + +\titlecontents{subsection}[5mm]{}% + {\contentspush{\makebox[6mm][l]{\thecontentslabel\hfill}}} + {\hspace*{-11mm}}% numberless + {\hspace{0.25em}\titlerule*[6pt]{.}\contentspage}% + +\titlecontents{subsubsection}[11mm]{}% + {\contentspush{\makebox[8mm][l]{\thecontentslabel\hfill}}} + {\hspace*{-19mm}}% numberless + {\hspace{0.25em}\titlerule*[6pt]{.}\contentspage}% + +\makeatletter +\renewcommand\tableofcontents{% +\begingroup% +\section*{\contentsname\quad{\color{optcolor}\leaders\hrule height 5pt depth -4.4pt\hfill}% + \@mkboth{% + \MakeUppercase\contentsname}{\MakeUppercase\contentsname}}% +\vspace*{-14pt} +\setlength{\columnsep}{10pt}% + \begin{multicols}{2}% + \@starttoc{toc}% +\end{multicols}% +\vspace*{-3pt}{\color{optcolor}\hrule height 0.6pt}% +\vspace*{5pt} +\endgroup +} +\makeatother + +% Custom thanks +\makeatletter +\renewcommand*{\@fnsymbol}[1]{\ensuremath{\ifcase#1\or \textcolor{pkgcolor}{*} +\or \textcolor{pkgcolor}{\dagger} \or \ddagger\or \mathsection +\or \mathparagraph\or \|\or **\or \dagger\dagger +\or \ddagger\ddagger \else\@ctrerr\fi}} +\makeatother + +% Custom \meta[...]{...}, \marg[...]{...} and \oarg[...]{...} for color +\ExplSyntaxOn +\RenewDocumentCommand{\meta}{O{}m} + { + \ltximg_meta_generic:Nnn \ltximg_meta:n { #1 } { #2 } + } +\RenewDocumentCommand{\marg}{O{}m} + { + \ltximg_meta_generic:Nnn \ltximg_marg:n { #1 } { #2 } + } +\RenewDocumentCommand{\oarg}{O{}m} + { + \ltximg_meta_generic:Nnn \ltximg_oarg:n { #1 } { #2 } + } +%^^A Variables and keys +\tl_new:N \l_ltximg_meta_font_tl + +\keys_define:nn { ltximg/meta } + { + type .choice:, + type / tt .code:n = \tl_set:Nn \l_ltximg_meta_font_tl { \ttfamily }, + type / rm .code:n = \tl_set:Nn \l_ltximg_meta_font_tl { \rmfamily }, + type .initial:n = rm, + cf .tl_set:N = \l_ltximg_meta_color_tl, + cf .initial:n = optcolor, + ac .tl_set:N = \l_ltximg_meta_anglecolor_tl, + ac .initial:n = lightgray, + sbc .tl_set:N = \l_ltximg_meta_brackcolor_tl, + sbc .initial:n = gray, + cbc .tl_set:N = \l_ltximg_meta_bracecolor_tl, + cbc .initial:n = gray, + } +%^^A Internal commands +\cs_new_protected:Npn \ltximg_meta_generic:Nnn #1 #2 #3 + { + \group_begin: + \keys_set:nn { ltximg/meta } { #2 } + \color{ \l_ltximg_meta_color_tl } + \l_ltximg_meta_font_tl + #1 { #3 } % #1 is \ltximg_meta:n, \ltximg_marg:n or \ltximg_oarg:n + \group_end: + } +\cs_new_protected:Npn \ltximg_meta:n #1 + { + \ltximg_meta_angle:n { \textlangle } + \ltximg_meta_meta:n { #1 } + \ltximg_meta_angle:n { \textrangle } + } +\cs_new_protected:Npn \ltximg_marg:n #1 + { + \ltximg_meta_brace:n { \textbraceleft } + \ltximg_meta:n { #1 } + \ltximg_meta_brace:n { \textbraceright } + } +\cs_new_protected:Npn \ltximg_oarg:n #1 + { + \ltximg_meta_brack:n { [ } + \ltximg_meta:n { #1 } + \ltximg_meta_brack:n { ] } + } +\cs_new_protected:Npn \ltximg_meta_meta:n #1 + { + \textnormal{\textit{#1}} + } +\cs_new_protected:Npn \ltximg_meta_angle:n #1 + { + \group_begin: + \fontfamily{lmr}\selectfont + \textcolor{\l_ltximg_meta_anglecolor_tl}{#1} + \group_end: + } +\cs_new_protected:Npn \ltximg_meta_brace:n #1 + { + \group_begin: + \color{\l_ltximg_meta_bracecolor_tl} + #1 + \group_end: + } +\cs_new_protected:Npn \ltximg_meta_brack:n #1 + { + \textcolor{\l_ltximg_meta_brackcolor_tl}{#1} + } + +% \ltximg for body document +\NewDocumentCommand{\ltximg}{} + { + \normalsize\texttt{\bfseries\textcolor{pkgcolor}{ltximg}} + } + +% \prgname{sm} : #1 index compiler, #2 index programs: +\NewDocumentCommand{\prgname}{sm} + { + \IfBooleanTF{#1} + { + \textcolor{ForestGreen}{\texttt{#2}} + \SortIndex{compiler}{Compiler>\small\texttt{#2}} + } + { + \textcolor{ForestGreen}{\texttt{#2}} + \SortIndex{programs}{Programs>\small\texttt{#2}} + } + } + +% \prgopt{sm} : #1 compiler opt, #2 program opt: +\NewDocumentCommand{\prgopt}{sm} + { + \IfBooleanTF{#1} + { + \mbox{\textcolor{gray}{\texttt{-{}#2}}} + \SortIndex{compiler ~ options}{Compiler ~ options>\small\texttt{-{}#2}} + } + { + \mbox{\textcolor{gray}{\texttt{-{}#2}}} + \SortIndex{#2}{\small\texttt{-{}#2} (program ~ option)}% + } + } + +% \scriptname*{m} +\NewDocumentCommand{\scriptname}{m} + { + \textcolor{ForestGreen}{\texttt{#1}} + \SortIndex{scripts}{Scripts>\small\texttt{#1}} + } + +% \scriptopt{m} +\NewDocumentCommand{\scriptopt}{m} + { + \mbox{\texttt{#1}} + \SortIndex{script ~ option}{Script ~ options>\small\texttt{#1}} + } + +% \myclass{m} +\NewDocumentCommand{\myclass}{ m } + { + \mbox{\textsf{\textcolor{SlateBlue}{#1}}} + \SortIndex{document}{Document ~ class>\small\texttt{#1}} + \SortIndex{#1}{\texttt{#1} ~ (class)} + } + +% \pkgname{m} +\NewDocumentCommand{\pkgname}{ m } + { + \textsf{\textcolor{SlateBlue}{#1}} + \SortIndex{packages}{Packages>\small\texttt{#1}} + \SortIndex{#1}{\texttt{#1} ~ (package)} + } + +% \pkgopt{m} +\NewDocumentCommand{\pkgopt}{ m } + { + \textsf{\textcolor{gray}{#1}} + \SortIndex{package ~ options}{Package ~ options>\small\texttt{#1}} + \SortIndex{#1}{\texttt{#1} ~ (package ~ option)} + } + +% \env{m} +\NewDocumentCommand{\env}{ m } + { + \textcolor{pkgcolor}{\texttt{#1}} + \SortIndex{environment}{Environments>\small\texttt{#1}} + } + +% \LVenv{m} +\NewDocumentCommand{\LVenv}{ m } + { + \textcolor{pkgcolor}{\texttt{#1}} + \SortIndex{environment ~ verbatim}{Environments ~ verbatim>\small\texttt{#1}} + } + +% \LWenv{m} +\NewDocumentCommand{\LWenv}{ m } + { + \textcolor{pkgcolor}{\texttt{#1}} + \SortIndex{environment ~ verbatim ~ write}{Environments ~ verbatim ~ write>\small\texttt{#1}} + } + +% \ics{sm} +\NewDocumentCommand{\ics}{sm} + { + \IfBooleanTF{#1} + { + \tl_set:Nn \l_tmpa_tl { #2 } + \regex_replace_once:nnN { (\*) } { \c{textcolor}\cB\{MediumOrchid\cE\}\cB\{\1\cE\} } \l_tmpa_tl + \textcolor{blue!75}{\ttfamily\textbackslash{\tl_use:N \l_tmpa_tl}} + } + { + \textcolor{blue!75}{\ttfamily{\textbackslash#2}} + } + \SortIndex{#2}{\texttt{\small\textbackslash#2}} + } + +% file extention +\NewDocumentCommand{\fext}{m} + { + \mbox{\textcolor{OrangeRed}{\texttt{.#1}}} + \SortIndex{file ~ extention}{File ~ extentions >\small\texttt{.#1}} + } + +% File +\NewDocumentCommand{\Fext}{m m} + { + \mbox{\textcolor{OrangeRed}{\texttt{#1}\fext{#2}}} + \SortIndex{file}{File >\small\texttt{#1.#2}} + } + + +% image format/extention +\NewDocumentCommand{\iext}{m} + { + \textcolor{optcolor}{\texttt{#1}} + \SortIndex{Image ~ format}{Image ~ formats>\small\texttt{#1}} + } + +% \sysydir{m} +\NewDocumentCommand{\sysdir}{m} + { + \mbox{\textcolor{OrangeRed}{\texttt{#1}}} + } + +% \sysfile{m} ...only for color in some examples +\NewDocumentCommand{\sysfile}{m} + { + \mbox{\textcolor{OrangeRed}{\texttt{#1}}} + } + +% \OSsystem{m} ...only for color in some examples +\NewDocumentCommand{\OSsystem}{m} + { + \mbox{\textcolor{OrangeRed}{\texttt{#1}}} + \SortIndex{Operating ~ system}{Operating ~ system>\small\texttt{#1}} + } + +% \cmdopt[short]{long} +\NewDocumentCommand{\cmdopt}{om} + { + \IfNoValueTF{#1} + { + \textcolor{optcolor}{\texttt{-\/-#2}} + } + { + \textcolor{optcolor}{\texttt{-{}#1}}, + \textcolor{optcolor}{\texttt{-\/-#2}} + } + \SortIndex{options}{\textsf{\myscript}\ options ~ in ~ command ~ line>\small\texttt{-\/-#2}} + } + +\ExplSyntaxOff +% \DescribeIF{m}, #1 image format +\newsavebox{\marginIF} +\NewDocumentCommand{\DescribeIF}{ m } + {% + \begin{lrbox}{\marginIF}% + \begin{minipage}[t]{\marginparwidth}% + \raggedleft\ttfamily\bfseries% + \textcolor{optcolor}{#1} + \end{minipage}% + \end{lrbox}% + \SortIndex{Image format}{Image formats>\small\texttt{#1}} + \leavevmode% + \marginpar{\usebox{\marginIF}}% + \ignorespaces% + }% + +% \myenv{environ} for margin +\NewDocumentCommand{\myenv}{m} + { + \begin{minipage}[t]{\marginparwidth}% + \raggedleft\ttfamily\small% + {\textcolor{gray}{\textbackslash begin\{}}{\bfseries\textcolor{pkgcolor}{#1}}\textcolor{gray}{\}}\par% + \meta[ac=lightgray,cf=gray]{env content}\par% + {\textcolor{gray}{\textbackslash end\{}}{\bfseries\textcolor{pkgcolor}{#1}}\textcolor{gray}{\}}% + \end{minipage}% + \SortIndex{Environment}{Environments suport by default>\small\texttt{#1}}% + } + +% \mytag{dtxtag} for margin +\NewDocumentCommand{\mytag}{m} + {% + \begin{minipage}[t]{\marginparwidth}% + \raggedleft\ttfamily\small% + \textcolor{gray}{\%<*}{\bfseries\textcolor{pkgcolor}{#1}}\textcolor{gray}{>}\par% + \meta[ac=lightgray,cf=gray]{content}\par% + \textcolor{gray}{\%}% + \end{minipage}% + \SortIndex{docstrip}{Docstrip tag>\small\texttt{#1}}% + }% + +% \DescribeTE{sm}, #1 tag, #2 env +\newsavebox{\marginenvtag} +\NewDocumentCommand{\DescribeTE}{sm}{% +\begin{lrbox}{\marginenvtag}% + \begin{minipage}[t]{\marginparwidth}% + \raggedleft + \IfBooleanTF{#1}{\mytag{#2}}{\myenv{#2}} + \end{minipage}% +\end{lrbox}% + \leavevmode% + \marginpar{\usebox{\marginenvtag}}% + \ignorespaces% +}% + +% DescribeOptFile*{options}{example}[!] +\newsavebox{\optinfile} +\NewDocumentCommand{\DescribeOptFile}{s m m O{\hphantom{!}}}{ +\begin{lrbox}{\optinfile}% + \begin{minipage}[t]{\marginparwidth}% + \raggedleft\ttfamily\bfseries% + \textcolor{gray}{\%}\textcolor{optcolor}{{#4}\myscript}\textcolor{gray}{\texttt{:}}% + \end{minipage}% +\end{lrbox}% +\leavevmode% +\lapbox[0pt]{-\marginparwidth-0.5\marginparsep}{\usebox{\optinfile}}% +\textcolor{optcolor}{\bfseries\texttt{{#2}}}% +\textcolor{gray}{\texttt{:}}\space% +\marg[type=tt,cbc=gray,ac=lightgray,cf=optcolor!85]{#3}% +\vspace*{2pt}\par% +\IfBooleanF{#1} + {% + \SortIndex{options}{\textsf{\myscript}\ options in input file>\small\texttt{#2}}% + }% +} + +% \DescribeCmd[...]{...}{...}{...} +\newsavebox{\optcmdline} +\NewDocumentCommand{\DescribeCmd}{ o m m m } + { + \begin{lrbox}{\optcmdline}% + \begin{minipage}[t]{\marginparwidth}% + \ttfamily\bfseries\raggedleft% + \IfNoValueTF{#1} + {\textcolor{optcolor}{-\/-#2}} + {\textcolor{optcolor}{-{#1}}\textcolor{gray}{,} \textcolor{optcolor}{-\/-#2}}% + \end{minipage}% + \SortIndex{options}{\textsf{\myscript}\ options in command line>\small\texttt{-\/-#2}}% + \end{lrbox}% + \leavevmode% + \marginpar{\usebox{\optcmdline}}% + \ignorespaces + \meta[ac=lightgray,cf=gray]{#3} + \hfill\textcolor{gray}{\textsf{(default: {#4})}}% + \vspace*{2pt}\par% +} + +% don't copy numbers in code example for listings +\newcommand*{\noaccsupp}[1]{\BeginAccSupp{ActualText={}}#1\EndAccSupp{}} + +% Create a language for documentation +\lstdefinelanguage{ltximg-doc}{ + texcsstyle=*,% + escapechar=`,% + showstringspaces=false,% + extendedchars=true, % + stringstyle = {\color{red}},% + alsoletter={\-,.},% +% comments + morecomment=[l]{\%},% + commentstyle=\lmmitalic\color{lightgray},% +% Important words 1 + keywordstyle=[1]{\color{NavyBlue}},% + keywords=[1]{PassOptionsToPackage,AtBeginDocument,documentclass,usepackage,section},% +% Important words 2 (macros) + keywordstyle=[2]{\color{blue!75}},% + keywords=[2]{graphicspath,RequirePackage,renewcommand,includegraphics,coordinate,draw,approx,% + PreviewBbAdjust,setlength,parindent,usetikzlibrary,tikzexternalize,psset,tikzset,PrependGraphicsExtensions,% + DefineShortVerb,lstMakeShortInline,MakeSpecialShortVerb,UndefineShortVerb,verb,myverb,macro,put,line},% +% Important words 3, options in input file + keywordstyle=[3]{\color{optcolor!85}},% + keywords=[3]{extrenv,deltenv,skipenv,options,arara,extensions,luatex,env,norun,% + clean,pst,tkz,eps,pdf,xetex,latex,luatex,dvips,png,latexmk,svg,srcenv,noprew,imgdir,prefix,output},% +% Important words 4, environments and tags + keywordstyle=[4]{\color{pkgcolor}},% + keywords=[4]{ltximg,noltximg,remove,pspicture,endpspicture,overlay,remember,% + description,filecontents,PSTexample,pgfpicture, endpgfpicture, tikzpicture, endtikzpicture, % + psgraph, endpsgraph,nopreview,postscript,picture},% +% Important words 5, directory + keywordstyle=[5]{\color{OrangeRed}},% + keywords=[5]{images,pics},% +% Important words 6, begin, end and other + keywordstyle=[6]{\color{gray}},% replace this color + keywords=[6]{begin,end,-recorder,doc,active,inactive,tightpage,BEGIN,END,% + -shell-escape,osf,--output-format,--exact-bbox,-o,dvi},% +% Important words 7, reserved for arara + keywordstyle=[7]{\color{araracolor}},% + keywords=[7]{lualatex,dvisvgm,halt,xelatex},% +% Important words 8, pkg and others load in examples + keywordstyle=[8]{\color{SlateBlue}},% + keywords=[8]{graphicx,grfext,tikz,article,document,preview,libertinus,calc,tikzmark,pst-pdf},% +% Important words 9, files used in examples + keywordstyle=[10]{\color{OrangeRed}},% + keywords=[10]{file.tex,test-fig-1981.tex,test-fig-1981.pdf,test-fig-1,test-fig-2,test-out,test-in.ltx,% + test-fig-1981.tex,test-out.tex,file-in.tex,file-out,test.tex,test-fig-all.dvi,test-fig-1.svg,test-fig-all.tex},% +}[keywords,tex,comments,strings]% end languaje + +% \begin{examplecode}[opts]...\end{examplecode} +\lstnewenvironment{examplecode}[1][]{% +\lstset{ + language=ltximg-doc,% + stringstyle = {\color{red}},% + basicstyle=\ttfamily\small,% + numbersep=1em,% + numberstyle=\tiny\color{gray}\noaccsupp,% + rulecolor=\color{gray!50},% + framesep=\fboxsep,% + framerule=\fboxrule,% + xleftmargin=\dimexpr\fboxsep+\fboxrule\relax,% + xrightmargin=\dimexpr\fboxsep+\fboxrule\relax,% +% literateee + literate=*{\{}{{\bfseries\textcolor{gray}{\{}}}{1} + {\}}{{\bfseries\textcolor{gray}{\}}}}{1} + {[}{{\textcolor{gray}{[}}}{1} + {]}{{\textcolor{gray}{]}}}{1} + {\*}{{\bfseries\textcolor{MediumOrchid}{*}}}{1} + {:}{{\textcolor{gray}{:}}}{1} + {,}{{\textcolor{gray}{,}}}{1} + {=}{{\textcolor{gray}{=}}}{1} + {/}{{\textcolor{OrangeRed}{/}}}{1} + {scale=1}{{\textcolor{gray}{scale=1}}}{7} + {\%\ ltximg}{{\textcolor{gray}{\%}\space\textcolor{optcolor}{ltximg}}}{8} + {\%\ arara}{{\textcolor{gray}{\%}\space\textcolor{araracolor}{arara}}}{7} + {\%<*remove>}{{\textcolor{gray}{\%<*}\textcolor{pkgcolor}{remove}\textcolor{gray}{>}}}{10} + {\%}{{\textcolor{gray}{\%}}}{10} + {\%<*ltximg>}{{\textcolor{gray}{\%<*}\textcolor{pkgcolor}{ltximg}\textcolor{gray}{>}}}{10} + {\%}{{\textcolor{gray}{\%}}}{10} + {\%<*noltximg>}{{\textcolor{gray}{\%<*}\textcolor{pkgcolor}{noltximg}\textcolor{gray}{>}}}{12} + {\%}{{\textcolor{gray}{\%}}}{12},% + #1,% + }% close lstset +}% +{\vspace{-\parskip}}% close examplecode + +% \begin{examplecmd}...\end{examplecmd} +\lstnewenvironment{examplecmd}{% +\lstset{ + language=ltximg-doc,% + basicstyle=\ttfamily\small,% + frame=single,% + alsoletter={\-,.,\-\-},% + rulecolor=\color{gray!50},% + framesep=\fboxsep,% + framerule=\fboxrule,% + xleftmargin=\dimexpr\fboxsep+\fboxrule\relax,% + xrightmargin=\dimexpr\fboxsep+\fboxrule\relax,% + keywordstyle=[20]{\color{gray}},% replace this color + keywords=[20]{-recorder,-shell-escape,--latex,-s,-o,--arara,--log,% + -no-shell-escape,-interaction,nonstopmode,--norun,--luatex,--latexmk,% + --svg,--png,--nopdf,--margins},% +% Reserved words (cmd line options) + deletekeywords=[4]{ltximg},% + classoffset=7,% + keywordstyle=\bfseries\color{pkgcolor},% + morekeywords={ltximg},% +% % Reserved words (cmd line options) + classoffset=8,% + keywordstyle={\color{ForestGreen}},% + morekeywords={gs,ps2pdf,pdftoppm,pdftocairo,pdftops,cd,perl,pdfcrop},% +% Only for command line options + classoffset=5,% + keywordstyle=\color{blue},% + keywords={user,machine},% + literate=*{[}{{\textcolor{darkgray}{[}}}{1} + {]}{{\textcolor{darkgray}{]}}}{1} + {=}{{\textcolor{gray}{=}}}{1} + {@}{{\textcolor{blue}{@}}}{1} + {\$}{{\textcolor{blue}{\$}}}{1} + {:}{{\textcolor{blue}{:}}}{1} + {§}{{\textcolor{red}{\$}}}{1} + {~}{{\textcolor{blue}{\bfseries\textasciitilde}}}{1}% + }% close lstset +}% +{\vspace{-\parskip}}% close examplecmd + +% \lstinline[style=inline]|...| +\lstdefinestyle{inline} + { + language=ltximg-doc,% + basicstyle=\ttfamily\color{gray},% + escapechar=`,% + upquote=true,% + deletekeywords=[8]{preview},% + morekeywords =[4]{preview},% + literate=*{\%}{{\bfseries\textcolor{gray}{\%}}}{1} + {\*}{{\bfseries\textcolor{MediumOrchid}{*}}}{1} + } + +% set default style +\lstset{style=inline} + +\begin{document} + +\title{% + {\fetamontotf latex environments }\\[3pt]% + \scalebox{3.4}{\LTXimg}\\[2pt]% + {\fetamontotf\addfontfeature{LetterSpace=12.0} to image format}\\% + \Large + v\fileversion{} --- \filedate\thanks{% + This file describes a documentation for version \fileversion, last revised \filedate.}\\[25pt]% + \author{% + \large% + \raisebox{-1pt}{\textcopyright}{}2013--2021 by Pablo González L% + \thanks{E-mail: \textcolor{optcolor}{\textsf{\guillemotleft}}\email{pablgonz@yahoo.com}\textcolor{optcolor}{\textsf{\guillemotright}}} + }% +\small +\textcolor{gray}{\textsc{ctan}}\,\,\,\url{https://www.ctan.org/pkg/ltximg}\\ +\textcolor{gray}{\scriptsize\faIcon[regular]{github}}\,\,\,\url{https://github.com/pablgonz/ltximg} +\vspace*{-2cm} +}% +\date{} +\maketitle + +\begin{abstract} +\ltximg{} is a \prgname{perl} \emph{script} that automates the process of +extracting and converting environments provided by \pkgname{TikZ}, % +\pkgname{PStricks} and other packages from \meta[cf=optcolor]{input file} to image +formats and standalone files using \prgname{ghostscript} and % +\prgname{poppler-utils}. Generates a file with only extracted environments +and another with all extracted environments converted to \ics{includegraphics}. +\end{abstract} + +\tableofcontents +\setlength{\parskip}{3pt} + +\section{License} + +This program is free software; you can redistribute it and/or modify +it under the terms of the \href{https://www.gnu.org/licenses/gpl-3.0.html}{GNU General Public License} as published by +the \href{https://www.fsf.org/}{Free Software Foundation}; either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \href{https://www.gnu.org/licenses/gpl-3.0.html}{GNU General Public License} +for more details. + +\section{Motivation and Acknowledgments} + +The original idea was to extend the functionality of the \scriptname{pst2pdf}\cite{pst2pdf} +script to work with \env{tikzpicture} and other environments. The \pkgname{TikZ}\cite{tikz} package +allows to \emph{externalize} the environments, but, the idea was to be able to extend this +to \emph{any type} of environment covering three central points: + +\begin{enumerate}[font=\small,noitemsep,leftmargin=*,nosep] + +\item Generate a separate image files for environments. + +\item Generate a standalone files with only the extracted environments. + +\item Generate a file replacing the environments by \ics{includegraphics}. +\end{enumerate} + +From the side of \hologo{TeX} there are some packages that cover several of these +points such as the \pkgname{preview}\cite{preview}, \pkgname{xcomment}\cite{xcomment}, \pkgname{extract}\cite{extract} +and \pkgname{cachepic}\cite{cachepic} packages among others, but none covered all points. + +In the network there are some solutions in \texttt{bash} that were able to +extract and convert environments, but in general they presented problems +when the document contained \emph{\enquote{verbatim style}} code or were only +available for \OSsystem{Linux}. + +\thispagestyle{plain} + +\newpage + +\pagestyle{myheader} + +Analysed the situation the best thing was to create a new \emph{\enquote{script}} that +was able to cover the three points and was multi platform, the union of all +these ideas is born \ltximg. + +This script would not be possible without the great work of Herbert Voß +author of \scriptname{pst2pdf}\footnote{\url{https://ctan.org/pkg/pst2pdf}} +and Heiko Oberdiek author of \scriptname{pdfcrop}\footnote{\url{https://ctan.org/pkg/pdfcrop}}. +Several parts of the code have been taken and adapted from both scripts. + +\section{Requirements for operation} +\label{sec:requirements} + +For the complete operation of \ltximg{} you need to have a modern % +\hologo{TeX} distribution such as \hologo{TeX} Live or \hologo{MiKTeX}, have +a version equal to or greater than \liningnums{5.28} of \prgname{perl}, a +version equal to or greater than \liningnums{9.52} of \prgname{ghostscript}, a +version equal to or greater than \liningnums{1.40} of \scriptname{pdfcrop} +and have a version equal to or greater than \liningnums{0.52} of % +\prgname{poppler-utils}. + +The script uses only packages from the core of the \prgname{perl}, the +distribution encapsulated in \hologo{TeX} Live 2020 for \OSsystem{Windows} +does not have the \verb|Win32::Console::ANSI| package, this does not +affect the operation of the script, but it does affect the presentation +of the messages when invoked from \verb|cmd|, it is recommended to use +a more modern (and comfortable) application such as \prgname{Windows Terminal}. +\hologo{MiKTeX} users must install the appropriate software for full +operation. + +The script auto detects the \prgname{ghostscript}, but not \prgname{poppler-utils}. +You should keep this in mind if you are using the script directly and not +the version provided in your \hologo{TeX} distribution. + +The script has been tested on \OSsystem{Windows} v10, \prgname{cygwin} v3.1.6, \prgname{Git for Windows} v2.30 and % +\OSsystem{Linux} (fedora 33) using \prgname{ghostscript} v9.53.3, \prgname{poppler-utils} v0.90, \prgname{perl} v5.32 +and the standard classes offers by \hologo{LaTeX}: \myclass{book}, \myclass{report}, \myclass{article} and +\myclass{letter}. The \pkgname{preview}\cite{preview} and \pkgname{pst-pdf}\cite{pst-pdf} packages are +required to process the \meta{input file} and if an \meta{output file} is generated, the \pkgname{graphicx}\cite{graphicx} +and \pkgname{grfext}\cite{grfext} packages will be needed. + +\section{How it works} +\label{sec:howtowork} + +It is important to have a general idea of how the \emph{\enquote{extraction and conversion}} +process works and the requirements that must be fulfilled so +that everything works correctly, for this we must be clear about some +concepts related to how to work with the \meta[cf=optcolor]{input file}, the \meta{verbatim content} +and the \meta{steps process}. + +\subsection{The input file} +\label{sec:inputfile} + +The \meta[cf=optcolor]{input file} must comply with \emph{certain characteristics} in order to +be processed, the content at the beginning and at the end of the \meta{input +file} is treated in a special way, before \lstinline|\documentclass| and after +\lstinline|\end{document}| can go any type of content, internally the script will +\emph{\enquote{split}} the \meta[cf=optcolor]{input file} at this points. + +If the \meta[cf=optcolor]{input file} contains files using \ics{input}\marg[type=tt]{file} or +\ics{include}\marg[type=tt]{file} these will not be processed, from the side of +the \emph{script} they only represent lines within the file, if you want +them to be processed it is better to use the \scriptname{latexpand}\footnote{\url{https://www.ctan.org/pkg/latexpand}} +first and then process the file. + +Like \ics{input}\marg[type=tt]{file} or \ics{include}\marg[type=tt]{file}, blank lines, vertical spaces and tab +characters are treated literally, for the \emph{script} the \meta[cf=optcolor]{input file} +is just a set of characters, as if it was a simple text file. It is +advisable to format the source code \meta[cf=optcolor]{input file} using utilities such +as \prgname{chktex}\footnote{\url{https://www.ctan.org/pkg/chktex}} and +\scriptname{latexindent}\footnote{\url{https://www.ctan.org/pkg/latexindent}}, especially if you want to +extract the source code of the environments. + +Both \ics{thispagestyle}\marg[type=tt]{style} and \ics{pagestyle}\marg[type=tt]{style} +are treated in a special way by the script, if they do not appear in the +preamble then \ics{pagestyle}\marg[type=tt]{empty} will be added and if they are present +and \marg[type=tt]{style} is different from \marg[type=tt]{empty} this +will be replaced by \marg[type=tt]{empty}. + +This is necessary for the image creation process, it does not affect the \meta{output file}, but +it does affect the \emph{standalone} files. For the script the process of dividing the \meta{input file} into four +parts and then processing them: + +\begin{examplecode}[numbers=left,frame=single] +% Part One: Everything before \documentclass +\documentclass{article} +% Part two: Everything between \documentclass and \begin{document} +\begin{document} +% Part three: : Everything between \begin{document} and \end{document} +\end{document} +% Part Four: Everything after \end{document} +\end{examplecode} + +If for some reason you have an environment \LWenv{filecontens} before \lstinline|\documentclass| or +in the preamble of the \meta{input file} that contains a \emph{sub-document} or \emph{environment} +you want to extract, the script will ignore them. Similarly, the content after \lstinline|\end{document}| +is ignored in the extraction process. + +\newpage + +\subsection{Verbatim contents} +\label{sec:verbatim} + +One of the greatest capabilities of this script is to \emph{\enquote{skip}} +the complications that \meta{verbatim content} produces with the extraction +of environments using tools outside the \enquote{\hologo{TeX} world}\footnote{Only \hologo{TeX} can +understand \hologo{TeX}, all other languages and programs are just lines in a file.}. +In order to \emph{\enquote{skip}} the complications, the \meta{verbatim content} is classified into +three types: + +\begin{itemize}[nosep] + \item Verbatim in line. + \item Verbatim standard. + \item Verbatim write. +\end{itemize} + +\subsection*{Verbatim in line} +\label{sec:verbatim:inline} + +The small pieces of code written using a \emph{\enquote{verbatim macro}} +are considered \meta{verbatim in line}, such as \lstinline+\verb|+\meta{code}\lstinline+|+ +or \lstinline+\verb*|+\meta{code}\lstinline+|+ or \lstinline+\macro+\marg[type=tt]{code} or +\lstinline+\macro+\oarg[type=tt]{opts}\marg[type=tt]{code}. + +Most \emph{\enquote{verbatim macro}} provide by packages \pkgname{minted}\cite{minted}, % +\pkgname{fancyvrb}\cite{fancyvrb} and \pkgname{listings}\cite{listings} have been tested and are fully +supported. They are automatically detected the \emph{verbatim macro} (including \texttt{\small\bfseries\textcolor{MediumOrchid}{*}} argument) generates by +\ics{newmint} and \ics{newmintinline} and the following list: + +\setlength{\multicolsep}{2ex} +\begin{multicols}{3} +\begin{itemize}[font=\sffamily\small,first=\small,partopsep=5pt,parsep=5pt,nosep,leftmargin=*] +\item \ics{mint} +\item \ics{spverb} +\item \ics{qverb} +\item \ics{fverb} +\item \ics{verb} +\item \ics{Verb} +\item \ics{lstinline} +\item \ics{pyginline} +\item \ics{pygment} +\item \ics{Scontents} +\item \ics{tcboxverb} +\item \ics{mintinline} +\end{itemize} +\end{multicols} + +Some packages define abbreviated versions for \emph{\enquote{verbatim macro}} as % +\ics{DefineShortVerb}, \ics{lstMakeShortInline} and % +\ics{MakeSpecialShortVerb}, will be detected automatically if are declared +explicitly in \meta[cf=optcolor]{input file}. + +The following consideration should be kept in mind for some packages that +use abbreviations for verbatim macros, such as \pkgname{shortvrb}\cite{doc} or % +\pkgname{doc}\cite{doc} for example in which there is no explicit \lstinline+\macro+ in the +document by means of which the abbreviated form can be detected, for +automatic detection need to find \ics{DefineShortVerb} explicitly to process +it correctly. The solution is quite simple, just add in \meta[cf=optcolor]{input file}: + +\begin{examplecode} +\UndefineShortVerb{\|} +\DefineShortVerb{\|} +\end{examplecode} + +depending on the package you are using. If your \emph{\enquote{verbatim macro}} is not +supported by default or can not detect, use the options described in \ref% +{sec:optline} and \ref{sec:optfile}. + +\subsection*{Verbatim standard} +\label{sec:verbatim:std} + +These are the \emph{\enquote{classic}} environments for \emph{\enquote{writing code}} are considered % +\meta{verbatim standard}, such as \LVenv{verbatim} and \LVenv{lstlisting} +environments. The following list (including \texttt{\small\bfseries\textcolor{MediumOrchid}{*}} argument) +is considered as \meta{verbatim standard} environments: + +\setlength{\multicolsep}{2ex} +\begin{multicols}{4} +\begin{itemize}[font=\sffamily\small, first=\small,noitemsep,leftmargin=*] +\item \LVenv{Example} +\item \LVenv{CenterExample} +\item \LVenv{SideBySideExample} +\item \LVenv{PCenterExample} +\item \LVenv{PSideBySideExample} +\item \LVenv{verbatim} +\item \LVenv{Verbatim} +\item \LVenv{BVerbatim} +\item \LVenv{LVerbatim} +\item \LVenv{SaveVerbatim} +\item \LVenv{PSTcode} +\item \LVenv{LTXexample} +\item \LVenv{tcblisting} +\item \LVenv{spverbatim} +\item \LVenv{minted} +\item \LVenv{listing} +\item \LVenv{lstlisting} +\item \LVenv{alltt} +\item \LVenv{comment} +\item \LVenv{chklisting} +\item \LVenv{verbatimtab} +\item \LVenv{listingcont} +\item \LVenv{boxedverbatim} +\item \LVenv{demo} +\item \LVenv{sourcecode} +\item \LVenv{xcomment} +\item \LVenv{pygmented} +\item \LVenv{pyglist} +\item \LVenv{program} +\item \LVenv{programl} +\item \LVenv{programL} +\item \LVenv{programs} +\item \LVenv{programf} +\item \LVenv{programsc} +\item \LVenv{programt} +\end{itemize} +\end{multicols} + +They are automatically detected \meta{verbatim standard} environments +(including \texttt{\small\bfseries\textcolor{MediumOrchid}{*}} argument) +generates by commands: + +\setlength{\multicolsep}{2ex} +\begin{multicols}{2} +\begin{itemize}[font=\sffamily\small,first=\small,noitemsep,leftmargin=*] +\item \ics{DefineVerbatimEnvironment} +\item \ics{NewListingEnvironment} +\item \ics{DeclareTCBListing} +\item \ics{ProvideTCBListing} +\item \ics{lstnewenvironment} +\item \ics{newtabverbatim} +\item \ics{specialcomment} +\item \ics{includecomment} +\item \ics{newtcblisting} +\item \ics{NewTCBListing} +\item \ics{newverbatim} +\item \ics{NewProgram} +\item \ics{newminted} +\end{itemize} +\end{multicols} + +If any of the \meta{verbatim standard} environments is not supported by +default or can not detected, you can use the options described in \ref% +{sec:optline} and \ref{sec:optfile}. + +\subsection*{Verbatim write} +\label{sec:verbatim:write} + +Some environments have the ability to write \emph{\enquote{external files}} +or \emph{\enquote{store content}} in memory, these environments are +considered \meta{verbatim write}, such as \LWenv{scontents}, \LWenv{filecontents} +or \LWenv{VerbatimOut} environments. The following list is considered (including \texttt{\small\bfseries\textcolor{MediumOrchid}{*}} argument) as % +\meta{verbatim write} environments: + +\setlength{\multicolsep}{2ex} +\begin{multicols}{4} +\begin{itemize}[font=\sffamily\small, first=\ttfamily\small,noitemsep,leftmargin=*] +\item \LWenv{scontents} +\item \LWenv{filecontents} +\item \LWenv{tcboutputlisting} +\item \LWenv{tcbexternal} +\item \LWenv{tcbwritetmp} +\item \LWenv{extcolorbox} +\item \LWenv{extikzpicture} +\item \LWenv{VerbatimOut} +\item \LWenv{verbatimwrite} +\item \LWenv{filecontentsdef} +\item \LWenv{filecontentshere} +\item \LWenv{filecontentsdefmacro} +\item \LWenv{filecontentsdefstarred} +\item \LWenv{filecontentsgdef} +\item \LWenv{filecontentsdefmacro} +\item \LWenv{filecontentsgdefmacro} +\end{itemize} +\end{multicols} + +They are automatically detected \meta{verbatim write} +(including \texttt{\small\bfseries\textcolor{MediumOrchid}{*}} argument) environments generates +by commands: + +\begin{itemize}[font=\sffamily\small, first=\small, noitemsep,leftmargin=*] +\item \ics{renewtcbexternalizetcolorbox} +\item \ics{renewtcbexternalizeenvironment} +\item \ics{newtcbexternalizeenvironment} +\item \ics{newtcbexternalizetcolorbox} +\item \ics{newenvsc} +\end{itemize} + +If any of the \meta{verbatim write} environments is not supported by default +or can not detected, you can use the options described in \ref{sec:optline} +and \ref{sec:optfile}. + +\subsection{Steps process} +\label{sec:steps:process} + +For creation of the image formats, extraction of source code of environments and creation of an +\meta[cf=optcolor]{output file}, \ltximg{} need a various steps. Let's assume that the % +\meta[cf=optcolor]{input file} is \sysfile{test.tex}, \meta[cf=optcolor]{output file} is % +\sysfile{test-out.tex}, the working directory are \enquote{\sysdir{./}}, the +directory for images are \sysdir{./images}, the temporary +directory is \sysdir{/tmp} and we want to generate images in \iext{pdf} +format and \meta{standalone} files for all environments extracted. + +We will use the following code as \sysfile{test.tex}: + +\begin{examplecode}[numbers=left,frame=single] +% Some commented lines at begin file +\documentclass{article} +\usepackage{tikz} +\begin{document} +Some text +\begin{tikzpicture} + Some code +\end{tikzpicture} +Always use \verb|\begin{tikzpicture}| and \verb|\end{tikzpicture}| to open +and close environment +\begin{tikzpicture} + Some code +\end{tikzpicture} +Some text +\begin{verbatim} +\begin{tikzpicture} + Some code +\end{tikzpicture} +\end{verbatim} +Some text +\end{document} +Some lines that will be ignored by the script +\end{examplecode} + +\subsection*{Validating Options} + +The first step is read and validated \oarg[type=tt,cf=optcolor,sbc=gray,ac=lightgray]{options} from the command +line and \sysfile{test.tex}, verifying that \sysfile{test.tex} contains \emph{some} environment to extract, +check the name and extension of \sysfile{test-out.tex}, check the directory \sysdir{./images} if it doesn't exist create it +and create a temporary directory \sysdir{/tmp/hG45uVklv9}. + +The entire \sysfile{test.tex} file is loaded into memory and \emph{\enquote{split}} to start the extraction process. + +\newpage + +\subsection*{Comment and ignore} +In the second step, once the file \sysfile{test.tex} is loaded and divided in memory, +proceeds (in general terms) as follows: + +\begin{quotation} +Search the words \lstinline|\begin{| and \lstinline|\end{| in verbatim standard, verbatim write, verbatim in line and +commented lines, if it finds them, converts to \lstinline|\BEGIN{| and \lstinline|\END{|, then places all code to +extract inside the \lstinline|\begin{preview}| \ldots \lstinline|\end{preview}|. +\end{quotation} + +At this point \emph{\enquote{all}} the code you want to extract is inside \lstinline|\begin{preview}|\ldots\lstinline|\end{preview}|. + +\subsection*{Creating files and extracting} + +In the third step, the script generate \meta{standalone} files: \sysfile{test-fig-1.tex}, +\sysfile{test-fig-2.tex}, \dots{} and saved in \sysdir{./images} then proceed in two ways +according to the \oarg[type=tt,cf=optcolor,sbc=gray,ac=lightgray]{options} +passed to generate a temporary file with a random number (1981 for example): + +\begin{enumerate}[leftmargin=*] +\item If script is call \emph{without} \cmdopt{noprew} options, the following lines +will be added at the beginning of the \sysfile{test.tex} (in memory): + +\begin{examplecode} +\PassOptionsToPackage{inactive}{pst-pdf}% +\AtBeginDocument{% +\RequirePackage[inactive]{pst-pdf}% +\RequirePackage[active,tightpage]{preview}% +\renewcommand\PreviewBbAdjust{-60pt -60pt 60pt 60pt}}% +% rest of input file +\end{examplecode} + +The different parts of the file read in memory are joined and save in a temporary +file \sysfile{test-fig-1981.tex} in \enquote{\sysdir{./}}. This file will contain all the environments +for extraction between \lstinline|\begin{preview}|\ldots\lstinline|\end{preview}| along with the rest of the document. +If the document contains images, these must be in the formats supported by the \emph{engine} selected to process the \meta{input file}. + +\item If script is call \emph{with} \cmdopt{noprew} options, the \lstinline|\begin{preview}|\ldots\lstinline|\end{preview}| +lines are only used as delimiters for extracting the content \emph{without} using the package \pkgname{preview}, the following lines +will be added at the beginning of the \sysfile{test.tex} (in memory): + +\begin{examplecode} +\PassOptionsToPackage{inactive}{pst-pdf}% +\AtBeginDocument{% +\RequirePackage[inactive]{pst-pdf}}% +% only environments extracted +\end{examplecode} + +Then it is joined with all extracted environments separated by \ics{newpage} and saved +in a temporary file \sysfile{test-fig-1981.tex} in \enquote{\sysdir{./}}. + +\end{enumerate} + +If \cmdopt{norun} is passed, the temporary file \sysfile{test-fig-1981.tex} +is renamed to \sysfile{test-fig-all.tex} and moved to \sysdir{./images}. + +\subsection*{Generate image formats} + +In the fourth step, the script generating the file \sysfile{test-fig-1981.pdf} +with all code extracted and croping, running: + +\begin{examplecmd} +[user@machine ~:]§ `\small\meta[type=tt,cf=ForestGreen,ac=lightgray]{compiler}` -no-shell-escape -interaction=nonstopmode -recorder test-fig-1981.tex +[user@machine ~:]§ pdfcrop --margins `\small\textcolor{gray}{0}` test-fig-1981.pdf test-fig-1981.pdf +\end{examplecmd} + +Now move \sysfile{test-fig-1981.pdf} to \sysdir{/tmp/hG45uVklv9} and rename to \sysfile{test-fig-all.pdf}, +generate image files \sysfile{test-fig-1.pdf} and \sysfile{test-fig-2.pdf} and copy to \sysdir{./images}, if the +image files exist, they will be rewritten each time you run the script. The file \sysfile{test-fig-1981.tex} is +moved to the \sysdir{./images} and rename to \sysfile{test-fig-all.tex}. + +Note the options passed to \meta[type=tt,cf=ForestGreen,ac=lightgray]{compiler} +always use \prgopt*{no-shell-escape} and \prgopt*{recorder} to generate the +\fext{fls} file which is used to delete temporary files and directories +after the process is completed. The \cmdopt{shell} option activates +\prgopt*{shell-escape} or \prgopt*{enable-write18} in \hologo{MiKTeX} +for compatibility with packages such as \pkgname{minted} or others. + +\subsection*{Create output file} + +In the fifth step, the script apply the option \cmdopt{clean}, remove all content betwen \lstinline|%<*remove> ... %| +and try to detect whether the \pkgname{graphicx} package and the \ics{graphicspath} command are in the preamble of the \meta[cf=optcolor]{output file} (in memory). +If it is not possible to find it, it will read the \fext{log} file generated by the temporary file with only preamble. +Once the detection is complete, the package \pkgname{grfext} and \ics*{PrependGraphicsExtensions*} will be added at the end of the preamble: + +\begin{examplecode}[numbers=left] +\usepackage{graphicx} +\graphicspath{{images/}} +\usepackage{grfext} +\PrependGraphicsExtensions*{.pdf} +\end{examplecode} + +Now converting all extracted code to \ics{includegraphics} and save \sysfile{test-out.tex} +in \enquote{\sysdir{./}}, then proceed to run: + +\begin{examplecmd} +[user@machine ~:]§ `\small\meta[type=tt,cf=ForestGreen,ac=lightgray]{compiler}` -recorder -no-shell-escape test-out.tex +\end{examplecmd} + +generating the file \sysfile{test-out.pdf}. + +\subsection*{Clean temporary files and dirs} + +In the sixth step, the script read the files \sysfile{test-fig-1981.fls} +and \sysfile{test-out.fls}, extract the information from the +temporary files and dirs generated in the process in \enquote{\sysdir{./}} and then +delete them together with the directory \sysdir{/tmp/hG45uVklv9}. + +Finally the output file \sysfile{test-out.tex} looks like this: + +\begin{examplecode}[numbers=left] +% some commented lines at begin document +\documentclass{article} +\usepackage{tikz} +\graphicspath{{images/}} +\usepackage{grfext} +\PrependGraphicsExtensions*{.pdf} +\begin{document} +Some text +\includegraphics[scale=1]{test-fig-1} +Always use \verb|\begin{tikzpicture}| and \verb|\end{tikzpicture}| to open +and close environment +\includegraphics[scale=1]{test-fig-2} +Some text +\begin{verbatim} +\begin{tikzpicture} + Some code +\end{tikzpicture} +\end{verbatim} +Some text +\end{document} +\end{examplecode} + +\section{Extract content} +\label{sec:extract} + +The script provides two ways to \meta{extract} content from \meta[cf=optcolor]{input file}, +using \meta[type=rm,cf=optcolor,ac=gray]{environments} and \meta[type=rm,cf=optcolor,ac=gray]{docstrip tags}. +Some environment (including \texttt{\small\bfseries\textcolor{MediumOrchid}{*}} argument) +are supported by default. If environments are nested, the outermost one will be extracted. + +\subsection{Default environments} +\label{sec:extract:env} + +\DescribeTE{preview} +Environment provide by \pkgname{preview}\cite{preview} package. If any \env{preview} environments +found in the \meta[cf=optcolor]{input file} will be extracted and converted these. Internally +the script converts all environments to extract in \env{preview} environments. +Is better comment this package in preamble unless the option \cmdopt[n]{noprew}{} is +used. This environment is reserved for the internal process of extraction and conversion, it +cannot be passed as an argument to the option \cmdopt{skipenv}. + +\vspace{0.25\baselineskip} + +\DescribeTE{postscript} +Environment provide by \pkgname{pst-pdf}\cite{pst-pdf}, \pkgname{auto-pst-pdf}\cite{auto-pst-pdf} +and \pkgname{auto-pst-pdf-lua}\cite{auto-pst-pdf-lua} packages. Since the \pkgname{pst-pdf}, \pkgname{auto-pst-pdf} +and \pkgname{auto-pst-pdf-lua} packages internally use the \pkgname{preview} package, is better comment this in preamble. +Only the \emph{content} of this environment is extracted and \emph{\enquote{not}} the environment itself when using the +\cmdopt{srcenv}{} or \cmdopt{subenv}{} options. + +\vspace{0.25\baselineskip} + +\DescribeTE{PSTexample} +Environment provide by \pkgname{pst-exa}\cite{pst-exa} packages. The script automatically detects the +\lstinline|\begin{PSTexample}| \lstinline|...\end{PSTexample}| +environments and processes them as separately compiled files. The user should have loaded the +package with the [\pkgopt{swpl}] or [\pkgopt{tcb}] option and run the script +using \cmdopt{latex}{} or \cmdopt{xetex}. This environment is reserved for the internal process of extraction and conversion, it +cannot be passed as an argument to the option \cmdopt{skipenv}{}. + +\vspace{0.25\baselineskip} + +\DescribeTE{pspicture} +Environment provide by \pkgname{PStricks}\cite{pstricks} package. The plain \hologo{TeX} +syntax \lstinline|\pspicture ... \endpspicture| its converted to \hologo{LaTeX} syntax +\lstinline|\begin{pspicture} ... \end{pspicture}| if not within the \env{PSTexample} or \env{postscript} environments. + +\vspace{0.75\baselineskip} + +\DescribeTE{psgraph} +Environment provide by \pkgname{pst-plot}\cite{pst-plot} package. The plain \hologo{TeX} syntax \lstinline|\psgraph ... \endpsgraph| +its converted to \hologo{LaTeX} syntax \lstinline|\begin{psgraph} ... \end{psgraph}| if +not within the \env{PSTexample} or \env{postscript} environments. + +\newpage + +\DescribeTE{tikzpicture} +Environment provide by \pkgname{TikZ}\cite{tikz} package. The plain \hologo{TeX} syntax \lstinline|\tikzpicture ... \tikzpicture| +its converted to \hologo{LaTeX} syntax \lstinline|\begin{tikzpicture} ... \end{tikzpicture}| +but no a short syntax \lstinline|\tikz ... ;|. + +\vspace{0.75\baselineskip} + +\DescribeTE{pgfpicture} +Environment provide by \pkgname{pgf}\cite{tikz} package. Since the script uses a +\emph{\enquote{recursive regular expression}} to extract environments, no presents problems +if present \env{pgfinterruptpicture}. + +If you need to extract other environments you can use one of the options described +in \ref{sec:optline} or \ref{sec:optfile}. + +\subsection{Extract with docstrip tags} +\label{sec:extract:tag} + +\DescribeTE*{ltximg} +All content included between \lstinline|%<*ltximg> ... %| is extracted. +The tags can \emph{not} be nested and should be at the beginning of the line and in separate lines. +Internally the script converts all this tags to \env{preview} environments. + +\begin{examplecode}[frame=single] +% no space before open tag %<* +%<*ltximg> +code to extract +% +% no space before close tag % ... %| are ignored and no extract. +The tags can \emph{not} be nested and should be at the beginning of the line and in separate lines. +Internally the script converts all this tags to \env{nopreview} environments. + +\begin{examplecode}[frame=single] +% no space before open tag %<* +%<*noltximg> +no extract this +% +% no space before close tag % ... %| are deleted in the \meta[cf=optcolor]{output file}. +The tags can \emph{not} be nested and should be at the beginning of the line and in separate lines. + +\begin{examplecode}[frame=single] +% no space before open tag %<* +%<*remove> +lines removed in output file +% +% no space before close tag % ... %|. Like this: + +\begin{examplecode}[numbers=left] +%<*remove> +% ltximg: options: { png, srcenv, xetex } +% ltximg: extrenv: { description } +% +\end{examplecode} + +\subsection*{Passing options from input file} + +Adding the following lines to the beginning of the file \sysfile{file-in.tex}: + +\begin{examplecode}[numbers=left] +% ltximg: options: { luatex, output = file-out, imgdir = pics, prefix = env } +% ltximg: skipenv: { tikzpicture } +% ltximg: deltenv: { filecontents } +\end{examplecode} +and run: +\begin{examplecmd} +[user@machine~:]§ ltximg file-in.tex +\end{examplecmd} + +Create a \sysdir{./pics} directory (if it does not exist) with all extracted environments, +except \env{tikzpicture}, converted to image formats (\iext{pdf}) in individual files, +an output file \meta[ac=LightSlateGrey,cf=OrangeRed]{file-out.tex} with all extracted environments +converted to \ics{includegraphics} and environment \LWenv{filecontents} removed, +a single file \meta[ac=LightSlateGrey,cf=OrangeRed]{file-in-env-all.ltx} with \emph{only} the extracted environments +using \prgname*{lualatex} and \pkgname{preview} package for process \meta[ac=LightSlateGrey,cf=OrangeRed]{file-in.tex} +and \meta[ac=LightSlateGrey,cf=OrangeRed]{file-out.tex}. + +\section{The way of \texttt{arara}} +\label{sec:arara} +By design, the script only runs \emph{\enquote{one or more compilation}} on top +of the \meta[cf=optcolor]{input file}, but, sometimes you need to process in a specific mode the \meta[cf=optcolor]{input file} +or needs to be processed with something other than \hologo{LaTeX}, \hologo{XeLaTeX}, \hologo{pdfLaTeX} or \hologo{LuaLaTeX} engine. +This is where \arara\cite{arara} comes in, this \emph{\enquote{great little tool}}, +is able to have complete control over the compilation of the \meta[cf=optcolor]{input file}, we just +have to keep a few considerations in mind: + +\begin{enumerate}[font=\small, nosep, noitemsep,leftmargin=*] +\item Read the documentation (this always comes first). +\item Add \lstinline|{ options: [-recorder] }| to \enquote{rule} for clean temporary files. +\item Avoiding the use of \lstinline|: clean: { extensions: [...] }|. +\item Don't set \lstinline|-jobname| and \lstinline|-output-directory| in any \enquote{rule}. +\end{enumerate} + +When the \cmdopt{arara} option is passed to the script, the line that runs in the system is: + +\begin{examplecmd} +[user@machine~:]§ `\small\prgname{arara}` --log file.tex +\end{examplecmd} + +If you have several \enquote{rules} within the file they will all be executed, to avoid this we must add: + +\begin{examplecode}[numbers=left] +% arara: halt +\end{examplecode} + +After the last \enquote{rule} you have at the beginning of the file. With all these considerations +in mind it is possible to extract and convert environments +from \emph{any file}. + +For example, by adding these lines at the beginning of the file: + +\begin{examplecode}[numbers=left] +% arara: lualatex: { options: [-recorder] } +% arara: lualatex: { options: [-recorder] } +%<*remove> +% ltximg: options: { arara, output = file-out, prefix = tkz} +% +\end{examplecode} + +and run: + +\begin{examplecmd} +[user@machine~:]§ ltximg test.tex +\end{examplecmd} + +Create a \sysdir{./images} directory (if it does not exist) with all extracted +environments converted to image format (\iext{pdf}) in individual files, +an output file \meta[ac=LightSlateGrey,cf=OrangeRed]{file-out.tex} with all exatracted environments +converted to \ics{includegraphics}, a single file \meta[ac=LightSlateGrey,cf=OrangeRed]{test-tkz-all.tex} +with only the extracted environments using \pkgname{preview} package and \prgname*{lualatex} \emph{\enquote{two times}} +for process \meta[ac=LightSlateGrey,cf=OrangeRed]{test.tex} and \meta[ac=LightSlateGrey,cf=OrangeRed]{file-out.tex}. + +Remember that the \meta[cf=optcolor]{input file} and \meta[cf=optcolor]{output file} +will be compiled using the same \enquote{rule}. One \emph{trick} to get around this situation is to use: + +\begin{examplecode}[numbers=left] +%<*remove> +% arara: lualatex: { options: [-recorder] } +% arara: lualatex: { options: [-recorder] } +% arara: halt +% ltximg: options: { arara, output = file-out, prefix = tkz} +% +% arara: xelatex: { options: [-recorder] } +% arara: xelatex: { options: [-recorder] } +\end{examplecode} + +The content betwen \lstinline|%<*remove> ... %| are remove from output file +before compiling. Thus, the output file \meta[ac=LightSlateGrey,cf=OrangeRed]{file-out.tex} will be +compiled using \prgname*{xelatex} \emph{\enquote{two times}}. + +As a final consideration, \ltximg{} passes options to the \pkgname{preview} package and +the \scriptname{pdfcrop} script according to the engine used. When using \cmdopt{arara} it +will \emph{\enquote{try}} to detect the used engine by means of a regular expression, if the +detection fails the default values will be used. + +This does not affect the process of creating \meta{standalone} files and can be prevented by using \cmdopt{noprew} +or \cmdopt{nocrop} at the cost of not having the images cropped. + +In this way we can \meta{compile} and \meta{convert} any document as long as the conditions +of the \meta[cf=optcolor]{input file} are met and the correct \enquote{rule} are used. + +\section{Note for \texttt{dvisvgm} users} +\label{sec:dvisvgm} + +By design, the image format \iext{svg} is created using \prgname{pdftocairo} over the +generated \iext{pdf} file, but, if you want to have a good \iext{svg} files that preserve our \emph{typographic} fonts it is best to +use \prgname{dvisvgm}\footnote{\url{https://ctan.org/pkg/dvisvgm}}. The best results of \prgname{dvisvgm}\cite{dvisvgm} are obtained when processing the file in \fext{dvi} or \fext{xdv} +format, there are two possible ways to do this: + +\begin{enumerate}[font=\small, nosep, noitemsep,leftmargin=*] +\item Execute the script using \cmdopt{subenv}{} and \cmdopt{norun}{} to generate \meta{standalone} files, move to \sysdir{./images} +and generate \fext{dvi} or \fext{xdv} files, then runing: + +\begin{examplecmd} +[user@machine~:]§ for i in *.tex; do `\meta[type=tt,cf=ForestGreen,ac=lightgray]{compiler} \oarg[type=tt,cf=gray,sbc=optcolor,ac=gray]{options}` §i;done +[user@machine~:]§ for i in *.dvi; do `\small\prgname{dvisvgm} \oarg[type=tt,cf=gray,sbc=optcolor,ac=gray]{options}` §i;done +\end{examplecmd} + +\item Execute the script using \cmdopt{norun}{}, move to \sysdir{./images} and generate \fext{dvi} or \fext{xdv} file, then runing: + +\begin{examplecmd} +[user@machine~:]§ `\meta[type=tt,cf=ForestGreen,ac=lightgray]{compiler} \oarg[type=tt,cf=gray,sbc=optcolor,ac=gray]{options}` test-fig-all.tex +[user@machine~:]§ `\small\prgname{dvisvgm} \oarg[type=tt,cf=gray,sbc=optcolor,ac=gray]{options}` test-fig-all.dvi +\end{examplecmd} + +\end{enumerate} + +\section{Example usign \texttt{latexmk}} + +If you are a user of \scriptname{latexmk}, another great utility that automates the compilation process, you must keep +in mind that this will run only in the \meta{output file}. Consider the following example +adapted from \href{https://tex.stackexchange.com/a/209059}{How to get tikzmark to work} and +\href{https://tex.stackexchange.com/a/114847}{Draw an aircraft with Tikz} +to generate an image in \iext{svg}, \iext{png} and \iext{pdf} format from environment \env{picture} using \prgname*{lualatex} and \scriptname{latexmk}. + +\begin{examplecode}[numbers=left] +%<*remove> +% ltximg: extrenv: {picture} +% ltximg: skipenv: {tikzpicture} +% +\documentclass{article} +\usepackage{tikz} +\usetikzlibrary{calc,tikzmark} +\setlength{\parindent}{0pt} +\begin{document} +\section{How to get Tikzmark to work} +By taking logarithms of both sides: + +\[ + t = \frac{30\cdot\ln(3/22)}{\ln(15/22)} + \tikzmark{calculator}\approx\tikzmark{otherside} + 156 +\] +\begin{tikzpicture}[overlay,remember picture] + \coordinate (target) at ($(pic cs:calculator)!1/2!(pic cs:otherside) - (0,.5ex)$); + \draw[arrows=->] (target) ++(0,-2ex) node [anchor=north] {use calculator} -- (target); +\end{tikzpicture} + +\section{Draw an aircraft with Tikz} +The best airplane ever drawn by David Carlise. No TikZ used, just the +classic and perhaps forgotten \verb|\begin{picture} ... \end{picture}|. + +\begin{picture}(200,100) + \put(30,40){\line(1,0){150}} \put(30,40){\line(0,1){60}} + \put(30,100){\line(1,0){20}} \put(50,100){\line(1,-4){10}} + \put(60,60){\line(1,0){100}} \put(160,60){\line(1,-1){20}} + \put(100,50){\line(0,-1){80}} \put(130,50){\line(0,-1){80}} + \put(100,-30){\line(1,0){30}} \put(100,61){\line(0,1){49}} + \put(130,61){\line(0,1){49}} \put(100,110){\line(1,0){30}} +\end{picture} +\end{document} +\end{examplecode} + +We now run: + +\begin{examplecmd} +[user@machine~:]§ ltximg --luatex --latexmk --svg --png -o file-out file-in.tex +\end{examplecmd} + +Create a \sysdir{./images} directory (if it does not exist) with all \env{picture} environments, +except \env{tikzpicture}, converted to image formats (\iext{svg}, \iext{png}, \iext{pdf}), +an output file \meta[ac=LightSlateGrey,cf=OrangeRed]{file-out.tex} with all \env{picture} environments +converted to \ics{includegraphics}, a single file \meta[ac=LightSlateGrey,cf=OrangeRed]{file-in-fig-all.ltx} with +only environments \env{picture} extracted using \prgname*{lualatex} and \pkgname{preview} package for process +\meta[ac=LightSlateGrey,cf=OrangeRed]{file-in.tex} and \scriptname{latexmk} for \emph{full} process +\meta[ac=LightSlateGrey,cf=OrangeRed]{file-out.tex}. + +\newpage + +\section{Final notes} + +The process and operations required to generate the various types of \meta{image +formats} or \meta{standalone} files have been described throughout the documentation, +but, as discussed in section \ref{sec:arara}, sometimes the requirements are a \emph{little +different}. + +This is the best way to extend the capabilities of the \ltximg{}. Although +many tasks can be \emph{automated}, in the end only the user knows what +the document contains and how it should be generated. + +Finding the correct \emph{\enquote{regular expressions}} and writing a \emph{\enquote{good documentation}} +would be the great mission (which does not end yet). + +\section{Change history} +\label{sec:change:history} + +The most recent publicly released of \ltximg{} is available at +\textsc{ctan}: \url{https://www.ctan.org/pkg/ltximg}. Historical and +developmental versions are available at \textcolor{gray}{\scriptsize\faIcon[regular]{github}} +\url{https://github.com/pablgonz/ltximg}. + +While general feedback via email is welcomed, specific bugs or feature +requests should be reported through the issue +tracker: \url{https://github.com/pablgonz/ltximg/issues}. + +This is a short list of some of the notable changes in the history of the \ltximg{} along with the +versions, both development (devp) and public (ctan). + +\setlength{\columnsep}{30pt} +\begin{multicols}{2} +\setlist[itemize,1]{label=\textendash,nosep,noitemsep,leftmargin=-10pt} +\begin{description}[font=\small\sffamily,style=nextline,nosep,noitemsep] +\item [v\fileversion\ (ctan), \filedate] \leavevmode\vspace{-\baselineskip} + \begin{itemize} + \item Add \texttt{-dALLOWPSTRANSPARENCY} to \texttt{ps2pdf}. + \item The \texttt{--xetex} option now uses \texttt{xelatex} and then \texttt{xdvipdfmx}. + \item Fix module detection under \hologo{TeX} Live on Windows. + \item Add \texttt{POD} and \texttt{man} documentation. + \end{itemize} +\item [v1.9 (ctan), 2020-08-22] \leavevmode\vspace{-\baselineskip} + \begin{itemize} + \item Fix \texttt{graphicx} detection. + \item Fix typos in documentation. + \item Add more contents to \texttt{.log} file. + \end{itemize} +\item [v1.8 (ctan), 2020-08-18] \leavevmode\vspace{-\baselineskip} + \begin{itemize} + \item It is now possible to extract any environment. + \item Add \texttt{--log}, \texttt{--runs}, \texttt{--latexmk} and \texttt{--dvilua} options. + \item All calls to the system are captured. + \item Re-write source code acording to \texttt{Perl} v5.3x. + \item Review of documentation. + \end{itemize} +\item [v1.7 (ctan), 2019-08-24] \leavevmode\vspace{-\baselineskip} + \begin{itemize} + \item Add \texttt{scontents} environment support. + \item Add \texttt{filecontentsdefmacro} environment support. + \item Fix regex in source code. + \item Update documentation. + \end{itemize} +\item [v1.6 (ctan), 2019-07-13] \leavevmode\vspace{-\baselineskip} + \begin{itemize} + \item Add \texttt{--zip} and \texttt{--tar} options. + \item Add new \texttt{Verb} from \texttt{fvextra}. + \item Fix and update source code and documentation. + \end{itemize} +\item [v1.5 (ctan), 2018-04-12] \leavevmode\vspace{-\baselineskip} + \begin{itemize} + \item Use \texttt{GitHub} to control version. + \item Rewrite and optimize code and options. + \item Change \texttt{pdf2svg} for \texttt{pdftocairo}. + \item Complete support for \texttt{pst-exa} package. + \item Escape characters in regex according to \texttt{Perl} v5.2x. + \end{itemize} +\item [v1.4 (devp), 2016-11-29] \leavevmode\vspace{-\baselineskip} + \begin{itemize} + \item Remove and rewrite code for regex and system call. + \item Add \texttt{--arara} compiler, clean and comment code. + \item Add \texttt{--dvips} and \texttt{--dvipdfm(x)} for creation images. + \item Add \texttt{bmp}, \texttt{tiff} image format. + \end{itemize} +\item [v1.3 (devp), 2016-08-14] \leavevmode\vspace{-\baselineskip} + \begin{itemize} + \item Rewrite some part of code (norun, nocrop, clean). + \item Suport \texttt{minted} and \texttt{tcolorbox} package. + \item Escape some characters in regex according to \texttt{Perl} v5.2x. + \item All options read from command line and input file. + \item Use \texttt{/tmp} dir for work process. + \end{itemize} +\item [v1.2 (ctan), 2015-04-22] \leavevmode\vspace{-\baselineskip} + \begin{itemize} + \item Remove unused modules. + \item Add more image format. + \item Fix regex. + \end{itemize} +\item [v1.1 (ctan), 2015-04-21] \leavevmode\vspace{-\baselineskip} + \begin{itemize} + \item Change \texttt{mogrify} to \texttt{gs} for image formats. + \item Create output file. + \item Rewrite source code and fix regex. + \item Change format date to iso format. + \end{itemize} +\item [v1.0 (ctan), 2013-12-01] \leavevmode\vspace{-\baselineskip} + \begin{itemize} + \item First public release. + \end{itemize} +\end{description} +\end{multicols} + +\newpage + +\let\stdsection\section +\def\section*#1{\stdsection{#1}} +\begin{thebibliography}{9} + +\bibitem{preview} \textsc{Kastrup, David}. \enquote{The \textsf{preview} +package for \hologo{LaTeX}}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/preview}, 2017. + +\bibitem{tikz} \textsc{Tantau, Till}. \enquote{The \textsf{TikZ} and \textsf{PGF} +Packages}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/pgf}, 2020. + +\bibitem{pstricks} \textsc{Van Zandt, Timothy}. \enquote{\textsf{PSTricks} - +\textsf{PostScript} macros for generic \hologo{TeX}}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/pstricks-base}, 2007. + +\bibitem{pst-plot} \textsc{Van Zandt, Timothy}. \enquote{\textsf{pst-plot} – +Plot data using \textsf{PSTricks}}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/pst-plot}, 2019. + +\bibitem{pst-pdf} \textsc{Niepraschk, Rolf}. \enquote{The \textsf{pst-pdf} +Packages}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/pst-pdf}, 2019. + +\bibitem{auto-pst-pdf} \textsc{Robertson, Will}. \enquote{The \textsf{auto-pst-pdf} +Packages}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/auto-pst-pdf}, 2009. + +\bibitem{auto-pst-pdf-lua} \textsc{Voß, Herbert}. \enquote{\textsf{auto-pst-pdf-lua} - Using +\hologo{LuaLaTeX} with \textsf{PSTricks}}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/auto-pst-pdf-lua}, 2018. + +\bibitem{pst-exa} \textsc{Voß, Herbert}. \enquote{\textsf{pst-exa} - Typeset +\textsf{PSTricks} examples, with \hologo{pdfTeX}}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/pst-exa}, 2017. + +\bibitem{pst2pdf} \textsc{Voß, Herbert}. \enquote{\textsf{pst2pdf} - A script +to compile \textsf{PSTricks} documents via \hologo{pdfTeX}}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/pst2pdf}, 2017. + +\bibitem{graphicx} \textsc{The \hologo{LaTeX3} Project}. \enquote{\textsf{graphics} – Enhanced +support for graphics}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/graphicx}, 2017. + +\bibitem{grfext} \textsc{Oberdiek, Heiko}. \enquote{The \textsf{grfext} +package}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/grfext}, 2019. + +\bibitem{xcomment} \textsc{Van Zandt, Timothy}. \enquote{The \textsf{xcomment} +package}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/xcomment}, 2010. + +\bibitem{extract} \textsc{Adriaens, Hendri}. \enquote{The \textsf{extract} +package}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/extract}, 2019. + +\bibitem{cachepic} \textsc{Trzeciak, Tomasz M}. \enquote{The \textsf{cachepic} +package}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/cachepic}, 2009. + +\bibitem{doc} \textsc{Mittelbach, Frank}. \enquote{The \textsf{doc} and \textsf{shortvrb} +Packages}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/doc}, 2020. + +\bibitem{fancyvrb} \textsc{Van Zandt, Timothy}. \enquote{The \textsf{fancyvrb} +package - Fancy Verbatims in \hologo{LaTeX}}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/fancyvrb}, 2020. + +\bibitem{listings} \textsc{Hoffmann, Jobst}. \enquote{The \textsf{listings} +package}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/listings}, 2020. + +\bibitem{minted} \textsc{Poore, Geoffrey M}. \enquote{The \textsf{minted} +package - Highlighted source code in \hologo{LaTeX}}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/minted}, 2017. + +\bibitem{arara} \textsc{The Island of \hologo{TeX}}. \enquote{\textsf{arara} - The +cool \hologo{TeX} automation tool}. Available from +\textsc{ctan}, \url{https://www.ctan.org/pkg/arara}, 2020. + +\bibitem{dvisvgm} \textsc{Gieseking, Martin}. \enquote{\textsf{dvisvgm} - A +fast \textsf{DVI} to \textsf{SVG} converter}. Available from +\textsc{ctan}, \url{https://ctan.org/pkg/dvisvgm}, 2020. + +\end{thebibliography} +\let\section\stdsection + +\addtocontents{toc}{\protect\setcounter{tocdepth}{2}} +\cleardoublepage +\phantomsection +\indexprologue{ +The italic numbers denote the pages where the corresponding entry is +described.} + +\printindex +\end{document} diff --git a/support/ltximg/ltximg.1 b/support/ltximg/ltximg.1 new file mode 100644 index 0000000000..81545b5470 --- /dev/null +++ b/support/ltximg/ltximg.1 @@ -0,0 +1,279 @@ +.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is >0, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.nr rF 0 +.if \n(.g .if rF .nr rF 1 +.if (\n(rF:(\n(.g==0)) \{\ +. if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 +. \} +. \} +.\} +.rr rF +.\" ======================================================================== +.\" +.IX Title "ltximg 1" +.TH ltximg 1 "2021-01-24" "2.0" "General Commands Manual" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +ltximg \- LaTeX environments to image and standalone files +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fBltximg\fR [<\fIoptions\fR>] [\-\-] <\fIfilename\fR>.<\fItex\fR|\fIltx\fR> +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBltximg\fR automates the process of extracting and converting +environments from LaTeX file to image formats and \fIstandalone\fR files +using \fIghostscript\fR and \fIpoppler-utils\fR. Generates a one file with +only extracted environments and other with all extracted environments +converted to \f(CW\*(C`\eincludegraphics\*(C'\fR. +.PP +By default the extracted environments are: +.PP +\&\fBpreview\fR \fBpspicture\fR \fBtikzpicture\fR \fBpgfpicture\fR \fBpsgraph\fR \fBpostscript\fR \fBPSTexample\fR +.SH "OPTIONS" +.IX Header "OPTIONS" +Options that accept a value require either a blank space or \f(CW\*(C`=\*(C'\fR between +the option and the value. Multiple short options can be bundling and +if the last option takes a comma separated list you need \f(CW\*(C`\-\-\*(C'\fR at the end. +Relative or absolute paths for directories and files is not supported. +.PP +If used without [<\fIoptions\fR>] the extracted environments are converted +to \fIpdf\fR image format and saved in \f(CW\*(C`./images\*(C'\fR directory using \f(CW\*(C`pdflatex\*(C'\fR +and \fIpreview\fR package for process. +.PP +General script options: +.IP "\fB\-h\fR, \fB\-\-help\fR" 4 +.IX Item "-h, --help" +Display command line help and exit. +.IP "\fB\-v\fR, \fB\-\-version\fR" 4 +.IX Item "-v, --version" +Display current version and exit. +.IP "\fB\-V\fR, \fB\-\-verbose\fR" 4 +.IX Item "-V, --verbose" +Verbose printing information. +.IP "\fB\-l\fR, \fB\-\-log\fR" 4 +.IX Item "-l, --log" +Write \f(CW\*(C`.log\*(C'\fR file with debug information. +.IP "\fB\-t\fR, \fB\-\-tif\fR" 4 +.IX Item "-t, --tif" +Create \f(CW\*(C`.tif\*(C'\fR files using \fIghostscript\fR. +.IP "\fB\-b\fR, \fB\-\-bmp\fR" 4 +.IX Item "-b, --bmp" +Create \f(CW\*(C`.bmp\*(C'\fR files using \fIghostscript\fR. +.IP "\fB\-j\fR, \fB\-\-jpg\fR" 4 +.IX Item "-j, --jpg" +Create \f(CW\*(C`.jpg\*(C'\fR files using \fIghostscript\fR. +.IP "\fB\-p\fR, \fB\-\-png\fR" 4 +.IX Item "-p, --png" +Create \f(CW\*(C`.png\*(C'\fR files using \fIghostscript\fR. +.IP "\fB\-e\fR, \fB\-\-eps\fR" 4 +.IX Item "-e, --eps" +Create \f(CW\*(C`.eps\*(C'\fR files using \fIpdftops\fR. +.IP "\fB\-s\fR, \fB\-\-svg\fR" 4 +.IX Item "-s, --svg" +Create \f(CW\*(C`.svg\*(C'\fR files using \fIpdftocairo\fR. +.IP "\fB\-P\fR, \fB\-\-ppm\fR" 4 +.IX Item "-P, --ppm" +Create \f(CW\*(C`.ppm\*(C'\fR files using \fIpdftoppm\fR. +.IP "\fB\-g\fR, \fB\-\-gray\fR" 4 +.IX Item "-g, --gray" +Gray scale for images using \fIghostscript\fR. +.IP "\fB\-f\fR, \fB\-\-force\fR" 4 +.IX Item "-f, --force" +Capture \f(CW\*(C`\epsset\*(C'\fR and \f(CW\*(C`\etikzset\*(C'\fR to extract. +.IP "\fB\-n\fR, \fB\-\-noprew\fR" 4 +.IX Item "-n, --noprew" +Create images files without \fIpreview\fR package. +.IP "\fB\-r\fR \fIinteger\fR, \fB\-\-runs\fR=\fIinteger\fR" 4 +.IX Item "-r integer, --runs=integer" +Set the number of times the compiler will run on the \fIinput\fR file for +environment extraction (default: 1). +.IP "\fB\-d\fR \fIinteger\fR, \fB\-\-dpi\fR=\fIinteger\fR" 4 +.IX Item "-d integer, --dpi=integer" +Dots per inch resolution for images (default: 150). +.IP "\fB\-m\fR \fIinteger\fR, \fB\-\-margins\fR=\fIinteger\fR" 4 +.IX Item "-m integer, --margins=integer" +Set margins in bp for \fIpdfcrop\fR (default: 0). +.IP "\fB\-o\fR \fIfilename\fR, \fB\-\-output\fR=\fIfilename\fR" 4 +.IX Item "-o filename, --output=filename" +Create \fIoutput\fR file. +.IP "\fB\-\-imgdir\fR=\fIdirname\fR" 4 +.IX Item "--imgdir=dirname" +Set name of directory to save images and files (default: images). +.IP "\fB\-\-prefix\fR=\fIstring\fR" 4 +.IX Item "--prefix=string" +Set \fIprefix\fR append to each generated files (default: fig). +.IP "\fB\-\-myverb\fR=\fImacroname\fR" 4 +.IX Item "--myverb=macroname" +Add \f(CW\*(C`\emacroname\*(C'\fR to verbatim inline search (default: myverb). +.IP "\fB\-\-clean\fR=\fIdoc\fR|\fIpst\fR|\fItkz\fR|\fIall\fR|\fIoff\fR" 4 +.IX Item "--clean=doc|pst|tkz|all|off" +Removes specific block text in \fIoutput\fR file (default: doc). +.IP "\fB\-\-zip\fR" 4 +.IX Item "--zip" +Compress files generated in \f(CW\*(C`.zip\*(C'\fR format. +.IP "\fB\-\-tar\fR" 4 +.IX Item "--tar" +Compress files generated in \f(CW\*(C`.tar.gz\*(C'\fR format. +.IP "\fB\-\-srcenv\fR" 4 +.IX Item "--srcenv" +Create files with only code of environments. +.IP "\fB\-\-subenv\fR" 4 +.IX Item "--subenv" +Create standalone files for environments. +.IP "\fB\-\-shell\fR" 4 +.IX Item "--shell" +Enable \f(CW\*(C`\ewrite18{SHELL COMMAND}\*(C'\fR. +.IP "\fB\-\-latex\fR" 4 +.IX Item "--latex" +Using \f(CW\*(C`latex>dvips>ps2pdf\*(C'\fR for compiler \fIinput\fR and \f(CW\*(C`pdflatex\*(C'\fR for compiler +\&\fIoutput\fR. +.IP "\fB\-\-dvips\fR" 4 +.IX Item "--dvips" +Using \f(CW\*(C`latex>dvips>ps2pdf\*(C'\fR for compiler \fIinput\fR and \f(CW\*(C`latex>dvips>ps2pdf\*(C'\fR for +compiler \fIoutput\fR. +.IP "\fB\-\-dvilua\fR" 4 +.IX Item "--dvilua" +Using \f(CW\*(C`dvilualatex>dvips>ps2pdf\*(C'\fR for compiler \fIinput\fR and \f(CW\*(C`lualatex\*(C'\fR for +compiler \fIoutput\fR. +.IP "\fB\-\-dvipdf\fR" 4 +.IX Item "--dvipdf" +Using \f(CW\*(C`latex>dvipdfmx\*(C'\fR for compiler \fIinput\fR and \f(CW\*(C`latex>dvipdfmx\*(C'\fR for compiler +\&\fIoutput\fR. +.IP "\fB\-\-xetex\fR" 4 +.IX Item "--xetex" +Using \f(CW\*(C`xelatex\*(C'\fR for compiler \fIinput\fR and \fIoutput\fR. +.IP "\fB\-\-luatex\fR" 4 +.IX Item "--luatex" +Using \f(CW\*(C`lualatex\*(C'\fR for compiler \fIinput\fR and \fIoutput\fR. +.IP "\fB\-\-arara\fR" 4 +.IX Item "--arara" +Use \f(CW\*(C`arara\*(C'\fR for compiler \fIinput\fR and \fIoutput\fR. +.IP "\fB\-\-latexmk\fR" 4 +.IX Item "--latexmk" +Using \f(CW\*(C`latexmk\*(C'\fR for compiler \fIoutput\fR file. +.IP "\fB\-\-norun\fR" 4 +.IX Item "--norun" +Run script, but no create images files. +.IP "\fB\-\-nopdf\fR" 4 +.IX Item "--nopdf" +Don't create a \f(CW\*(C`.pdf\*(C'\fR image files. +.IP "\fB\-\-nocrop\fR" 4 +.IX Item "--nocrop" +Don't run \fIpdfcrop\fR. +.IP "\fB\-\-extrenv\fR=\fIenv1,env2,...\fR" 4 +.IX Item "--extrenv=env1,env2,..." +Add new environments to extract. +.IP "\fB\-\-skipenv\fR=\fIenv1,env2,...\fR" 4 +.IX Item "--skipenv=env1,env2,..." +Skip some default environments to extract. +.IP "\fB\-\-verbenv\fR=\fIenv1,env2,...\fR" 4 +.IX Item "--verbenv=env1,env2,..." +Add new verbatim environments. +.IP "\fB\-\-writenv\fR=\fIenv1,env2,...\fR" 4 +.IX Item "--writenv=env1,env2,..." +Add new verbatim write environments. +.IP "\fB\-\-deltenv\fR=\fIenv1,env2,...\fR" 4 +.IX Item "--deltenv=env1,env2,..." +Delete environments in \fIoutput\fR file. +.SH "EXAMPLE" +.IX Header "EXAMPLE" +\&\fBltximg\fR \-\-latex \-e \-p \-\-subenv \-o test\-out.ltx test\-in.ltx +.PP +Create a \f(CW\*(C`./images\*(C'\fR directory (if it doesn't exist) with all extracted +environments converted to \f(CW\*(C`.pdf\*(C'\fR, \f(CW\*(C`.eps\*(C'\fR, \f(CW\*(C`.png\*(C'\fR and \fIstandalone\fR +files, a file \fItest\-in\-fig\-all.ltx\fR with all extracted environments +and the file \fItest\-out.ltx\fR with all environments converted to +\&\f(CW\*(C`\eincludegraphics\*(C'\fR using \f(CW\*(C`latex>dvips>ps2pdf\*(C'\fR and \fIpreview\fR +package for \fItest\-in.ltx\fR and \f(CW\*(C`pdflatex\*(C'\fR for \fItest\-out.ltx\fR. +.SH "DOCUMENTATION" +.IX Header "DOCUMENTATION" +For full documentation use: +.PP +texdoc \fBltximg\fR +.SH "ISSUES AND REPORTS" +.IX Header "ISSUES AND REPORTS" +\&\fBRepository\fR : +.PP +\&\fBBug tracker\fR: +.SH "AUTHOR" +.IX Header "AUTHOR" +Pablo González Luengo, \fIpablgonz@yahoo.com\fR. +.SH "COPYRIGHT AND LICENSE" +.IX Header "COPYRIGHT AND LICENSE" +Copyright 2013\-2021 Pablo González, \fIpablgonz@yahoo.com\fR. +.PP +This program is free software; you can redistribute it and/or modify +it under the terms of the \s-1GNU\s0 General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. +.PP +This program is distributed in the hope that it will be useful, but +\&\s-1WITHOUT ANY WARRANTY\s0; without even the implied warranty of +\&\s-1MERCHANTABILITY\s0 or \s-1FITNESS FOR A PARTICULAR PURPOSE.\s0 See the \s-1GNU\s0 +General Public License for more details. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fBgs\fR\|(1), \fBdvips\fR\|(1), \fBps2pdf\fR\|(1), \fBpdfcrop\fR\|(1), \fBpdftops\fR\|(1), \fBpdftocairo\fR\|(1), \fBpdftoppm\fR\|(1) diff --git a/support/ltximg/ltximg.man1.pdf b/support/ltximg/ltximg.man1.pdf new file mode 100644 index 0000000000..0cb98fe28c Binary files /dev/null and b/support/ltximg/ltximg.man1.pdf differ diff --git a/support/ltximg/ltximg.pl b/support/ltximg/ltximg.pl new file mode 100644 index 0000000000..791c931685 --- /dev/null +++ b/support/ltximg/ltximg.pl @@ -0,0 +1,3284 @@ +#!/usr/bin/env perl +use v5.26; + +############################# LICENCE ################################## +# This program is free software; you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation; either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # +# General Public License for more details. # +######################################################################## + +use Getopt::Long qw(:config bundling_values require_order no_ignore_case); +use File::Spec::Functions qw(catfile devnull); +use File::Basename; +use Archive::Tar; +use Data::Dumper; +use FileHandle; +use IO::Compress::Zip qw(:all); +use File::Path qw(remove_tree); +use File::Temp qw(tempdir); +use POSIX qw(strftime); +use File::Copy; +use File::Find; +use Env qw(PATH); +use autodie; +use Config; +use Cwd; +use if $^O eq 'MSWin32', 'Win32'; +use if $^O eq 'MSWin32', 'Module::Load::Conditional' => qw(can_load check_install requires); +# Need on Windows cmd for colors, TeX Live not provide 'Win32::Console::ANSI' +if($^O eq 'MSWin32' && check_install( module => 'Win32::Console::ANSI')) { + require Win32::Console::ANSI; +} +use Term::ANSIColor; + +### Directory for work and temp files +my $tempDir = tempdir( CLEANUP => 1); +my $workdir = cwd; + +### Script identification +my $scriptname = 'ltximg'; +my $program = 'LTXimg'; +my $nv = 'v2.0'; +my $date = '2021-01-24'; +my $copyright = <<"END_COPYRIGHT" ; +[$date] - LaTeX environments to image and standalone files +END_COPYRIGHT + +### Standart info in terminal +my $title = "$program $nv $copyright"; + +### Log vars +my $LogFile = "$scriptname.log"; +my $LogWrite; +my $LogTime = strftime("%y-%m-%d %H:%M:%S", localtime); + +### Default values +my $skiptag = 'noltximg'; # internal tag for regex +my $extrtag = 'ltximg'; # internal tag for regex +my @extr_env_tmp; # save extract environments +my @skip_env_tmp; # save skip environments +my @verb_env_tmp; # save verbatim environments +my @verw_env_tmp; # save verbatim write environments +my @delt_env_tmp; # save delete environments in output file +my @clean; # clean document options +my $outfile = 0; # write output file +my $outsrc = 0; # write standalone files +my $PSTexa = 0; # run extract PSTexample environments +my $STDenv = 0; # run extract standart environments +my $verbose = 0; # verbose info +my $gscmd; # ghostscript executable name +my $write18; # storing write18 for compiler in TeXLive and MikTeX +my $log = 0; # log file +my @currentopt; # storing current options for log file + +### Hash to store options for Getopt::Long and log file +my %opts_cmd; +$opts_cmd{string}{prefix} = 'fig'; +$opts_cmd{string}{dpi} = '150'; +$opts_cmd{string}{runs} = '1'; +$opts_cmd{string}{margin} = '0'; +$opts_cmd{string}{imgdir} = 'images'; +$opts_cmd{string}{myverb} = 'myverb'; +$opts_cmd{clean} = 'doc'; + +### Error in command line +sub errorUsage { + my $msg = shift; + die color('red').'* Error!!: '.color('reset').$msg. + " (run $scriptname --help for more information)\n"; + return; +} + +### Extended error messages +sub exterr { + chomp(my $msg_errno = $!); + chomp(my $msg_extended_os_error = $^E); + if ($msg_errno eq $msg_extended_os_error) { + $msg_errno; + } + else { + "$msg_errno/$msg_extended_os_error"; + } +} + +### Funtion uniq +sub uniq { + my %seen; + return grep !$seen{$_}++, @_; +} + +### Funtion array_minus +sub array_minus(\@\@) { + my %e = map{ $_ => undef } @{$_[1]}; + return grep !exists $e{$_}, @{$_[0]}; +} + +### Funtion to create hash begin -> BEGIN, end -> END +sub crearhash { + my %cambios; + for my $aentra(@_){ + for my $initend (qw(begin end)) { + $cambios{"\\$initend\{$aentra"} = "\\\U$initend\E\{$aentra"; + } + } + return %cambios; +} + +### Print colored info in screen +sub Infocolor { + my $type = shift; + my $info = shift; + if ($type eq 'Running') { + print color('cyan'), '* ', color('reset'), color('green'), + "$type: ", color('reset'), color('cyan'), "$info\r\n", color('reset'); + } + if ($type eq 'Warning') { + print color('bold red'), "* $type: ", color('reset'), + color('yellow'), "$info\r\n", color('reset'); + } + if ($type eq 'Finish') { + print color('cyan'), '* ', color('reset'), color('magenta'), + "$type!: ", color('reset'), color('green'), "$info\r\n",color('reset'); + } + return; +} + +### Write Log line and print msg (common) +sub Infoline { + my $msg = shift; + my $now = strftime("%y-%m-%d %H:%M:%S", localtime); + if ($log) { $LogWrite->print(sprintf "[%s] * %s\n", $now, $msg); } + say $msg; + return; +} + +### Write Log line (no print msg and time stamp) +sub Logline { + my $msg = shift; + if ($log) { $LogWrite->print("$msg\n"); } + return; +} + +### Write Log line (time stamp) +sub Log { + my $msg = shift; + my $now = strftime("%y-%m-%d %H:%M:%S", localtime); + if ($log) { $LogWrite->print(sprintf "[%s] * %s\n", $now, $msg); } + return; +} + +### Write array env in Log +sub Logarray { + my ($env_ref) = @_; + my @env_tmp = @{ $env_ref }; # dereferencing and copying each array + if ($log) { + if (@env_tmp) { + my $tmp = join "\n", map { qq/* $_/ } @env_tmp; + print {$LogWrite} "$tmp\n"; + } + else { + print {$LogWrite} "Not found\n"; + } + } + return; +} + +### Extended print info for execute system commands using $ command +sub Logrun { + my $msg = shift; + my $now = strftime("%y-%m-%d %H:%M:%S", localtime); + if ($log) { $LogWrite->print(sprintf "[%s] \$ %s\n", $now, $msg); } + return; +} + +### Capture and execute system commands +sub RUNOSCMD { + my $cmdname = shift; + my $argcmd = shift; + my $showmsg = shift; + my $captured = "$cmdname $argcmd"; + Logrun($captured); + if ($showmsg eq 'show') { + if ($verbose) { + Infocolor('Running', $captured); + } + else{ Infocolor('Running', $cmdname); } + } + if ($showmsg eq 'only' and $verbose) { + Infocolor('Running', $captured); + } + # Run system system command + $captured = qx{$captured}; + if ($log) { $LogWrite->print($captured); } + if ($? == -1) { + my $errorlog = "* Error!!: ".$cmdname." failed to execute (%s)!\n"; + my $errorprint = "* Error!!: ".color('reset').$cmdname." failed to execute (%s)!\n"; + if ($log) { $LogWrite->print(sprintf $errorlog, exterr); } + print STDERR color('red'); + die sprintf $errorprint, exterr; + } elsif ($? & 127) { + my $errorlog = "* Error!!: ".$cmdname." died with signal %d!\n"; + my $errorprint = "* Error!!: ".color('reset').$cmdname." died with signal %d!\n"; + if ($log) { $LogWrite->print(sprintf $errorlog, ($? & 127)); } + print STDERR color('red'); + die sprintf $errorprint, ($? & 127); + } elsif ($? != 0 ) { + my $errorlog = "* Error!!: ".$cmdname." exited with error code %d!\n"; + my $errorprint = "* Error!!: ".color('reset').$cmdname." exited with error code %d!\n"; + if ($log) { $LogWrite->print(sprintf $errorlog, $? >> 8); } + print STDERR color('red'); + die sprintf $errorprint, $? >> 8; + } + if ($verbose) { print $captured; } + return; +} + +### Help for command line +sub usage { +find_ghostscript(); + +my $usage = <<"END_OF_USAGE"; +${title}Syntax +\$ ltximg [] [--] . + +Description + ltximg is a "perl" script that automates the process of extracting and + converting "environments" provided by tikz, pstricks and other packages + from LaTeX file to image formats and "standalone" files using ghostscript + and poppler-utils. Generates a one file with only extracted environments + and other with all extracted environments converted to \\includegraphics. + + By default the extracted environments are: + + preview pspicture tikzpicture pgfpicture psgraph postscript PSTexample + +Options + Options that accept a value require either a blank space or = between + the option and the value. Multiple short options can be bundling and + if the last option takes a comma separated list you need -- at the end. + Relative or absolute paths for directories and files is not supported. + + If used without [] the extracted environments are converted + to pdf image format and saved in "./images" directory using pdflatex + and preview package for process. + + [default] +-h, --help Display command line help and exit [off] +-v, --version Display current version ($nv) and exit [off] +-V, --verbose Verbose printing information [off] +-l, --log Write .log file with debug information [off] +-t, --tif Create .tif files using ghostscript [$gscmd] +-b, --bmp Create .bmp files using ghostscript [$gscmd] +-j, --jpg Create .jpg files using ghostscript [$gscmd] +-p, --png Create .png files using ghostscript [$gscmd] +-e, --eps Create .eps files using poppler-utils [pdftops] +-s, --svg Create .svg files using poppler-utils [pdftocairo] +-P, --ppm Create .ppm files using poppler-utils [pdftoppm] +-g, --gray Gray scale for images using ghostscript [off] +-f, --force Capture "\\psset" and "\\tikzset" to extract [off] +-n, --noprew Create images files without "preview" package [off] +-r , --runs= + Set the number of times the compiler will run + on the input file for environment extraction [1] +-d , --dpi= + Dots per inch resolution for images [150] +-m , --margins= + Set margins in bp for pdfcrop [0] +-o , --output= + Create output file [off] +--imgdir= Set name of directory to save images/files [images] +--prefix= Set prefix append to each generated files [fig] +--myverb= Add "\\macroname" to verbatim inline search [myverb] +--clean=doc|pst|tkz|all|off + Removes specific block text in output file [doc] +--zip Compress files generated in .zip [off] +--tar Compress files generated in .tar.gz [off] +--srcenv Create files with only code of environments [off] +--subenv Create standalone files for environments [off] +--shell Enable \\write18\{shell command\} [off] +--latex Using latex>dvips>ps2pdf for compiler input + and pdflatex for compiler output [off] +--dvips Using latex>dvips>ps2pdf for compiler input + and latex>dvips>ps2pdf for compiler output [off] +--dvilua Using dvilualatex>dvips>ps2pdf for compiler + input and lualatex for compiler output [off] +--dvipdf Using latex>dvipdfmx for compiler input and + latex>dvipdfmx for compiler output [off] +--xetex Using xelatex for compiler input and output [off] +--luatex Using lualatex for compiler input and output [off] +--arara Use arara for compiler input and output [off] +--latexmk Using latexmk for compiler output file [off] +--norun Run script, but no create images files [off] +--nopdf Don't create a ".pdf" image files [off] +--nocrop Don't run pdfcrop [off] +--extrenv= Add new environments to extract [empty] +--skipenv= Skip some default environments to extract [empty] +--verbenv= Add new verbatim environments [empty] +--writenv= Add new verbatim write environments [empty] +--deltenv= Delete environments in output file [empty] + +Example +\$ ltximg --latex -e -p --subenv --imgdir mypics -o test-out.ltx test-in.ltx + + Create a "./mypics" directory (if it doesn't exist) with all + extracted environments converted to ".pdf", ".eps", ".png" and + standalone files ".ltx", a file "test-in-fig-all.ltx" with all + extracted environments and the file "test-out.ltx" with all + environments converted to \\includegraphics using latex>dvips>ps2pdf + and preview package for and pdflatex for + . + +Documentation +For full documentation use: +\$ texdoc ltximg + +Issues and reports +Repository : https://github.com/pablgonz/ltximg +Bug tracker: https://github.com/pablgonz/ltximg/issues +Copyright(C) 2013-2021 by Pablo González, pablgonzyahoo.com +END_OF_USAGE +print $usage; +exit 0; +} + +### Getopt configuration +my $result=GetOptions ( +# image options + 'b|bmp' => \$opts_cmd{image}{bmp}, # gs + 't|tif' => \$opts_cmd{image}{tif}, # gs + 'j|jpg' => \$opts_cmd{image}{jpg}, # gs + 'p|png' => \$opts_cmd{image}{png}, # gs + 's|svg' => \$opts_cmd{image}{svg}, # pdftocairo + 'e|eps' => \$opts_cmd{image}{eps}, # pdftops + 'P|ppm' => \$opts_cmd{image}{ppm}, # pdftoppm +# compilers + 'arara' => \$opts_cmd{compiler}{arara}, # arara compiler + 'xetex' => \$opts_cmd{compiler}{xetex}, # xelatex compiler + 'latex' => \$opts_cmd{compiler}{latex}, # latex compiler + 'latexmk' => \$opts_cmd{compiler}{latexmk}, # latex compiler + 'dvips' => \$opts_cmd{compiler}{dvips}, # dvips compiler + 'dvipdf' => \$opts_cmd{compiler}{dvipdf}, # dvipdfmx compiler + 'dvilua' => \$opts_cmd{compiler}{dvilua}, # dvilualatex compiler + 'luatex' => \$opts_cmd{compiler}{luatex}, # lualatex compiler +# boolean + 'zip' => \$opts_cmd{boolean}{zip}, # zip images dir + 'tar' => \$opts_cmd{boolean}{tar}, # tar images dir + 'shell' => \$opts_cmd{boolean}{shell}, # set write18 for compiler + 'nopdf' => \$opts_cmd{boolean}{nopdf}, # no pdf image format + 'norun' => \$opts_cmd{boolean}{norun}, # no run compiler + 'nocrop' => \$opts_cmd{boolean}{nocrop}, # no run pdfcrop + 'subenv' => \$opts_cmd{boolean}{subenv}, # subfile environments (bolean) + 'srcenv' => \$opts_cmd{boolean}{srcenv}, # source files (bolean) + 'g|gray' => \$opts_cmd{boolean}{gray}, # gray (boolean) + 'f|force' => \$opts_cmd{boolean}{force}, # force (boolean) + 'n|noprew' => \$opts_cmd{boolean}{noprew}, # no preview (boolean) +# string + 'd|dpi=i' => \$opts_cmd{string}{dpi}, # positive integer < 2500 + 'r|runs=i' => \$opts_cmd{string}{runs}, # positive integer 1,2,3 + 'm|margins=i' => \$opts_cmd{string}{margins}, # integer + 'extrenv=s{1,9}' => \@extr_env_tmp, # extract environments + 'skipenv=s{1,9}' => \@skip_env_tmp, # skip environments + 'verbenv=s{1,9}' => \@verb_env_tmp, # verbatim environments + 'writenv=s{1,9}' => \@verw_env_tmp, # verbatim write environments + 'deltenv=s{1,9}' => \@delt_env_tmp, # delete environments + 'o|output=s{1}' => \$opts_cmd{string}{output}, # output file name (string) + 'imgdir=s{1}' => \$opts_cmd{string}{imgdir}, # images dir name + 'myverb=s{1}' => \$opts_cmd{string}{myverb}, # \myverb inline (string) + 'prefix=s{1}' => \$opts_cmd{string}{prefix}, # prefix + 'clean=s{1}' => \$opts_cmd{clean}, # clean output file +# internal + 'h|help' => \$opts_cmd{internal}{help}, # help + 'v|version' => \$opts_cmd{internal}{version}, # version + 'l|log' => \$log, # write log file + 'V|verbose' => \$verbose, # verbose mode + ) or do { $log = 0 ; die usage(0); }; + +### Open log file +if ($log) { + if (!defined $ARGV[0]) { errorUsage('Input filename missing'); } + my $tempname = $ARGV[0]; + $tempname =~ s/\.(tex|ltx)$//; + if ($LogFile eq "$tempname.log") { $LogFile = "$scriptname-log.log"; } + $LogWrite = FileHandle->new("> $LogFile"); +} + +### Init ltximg.log file +Log("The script $scriptname $nv was started in $workdir"); +Log("Creating the temporary directory $tempDir"); + +### Make ENV safer (perldoc perlsec) +delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; + +### The next code it's part of pdfcrop (adapted from TexLive 2014) +# Windows detection +my $Win = 0; +if ($^O =~ /mswin32/i) { $Win = 1; } + +my $archname = $Config{'archname'}; +$archname = 'unknown' unless defined $Config{'archname'}; + +# Get ghostscript command name +sub find_ghostscript { + if ($log) { + Log('General information about the Perl instalation and operating system'); + print {$LogWrite} "* Perl executable: $^X\n"; + if ($] < 5.006) { + print {$LogWrite} "* Perl version: $]\n"; + } + else { + printf {$LogWrite} "* Perl version: v%vd\n", $^V; + } + if (defined &ActivePerl::BUILD) { + printf {$LogWrite} "* Perl product: ActivePerl, build %s\n", ActivePerl::BUILD(); + } + printf {$LogWrite} "* Pointer size: $Config{'ptrsize'}\n"; + printf {$LogWrite} "* Pipe support: %s\n", + (defined $Config{'d_pipe'} ? 'yes' : 'no'); + printf {$LogWrite} "* Fork support: %s\n", + (defined $Config{'d_fork'} ? 'yes' : 'no'); + } + my $system = 'unix'; + $system = 'win' if $^O =~ /mswin32/i; + $system = 'msys' if $^O =~ /msys/i; + $system = 'cygwin' if $^O =~ /cygwin/i; + $system = 'miktex' if defined $ENV{'TEXSYSTEM'} and + $ENV{'TEXSYSTEM'} =~ /miktex/i; + if ($log) { + print {$LogWrite} "* OS name: $^O\n"; + print {$LogWrite} "* Arch name: $archname\n"; + if ($^O eq 'MSWin32') { + my $tmp = Win32::GetOSName(); + print {$LogWrite} "* System: $tmp\n"; + } + else { print {$LogWrite} "* System: $system\n"; } + } + Log('Trying to locate the executable for Ghostscript'); + my %candidates = ( + 'unix' => [qw|gs|], + 'win' => [qw|gswin32c|], + 'msys' => [qw|gswin64c gswin32c|], + 'cygwin' => [qw|gs|], + 'miktex' => [qw|mgs gswin32c|], + ); + if ($system eq 'win' or $system eq 'miktex') { + if ($archname =~ /mswin32-x64/i) { + my @a = (); + foreach my $name (@{$candidates{$system}}) { + push @a, 'gswin64c' if $name eq 'gswin32c'; + push @a, $name; + } + $candidates{$system} = \@a; + } + } + my %exe = ( + 'unix' => q{}, + 'win' => '.exe', + 'msys' => '.exe', + 'cygwin' => '.exe', + 'miktex' => '.exe', + ); + my $candidates_ref = $candidates{$system}; + my $exe = $Config{'_exe'}; + $exe = $exe{$system} unless defined $exe; + my @path = File::Spec->path(); + my $found = 0; + foreach my $candidate (@$candidates_ref) { + foreach my $dir (@path) { + my $file = File::Spec->catfile($dir, "$candidate$exe"); + if (-x $file) { + $gscmd = $candidate; + $found = 1; + if ($log) { print {$LogWrite} "* Found ($candidate): $file\n"; } + last; + } + if ($log) { print {$LogWrite} "* Not found ($candidate): $file\n"; } + } + last if $found; + } + if (not $found and $Win and $system ne 'msys') { + $found = SearchRegistry(); + } + if (not $found and $system eq 'msys') { + $found = Searchbyregquery(); + } + if ($found) { + if ($log) { print {$LogWrite} "* Autodetected ghostscript command: $gscmd\n"; } + } + else { + $gscmd = $$candidates_ref[0]; + if ($log) { print {$LogWrite} "* Default ghostscript command: $gscmd\n"; } + } +} + +sub SearchRegistry { + my $found = 0; + # The module Win32::TieRegistry not aviable in cygwin/msys + eval 'use Win32::TieRegistry qw|KEY_READ REG_SZ|'; + if ($@) { + if ($log) { + print {$LogWrite} "* Registry lookup for Ghostscript failed:\n"; + my $msg = $@; + $msg =~ s/\s+$//; + foreach (split /\r?\n/, $msg) { + print {$LogWrite} " $_\n"; + } + } + return $found; + } + my $open_params = {Access => KEY_READ(), Delimiter => q{/}}; + my $key_name_software = 'HKEY_LOCAL_MACHINE/SOFTWARE/'; + my $current_key = $key_name_software; + my $software = new Win32::TieRegistry $current_key, $open_params; + if (not $software) { + if ($log) { + print {$LogWrite} "* Cannot find or access registry key `$current_key'!\n"; + } + return $found; + } + if ($log) { print {$LogWrite} "* Search registry at `$current_key'.\n"; } + my %list; + foreach my $key_name_gs (grep /Ghostscript/i, $software->SubKeyNames()) { + $current_key = "$key_name_software$key_name_gs/"; + if ($log) { print {$LogWrite} "* Registry entry found: $current_key\n"; } + my $key_gs = $software->Open($key_name_gs, $open_params); + if (not $key_gs) { + if ($log) { print {$LogWrite} "* Cannot open registry key `$current_key'!\n"; } + next; + } + foreach my $key_name_version ($key_gs->SubKeyNames()) { + $current_key = "$key_name_software$key_name_gs/$key_name_version/"; + if ($log) { print {$LogWrite} "* Registry entry found: $current_key\n"; } + if (not $key_name_version =~ /^(\d+)\.(\d+)$/) { + if ($log) { print {$LogWrite} " The sub key is not a version number!\n"; } + next; + } + my $version_main = $1; + my $version_sub = $2; + $current_key = "$key_name_software$key_name_gs/$key_name_version/"; + my $key_version = $key_gs->Open($key_name_version, $open_params); + if (not $key_version) { + if ($log) { print {$LogWrite} "* Cannot open registry key `$current_key'!\n"; } + next; + } + $key_version->FixSzNulls(1); + my ($value, $type) = $key_version->GetValue('GS_DLL'); + if ($value and $type == REG_SZ()) { + if ($log) { print {$LogWrite} " GS_DLL = $value\n"; } + $value =~ s|([\\/])([^\\/]+\.dll)$|$1gswin32c.exe|i; + my $value64 = $value; + $value64 =~ s/gswin32c\.exe$/gswin64c.exe/; + if ($archname =~ /mswin32-x64/i and -f $value64) { + $value = $value64; + } + if (-f $value) { + if ($log) { print {$LogWrite} "EXE found: $value\n"; } + } + else { + if ($log) { print {$LogWrite} "EXE not found!\n"; } + next; + } + my $sortkey = sprintf '%02d.%03d %s', + $version_main, $version_sub, $key_name_gs; + $list{$sortkey} = $value; + } + else { + if ($log) { print {$LogWrite} "Missing key `GS_DLL' with type `REG_SZ'!\n"; } + } + } + } + foreach my $entry (reverse sort keys %list) { + $gscmd = $list{$entry}; + if ($log) { print {$LogWrite} "* Found (via registry): $gscmd\n"; } + $found = 1; + last; + } + return $found; +} # end GS search registry + +### This part is only necessary if you're using Git on windows and don't +### have gs configured in PATH. Git for windows don't have a Win32::TieRegistry +### module for perl (is not supported in the current versions of msys). +sub Searchbyregquery { + my $found = 0; + my $gs_regkey; + my $opt_reg = '//s //v'; + if ($log) { print {$LogWrite} "* Search Ghostscript in Windows registry under mingw/msys:\n";} + $gs_regkey = qx{reg query "HKLM\\Software\\GPL Ghostscript" $opt_reg GS_DLL}; + if ($? == 0) { + if ($log) { print {$LogWrite} "* Registry entry found for GS_DLL (64 bits version)\n";} + } + else { + $gs_regkey = qx{reg query "HKLM\\Software\\Wow6432Node\\GPL Ghostscript" $opt_reg GS_DLL}; + if ($? == 0) { + if ($log) { print {$LogWrite} "* Registry entry found for GS_DLL (32 bits version)\n";} + } + } + my ($gs_find) = $gs_regkey =~ m/(?:\s* GS_DLL \s* REG_SZ \s*) (.+?)(?:\.dll.+?\R)/s; + if ($gs_find) { + my ($gs_vol, $gs_path, $gs_ver) = $gs_find =~ m/ + (\w{1})(?:\:) # volumen + (.+?) # path to executable + (?:\\gsdll) # LIB + (\d{2}) # Version + /xs; + # Adjust + $gs_vol = lc($gs_vol); + $gs_path = '/'.$gs_vol.$gs_path; + $gs_path =~ s|\\|/|gmsxi; + # Add to PATH + if ($log) { print {$LogWrite} "* Add $gs_path to PATH for current session\n"; } + $PATH .= ":$gs_path"; + # Set executable + $gscmd = 'gswin'.$gs_ver.'c'; + if ($log) { print {$LogWrite} "* Found (via reg query): $gscmd\n"; } + $found = 1; + } + if ($@) { + if ($log) { + print {$LogWrite} "* Registry lookup for Ghostscript by reg query failed:\n"; + my $msg = $@; + $msg =~ s/\s+$//; + foreach (split /\r?\n/, $msg) { + print {$LogWrite} " $_\n"; + } + } + return $found; + } + return $found; +} + +### Call GS +find_ghostscript(); + +### Windows need suport space in path +if ($Win and $gscmd =~ /\s/) { $gscmd = "\"$gscmd\"";} + +### Help +if (defined $opts_cmd{internal}{help}) { + usage(1); + exit 0; +} + +### Version +if (defined $opts_cmd{internal}{version}) { + print $title; + exit 0; +} + +### Check from command line +@ARGV > 0 or errorUsage('Input filename missing'); +@ARGV < 2 or errorUsage('Unknown option or too many input files'); + +### Check extention +my @SuffixList = ('.tex', '.ltx'); +my ($name, $path, $ext) = fileparse($ARGV[0], @SuffixList); +if ($ext eq '.tex' or $ext eq '.ltx') { + $ext = $ext; +} +else { + errorUsage('Invalid or empty extention for input file'); +} + +### Read in memory, need [:crlf] for old windows files +Log("Read input file $name$ext in memory"); +open my $INPUTfile, '<:crlf', "$name$ext"; + my $ltxfile; + { + local $/; + $ltxfile = <$INPUTfile>; + } +close $INPUTfile; + +### Set tmp random number for and others +my $tmp = int(rand(10000)); + +### Identification message in terminal +print $title; + +### Remove white space and '=' in array captured from command line +s/^\s*(\=):?|\s*//mg foreach @extr_env_tmp; +s/^\s*(\=):?|\s*//mg foreach @skip_env_tmp; +s/^\s*(\=):?|\s*//mg foreach @verb_env_tmp; +s/^\s*(\=):?|\s*//mg foreach @verw_env_tmp; +s/^\s*(\=):?|\s*//mg foreach @delt_env_tmp; + +### Split comma separte list options from command line +@extr_env_tmp = split /,/,join q{},@extr_env_tmp; +@skip_env_tmp = split /,/,join q{},@skip_env_tmp; +@verb_env_tmp = split /,/,join q{},@verb_env_tmp; +@verw_env_tmp = split /,/,join q{},@verw_env_tmp; +@delt_env_tmp = split /,/,join q{},@delt_env_tmp; + +### Validate environments options from comand line +if (grep /(^\-|^\.).*?/, @extr_env_tmp) { + Log('Error!!: Invalid argument for --extrenv, some argument from list begin with -'); + errorUsage('Invalid argument for --extrenv option'); +} +if (grep /(^\-|^\.).*?/, @skip_env_tmp) { + Log('Error!!: Invalid argument for --skipenv, some argument from list begin with -'); + errorUsage('Invalid argument for --skipenv option'); +} +if (grep /(^\-|^\.).*?/, @verb_env_tmp) { + Log('Error!!: Invalid argument for --verbenv, some argument from list begin with -'); + errorUsage('Invalid argument for --verbenv option'); +} +if (grep /(^\-|^\.).*?/, @verw_env_tmp) { + Log('Error!!: Invalid argument for --writenv, some argument from list begin with -'); + errorUsage('Invalid argument for --writenv option'); +} +if (grep /(^\-|^\.).*?/, @delt_env_tmp) { + Log('Error!!: Invalid argument for --deltenv, some argument from list begin with -'); + errorUsage('Invalid argument for --deltenv option'); +} + +### Default environment to extract +my @extr_tmp = qw ( + preview postscript tikzpicture pgfpicture pspicture psgraph PSTexample + ); +push @extr_env_tmp, @extr_tmp; + +### Default verbatim environment +my @verb_tmp = qw ( + Example CenterExample SideBySideExample PCenterExample PSideBySideExample + verbatim Verbatim BVerbatim LVerbatim SaveVerbatim PSTcode + LTXexample tcblisting spverbatim minted listing lstlisting + alltt comment chklisting verbatimtab listingcont boxedverbatim + demo sourcecode xcomment pygmented pyglist program programl + programL programs programf programsc programt + ); +push @verb_env_tmp, @verb_tmp; + +### Default verbatim write environment +my @verbw_tmp = qw ( + scontents filecontents tcboutputlisting tcbexternal tcbwritetmp extcolorbox extikzpicture + VerbatimOut verbatimwrite filecontentsdef filecontentshere filecontentsdefmacro + filecontentsdefstarred filecontentsgdef filecontentsdefmacro filecontentsgdefmacro + ); +push @verw_env_tmp, @verbw_tmp; + +######################################################################## +# One problem that can arise is the filecontents environment, this can # +# contain a complete document and be anywhere, before dividing we will # +# make some replacements for this and comment lines # +######################################################################## + +### Create a Regex for verbatim write environment +@verw_env_tmp = uniq(@verw_env_tmp); +my $tmpverbw = join q{|}, map { quotemeta } sort { length $a <=> length $b } @verw_env_tmp; +$tmpverbw = qr/$tmpverbw/x; +my $tmp_verbw = qr { + ( + (?: + \\begin\{$tmpverbw\*?\} + (?: + (?>[^\\]+)| + \\ + (?!begin\{$tmpverbw\*?\}) + (?!end\{$tmpverbw\*?\})| + (?-1) + )* + \\end\{$tmpverbw\*?\} + ) + ) + }x; + +### A pre-regex for comment lines +my $tmpcomment = qr/^ \s* \%+ .+? $ /mx; + +### Hash for replace in verbatim's and comment lines +my %document = ( + '\begin{document}' => '\BEGIN{document}', + '\end{document}' => '\END{document}', + '\documentclass' => '\DOCUMENTCLASS', + '\pagestyle{' => '\PAGESTYLE{', + '\thispagestyle{' => '\THISPAGESTYLE{', + ); + +### Changes in for verbatim write and comment lines +while ($ltxfile =~ / $tmp_verbw | $tmpcomment /pgmx) { + my ($pos_inicial, $pos_final) = ($-[0], $+[0]); + my $encontrado = ${^MATCH}; + while (my($busco, $cambio) = each %document) { + $encontrado =~ s/\Q$busco\E/$cambio/g; + } + substr $ltxfile, $pos_inicial, $pos_final-$pos_inicial, $encontrado; + pos ($ltxfile) = $pos_inicial + length $encontrado; +} + +### Now, split input file in $atbegindoc and contain % ltximg : +my ($atbegindoc, $document) = $ltxfile =~ m/\A (\s* .*? \s*) (\\documentclass.*)\z/msx; + +### Capture options in preamble of +# % ltximg : extrenv : {extrenv1, extrenv2, ... , extrenvn} +# % ltximg : skipenv : {skipenv1, skipenv2, ... , skipenvn} +# % ltximg : verbenv : {verbwrt1, verbwrt2, ... , verbwrtn} +# % ltximg : writenv : {verbwrt1, verbwrt2, ... , verbwrtn} +# % ltximg : deltenv : {deltenv1, deltenv2, ... , deltenvn} +# % ltximg : options : {opt1=arg, opt2=arg, ... , booleans} + +my $readoptfile = qr/ + ^ %+ \s* ltximg (?&SEPARADOR) (?(?&CLAVE)) (?&SEPARADOR) \{ (?(?&ARGUMENTOS)) \} + (?(DEFINE) + (? \w+ ) + (? .+? ) + (? \s* : \s* ) + ) +/mx; + +### Search options in and store in %opts_file +my %opts_file; +while ($atbegindoc =~ /$readoptfile/g) { + my ($clave, $argumentos) = @+{qw(clave argumentos)}; + my @argumentos = split /\s*,\s*?/, $argumentos; + for (@argumentos) { s/^ \s* | \s* $//gx; } + if ($clave eq 'options') { + for my $argumento (@argumentos) { + if ($argumento =~ /(?\S+) \s* = \s* (?\S+)/x) { + $opts_file{$clave}{$+{'key'}} = $+{'valor'}; + } + else { + $opts_file{$clave}{$argumento} = 1; + } + } + } + else { + push @{ $opts_file{ $clave } }, @argumentos; + } +} + +### Process options from +if(%opts_file) { + Infocolor('Warning', "Found options for script in $name$ext"); + # Search and extract options from + Log("Searching options for script in $name$ext"); + if (exists $opts_file{extrenv}) { + Log("Found \% ltximg\: extrenv\: \{...\} in $name$ext"); + if (grep /(^\-|^\.).*?/, @{$opts_file{extrenv}}) { + Log('Error!!: Invalid argument for % ltximg: extrenv: {...}, some argument from list begin with -'); + errorUsage('Invalid argument in % ltximg: extrenv: {...}'); + } + Logarray(\@{$opts_file{extrenv}}); + push @extr_env_tmp, @{$opts_file{extrenv}}; + } + # Add skipenv options from + if (exists $opts_file{skipenv}) { + Log("Found \% ltximg\: skipenv\: \{...\} in $name$ext"); + if (grep /(^\-|^\.).*?/, @{$opts_file{skipenv}}) { + Log('Error!!: Invalid argument for % ltximg: skipenv: {...}, some argument from list begin with -'); + errorUsage('Invalid argument in % ltximg: skipenv: {...}'); + } + Logarray(\@{$opts_file{skipenv}}); + push @skip_env_tmp, @{$opts_file{skipenv}}; + } + # Add verbenv options from + if (exists $opts_file{verbenv}) { + Log("Found \% ltximg\: verbenv\: \{...} in $name$ext"); + if (grep /(^\-|^\.).*?/, @{$opts_file{verbenv}}) { + Log('Error!!: Invalid argument for % ltximg: verbenv: {...}, some argument from list begin with -'); + errorUsage('Invalid argument in % ltximg: verbenv: {...}'); + } + Logarray(\@{ $opts_file{verbenv}}); + push @verb_env_tmp, @{$opts_file{verbenv}}; + } + # Add writenv options from + if (exists $opts_file{writenv}) { + Log("Found \% ltximg\: writenv\: \{...\} in $name$ext"); + if (grep /(^\-|^\.).*?/, @{ $opts_file{writenv}}) { + Log('Error!!: Invalid argument for % ltximg: writenv: {...}, some argument from list begin with -'); + errorUsage('Invalid argument in % ltximg: writenv: {...}'); + } + Logarray(\@{ $opts_file{writenv}}); + push @verw_env_tmp, @{$opts_file{writenv}}; + } + # Add deltenv options from + if (exists $opts_file{deltenv}) { + Log("Found \% ltximg\: deltenv\: \{...\} in $name$ext"); + if (grep /(^\-|^\.).*?/, @{$opts_file{deltenv}}) { + Log('Error!!: Invalid argument for % ltximg: deltenv: {...}, some argument from list begin with -'); + errorUsage('Invalid argument in % ltximg: deltenv: {...}'); + } + Logarray(\@{ $opts_file{deltenv}}); + push @delt_env_tmp, @{$opts_file{deltenv}}; + } + # Add all other options from + if (exists $opts_file{options}) { + Log("Found \% ltximg\: options\: \{...\} in $name$ext"); + # Add compilers from + for my $opt (qw(arara xetex luatex latex dvips dvipdf dvilua latexmk)) { + if (exists $opts_file{options}{$opt}) { + Log("Found [$opt] compiler option in $name$ext"); + $opts_cmd{compiler}{$opt} = 1; + } + } + # Add image options + for my $opt (qw(eps ppm svg png jpg bmp tif)) { + if (exists $opts_file{options}{$opt}) { + Log("Found [$opt] image option in $name$ext"); + $opts_cmd{image}{$opt} = 1; + } + } + # Add boolean options + for my $opt (qw(shell nopdf norun nocrop srcenv subenv zip tar gray force noprew)) { + if (exists $opts_file{options}{$opt}) { + Log("Found [$opt] option in $name$ext"); + $opts_cmd{boolean}{$opt} = 1; + } + } + # Add string options + for my $opt (qw(dpi myverb margins prefix imgdir output runs)) { + if (exists $opts_file{options}{$opt}) { + Log("Found [$opt = $opts_file{options}{$opt}] in $name$ext"); + $opts_cmd{string}{$opt} = $opts_file{options}{$opt}; + } + } + # Add clean option + for my $opt (qw(doc off pst tkz all)) { + if ($opts_file{options}{clean} eq "$opt" ) { + Log("Found [clean = $opt] in $name$ext"); + $opts_cmd{clean} = $opt; + } + } + } +} + +### Validate --dpi +if( $opts_cmd{string}{dpi} <= 0 or $opts_cmd{string}{dpi} >= 2500) { + Log('Error!!: Invalid argument for --dpi, argument out of range'); + errorUsage('Invalid argument for --dpi option'); +} + +### Validate --runs +if( $opts_cmd{string}{runs} <= 0 or $opts_cmd{string}{runs} >= 3) { + Log('Error!!: Invalid argument for --runs, argument out of range'); + errorUsage('Invalid argument for --runs option'); +} + +### Check --arara and others compilers +if ($opts_cmd{compiler}{arara}) { + # Search others compilers options + for my $opt (qw(xetex luatex latex dvips dvipdf dvilua latexmk)) { + if (defined $opts_cmd{compiler}{$opt}) { + Log("Error!!: Options --arara and --$opt are mutually exclusive"); + errorUsage("Options --arara and --$opt are mutually exclusive"); + } + } +} + +### Check --srcenv and --subenv option +if ($opts_cmd{boolean}{srcenv} && $opts_cmd{boolean}{subenv}) { + Log('Error!!: Options --srcenv and --subenv are mutually exclusive'); + errorUsage('Options --srcenv and --subenv are mutually exclusive'); +} + +### If --srcenv or --subenv option are OK activate write +if ($opts_cmd{boolean}{srcenv}) { + $outsrc = 1; + $opts_cmd{boolean}{subenv} = undef; +} +if ($opts_cmd{boolean}{subenv}) { + $outsrc = 1; + $opts_cmd{boolean}{srcenv} = undef; +} + +### Add pdf image format if --nopdf +if (!$opts_cmd{boolean}{nopdf}) { + $opts_cmd{image}{pdf} = 1; +} + +### Store defined image formats in $format +my $format = join q{, },grep { defined $opts_cmd{image}{$_} } keys %{$opts_cmd{image}}; + +### Write defined image format in log file +if (!$opts_cmd{boolean}{norun}) { + Log("Defined image formats for creating: $format"); +} + +### Check --norun and no images type +if (!$opts_cmd{boolean}{norun} and $format eq q{}) { + Log('Error!!: Option --nopdf need --norun or an image option'); + errorUsage('Option --nopdf need --norun or an image option'); +} + +### Check --dvips and no eps image type +if ($opts_cmd{compiler}{dvips} and !$opts_cmd{image}{eps} and !$opts_cmd{boolean}{norun}) { + Log('Error!!: Option --dvips need --eps'); + errorUsage('Option --dvips need --eps'); +} + +### Validate myverb = macro option +if (defined $opts_cmd{string}{myverb}) { + if ($opts_cmd{string}{myverb} =~ /^(?:\\|\-).+?/) { + Log('Error!!: Invalid argument for --myverb option, argument begin with - or \ '); + errorUsage('Invalid argument for --myverb'); + } + else { Log("Set myverb = $opts_cmd{string}{myverb}"); } +} + +### Validate imgdir = string option +if (defined $opts_cmd{string}{imgdir}) { + if ($opts_cmd{string}{imgdir} =~ /^(?:\\|\-).+?/) { + Log('Error!!: Invalid argument for --imgdir option, argument begin with -, \ or /'); + errorUsage('Invalid argument for --imgdir'); + } + else { Log("Set imgdir = $opts_cmd{string}{imgdir}"); } +} + +### Validate clean +my %clean = map { $_ => 1 } @clean; +$clean{doc} = 1; # by default clean = doc + +### Pass $opts_cmd{clean} to $clean{$opt} +for my $opt (qw(doc off pst tkz all)) { + if ($opts_cmd{clean} eq "$opt") { + $clean{$opt} = 1; + push @currentopt, "--clean=$opt"; + } +} + +### Activate clean options for script +if ($clean{pst} or $clean{tkz}) { $clean{doc} = 1; } +if ($clean{all}) { @clean{qw(pst doc tkz)} = (1) x 3; } +if ($clean{off}) { undef %clean; } + +### Validating the name and save extension +my $outext; +if (defined $opts_cmd{string}{output}) { + Log('Validating name and extension for output file'); + # Capture and split + my ($outname, $outpath, $tmpext) = fileparse($opts_cmd{string}{output}, @SuffixList); + if ($outname =~ /(^\-|^\.).*?/) { + Log('The name of output file begin with dash -'); + errorUsage("$opts_cmd{string}{output} it is not a valid name for output file"); + } + if ($tmpext eq q{}) { # Check and set extension + Log("Set extension for output file to $ext"); + $outext = $ext; + } + else { + Log("Set extension for output file to $tmpext"); + $outext = $tmpext; + } + if ($outname eq $name) { # Check name + Log("The name of the output file must be different that $name"); + Infoline("Changing the output file name to $name-out"); + $opts_cmd{string}{output} = "$name-out"; + } + else { + Log("Set name of the output file to $outname"); + $opts_cmd{string}{output} = $outname; + } + # If output name are ok, then $outfile = 1 + $outfile = 1; +} + +### Storing the current options of script in array for ltximg.log file +my @allopt = qw (arara xetex luatex latex dvips dvipdf dvilua latexmk + shell nopdf norun nocrop srcenv subenv zip tar gray force + noprew eps ppm svg png jpg bmp tif dpi myverb margins + prefix imgdir output runs + ); + +for my $opt (@allopt) { + if (defined $opts_cmd{boolean}{$opt}) { + push @currentopt, "--$opt"; + } + if (defined $opts_cmd{compiler}{$opt}) { + push @currentopt, "--$opt"; + } + if (defined $opts_cmd{image}{$opt}) { + push @currentopt, "--$opt"; + } + if (defined $opts_cmd{string}{$opt}) { + push @currentopt, "--$opt=$opts_cmd{string}{$opt}" + } +} + +### Write all options in ltximg.log file +@currentopt = sort { length $a <=> length $b } @currentopt; +Log('The script will execute the following options:'); +Logarray(\@currentopt); + +### Rules to capture for regex +my $braces = qr/ (?:\{)(.+?)(?:\}) /msx; +my $braquet = qr/ (?:\[)(.+?)(?:\]) /msx; +my $no_corchete = qr/ (?:\[ .*? \])? /msx; + +### Array for capture new verbatim environments defined in input file +my @new_verb = qw ( + newtcblisting DeclareTCBListing ProvideTCBListing NewTCBListing + lstnewenvironment NewListingEnvironment NewProgram specialcomment + includecomment DefineVerbatimEnvironment newverbatim newtabverbatim + ); + +### Regex to capture names for new verbatim environments from input file +my $newverbenv = join q{|}, map { quotemeta} sort { length $a <=> length $b } @new_verb; +$newverbenv = qr/\b(?:$newverbenv) $no_corchete $braces/msx; + +### Array for capture new verbatim write environments defined in input file +my @new_verb_write = qw ( + renewtcbexternalizetcolorbox renewtcbexternalizeenvironment + newtcbexternalizeenvironment newtcbexternalizetcolorbox newenvsc + ); + +### Regex to capture names for new verbatim write environments from input file +my $newverbwrt = join q{|}, map { quotemeta} sort { length $a <=> length $b } @new_verb_write; +$newverbwrt = qr/\b(?:$newverbwrt) $no_corchete $braces/msx; + +### Regex to capture MINTED related environments +my $mintdenv = qr/\\ newminted $braces (?:\{.+?\}) /x; +my $mintcenv = qr/\\ newminted $braquet (?:\{.+?\}) /x; +my $mintdshrt = qr/\\ newmint $braces (?:\{.+?\}) /x; +my $mintcshrt = qr/\\ newmint $braquet (?:\{.+?\}) /x; +my $mintdline = qr/\\ newmintinline $braces (?:\{.+?\}) /x; +my $mintcline = qr/\\ newmintinline $braquet (?:\{.+?\}) /x; + +### Filter input file, now $ltxfile is pass to $filecheck +Log("Filter $name$ext \(remove % and comments\)"); +my @filecheck = $ltxfile; +s/%.*\n//mg foreach @filecheck; # del comments +s/^\s*|\s*//mg foreach @filecheck; # del white space +my $filecheck = join q{}, @filecheck; + +### Search verbatim and verbatim write environments +Log("Search verbatim and verbatim write environments in $name$ext"); + +### Search new verbatim write names in +my @newv_write = $filecheck =~ m/$newverbwrt/xg; +if (@newv_write) { + Log("Found new verbatim write environments in $name$ext"); + Logarray(\@newv_write); + push @verw_env_tmp, @newv_write; +} + +### Search new verbatim environments in (for) +my @verb_input = $filecheck =~ m/$newverbenv/xg; +if (@verb_input) { + Log("Found new verbatim environments in $name$ext"); + Logarray(\@verb_input); + push @verb_env_tmp, @verb_input; +} + +### Search \newminted{$mintdenv}{options} in , need add "code" (for) +my @mint_denv = $filecheck =~ m/$mintdenv/xg; +if (@mint_denv) { + Log("Found \\newminted\{envname\} in $name$ext"); + # Append "code" + $mintdenv = join "\n", map { qq/$_\Qcode\E/ } @mint_denv; + @mint_denv = split /\n/, $mintdenv; + Logarray(\@mint_denv); + push @verb_env_tmp, @mint_denv; +} + +### Search \newminted[$mintcenv]{lang} in (for) +my @mint_cenv = $filecheck =~ m/$mintcenv/xg; +if (@mint_cenv) { + Log("Found \\newminted\[envname\] in $name$ext"); + Logarray(\@mint_cenv); + push @verb_env_tmp, @mint_cenv; +} + +### Remove repetead again :) +@verb_env_tmp = uniq(@verb_env_tmp); + +### Capture verbatim inline macros in input file +Log("Search verbatim macros in $name$ext"); + +### Store all minted inline/short in @mintline +my @mintline; + +### Search \newmint{$mintdshrt}{options} in (while) +my @mint_dshrt = $filecheck =~ m/$mintdshrt/xg; +if (@mint_dshrt) { + Log("Found \\newmint\{macroname\} (short) in $name$ext"); + Logarray(\@mint_dshrt); + push @mintline, @mint_dshrt; +} + +### Search \newmint[$mintcshrt]{lang}{options} in (while) +my @mint_cshrt = $filecheck =~ m/$mintcshrt/xg; +if (@mint_cshrt) { + Log("Found \\newmint\[macroname\] (short) in $name$ext"); + Logarray(\@mint_cshrt); + push @mintline, @mint_cshrt; +} + +### Search \newmintinline{$mintdline}{options} in (while) +my @mint_dline = $filecheck =~ m/$mintdline/xg; +if (@mint_dline) { + Log("Found \\newmintinline\{macroname\} in $name$ext"); + # Append "inline" + $mintdline = join "\n", map { qq/$_\Qinline\E/ } @mint_dline; + @mint_dline = split /\n/, $mintdline; + Logarray(\@mint_dline); + push @mintline, @mint_dline; +} + +### Search \newmintinline[$mintcline]{lang}{options} in (while) +my @mint_cline = $filecheck =~ m/$mintcline/xg; +if (@mint_cline) { + Log("Found \\newmintinline\[macroname\] in $name$ext"); + Logarray(\@mint_cline); + push @mintline, @mint_cline; +} + +### Add standart mint, mintinline and lstinline +my @mint_tmp = qw(mint mintinline lstinline); + +### Join all inline verbatim macros captured +push @mintline, @mint_tmp; +@mintline = uniq(@mintline); + +### Create a regex using @mintline +my $mintline = join q{|}, map { quotemeta } sort { length $a <=> length $b } @mintline; +$mintline = qr/\b(?:$mintline)/x; + +### Reserved words in verbatim inline (while) +my %changes_in = ( + '%<*ltximg>' => '%<*LTXIMG>', + '%' => '%', + '%<*noltximg>' => '%<*NOLTXIMG>', + '%' => '%', + '%<*remove>' => '%<*REMOVE>', + '%' => '%', + '\psset' => '\PSSET', + '\tikzset' => '\TIKZSET', + '\pspicture' => '\TRICKS', + '\endpspicture' => '\ENDTRICKS', + '\pgfpicture' => '\PGFTRICKS', + '\endpgfpicture' => '\ENDPGFTRICKS', + '\tikzpicture' => '\TKZTRICKS', + '\endtikzpicture' => '\ENDTKZTRICKS', + '\psgraph' => '\PSGRAPHTRICKS', + '\endpsgraph' => '\ENDPSGRAPHTRICKS', + '\usepackage' => '\USEPACKAGE', + '{graphicx}' => '{GRAPHICX}', + '\graphicspath{' => '\GRAPHICSPATH{', + ); + +### Hash to replace \begin and \end in verbatim inline +my %init_end = ( + '\begin{' => '\BEGIN{', + '\end{' => '\END{', + ); + +### Join changes in new hash (while) for verbatim inline +my %cambios = (%changes_in,%init_end); + +### Variables and constantes +my $no_del = "\0"; +my $del = $no_del; + +### Rules +my $llaves = qr/\{ .+? \} /x; +my $no_llaves = qr/(?: $llaves )? /x; +my $corchetes = qr/\[ .+? \] /x; +my $delimitador = qr/\{ (?.+?) \} /x; +my $scontents = qr/Scontents [*]? $no_corchete /ix; +my $verb = qr/(?:((spv|(?:q|f)?v|V)erb|$opts_cmd{string}{myverb})[*]?) /ix; +my $lst = qr/(?:(lst|pyg)inline)(?!\*) $no_corchete /ix; +my $mint = qr/(?: $mintline |SaveVerb) (?!\*) $no_corchete $no_llaves $llaves /ix; +my $no_mint = qr/(?: $mintline) (?!\*) $no_corchete /ix; +my $marca = qr/\\ (?:$verb | $lst |$scontents | $mint |$no_mint) (?:\s*)? (\S) .+? \g{-1} /sx; +my $comentario = qr/^ \s* \%+ .+? $ /mx; +my $definedel = qr/\\ (?: DefineShortVerb | lstMakeShortInline| MakeSpecialShortVerb ) [*]? $no_corchete $delimitador /ix; +my $indefinedel = qr/\\ (?: (Undefine|Delete)ShortVerb | lstDeleteShortInline) $llaves /ix; + +Log('Making changes to inline/multiline verbatim before extraction'); + +### Changes in input file for verbatim inline/multiline +while ($document =~ + / $marca + | $comentario + | $definedel + | $indefinedel + | $del .+? $del + /pgmx) { + my ($pos_inicial, $pos_final) = ($-[0], $+[0]); + my $encontrado = ${^MATCH}; + if ($encontrado =~ /$definedel/) { + $del = $+{del}; + $del = "\Q$+{del}" if substr($del,0,1) ne '\\'; + } + elsif ($encontrado =~ /$indefinedel/) { + $del = $no_del; + } + else { + while (my($busco, $cambio) = each %cambios) { + $encontrado =~ s/\Q$busco\E/$cambio/g; + } + substr $document, $pos_inicial, $pos_final-$pos_inicial, $encontrado; + pos ($document) = $pos_inicial + length $encontrado; + } +} + +### Change "escaped braces" to (this label is not the one in the document) +$document =~ s/\\[{]//g; +$document =~ s/\\[}]//g; + +### Regex for verbatim inline/multiline with braces {...} +my $nestedbr = qr / ( [{] (?: [^{}]++ | (?-1) )*+ [}] ) /x; +my $fvextra = qr /\\ (?: (Save|Esc)Verb [*]?) $no_corchete /x; +my $mintedbr = qr /\\ (?:$mintline|pygment) (?!\*) $no_corchete $no_llaves /x; +my $tcbxverb = qr /\\ (?: tcboxverb [*]?| Scontents [*]? |$opts_cmd{string}{myverb} [*]?|lstinline) $no_corchete /x; +my $verb_brace = qr / (?:$tcbxverb|$mintedbr|$fvextra) (?:\s*)? $nestedbr /x; + +### Change \verb*{code} for verbatim inline/multiline +while ($document =~ /$verb_brace/pgmx) { + my ($pos_inicial, $pos_final) = ($-[0], $+[0]); + my $encontrado = ${^MATCH}; + while (my($busco, $cambio) = each %cambios) { + $encontrado =~ s/\Q$busco\E/$cambio/g; + } + substr $document, $pos_inicial, $pos_final-$pos_inicial, $encontrado; + pos ($document) = $pos_inicial + length $encontrado; +} + +### We recovered the escaped braces +$document =~ s//\\{/g; +$document =~ s//\\}/g; + +### Reverse changes for extract and output file +my %changes_out = ( + '\PSSET' => '\psset', + '\TIKZSET' => '\tikzset', + '\TRICKS' => '\pspicture', + '\ENDTRICKS' => '\endpspicture', + '\PGFTRICKS' => '\pgfpicture', + '\ENDPGFTRICKS' => '\endpgfpicture', + '\TKZTRICKS' => '\tikzpicture', + '\ENDTKZTRICKS' => '\endtikzpicture', + '\PSGRAPHTRICKS' => '\psgraph', + '\ENDPSGRAPHTRICKS' => '\endpsgraph', + '\USEPACKAGE' => '\usepackage', + '{GRAPHICX}' => '{graphicx}', + '\GRAPHICSPATH{' => '\graphicspath{', + '\BEGIN{' => '\begin{', + '\END{' => '\end{', + '\DOCUMENTCLASS' => '\documentclass', + '\PAGESTYLE{' => '\pagestyle{', + '\THISPAGESTYLE{' => '\thispagestyle{', + ); + +### Reverse tags, need back in all file to extract +my %reverse_tag = ( + '%<*LTXIMG>' => '%<*ltximg>', + '%' => '%', + '%<*NOLTXIMG>' => '%<*noltximg>', + '%' => '%', + '%<*REMOVE>' => '%<*remove>', + '%' => '%', + ); + +### First we do some security checks to ensure that they are verbatim and +### verbatim write environments are unique and disjointed +@verb_env_tmp = array_minus(@verb_env_tmp, @verw_env_tmp); #disjointed +my @verbatim = uniq(@verb_env_tmp); +my %verbatim = crearhash(@verbatim); + +Log('The environments that are considered verbatim:'); +Logarray(\@verbatim); + +### Create a Regex for verbatim standart environment +my $verbatim = join q{|}, map { quotemeta } sort { length $a <=> length $b } @verbatim; +$verbatim = qr/$verbatim/x; +my $verb_std = qr { + ( + (?: + \\begin\{$verbatim\*?\} + (?: + (?>[^\\]+)| + \\ + (?!begin\{$verbatim\*?\}) + (?!end\{$verbatim\*?\})| + (?-1) + )* + \\end\{$verbatim\*?\} + ) + ) + }x; + +### Verbatim write +@verw_env_tmp = array_minus(@verw_env_tmp, @verb_env_tmp); #disjointed +my @verbatim_w = uniq(@verw_env_tmp); +my %verbatim_w = crearhash(@verbatim_w); + +Log('The environments that are considered verbatim write:'); +Logarray(\@verbatim_w); + +### Create a Regex for verbatim write environment +my $verbatim_w = join q{|}, map { quotemeta } sort { length $a <=> length $b } @verbatim_w; +$verbatim_w = qr/$verbatim_w/x; +my $verb_wrt = qr { + ( + (?: + \\begin\{$verbatim_w\*?\} + (?: + (?>[^\\]+)| + \\ + (?!begin\{$verbatim_w\*?\}) + (?!end\{$verbatim_w\*?\})| + (?-1) + )* + \\end\{$verbatim_w\*?\} + ) + ) + }x; + +### Check skip environments +my @skipped; +if (@skip_env_tmp) { + my %envcheck = map { $_ => 1 } @skip_env_tmp; + if (exists $envcheck{PSTexample}) { + Log('The [PSTexample] environment is not allowed for skipping'); + @skip_env_tmp = grep !/PSTexample/, @skip_env_tmp; + } + if (exists $envcheck{preview}) { + Log('The [preview] environment is not allowed for skipping'); + @skip_env_tmp = grep !/preview/, @skip_env_tmp; + } + # Valid environments for skip + for my $skip (qw(pspicture tikzpicture pgfpicture psgraph postscript)) { + if (exists $envcheck{$skip}) { + push @skipped,$skip; + } + } +} + +### List of environments to be skiped from extraction +@skipped = uniq(@skip_env_tmp); +Log('The environments that will be skiped for extraction:'); +Logarray(\@skipped); + +### Create a Regex for skip environment +my $skipenv = join q{|}, map { quotemeta } sort { length $a <=> length $b } @skipped; +$skipenv = qr/$skipenv/x; +my $skip_env = qr { + ( + (?: + \\begin\{$skipenv\*?\} + (?: + (?>[^\\]+)| + \\ + (?!begin\{$skipenv\*?\}) + (?!end\{$skipenv\*?\})| + (?-1) + )* + \\end\{$skipenv\*?\} + ) + ) + }x; + +### Check reserved environments +my %envcheck = map { $_ => 1 } @extr_env_tmp; + +if (exists $envcheck{document}) { + Log('The [document] environment is allowed for extraction'); + @extr_env_tmp = grep !/document/, @extr_env_tmp; +} +if (exists $envcheck{nopreview}) { + Log('The [nopreview] environment is allowed for extraction'); + @extr_env_tmp = grep !/nopreview/, @extr_env_tmp; +} + +### An array with all environments to extract, including nopreview +my @extract_env = qw(nopreview); +push @extract_env,@extr_env_tmp; + +### Some oprations for skip environments +@extract_env = array_minus(@extract_env, @skip_env_tmp); +@extract_env = uniq(@extract_env); + +### Hash for regex +my %extract_env = crearhash(@extract_env); + +Log('The environments that will be searched for extraction:'); +my @real_extract_env = grep !/nopreview/, @extract_env; +Logarray(\@real_extract_env); + +### Create a regex to extract environments +my $environ = join q{|}, map { quotemeta } sort { length $a <=> length $b } @extract_env; +$environ = qr/$environ/x; +my $extr_tmp = qr { + ( + (?: + \\begin\{$environ\*?\} + (?: + (?>[^\\]+)| + \\ + (?!begin\{$environ\*?\}) + (?!end\{$environ\*?\})| + (?-1) + )* + \\end\{$environ\*?\} + ) + ) + }x; + +### Check delete environments +if (@delt_env_tmp) { + my %envcheck = map { $_ => 1 } @delt_env_tmp; + if (exists $envcheck{document}) { + Log('The [document] environment is not allowed for delete'); + @delt_env_tmp = grep !/document/, @delt_env_tmp; + } +} + +### An array of environments to be removed in +my @delete_env = uniq(@delt_env_tmp); +my %delete_env = crearhash(@delete_env); + +Log('The environments that will be removed in output file:'); +Logarray(\@delete_env); + +### Create a Regex for delete environment in +my $delenv = join q{|}, map { quotemeta } sort { length $a <=> length $b } @delete_env; +$delenv = qr/$delenv/x; +my $delt_env = qr { + ( + (?: + \\begin\{$delenv\*?\} + (?: + (?>[^\\]+)| + \\ + (?!begin\{$delenv\*?\}) + (?!end\{$delenv\*?\})| + (?-1) + )* + \\end\{$delenv\*?\} + ) + ) + }x; + +######################################################################## +# In this first part the script only detects verbatim environments and # +# verbatim write don't distinguish between which ones are extracted, # +# that's done in a second pass. # +######################################################################## + +Log('Making changes to verbatim and verbatim write environments before extraction'); + +### First, revert %<*TAGS> to %<*tags> in all document +my $ltxtags = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %reverse_tag; +$document =~ s/^($ltxtags)/$reverse_tag{$1}/gmsx; + +### Create an array with the temporary extraction list, no verbatim environments +my @extract_tmp = array_minus(@extract_env, @verb_env_tmp); +@extract_tmp = array_minus(@extract_tmp, @verw_env_tmp); +@extract_tmp = uniq(@extract_tmp); +my %extract_tmp = crearhash(@extract_tmp); + +### Hash and Regex for changes, this "regex" is re-used in ALL script +my %replace = (%verbatim, %extract_tmp, %changes_in, %document); # revert tags again :) +my $find = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %replace; + +### We go line by line and make the changes in verbatim's envoronments (/p for ${^MATCH}) +while ($document =~ /$verb_wrt | $verb_std /pgmx) { + my ($pos_inicial, $pos_final) = ($-[0], $+[0]); + my $encontrado = ${^MATCH}; + if ($encontrado =~ /$verb_wrt/) { + $encontrado =~ s/($find)/$replace{$1}/g; + substr $document, $pos_inicial, $pos_final-$pos_inicial, $encontrado; + pos ($document) = $pos_inicial + length $encontrado; + } + if ($encontrado =~ /$verb_std/) { + %replace = (%verbatim_w, %extract_tmp, %changes_in, %document); + $find = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %replace; + $encontrado =~ s/($find)/$replace{$1}/g; + substr $document, $pos_inicial, $pos_final-$pos_inicial, $encontrado; + pos ($document) = $pos_inicial + length $encontrado; + } +} + +### Now split document +my ($preamble,$bodydoc,$enddoc) = $document =~ m/\A (.+?) (\\begin\{document\} .+?)(\\end\{document\}.*)\z/msx; + +### Internal for mark verbatim and verbatim write environments +my $dtxverb = "verbatim$tmp"; + +### Match , if they're matched, we turn them :) +my @tag_extract = $bodydoc =~ m/(?:^\%<\*ltximg>.+?\%<\/ltximg>)/gmsx; +my @tag_noextract = $bodydoc =~ m/(?:^\%<\*noltximg>.+?\%<\/noltximg>)/gmsx; + +if (@tag_extract) { + Log('Pass extract tags %<*ltximg> ... % to \begin{preview} ... \end{preview}'); + $bodydoc =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + ^\%<\*$extrtag>(.+?)\%<\/$extrtag>/\\begin\{preview\}$1\\end\{preview\}/gmsx; +} +if (@tag_noextract) { + Log('Pass no extract tags %<*noltximg> ... % to \begin{nopreview} ... \end{nopreview}'); + $bodydoc =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + ^\%<\*$skiptag>(.+?)\%<\/$skiptag>/\\begin\{nopreview\}$1\\end\{nopreview\}/gmsx; +} + +######################################################################## +# We now make the real changes for environment extraction. Since we # +# don't know what kind of environments are passed, need to redefine # +# all regex to make the changes. # +######################################################################## + +my @new_verb_tmp = array_minus(@verbatim, @extract_env); +$verbatim = join q{|}, map { quotemeta } sort { length $a <=> length $b } @new_verb_tmp; +$verbatim = qr/$verbatim/x; +$verb_std = qr { + ( + (?: + \\begin\{$verbatim\*?\} + (?: + (?>[^\\]+)| + \\ + (?!begin\{$verbatim\*?\}) + (?!end\{$verbatim\*?\})| + (?-1) + )* + \\end\{$verbatim\*?\} + ) + ) + }x; + +my @new_verbw_tmp = array_minus(@verbatim_w, @extract_env); +$verbatim_w = join q{|}, map { quotemeta } sort { length $a <=> length $b } @new_verbw_tmp; +$verbatim_w = qr/$verbatim_w/x; +$verb_wrt = qr { + ( + (?: + \\begin\{$verbatim_w\*?\} + (?: + (?>[^\\]+)| + \\ + (?!begin\{$verbatim_w\*?\}) + (?!end\{$verbatim_w\*?\})| + (?-1) + )* + \\end\{$verbatim_w\*?\} + ) + ) + }x; + +### Regex using hash +%replace = (%extract_env); +$find = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %replace; + +### We go line by line and make the changes (/p for ${^MATCH}) +while ($bodydoc =~ /$verb_wrt | $verb_std /pgmx) { + my ($pos_inicial, $pos_final) = ($-[0], $+[0]); + my $encontrado = ${^MATCH}; + $encontrado =~ s/($find)/$replace{$1}/g; + substr $bodydoc, $pos_inicial, $pos_final-$pos_inicial, $encontrado; + pos ($bodydoc) = $pos_inicial + length $encontrado; +} + +### Now put a internal dtxmark in no extraction/replace environments +Log("Pass verbatim write environments to %<*$dtxverb> ... %"); +$bodydoc =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + ($verb_wrt)/\%<\*$dtxverb>$1\%<\/$dtxverb>/gmsx; +$preamble =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + ($verb_wrt)/\%<\*$dtxverb>$1\%<\/$dtxverb>/gmsx; +$atbegindoc =~ s/($verb_wrt)/\%<\*$dtxverb>$1\%<\/$dtxverb>/gmsx; + +Log("Pass verbatim environments to %<*$dtxverb> ... %"); +$bodydoc =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + ($verb_std)/\%<\*$dtxverb>$1\%<\/$dtxverb>/gmsx; +$preamble =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + ($verb_std)/\%<\*$dtxverb>$1\%<\/$dtxverb>/gmsx; +$atbegindoc =~ s/($verb_std)/\%<\*$dtxverb>$1\%<\/$dtxverb>/gmsx; + +### Check plain TeX syntax +my %plainsyntax = map { $_ => 1 } @extract_env; # anon hash + +if (exists $plainsyntax{pspicture}) { + Log('Convert plain \pspicture to LaTeX syntax [skip in PSTexample]'); + $bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + \\begin\{PSTexample\}.+?\\end\{PSTexample\}(*SKIP)(*F)| + \\pspicture(\*)?(.+?)\\endpspicture/\\begin\{pspicture$1\}$2\\end\{pspicture$1\}/gmsx; +} + +if (exists $plainsyntax{psgraph}) { + Log('Convert plain \psgraph to LaTeX syntax [skip in PSTexample]'); + $bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + \\begin\{PSTexample\}.+?\\end\{PSTexample\}(*SKIP)(*F)| + \\psgraph(\*)?(.+?)\\endpsgraph/\\begin\{psgraph$1\}$2\\end\{psgraph$1\}/gmsx; +} + +if (exists $plainsyntax{tikzpicture}) { + Log('Convert plain \tikzpicture to LaTeX syntax'); + $bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + \\tikzpicture(.+?)\\endtikzpicture/\\begin{tikzpicture}$1\\end{tikzpicture}/gmsx; +} + +if (exists $plainsyntax{pgfpicture}) { + Log('Convert plain \pgfpicture to LaTeX syntax'); + $bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + \\pgfpicture(.+?)\\endpgfpicture/\\begin{pgfpicture}$1\\end{pgfpicture}/gmsx; +} + +### Force mode for pstricks/psgraph/tikzpiture +if ($opts_cmd{boolean}{force}) { + if (exists $plainsyntax{pspicture} or exists $plainsyntax{psgraph}) { + Log('Try to capture \psset{...} for pstricks environments [force mode]'); + $bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + \\begin\{PSTexample\}.+?\\end\{PSTexample\}(*SKIP)(*F)| + \\begin\{postscript\}.+?\\end\{postscript\}(*SKIP)(*F)| + (? + (?:\\psset\{(?:\{.*?\}|[^\{])*\}.+?)? # if exist ...save + \\begin\{(? pspicture\*?| psgraph)\} .+? \\end\{\k\} + ) + /\\begin\{preview\}$+{code}\\end\{preview\}/gmsx; + } + if (exists $plainsyntax{tikzpicture}) { + Log('Try to capture \tikzset{...} for tikzpicture environments [force mode]'); + $bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + \\begin\{postscript\}.+?\\end\{postscript\}(*SKIP)(*F)| + (? + (?:\\tikzset\{(?:\{.*?\}|[^\{])*\}.+?)? # if exist ...save + \\begin\{(? tikzpicture)\} .+? \\end\{\k\} + ) + /\\begin\{preview\}$+{code}\\end\{preview\}/gmsx; + } +} + +Log('Pass skip environments to \begin{nopreview} ... \end{nopreview}'); +$bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + \\begin\{PSTexample\}.+?\\end\{PSTexample\}(*SKIP)(*F)| + ($skip_env)/\\begin\{nopreview\}$1\\end\{nopreview\}/gmsx; + +### Pass all captured environments in body \begin{preview} ... \end{preview} +Log('Pass all captured environments to \begin{preview} ... \end{preview}'); +$bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + ($extr_tmp)/\\begin\{preview\}$1\\end\{preview\}/gmsx; + +######################################################################## +# All environments are now classified: # +# Extraction -> \begin{preview} ... \end{preview} # +# No Extraction -> \begin{nopreview} ... \end{nopreview} # +# Verbatim's -> %<\*$dtxverb> ... <\/$dtxverb> # +######################################################################## + +### The %<*remove> ... % tags need a special treatment :) +$bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + ^(\%<(?:\*|\/))(remove)(\>)/$1$2$tmp$3/gmsx; +$preamble =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + ^(\%<(?:\*|\/))(remove)(\>)/$1$2$tmp$3/gmsx; +$atbegindoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| + ^(\%<(?:\*|\/))(remove)(\>)/$1$2$tmp$3/gmsx; + +### Pass \begin{preview} ... \end{preview} to \START{preview} ... \STOP{preview} +### Pass \begin{nopreview} ... \end{nopreview} to \START{nopreview} ... \STOP{nopreview} +$bodydoc =~ s/\\begin\{((no)?preview)\}/\\START\{$1\}/gmsx; +$bodydoc =~ s/\\end\{((no)?preview)\}/\\STOP\{$1\}/gmsx; + +### We restore the changes of all environments in body +my @lineas = split /\n/, $bodydoc; +my $NEWDEL; +for (@lineas) { + %replace = (%changes_out); + $find = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %replace; + if (/\\START\{((no)?preview)(?{ $NEWDEL = "\Q$^N" })\}/ .. /\\STOP\{$NEWDEL\}/) { + s/($find)/$replace{$1}/msgx; + } + if (/\%<\*($dtxverb)(?{ $NEWDEL = "\Q$^N" })>/ .. /\%<\/$NEWDEL>/) { + s/($find)/$replace{$1}/msgx; + } +} +$bodydoc = join "\n", @lineas; + +### We restore the changes of all environments in preamble +while ($preamble =~ /\%<\*$dtxverb>(.+?)\%<\/$dtxverb>/pgmsx) { + %cambios = (%changes_out); + my ($pos_inicial, $pos_final) = ($-[0], $+[0]); + my $encontrado = ${^MATCH}; + while (my($busco, $cambio) = each %cambios) { + $encontrado =~ s/\Q$busco\E/$cambio/msxg; + } + substr $preamble, $pos_inicial, $pos_final-$pos_inicial, $encontrado; + pos ($preamble) = $pos_inicial + length $encontrado; +} + +### Set wrapped environments for extraction +my $wrapping = "$scriptname$tmp"; +Log("Set up the environment [$wrapping] to encapsulate the extraction"); + +### Set vars for match/regex +my $BP = "\\\\begin\{$wrapping\}"; +my $EP = "\\\\end\{$wrapping\}"; +my $BE = '\\\\begin\{PSTexample\}'; +my $EE = '\\\\end\{PSTexample\}'; + +### Wrap environments for extraction +Log("Pass all captured environments to \\begin{$wrapping} ... \\end{$wrapping}"); +$bodydoc =~ s/\\START\{preview\} + (?.+? ) + \\STOP\{preview\} + /\\begin\{$wrapping\}$+{code}\\end\{$wrapping\}/gmsx; + +$bodydoc =~ s/\\START\{nopreview\} + (?.+? ) + \\STOP\{nopreview\} + /\\begin\{nopreview\}\%$tmp$+{code}\\end\{nopreview\}\%$tmp/gmsx; + +### We put back ltximg tags :) +$bodydoc =~ s/($ltxtags)/$reverse_tag{$1}/gmsx; +$preamble =~ s/($ltxtags)/$reverse_tag{$1}/gmsx; + +### First search PSTexample environments for extract +my @exa_extract = $bodydoc =~ m/(?:\\begin\{$wrapping\})($BE.+?$EE)(?:\\end\{$wrapping\})/gmsx; +my $exaNo = scalar @exa_extract; + +### Set vars for log and print in terminal +my $envEXA = $exaNo > 1 ? 'PSTexample environments' : 'PSTexample environment'; +my $fileEXA = $exaNo > 1 ? 'files' : 'file'; + +### Check if PSTexample environment found +if ($exaNo!=0) { + $PSTexa = 1; + Log("Found $exaNo $envEXA in $name$ext"); + my $figNo = 1; + for my $item (@exa_extract) { + Logline("%##### PSTexample environment captured number $figNo ######%"); + Logline($item); + $figNo++; + } + # Add [graphic={[...]...}] to \begin{PSTexample}[...] + Log('Append [graphic={[...]...}] to \begin{PSTexample}[...]'); + $figNo = 1; + while ($bodydoc =~ /\\begin\{$wrapping\}(\s*)?\\begin\{PSTexample\}(\[.+?\])?/gsm) { + my $swpl_grap = "graphic=\{\[scale=1\]$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-exa"; + my $corchetes = $1; + my ($pos_inicial, $pos_final) = ($-[1], $+[1]); + if (not $corchetes) { $pos_inicial = $pos_final = $+[0]; } + if (not $corchetes or $corchetes =~ /\[\s*\]/) { + $corchetes = "[$swpl_grap-$figNo}]"; + } + else { $corchetes =~ s/\]/,$swpl_grap-$figNo}]/; } + substr($bodydoc, $pos_inicial, $pos_final - $pos_inicial) = $corchetes; + pos($bodydoc) = $pos_inicial + length $corchetes; + } + continue { $figNo++; } + Log('Pass PSTexample environments to \begin{nopreview} ... \end{nopreview}'); + $bodydoc =~ s/\\begin\{$wrapping\} + (?\\begin\{PSTexample\} .+? \\end\{PSTexample\}) + \\end\{$wrapping\} + /\\begin\{nopreview\}\%$tmp$+{code}\\end\{nopreview\}\%$tmp/gmsx; +} + +### Second search standart environments for extract +my @env_extract = $bodydoc =~ m/(?<=$BP)(.+?)(?=$EP)/gms; +my $envNo = scalar @env_extract; + +### Set vars for log and print in terminal +my $envSTD = $envNo > 1 ? 'standard environments' : 'standard environment'; +my $fileSTD = $envNo > 1 ? 'files' : 'file'; + +### If any standard environments found +if ($envNo!=0) { + $STDenv = 1; + Log("Found $envNo $envSTD in $name$ext"); + my $figNo = 1; + for my $item (@env_extract) { + Logline("%##### Standard environment captured number $figNo ######%"); + Logline($item); + $figNo++; + } +} + +### Run script process only if any enviroment found in +if ($envNo == 0 and $exaNo == 0) { + errorUsage("$scriptname can not find any environment to extract in $name$ext"); +} + +### Set directory to save generated files, need full path for goog log :) +my $imgdirpath = File::Spec->rel2abs($opts_cmd{string}{imgdir}); + +if (-e $opts_cmd{string}{imgdir}) { + Infoline("The generated files will be saved in $imgdirpath"); +} +else { + Infoline("Creating the directory $imgdirpath to save the generated files"); + Infocolor('Running', "mkdir $imgdirpath"); + Logline("[perl] mkdir($opts_cmd{string}{imgdir},0744)"); + mkdir $opts_cmd{string}{imgdir},0744 or errorUsage("Can't create the directory $opts_cmd{string}{imgdir}"); +} + +### Set compiler +my $compiler = $opts_cmd{compiler}{xetex} ? 'xelatex' + : $opts_cmd{compiler}{luatex} ? 'lualatex' + : $opts_cmd{compiler}{latex} ? 'latex' + : $opts_cmd{compiler}{dvips} ? 'latex' + : $opts_cmd{compiler}{dvilua} ? 'dvilualatex' + : $opts_cmd{compiler}{dvipdf} ? 'latex' + : $opts_cmd{compiler}{arara} ? 'arara' + : 'pdflatex' + ; + +if (!$opts_cmd{boolean}{norun}) { + if ($compiler eq 'arara') { + Log("The file will be processed using $compiler, no ducks will be harmed in this process"); + } + else { Log("The file will be processed using $compiler"); } +} + +### Set option for pdfcrop (last version of pdfcrop https://github.com/ho-tex/pdfcrop) +my $opt_crop = $opts_cmd{compiler}{xetex} ? "--xetex --margins $opts_cmd{string}{margin}" + : $opts_cmd{compiler}{luatex} ? "--luatex --margins $opts_cmd{string}{margin}" + : $opts_cmd{compiler}{latex} ? "--margins $opts_cmd{string}{margin}" + : "--pdftex --margins $opts_cmd{string}{margin}" + ; + +### Set options for preview packpage +my $opt_prew = $opts_cmd{compiler}{xetex} ? 'xetex,' + : $opts_cmd{compiler}{latex} ? q{} + : $opts_cmd{compiler}{dvipdf} ? q{} + : $opts_cmd{compiler}{dvips} ? q{} + : $opts_cmd{compiler}{dvilua} ? q{} + : 'pdftex,' + ; + +######################################################################## +# One problem with using arara is that we don't know what the file is # +# really compiled with, this affects [preview] and [pdfcrop]. # +######################################################################## + +### Try to capture arara:compiler in preamble of +my @arara_engines = qw (latex pdflatex lualatex xelatex luahbtex); +my $arara_engines = join q{|}, map { quotemeta} sort { length $a <=> length $b } @arara_engines; +$arara_engines = qr/\b(?:$arara_engines)/x; +my $arara_rule = qr /^(?:\%\s{1}arara[:]\s{1}) ($arara_engines) /msx; + +### Set options for [compiler], [preview] and [pdfcrop] +if ($compiler eq 'arara') { + Log('Trying to detect some suported [engine] in the rules of arara'); + my @engine = $atbegindoc =~ m/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)|$arara_rule/msx; + my %engine = map { $_ => 1 } @engine; # anon hash + if (exists $engine{latex}) { + Log('The [latex] engine was found in arara rule'); + # Set options for [preview] and [pdfcrop] + $opt_crop = "--margins $opts_cmd{string}{margin}"; + $opt_prew = q{}; + } + elsif (exists $engine{lualatex} or exists $engine{luahbtex}) { + Log('The [lualatex] engine was found in arara rule'); + # Set options for [preview] and [pdfcrop] + $opt_crop = "--luatex --margins $opts_cmd{string}{margin}"; + $opt_prew = 'pdftex,'; + } + elsif (exists $engine{xelatex}) { + Log('The [xelatex] engine was found in arara rule'); + # Set options for [preview] and [pdfcrop] + $opt_crop = "--xetex --margins $opts_cmd{string}{margin}"; + $opt_prew = 'xetex,'; + } + elsif (exists($engine{pdflatex})) { + Log('The [pdflatex] engine was found in arara rule'); + # Set options for [preview] and [pdfcrop] + $opt_crop = "--pdftex --margins $opts_cmd{string}{margin}"; + $opt_prew = 'pdftex,'; + } + else { + Log('No supported [engine] could be detected, default values will be used'); + # Set options for [preview] and [pdfcrop] + $opt_crop = "--pdftex --margins $opts_cmd{string}{margin}"; + $opt_prew = 'pdftex,'; + } +} + +### Message in command line for compiler +my $msg_compiler = $opts_cmd{compiler}{xetex} ? 'xelatex' + : $opts_cmd{compiler}{luatex} ? 'lualatex' + : $opts_cmd{compiler}{latex} ? 'latex>dvips>ps2pdf' + : $opts_cmd{compiler}{dvips} ? 'latex>dvips>ps2pdf' + : $opts_cmd{compiler}{dvilua} ? 'dvilualatex>dvips>ps2pdf' + : $opts_cmd{compiler}{dvipdf} ? 'latex>dvipdfmx' + : $opts_cmd{compiler}{arara} ? 'arara' + : 'pdflatex' + ; + +### Set write18 for compiler +if ($opts_cmd{boolean}{shell}) { + $write18 = '-shell-escape'; + $write18 = '--enable-write18' if defined $ENV{'TEXSYSTEM'} and $ENV{'TEXSYSTEM'} =~ /miktex/i; +} +else { + $write18 = '-no-shell-escape'; + $write18 = '--disable-write18' if defined $ENV{'TEXSYSTEM'} and $ENV{'TEXSYSTEM'} =~ /miktex/i; +} + +### Set options for compiler +my $opt_compiler = $opts_cmd{compiler}{arara} ? '--log' + : $opts_cmd{compiler}{xetex} ? "$write18 -interaction=nonstopmode -recorder -no-pdf" + : "$write18 -interaction=nonstopmode -recorder" + ; + +if (!$opts_cmd{boolean}{norun}) { + Log("The options '$opt_compiler' will be passed to [$compiler]"); +} + +### Set -q for system command line (gs, poppler-utils, dvips, dvipdfmx) +my $quiet = $verbose ? q{} + : '-q' + ; + +### Set options for ghostscript in command line +my %opt_gs_dev = ( + pdf => '-dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=pdfwrite', + gray => '-dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sColorConversionStrategy=Gray -sProcessColorModel=DeviceGray', + png => "-dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=pngalpha -r$opts_cmd{string}{dpi}", + bmp => "-dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=bmp32b -r$opts_cmd{string}{dpi}", + jpg => "-dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=jpeg -r$opts_cmd{string}{dpi} -dJPEGQ=100 -dGraphicsAlphaBits=4 -dTextAlphaBits=4", + tif => "-dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=tiff32nc -r$opts_cmd{string}{dpi}", + ); + +### Set executable from poppler-utils +my %cmd_poppler = ( + eps => "pdftops", + ppm => "pdftoppm", + svg => "pdftocairo", + ); + +### Set options for poppler-utils +my %opt_poppler = ( + eps => "$quiet -eps", + ppm => "$quiet -r $opts_cmd{string}{dpi}", + svg => "$quiet -svg", + ); + +### Copy preamble and body for temp file with all environments +my $atbeginout = $atbegindoc; +my $preamout = $preamble; +my $tmpbodydoc = $bodydoc; + +### Match \pagestyle and \thispagestyle in preamble +my $style_page = qr /(?:\\)(?:this)?(?:pagestyle\{) (.+?) (?:\})/x; +my @style_page = $preamout =~ m/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| $style_page/gmsx; +my %style_page = map { $_ => 1 } @style_page; # anon hash + +### Seting \pagestyle{empty} for subfiles and process +if (@style_page) { + if (!exists $style_page{empty}) { + Log("Replacing page style for generated files"); + $preamout =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + (\\(this)?pagestyle)(?:\{.+?\})/$1\{empty\}/gmsx; + } +} +else { + Log('Add \pagestyle{empty} for generated files'); + $preamout = $preamout."\\pagestyle\{empty\}\n"; +} + +#### Remove wraped postscript environments provide by pst-pdf, auto-pst-pdf, auto-pst-pdf-lua pkgs +Log("Convert postscript environments to \\begin\{$wrapping\} ... \\end\{$wrapping\} for standalone files"); +$tmpbodydoc =~ s/(?:$BP)(?:\\begin\{postscript\})(?:\s*\[ [^]]*? \])? + (?.+?) + (?:\\end\{postscript\}) + (?:$EP) + /\\begin\{$wrapping\}$+{code}\\end\{$wrapping\}/gmsx; + +### We created a preamble for standalone files +my $sub_prea = "$atbeginout$preamout".'\begin{document}'; + +### Revert changes +$sub_prea =~ s/\%<\*$dtxverb>\s*(.+?)\s*\%<\/$dtxverb>/$1/gmsx; +%replace = (%changes_out); +$find = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %replace; +$sub_prea =~ s/($find)/$replace{$1}/g; +$sub_prea =~ s/(remove$tmp)/remove/g; + +### Write standalone files for environments +if ($outsrc) { + my $src_name = "$name-$opts_cmd{string}{prefix}-"; + my $srcNo = 1; + if ($opts_cmd{boolean}{srcenv}) { + Log('Extract source code of all captured environments without preamble'); + if ($STDenv) { + if (-e "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-1$ext") { + Log("Recreating $envNo $fileSTD [$ext] with source code for $envSTD in $imgdirpath"); + print "Recreating $envNo $fileSTD ", color('magenta'), "[$ext]", + color('reset'), " with source code for $envSTD\r\n"; + } + else { + Log("Creating $envNo $fileSTD [$ext] with source code for $envSTD in $imgdirpath"); + print "Creating $envNo $fileSTD ", color('magenta'), "[$ext]", + color('reset'), " with source code for $envSTD\r\n"; + } + # Write files + while ($tmpbodydoc =~ m/$BP\s*(?.+?)\s*$EP/gms) { + open my $outexasrc, '>', "$opts_cmd{string}{imgdir}/$src_name$srcNo$ext"; + print {$outexasrc} $+{'env_src'}; + close $outexasrc; + } + continue { $srcNo++; } + } + if ($PSTexa) { + if (-e "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-exa-1$ext") { + Log("Recreating $exaNo $fileEXA [$ext] with source code for $envEXA in $imgdirpath"); + print "Recreating $exaNo $fileEXA ", color('magenta'), "[$ext]", + color('reset'), " with source code for $envEXA\r\n"; + } + else { + Log("Creating $exaNo $fileEXA [$ext] with source code for $envEXA in $imgdirpath"); + print "Creating $exaNo $fileEXA ", color('magenta'), "[$ext]", + color('reset'), " with source code for $envEXA\r\n"; + } + # Write files + while ($tmpbodydoc =~ m/$BE\[.+?(?$opts_cmd{string}{imgdir}\/.+?-\d+)\}\]\s*(?.+?)\s*$EE/gms) { + open my $outstdsrc, '>', "$+{'pst_exa_name'}$ext"; + print {$outstdsrc} $+{'exa_src'}; + close $outstdsrc; + } + } + } + if ($opts_cmd{boolean}{subenv}) { + Log('Extract source code of all captured environments with preamble'); + if ($STDenv) { + if (-e "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-1$ext") { + Log("Recreating a $envNo standalone $fileSTD [$ext] for $envSTD in $imgdirpath"); + print "Recreating a $envNo standalone $fileSTD ", color('magenta'), "[$ext]", + color('reset'), " for $envSTD\r\n"; + } + else { + Log("Creating a $envNo standalone $fileSTD [$ext] for $envSTD in $imgdirpath"); + print "Creating a $envNo standalone $fileSTD ", color('magenta'), "[$ext]", + color('reset'), " for $envSTD\r\n"; + } + # Write files + while ($tmpbodydoc =~ m/$BP(?:\s*)?(?.+?)(?:\s*)?$EP/gms) { + open my $outstdfile, '>', "$opts_cmd{string}{imgdir}/$src_name$srcNo$ext"; + print {$outstdfile} "$sub_prea\n$+{'env_src'}\n\\end\{document\}"; + close $outstdfile; + } + continue { $srcNo++; } + } + if ($PSTexa) { + if (-e "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-exa-1$ext") { + Log("Recreating a $exaNo standalone $fileEXA [$ext] for $envEXA in $imgdirpath"); + print "Recreating a $exaNo standalone $fileEXA ", color('magenta'), "[$ext]", + color('reset'), " for $envEXA\r\n"; + } + else { + Log("Creating a $exaNo standalone $fileEXA [$ext] for $envEXA in $imgdirpath"); + print "Creating a $exaNo standalone $fileEXA ", color('magenta'), "[$ext]", + color('reset'), " for $envEXA\r\n"; + } + # Write files + while ($tmpbodydoc =~ m/$BE\[.+?(?$opts_cmd{string}{imgdir}\/.+?-\d+)\}\]\s*(?.+?)\s*$EE/gms) { + open my $outexafile, '>', "$+{'pst_exa_name'}$ext"; + print {$outexafile} "$sub_prea\n$+{'exa_src'}\n\\end\{document\}"; + close $outexafile; + } + } + } +} + +### Store options for preview and pst-pdf (add at begin document) +my $previewpkg = <<"EXTRA"; +\\PassOptionsToPackage\{inactive\}\{pst-pdf\}% +\\AtBeginDocument\{% +\\RequirePackage\[inactive\]\{pst-pdf\}% +\\RequirePackage\[${opt_prew}active,tightpage\]\{preview\}% +\\renewcommand\\PreviewBbAdjust\{-60pt -60pt 60pt 60pt\}\}% +EXTRA + +### Store options for pst-pdf (add at begin document) +my $pstpdfpkg = <<'EXTRA'; +\PassOptionsToPackage{inactive}{pst-pdf} +\AtBeginDocument{% +\RequirePackage[inactive]{pst-pdf}}% +EXTRA + +### First match preview package in preamble (prevent option clash) +my $REQPACK = quotemeta'\RequirePackage'; +my $USEPACK = quotemeta'\usepackage'; +my $CORCHETES = qr/\[ [^]]*? \]/x; + +my $PALABRAS = qr/\b (?: preview )/x; +my $FAMILIA = qr/\{ \s* $PALABRAS (?: \s* [,] \s* $PALABRAS )* \s* \}(\%*)?/x; + +Log('Remove preview package (if found) in preamble [memory]'); +$preamout =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + ^ $USEPACK (?: $CORCHETES )? $FAMILIA \s*//msxg; +$preamout =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + (?: ^ $USEPACK \{ | \G) [^}]*? \K (,?) \s* $PALABRAS (\s*) (,?) /$1 and $3 ? ',' : $1 ? $2 : ''/gemsx; +$preamout =~ s/^\\usepackage\{\}(?:[\t ]*(?:\r?\n|\r))+/\n/gmsx; + +### Remove %<*$dtxverb> ... % in tmpbodydoc and preamout +$tmpbodydoc =~ s/\%<\*$dtxverb>(.+?)\%<\/$dtxverb>/$1/gmsx; +$preamout =~ s/\%<\*$dtxverb>(.+?)\%<\/$dtxverb>/$1/gmsx; +$atbeginout =~ s/\%<\*$dtxverb>(.+?)\%<\/$dtxverb>/$1/gmsx; + +### Adjust nopreview environments +$tmpbodydoc =~ s/\\begin\{nopreview\}\%$tmp + (? .+?) + \\end\{nopreview\}\%$tmp + /\\begin\{nopreview\}\n$+{code}\n\\end\{nopreview\}\n/gmsx; + +### Adjust $wrapping environments (need \n after close for some environments, like a Verbatim) +$tmpbodydoc =~ s/\\begin\{$wrapping\} + (?.+?) + \\end\{$wrapping\} + /\\begin\{$wrapping\}\n$+{code}\n\\end\{$wrapping\}/gmsx; + +### Reverse changes for temporary file with all env (no in -exa file) +$tmpbodydoc =~ s/($find)/$replace{$1}/g; +$tmpbodydoc =~ s/(\%$tmp)//g; +$tmpbodydoc =~ s/(remove$tmp)/remove/g; +$preamout =~ s/($find)/$replace{$1}/g; +$atbeginout =~ s/(remove$tmp)/remove/g; +$atbeginout =~ s/($find)/$replace{$1}/g; + +### We created a preamble for individual files with all environments +$sub_prea = $opts_cmd{boolean}{noprew} ? "$atbeginout$pstpdfpkg$preamout".'\begin{document}' + : "$atbeginout$previewpkg$preamout" + ; + +### Create a one file with "all" PSTexample environments extracted +if ($PSTexa) { + @exa_extract = undef; + Log("Adding packages to $name-$opts_cmd{string}{prefix}-exa-$tmp$ext"); + Logline($pstpdfpkg); + Log('Convert plain Tex syntax for pspicture and psgraph to LaTeX syntax in PSTexample environments'); + while ($tmpbodydoc =~ m/$BE\[.+? $opts_cmd{string}{imgdir}\/.+?-\d+\}\] .+?$EE/pgsmx ) { # search + my ($pos_inicial, $pos_final) = ($-[0], $+[0]); + my $encontrado = ${^MATCH}; + $encontrado =~ s/\\pspicture(\*)?(.+?)\\endpspicture/\\begin\{pspicture$1\}$2\\end\{pspicture$1\}/gmsx; + $encontrado =~ s/\\psgraph(\*)?(.+?)\\endpsgraph/\\begin\{psgraph$1\}$2\\end\{psgraph$1\}/gmsx; + substr $tmpbodydoc, $pos_inicial, $pos_final-$pos_inicial, $encontrado; + pos ($tmpbodydoc) = $pos_inicial + length $encontrado; + } + # Write files + Infoline("Creating $name-$opts_cmd{string}{prefix}-exa-$tmp$ext with $exaNo $envEXA extracted"); + while ($tmpbodydoc =~ m/$BE\[.+? $opts_cmd{string}{imgdir}\/.+?-\d+\}\](?.+?)$EE/gmsx ) { # search + push @exa_extract, $+{'exa_src'}."\\newpage\n"; + open my $allexaenv, '>', "$name-$opts_cmd{string}{prefix}-exa-$tmp$ext"; + print {$allexaenv} "$atbeginout$pstpdfpkg$preamout".'\begin{document}'."@exa_extract"."\\end\{document\}"; + close $allexaenv; + } + # Remove [graphic={...}] in PSTexample example environments + $tmpbodydoc =~ s/($BE)(?:\[graphic=\{\[scale=1\]$opts_cmd{string}{imgdir}\/.+?-\d+\}\])/$1/gmsx; + $tmpbodydoc =~ s/($BE\[.+?)(?:,graphic=\{\[scale=1\]$opts_cmd{string}{imgdir}\/.+?-\d+\})(\])/$1$2/gmsx; + # Moving and renaming + if ($opts_cmd{boolean}{norun}) { + Infoline("Moving and renaming $name-$opts_cmd{string}{prefix}-exa-$tmp$ext to $name-$opts_cmd{string}{prefix}-exa-all$ext"); + if (-e "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-exa-all$ext") { + Infocolor('Warning', "The file [$name-$opts_cmd{string}{prefix}-exa-all$ext] already exists and will be rewritten"); + Log("Rewriting the file $name-$opts_cmd{string}{prefix}-exa-all$ext in $imgdirpath"); + } + else { + Log("Writing the file $name-$opts_cmd{string}{prefix}-exa-all$ext in $imgdirpath"); + } + if ($verbose) { + Infocolor('Running', "mv $workdir/$name-$opts_cmd{string}{prefix}-exa-$tmp$ext $imgdirpath/$name-$opts_cmd{string}{prefix}-exa-all$ext"); + } + else { + Infocolor('Running', "mv $name-$opts_cmd{string}{prefix}-exa-$tmp$ext ./$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-exa-all$ext"); + } + Logline("[perl] move($workdir/$name-$opts_cmd{string}{prefix}-exa-$tmp$ext, $imgdirpath/$name-$opts_cmd{string}{prefix}-exa-all$ext)"); + move("$workdir/$name-$opts_cmd{string}{prefix}-exa-$tmp$ext", "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-exa-all$ext") + or die "* Error!!: Couldn't be renamed $name-$opts_cmd{string}{prefix}-exa-$tmp$ext to ./$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-exa-all$ext"; + } +} + +### Create a one file with "all" standard environments extracted +if ($STDenv) { + if ($opts_cmd{boolean}{noprew}) { + Log("Creating $name-$opts_cmd{string}{prefix}-$tmp$ext with $envNo $envSTD extracted [no preview]"); + print "Creating $name-$opts_cmd{string}{prefix}-$tmp$ext with $envNo $envSTD extracted", + color('magenta'), " [no preview]\r\n",color('reset'); + } + else { + Log("Creating $name-$opts_cmd{string}{prefix}-$tmp$ext with $envNo $envSTD extracted [preview]"); + print "Creating $name-$opts_cmd{string}{prefix}-$tmp$ext with $envNo $envSTD extracted", + color('magenta'), " [preview]\r\n",color('reset'); + } + open my $allstdenv, '>', "$name-$opts_cmd{string}{prefix}-$tmp$ext"; + if ($opts_cmd{boolean}{noprew}) { + my @env_extract; + while ($tmpbodydoc =~ m/(?:$BP)(?.+?)(?:$EP)/gms) { + push @env_extract, $+{'env_src'}."\\newpage\n"; + } + Log("Adding packages to $name-$opts_cmd{string}{prefix}-$tmp$ext"); + Logline($pstpdfpkg); + print {$allstdenv} $sub_prea."@env_extract"."\\end{document}"; + } + else { + Log("Adding packages to $name-$opts_cmd{string}{prefix}-$tmp$ext"); + Logline($previewpkg); + Log("Convert $wrapping to preview environments in $name-$opts_cmd{string}{prefix}-$tmp$ext"); + # Convert $wrapping to preview environments + $tmpbodydoc =~ s/\\begin\{$wrapping\}(?.+?)\\end\{$wrapping\} + /\\begin\{preview\}$+{code}\\end\{preview\}\n/gmsx; + print {$allstdenv} $sub_prea.$tmpbodydoc."\n\\end{document}"; + } + close $allstdenv; + if ($opts_cmd{boolean}{norun}) { + # Moving and renaming + Infoline("Moving and renaming $name-$opts_cmd{string}{prefix}-$tmp$ext to $name-$opts_cmd{string}{prefix}-all$ext"); + if (-e "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-all$ext") { + Infocolor('Warning', "The file [$name-$opts_cmd{string}{prefix}-all$ext] already exists and will be rewritten"); + Log("Rewriting the file $name-$opts_cmd{string}{prefix}-all$ext in $imgdirpath"); + } + else { + Log("Writing the file $name-$opts_cmd{string}{prefix}-all$ext in $imgdirpath"); + } + if ($verbose) { + Infocolor('Running', "mv $workdir/$name-$opts_cmd{string}{prefix}-$tmp$ext $imgdirpath/$name-$opts_cmd{string}{prefix}-all$ext"); + } + else { + Infocolor('Running', "mv $name-$opts_cmd{string}{prefix}-$tmp$ext ./$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-all$ext"); + } + Logline("[perl] move($workdir/$name-$opts_cmd{string}{prefix}-$tmp$ext, $imgdirpath/$name-$opts_cmd{string}{prefix}-all$ext)"); + move("$workdir/$name-$opts_cmd{string}{prefix}-$tmp$ext", "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-all$ext") + or die "* Error!!: Couldn't be renamed $name-$opts_cmd{string}{prefix}-$tmp$ext to ./$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-all$ext"; + } +} + +### Compiler and generate PDF files -dALLOWPSTRANSPARENCY +if (!$opts_cmd{boolean}{norun}) { +Log('Generate a PDF file with all captured environments'); +my @compiler = (1..$opts_cmd{string}{runs}); +opendir (my $DIR, $workdir); + while (readdir $DIR) { + if (/(?$name-$opts_cmd{string}{prefix}(-exa)?)(?-$tmp$ext)/) { + Log("Compiling the file $+{name}$+{type} using [$msg_compiler]"); + print "Compiling the file $+{name}$+{type} using ", color('magenta'), "[$msg_compiler]\r\n",color('reset'); + for (@compiler){ + RUNOSCMD("$compiler $opt_compiler","$+{name}$+{type}",'show'); + } + # Using xdvipdfmx + if ($compiler eq 'xelatex') { + RUNOSCMD("xdvipdfmx $quiet -E", "-o $+{name}-$tmp.pdf $+{name}-$tmp.xdv",'show'); + } + # Compiling file using latex>dvips>ps2pdf + if ($compiler eq 'dvips' or $compiler eq 'latex' or $compiler eq 'dvilualatex') { + RUNOSCMD("dvips $quiet -Ppdf", "-o $+{name}-$tmp.ps $+{name}-$tmp.dvi",'show'); + RUNOSCMD("ps2pdf -sPDFSETTINGS=prepress -sAutoRotatePages=None -dALLOWPSTRANSPARENCY", "$+{name}-$tmp.ps $+{name}-$tmp.pdf",'show'); + } + # Compiling file using latex>dvipdfmx + if ($compiler eq 'dvipdf') { + RUNOSCMD("dvipdfmx $quiet", "$+{name}-$tmp.dvi",'show'); + } + # Moving and renaming temp files with source code + Infoline("Moving and renaming $+{name}$+{type} to $+{name}-all$ext"); + if (-e "$opts_cmd{string}{imgdir}/$+{name}-all$ext") { + Infocolor('Warning', "The file [$+{name}-all$ext] already exists and will be rewritten"); + Log("Rewriting the file $+{name}-all$ext with all source for environments in $imgdirpath"); + } + else { + Log("Writing the file $+{name}-all$ext with all source for environments in $imgdirpath"); + } + if ($verbose){ + Infocolor('Running', "mv $workdir/$+{name}$+{type} $imgdirpath/$+{name}-all$ext"); + } + else { + Infocolor('Running', "mv $+{name}$+{type} ./$opts_cmd{string}{imgdir}/$+{name}-all$ext"); + } + Logline("[perl] move($workdir/$+{name}$+{type}, $imgdirpath/$+{name}-all$ext)"); + move("$workdir/$+{name}$+{type}", "$opts_cmd{string}{imgdir}/$+{name}-all$ext") + or die "* Error!!: Couldn't be renamed $+{name}$+{type} to $opts_cmd{string}{imgdir}/$+{name}-all$ext"; + # pdfcrop + if (!$opts_cmd{boolean}{nocrop}) { + Infoline("Cropping the file $+{name}-$tmp.pdf"); + RUNOSCMD("pdfcrop $opt_crop", "$+{name}-$tmp.pdf $+{name}-$tmp.pdf",'show'); + } + # gray + if ($opts_cmd{boolean}{gray}) { + Infoline("Creating the file $+{name}-all.pdf [gray] in $tempDir"); + RUNOSCMD("$gscmd $quiet $opt_gs_dev{gray} ","-o $tempDir/$+{name}-all.pdf $workdir/$+{name}-$tmp.pdf",'show'); + } + else { + Infoline("Creating the file $+{name}-all.pdf in $tempDir"); + if ($verbose){ + Infocolor('Running', "mv $workdir/$+{name}-$tmp.pdf $tempDir/$+{name}-all.pdf"); + } + else { Infocolor('Running', "mv $+{name}-$tmp.pdf $tempDir/$+{name}-all.pdf"); } + # Renaming pdf file + Logline("[perl] move($workdir/$+{name}-$tmp.pdf, $tempDir/$+{name}-all.pdf)"); + move("$workdir/$+{name}-$tmp.pdf", "$tempDir/$+{name}-all.pdf") + or die "* Error!!: Couldn't be renamed $+{name}-$tmp.pdf to $tempDir/$+{name}-all.pdf"; + } + } + } +closedir $DIR; +} + +### Create image formats in separate files +if (!$opts_cmd{boolean}{norun}) { + Log("Creating the image formats: $format, working on $tempDir"); + opendir(my $DIR, $tempDir); + while (readdir $DIR) { + # PDF/PNG/JPG/BMP/TIFF format suported by ghostscript + if (/(?$name-$opts_cmd{string}{prefix}(-exa)?)(?-all\.pdf)/) { + for my $var (qw(pdf png jpg bmp tif)) { + if (defined $opts_cmd{image}{$var}) { + Log("Generating format [$var] from file $+{name}$+{type} in $imgdirpath using $gscmd"); + print 'Generating format', color('blue'), " [$var] ", color('reset'),"from file $+{name}$+{type}\r\n"; + RUNOSCMD("$gscmd $quiet $opt_gs_dev{$var} ", "-o $workdir/$opts_cmd{string}{imgdir}/$+{name}-%1d.$var $tempDir/$+{name}$+{type}",'show'); + } + } + } + # EPS/PPM/SVG format suported by poppler-utils + if (/(?$name-$opts_cmd{string}{prefix}-exa)(?-all\.pdf)/) { # pst-exa package + for my $var (qw(eps ppm svg)) { + if (defined $opts_cmd{image}{$var}) { + Log("Generating format [$var] from file $+{name}$+{type} in $imgdirpath using $cmd_poppler{$var}"); + print 'Generating format', color('blue'), " [$var] ", color('reset'),"from file $+{name}$+{type}\r\n"; + if (!$verbose){ + Infocolor('Running', "$cmd_poppler{$var} $opt_poppler{$var}"); + } + for (my $epsNo = 1; $epsNo <= $exaNo; $epsNo++) { + RUNOSCMD("$cmd_poppler{$var} $opt_poppler{$var}", "-f $epsNo -l $epsNo $tempDir/$+{name}$+{type} $workdir/$opts_cmd{string}{imgdir}/$+{name}-$epsNo.$var",'only'); + } + } + } + } + if (/(?$name-$opts_cmd{string}{prefix})(?-all\.pdf)/) { + for my $var (qw(eps ppm svg)) { + if (defined $opts_cmd{image}{$var}) { + Log("Generating format [$var] from file $+{name}$+{type} in $imgdirpath using $cmd_poppler{$var}"); + print 'Generating format', color('blue'), " [$var] ", color('reset'),"from file $+{name}$+{type}\r\n"; + if (!$verbose){ + Infocolor('Running', "$cmd_poppler{$var} $opt_poppler{$var}"); + } + for (my $epsNo = 1; $epsNo <= $envNo; $epsNo++) { + RUNOSCMD("$cmd_poppler{$var} $opt_poppler{$var}", "-f $epsNo -l $epsNo $tempDir/$+{name}$+{type} $workdir/$opts_cmd{string}{imgdir}/$+{name}-$epsNo.$var",'only'); + } + } + } + } + } # close while + closedir $DIR; + # Renaming PPM image files + if (defined $opts_cmd{image}{ppm}) { + Log("Renaming [ppm] images in $imgdirpath"); + if ($verbose){ + print 'Renaming', color('blue'), " [ppm] ", color('reset'),"images in $imgdirpath\r\n"; + } + opendir(my $DIR, $opts_cmd{string}{imgdir}); + while (readdir $DIR) { + if (/(?$name-$opts_cmd{string}{prefix}(-exa)?-\d+\.ppm)(?-\d+)(?\.ppm)/) { + if ($verbose){ + Infocolor('Running', "mv $+{name}$+{sep}$+{ppm} $+{name}"); + } + Logline("[perl] move($imgdirpath/$+{name}$+{sep}$+{ppm}, $imgdirpath/$+{name})"); + move("$opts_cmd{string}{imgdir}/$+{name}$+{sep}$+{ppm}", "$opts_cmd{string}{imgdir}/$+{name}") + or die "* Error!!: Couldn't be renamed $+{name}$+{sep}$+{ppm} to $+{name}"; + } + } + closedir $DIR; + } +} # close run + +### Constant +my $findgraphicx = 'true'; + +### Add $atbegindoc to $preamble +$preamble = "$atbegindoc$preamble"; + +### Replacing the extracted environments with \\includegraphics +if ($outfile) { + my @tag_remove_preamble = $preamble =~ m/(?:^\%<\*remove$tmp>.+?\%<\/remove$tmp>)/gmsx; + if (@tag_remove_preamble) { + Log("Removing the content between <*remove> ... tags in preamble for $opts_cmd{string}{output}$outext"); + $preamble =~ s/^\%<\*remove$tmp>\s*(.+?)\s*\%<\/remove$tmp>(?:[\t ]*(?:\r?\n|\r))?+//gmsx; + } + Log("Convert standard extracted environments to \\includegraphics for $opts_cmd{string}{output}$outext"); + my $grap = "\\includegraphics[scale=1]{$name-$opts_cmd{string}{prefix}-"; + my $close = '}'; + my $imgNo = 1; + $bodydoc =~ s/$BP.+?$EP/$grap@{[$imgNo++]}$close/msg; +} + +### pst-exa package +my $pstexa = qr/(?:\\ usepackage) \[\s*(.+?)\s*\] (?:\{\s*(pst-exa)\s*\} ) /x; +my @pst_exa; +my %pst_exa; + +### Search pst-exa package +@pst_exa = $preamble =~ m/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)|$pstexa/gmsx; +%pst_exa = map { $_ => 1 } @pst_exa; + +### If found comment and adjust path for graphic files +if (@pst_exa and $outfile) { + Log("Comment pst-exa package in preamble for $opts_cmd{string}{output}$outext"); + $findgraphicx = 'false'; + $preamble =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + (\\usepackage\[)\s*(swpl|tcb)\s*(\]\{pst-exa\})/\%$1$2,pdf$3/msxg; + if (exists $pst_exa{tcb}) { + Log("Suport for \\usepackage[tcb,pdf]\{pst-exa\} for $opts_cmd{string}{output}$outext"); + $bodydoc =~ s/(graphic=\{)\[(scale=\d*)\]($opts_cmd{string}{imgdir}\/$name-$opts_cmd{string}{prefix}-exa-\d*)\}/$1$2\}\{$3\}/gsmx; + } +} + +### Regex for clean file (pst) in preamble +$PALABRAS = qr/\b (?: pst-\w+ | pstricks (?: -add | -pdf )? | psfrag |psgo |vaucanson-g| auto-pst-pdf(?: -lua )? )/x; +$FAMILIA = qr/\{ \s* $PALABRAS (?: \s* [,] \s* $PALABRAS )* \s* \}(\%*)?/x; + +### Clean PST content in preamble +if ($clean{pst} and $outfile) { + Log("Remove pstricks packages in preamble for $opts_cmd{string}{output}$outext"); + $preamble =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + ^ $USEPACK (?: $CORCHETES )? $FAMILIA \s*//msxg; + $preamble =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + (?: ^ $USEPACK \{ | \G) [^}]*? \K (,?) \s* $PALABRAS (\s*) (,?) /$1 and $3 ? ',' : $1 ? $2 : ''/gemsx; + if (@pst_exa) { + Log("Uncomment pst-exa package in preamble for $opts_cmd{string}{output}$outext"); + $preamble =~ s/(?:\%)(\\usepackage\[\s*)(swpl|tcb)(,pdf\s*\]\{pst-exa\})/$1$2$3/msxg; + } + Log("Remove \\psset\{...\} in preamble for $opts_cmd{string}{output}$outext"); + $preamble =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + \\psset\{(?:\{.*?\}|[^\{])*\}(?:[\t ]*(?:\r?\n|\r))+//gmsx; + Log("Remove \\SpecialCoor in preamble for $opts_cmd{string}{output}$outext"); + $preamble =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + \\SpecialCoor(?:[\t ]*(?:\r?\n|\r))+//gmsx; + Log("Remove empty lines in preamble for $opts_cmd{string}{output}$outext"); + $preamble =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| + ^\\usepackage\{\}(?:[\t ]*(?:\r?\n|\r))+/\n/gmsx; +} + +### To be sure that the package graphicx and \graphicspath is in the main +### document and not in a verbatim write environment we make the changes +my %tmpreplace = ( + 'graphicx' => 'TMPGRAPHICXTMP', + 'graphicspath' => 'TMPGRAPHICSPATHTMP', +); +my $findtmp = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %tmpreplace; + +### We go line by line and make the changes [need /p for ${^MATCH}] +while ($preamble =~ /\%<\*$dtxverb>(.+?)\%<\/$dtxverb> | $tmpcomment /pgmsx) { + my ($pos_inicial, $pos_final) = ($-[0], $+[0]); + my $encontrado = ${^MATCH}; + $encontrado =~ s/($findtmp)/$tmpreplace{$1}/g; + substr $preamble, $pos_inicial, $pos_final-$pos_inicial, $encontrado; + pos ($preamble) = $pos_inicial + length $encontrado; +} + +### Now we're trying to capture \graphicspath{...} +my $graphicspath= qr/\\ graphicspath \{ ((?: $llaves )+) \}/ix; +my @graphicspath; +@graphicspath = $preamble =~ m/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)|($graphicspath)/gmsx; + +if (@graphicspath and $outfile) { + Log("Found \\graphicspath in preamble for $opts_cmd{string}{output}$outext"); + $findgraphicx = 'false'; + while ($preamble =~ /$graphicspath /pgmx) { + my ($pos_inicial, $pos_final) = ($-[0], $+[0]); + my $encontrado = ${^MATCH}; + if ($encontrado =~ /$graphicspath/) { + my $argumento = $1; + if ($argumento !~ /\{$opts_cmd{string}{imgdir}\/\}/) { + $argumento .= "\{$opts_cmd{string}{imgdir}/\}"; + my $cambio = "\\graphicspath{$argumento}"; + substr $preamble, $pos_inicial, $pos_final-$pos_inicial, $cambio; + pos($preamble) = $pos_inicial + length $cambio; + } + } + } +} + +### Possible packages that load graphicx +my @pkgcandidates = qw ( + rotating epsfig lyluatex xunicode parsa xepersian-hm gregoriotex teixmlslides + teixml fotex hvfloat pgfplots grfpaste gmbase hep-paper postage schulealt + schule utfsym cachepic abc doclicense rotating epsfig semtrans mgltex + graphviz revquantum mpostinl cmpj cmpj2 cmpj3 chemschemex register papercdcase + flipbook wallpaper asyprocess draftwatermark rutitlepage dccpaper-base + nbwp-manual mandi fmp toptesi isorot pinlabel cmll graphicx-psmin ptmxcomp + countriesofeurope iodhbwm-templates fgruler combinedgraphics pax pdfpagediff + psfragx epsdice perfectcut upmethodology-fmt ftc-notebook tabvar vtable + teubner pas-cv gcard table-fct pdfpages keyfloat pdfscreen showexpl simplecd + ifmslide grffile reflectgraphics markdown bclogo tikz-page pst-uml realboxes + musikui csbulobalka lwarp mathtools sympytex mpgraphics miniplot.sty:77 + dottex pdftricks2 feupphdteses tex4ebook axodraw2 hagenberg-thesis dlfltxb + hu-berlin-bundle draftfigure quicktype endofproofwd euflag othelloboard + pdftricks unswcover breqn pdfswitch latex-make figlatex repltext etsvthor + cyber xcookybooky xfrac mercatormap chs-physics-report tikzscale ditaa + pst-poker gmp CJKvert asypictureb hletter tikz-network powerdot-fuberlin + skeyval gnuplottex plantslabels fancytooltips ieeepes pst-vectorian + phfnote overpic xtuformat stubs graphbox ucs pdfwin metalogo mwe + inline-images asymptote UNAMThesis authorarchive amscdx pst-pdf adjustbox + trimclip fixmetodonotes incgraph scanpages pst-layout alertmessage + svg quiz2socrative realhats autopdf egplot decorule figsize tikzexternal + pgfcore frontespizio textglos graphicx tikz tcolorbox pst-exa + ); + +my $pkgcandidates = join q{|}, map { quotemeta } sort { length $a <=> length $b } @pkgcandidates; +$pkgcandidates = qr/$pkgcandidates/x; +my @graphicxpkg; + +### Now we're trying to capture graphicx package +@graphicxpkg = $preamble =~ m/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)|($pkgcandidates)/gmsx; +if (@graphicxpkg and $outfile and $findgraphicx ne 'false') { + Log("Found graphicx package in preamble for $opts_cmd{string}{output}$outext"); + $findgraphicx = 'false'; +} + +### Revert changes in preamble for temp +my %tmpoutreplace = ( + 'TMPGRAPHICXTMP' => 'graphicx', + 'TMPGRAPHICSPATHTMP' => 'graphicspath', +); + +%replace = (%changes_out,%tmpoutreplace); +$find = join q{|}, map {quotemeta} sort { length $a <=> length $b } keys %replace; + +### Capture graphicx.sty in .log of LaTeX file +if ($findgraphicx ne 'false' and $outfile) { + Log("Couldn't capture the graphicx package for $opts_cmd{string}{output}$ext in preamble"); + my $ltxlog; + my @graphicx; + my $null = devnull(); + # Copy preamble and revert changes + my $preambletmp = $preamble; + $preambletmp =~ s/($find)/$replace{$1}/g; + $preambletmp =~ s/\%<\*$dtxverb>(.+?)\%<\/$dtxverb>/$1/gmsx; + Log("Creating $name-$opts_cmd{string}{prefix}-$tmp$ext [only preamble]"); + if ($verbose) { say "Creating [$name-$opts_cmd{string}{prefix}-$tmp$ext] with only preamble"; } + open my $OUTfile, '>', "$name-$opts_cmd{string}{prefix}-$tmp$ext"; + print {$OUTfile} "$preambletmp\n\\stop"; + close $OUTfile; + # Set compiler + if ($opts_cmd{compiler}{arara}) { + my @engine = $atbegindoc =~ m/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)|$arara_rule/msx; + my %engine = map { $_ => 1 } @engine; + if (%engine) { + for my $var (@arara_engines) { + if (defined $engine{$var}) { + Log("Found engine [$var] for arara"); + $compiler = $var; + } + } + } + else { + Log("Not detected engine for arara, use default [pdflatex]"); + $compiler = 'pdflatex'; + } + } + if ($opts_cmd{compiler}{latex}) { $compiler = 'pdflatex'; } + if ($opts_cmd{compiler}{dvilua}) { $compiler = 'lualatex'; } + # Compiling file + RUNOSCMD("$compiler $write18 -interaction=batchmode", "$name-$opts_cmd{string}{prefix}-$tmp$ext >$null", 'only'); + # Restore arara compiler + if ($opts_cmd{compiler}{arara}) { $compiler = 'arara'; } + Log("Search graphicx package in $name-$opts_cmd{string}{prefix}-$tmp.log"); + open my $LaTeXlog, '<', "$name-$opts_cmd{string}{prefix}-$tmp.log"; + { + local $/; + $ltxlog = <$LaTeXlog>; + } + close $LaTeXlog; + # Try to capture graphicx + @graphicx = $ltxlog =~ m/.+? (graphicx\.sty)/xg; + if (@graphicx) { + Log("Found graphicx package in $name-$opts_cmd{string}{prefix}-$tmp.log"); + } + else { + Log("Not found graphicx package in $name-$opts_cmd{string}{prefix}-$tmp.log"); + Log("Add \\usepackage\{graphicx\} to preamble of $opts_cmd{string}{output}$outext"); + $preamble= "$preamble\\usepackage\{graphicx\}\n"; + } +} + +### Add last lines +if ($outfile) { + if (!@graphicspath) { + Log("Not found \\graphicspath in preamble for $opts_cmd{string}{output}$outext"); + Log("Add \\graphicspath\{\{$opts_cmd{string}{imgdir}/\}\} to preamble for $opts_cmd{string}{output}$ext"); + $preamble= "$preamble\\graphicspath\{\{$opts_cmd{string}{imgdir}/\}\}\n"; + } + Log("Add \\usepackage\{grfext\} to preamble for $opts_cmd{string}{output}$ext"); + $preamble = "$preamble\\usepackage\{grfext\}\n"; + Log("Add \\PrependGraphicsExtensions\*\{\.pdf\} to preamble for $opts_cmd{string}{output}$ext"); + $preamble = "$preamble\\PrependGraphicsExtensions\*\{\.pdf\}"; + $preamble =~ s/\%<\*$dtxverb>\s*(.+?)\s*\%<\/$dtxverb>/$1/gmsx; + $preamble =~ s/^\\usepackage\{\}(?:[\t ]*(?:\r?\n|\r))+/\n/gmsx; + $preamble =~ s/^(?:[\t ]*(?:\r?\n|\r))?+//gmsx; +} + +### We remove environments from the +if (%delete_env and $outfile) { + Log("Remove environments in body of $opts_cmd{string}{output}$ext"); + %replace = (%delete_env); + $find = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %replace; + # We must prevent eliminating somewhere wrong + # We re-create the regular expressions to make the changes + my @new_verb_tmp = array_minus(@verbatim, @delete_env); + $verbatim = join q{|}, map { quotemeta } sort { length $a <=> length $b } @new_verb_tmp; + $verbatim = qr/$verbatim/x; + $verb_std = qr { + ( + (?: + \\begin\{$verbatim\*?\} + (?: + (?>[^\\]+)| + \\ + (?!begin\{$verbatim\*?\}) + (?!end\{$verbatim\*?\})| + (?-1) + )* + \\end\{$verbatim\*?\} + ) + ) + }x; + + my @new_verbw_tmp = array_minus(@verbatim_w, @delete_env); + $verbatim_w = join q{|}, map { quotemeta } sort { length $a <=> length $b } @new_verbw_tmp; + $verbatim_w = qr/$verbatim_w/x; + $verb_wrt = qr { + ( + (?: + \\begin\{$verbatim_w\*?\} + (?: + (?>[^\\]+)| + \\ + (?!begin\{$verbatim_w\*?\}) + (?!end\{$verbatim_w\*?\})| + (?-1) + )* + \\end\{$verbatim_w\*?\} + ) + ) + }x; + while ($bodydoc =~ /$verb_wrt | $verb_std /pgmx) { + my ($pos_inicial, $pos_final) = ($-[0], $+[0]); + my $encontrado = ${^MATCH}; + $encontrado =~ s/($find)/$replace{$1}/g; + substr $bodydoc, $pos_inicial, $pos_final-$pos_inicial, $encontrado; + pos ($bodydoc) = $pos_inicial + length $encontrado; + } + # Now remove + $bodydoc =~ s/($delt_env)(?:[\t ]*(?:\r?\n|\r))?+//gmsx; +} + +### Create a +if ($outfile) { + # Options for out_file (add $end to outfile) + my $out_file = $clean{doc} ? "$preamble\n$bodydoc\n\\end\{document\}" + : "$preamble\n$bodydoc\n$enddoc" + ; + # Clean \psset{...} content in + if ($clean{pst}) { + $out_file =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \%<\*$dtxverb> .+? \%<\/$dtxverb>(*SKIP)(*F)| + \\psset\{(?:\{.*?\}|[^\{])*\}(?:[\t ]*(?:\r?\n|\r))?+//gmsx; + } + # Clean \tikzset{...} content in + if ($clean{tkz}) { + $out_file =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| + \%<\*$dtxverb> .+? \%<\/$dtxverb>(*SKIP)(*F)| + \\tikzset\{(?:\{.*?\}|[^\{])*\}(?:[\t ]*(?:\r?\n|\r))?+//gmsx; + } + # Revert all changes in outfile + $out_file =~ s/\\begin\{nopreview\}\%$tmp\s*(.+?)\s*\\end\{nopreview\}\%$tmp/$1/gmsx; + my @tag_remove_outfile = $out_file =~ m/(?:^\%<\*remove$tmp>.+?\%<\/remove$tmp>)/gmsx; + if (@tag_remove_outfile) { + Log("Removing the content between <*remove> ... tags in all $opts_cmd{string}{output}$outext"); + $out_file =~ s/^\%<\*remove$tmp>\s*(.+?)\s*\%<\/remove$tmp>(?:[\t ]*(?:\r?\n|\r))?+//gmsx; + } + # Remove internal mark for verbatim and verbatim write environments + $out_file =~ s/\%<\*$dtxverb>\s*(.+?)\s*\%<\/$dtxverb>/$1/gmsx; + %replace = (%changes_out); + $find = join q{|}, map {quotemeta} sort { length $a <=> length $b } keys %replace; + $out_file =~ s/($find)/$replace{$1}/g; + if (-e "$opts_cmd{string}{output}$outext") { + Log("Rewriting the file $opts_cmd{string}{output}$outext in $workdir"); + Infocolor('Warning', "The file [$opts_cmd{string}{output}$outext] already exists and will be rewritten"); + } + else{ + Infoline("Creating the file $opts_cmd{string}{output}$outext"); + Log("Write the file $opts_cmd{string}{output}$outext in $workdir"); + } + # Write + open my $OUTfile, '>', "$opts_cmd{string}{output}$outext"; + print {$OUTfile} $out_file; + close $OUTfile; +} + +### Set compiler for process +$compiler = $opts_cmd{compiler}{xetex} ? 'xelatex' + : $opts_cmd{compiler}{luatex} ? 'lualatex' + : $opts_cmd{compiler}{dvips} ? 'latex' + : $opts_cmd{compiler}{dvilua} ? 'lualatex' + : $opts_cmd{compiler}{dvipdf} ? 'latex' + : $opts_cmd{compiler}{arara} ? 'arara' + : $opts_cmd{compiler}{latexmk} ? 'latexmk' + : 'pdflatex' + ; + +### Set options for latexmk +my $ltxmkopt = $opts_cmd{compiler}{xetex} ? "-pdfxe -silent -xelatex=\"xelatex $write18 -recorder %O %S\"" + : $opts_cmd{compiler}{luatex} ? "-pdflua -silent -lualatex=\"lualatex $write18 -recorder %O %S\"" + : $opts_cmd{compiler}{dvilua} ? "-pdflua -silent -lualatex=\"lualatex $write18 -recorder %O %S\"" + : $opts_cmd{compiler}{dvips} ? "-pdfps -silent -latex=\"latex $write18 -recorder %O %S\"" + : $opts_cmd{compiler}{dvipdf} ? "-pdfdvi -silent -latex=\"latex $write18 -recorder %O %S\"" + : "-pdf -silent -pdflatex=\"pdflatex $write18 -recorder %O %S\"" + ; + +### Set options for compiler +$opt_compiler = $opts_cmd{compiler}{arara} ? '--log' + : $opts_cmd{compiler}{latexmk} ? "$ltxmkopt" + : "$write18 -interaction=nonstopmode -recorder" + ; + +### Message in command line for compiler +$msg_compiler = $opts_cmd{compiler}{xetex} ? 'xelatex' + : $opts_cmd{compiler}{luatex} ? 'lualatex' + : $opts_cmd{compiler}{latex} ? 'pdflatex' + : $opts_cmd{compiler}{dvips} ? 'latex>dvips>ps2pdf' + : $opts_cmd{compiler}{dvilua} ? 'lualatex' + : $opts_cmd{compiler}{dvipdf} ? 'latex>dvipdfmx' + : $opts_cmd{compiler}{arara} ? 'arara' + : 'latexmk' + ; + +### Now set message for latexmk +if ($opts_cmd{compiler}{latexmk}) { + $msg_compiler = 'latexmk'; +} + +### Compiling +if (!$opts_cmd{boolean}{norun} and $outfile) { + Log("Compiling the file $opts_cmd{string}{output}$outext using [$msg_compiler]"); + print "Compiling the file $opts_cmd{string}{output}$outext using ", color('magenta'), "[$msg_compiler]\r\n",color('reset'); + RUNOSCMD("$compiler $opt_compiler", "$opts_cmd{string}{output}$outext",'show'); + # Compiling using dvips>ps2pdf + if ($opts_cmd{compiler}{dvips}) { + RUNOSCMD("dvips $quiet -Ppdf", "$opts_cmd{string}{output}.dvi",'show'); + RUNOSCMD("ps2pdf -sPDFSETTINGS=prepress -sAutoRotatePages=None", "$opts_cmd{string}{output}.ps $opts_cmd{string}{output}.pdf", 'show'); + } + # Compiling using latex>dvipdfmx + if ($opts_cmd{compiler}{dvipdf}) { + RUNOSCMD("dvipdfmx $quiet", "$opts_cmd{string}{output}.dvi", 'show'); + } +} + +### Remove temporary files +my @tmpfiles; +my @protected = qw(); +my $flsline = 'OUTPUT'; +my @flsfile; + +### Protect generated files +if (defined $opts_cmd{string}{output}) { + push @protected, "$opts_cmd{string}{output}$outext", "$opts_cmd{string}{output}.pdf"; +} + +### Find files +find(\&aux_files, $workdir); +sub aux_files{ + my $findtmpfiles = $_; + if (-f $findtmpfiles && $findtmpfiles =~ m/$name-$opts_cmd{string}{prefix}(-exa)?-$tmp.+?$/) { # search + push @tmpfiles, $_; + } + return; +} + +### Add if exists +if (-e 'arara.log') { + push @flsfile, 'arara.log'; +} +if (-e "$name-$opts_cmd{string}{prefix}-$tmp.fls") { + push @flsfile, "$name-$opts_cmd{string}{prefix}-$tmp.fls"; +} +if (-e "$name-$opts_cmd{string}{prefix}-exa-$tmp.fls") { + push @flsfile, "$name-$opts_cmd{string}{prefix}-exa-$tmp.fls"; +} +if (-e "$opts_cmd{string}{output}.fls") { + push @flsfile, "$opts_cmd{string}{output}.fls"; +} + +### Read .fls file +for my $filename(@flsfile){ + open my $RECtmp, '<', $filename; + push @tmpfiles, grep /^$flsline/,<$RECtmp>; + close $RECtmp; +} +foreach (@tmpfiles) { s/^$flsline\s+|\s+$//g; } +push @tmpfiles, @flsfile; +@tmpfiles = uniq(@tmpfiles); +@tmpfiles = array_minus(@tmpfiles, @protected); + +Log('The files that will be deleted are:'); +Logarray(\@tmpfiles); + +### Remove only if exist +if (@tmpfiles) { + Infoline("Remove temporary files created in $workdir"); + foreach my $tmpfiles (@tmpfiles) { + move($tmpfiles, $tempDir); + } +} + +### Find dirs created by minted +my @deldirs; +my $mintdir = "\_minted\-$name-$opts_cmd{string}{prefix}-$tmp"; +my $mintdirexa = "\_minted\-$name-$opts_cmd{string}{prefix}-exa-$tmp"; +if (-e $mintdir) { push @deldirs, $mintdir; } +if (-e $mintdirexa) { push @deldirs, $mintdirexa; } + +Log('The directory that will be deleted are:'); +Logarray(\@deldirs); + +### Remove only if exist +if (@deldirs) { + Infoline("Remove temporary directories created by minted in $workdir"); + foreach my $deldirs (@deldirs) { + remove_tree($deldirs); + } +} + +### Compress ./images with all generated files +my $archivetar; +if ($opts_cmd{boolean}{zip} or $opts_cmd{boolean}{tar}) { + my $stamp = strftime("%Y-%m-%d", localtime); + $archivetar = "$opts_cmd{string}{imgdir}-$stamp"; + + my @savetozt; + find(\&zip_tar, $opts_cmd{string}{imgdir}); + sub zip_tar{ + my $filesto = $_; + if (-f $filesto && $filesto =~ m/$name-$opts_cmd{string}{prefix}-.+?$/) { # search + push @savetozt, $File::Find::name; + } + return; + } + Log("The files are compress found in $imgdirpath are:"); + Logarray(\@savetozt); + if ($opts_cmd{boolean}{zip}) { + if (-e "$archivetar.zip") { + Infocolor('Warning', "The file [$archivetar.zip] already exists and will be rewritten"); + Log("Rewriting the file $archivetar.zip in $workdir"); + } + else{ + print "Creating the file ", color('magenta'), "[$archivetar.zip]", + color('reset'), " with generate files in ./$opts_cmd{string}{imgdir}\r\n"; + Log("Writen the file $archivetar.tar.gz in $workdir"); + } + zip \@savetozt => "$archivetar.zip"; + } + if ($opts_cmd{boolean}{tar}) { + if (-e "$archivetar.tar.gz") { + Infocolor('Warning', "The file [$archivetar.tar.gz] already exists and will be rewritten"); + Log("Rewriting the file $archivetar.tar.gz in $workdir"); + } + else{ + print "Creating the file ", color('magenta'), "[$archivetar.tar.gz]", + color('reset'), " with generate files in ./$opts_cmd{string}{imgdir}\r\n"; + Log("Writen the file $archivetar.tar.gz in $workdir"); + } + my $imgdirtar = Archive::Tar->new(); + $imgdirtar->add_files(@savetozt); + $imgdirtar->write("$archivetar.tar.gz", 9); + } +} + +### End script process +if (!$opts_cmd{boolean}{norun} and ($opts_cmd{boolean}{srcenv} or $opts_cmd{boolean}{subenv})) { + Log("The image files: $format and generated files are in $imgdirpath"); +} +if (!$opts_cmd{boolean}{norun} and (!$opts_cmd{boolean}{srcenv} and !$opts_cmd{boolean}{subenv})) { + Log("The image files: $format are in $imgdirpath"); +} +if ($opts_cmd{boolean}{norun} and ($opts_cmd{boolean}{srcenv} or $opts_cmd{boolean}{subenv})) { + Log("The generated files are in $imgdirpath"); +} +if ($outfile) { Log("The file $opts_cmd{string}{output}$ext are in $workdir"); } + +Infocolor('Finish', "The execution of $scriptname has been successfully completed"); + +Log("The execution of $scriptname has been successfully completed"); + +__END__ +=encoding UTF-8 + +=head1 NAME + +ltximg - LaTeX environments to image and standalone files + +=head1 SYNOPSIS + +B [EIE] [S<-->] EIE.EI|IE + +=head1 DESCRIPTION + +B automates the process of extracting and converting +environments from LaTeX file to image formats and I files +using I and I. Generates a one file with +only extracted environments and other with all extracted environments +converted to C<\includegraphics>. + +By default the extracted environments are: + +B B B B B B B + +=head1 OPTIONS + +Options that accept a value require either a blank space or C<=> between +the option and the value. Multiple short options can be bundling and +if the last option takes a comma separated list you need C<--> at the end. +Relative or absolute paths for directories and files is not supported. + +If used without [EIE] the extracted environments are converted +to I image format and saved in C<./images> directory using C +and I package for process. + +General script options: + +=over 4 + +=item B<-h>, B<--help> + +Display command line help and exit. + +=item B<-v>, B<--version> + +Display current version and exit. + +=item B<-V>, B<--verbose> + +Verbose printing information. + +=item B<-l>, B<--log> + +Write C<.log> file with debug information. + +=item B<-t>, B<--tif> + +Create C<.tif> files using I. + +=item B<-b>, B<--bmp> + +Create C<.bmp> files using I. + +=item B<-j>, B<--jpg> + +Create C<.jpg> files using I. + +=item B<-p>, B<--png> + +Create C<.png> files using I. + +=item B<-e>, B<--eps> + +Create C<.eps> files using I. + +=item B<-s>, B<--svg> + +Create C<.svg> files using I. + +=item B<-P>, B<--ppm> + +Create C<.ppm> files using I. + +=item B<-g>, B<--gray> + +Gray scale for images using I. + +=item B<-f>, B<--force> + +Capture C<\psset> and C<\tikzset> to extract. + +=item B<-n>, B<--noprew> + +Create images files without I package. + +=item B<-r> I, B<--runs>=I + +Set the number of times the compiler will run on the F file for +environment extraction (default: 1). + +=item B<-d> I, B<--dpi>=I + +Dots per inch resolution for images (default: 150). + +=item B<-m> I, B<--margins>=I + +Set margins in bp for I (default: 0). + +=item B<-o> F, B<--output>=F + +Create F file. + +=item B<--imgdir>=I + +Set name of directory to save images and files (default: images). + +=item B<--prefix>=I + +Set I append to each generated files (default: fig). + +=item B<--myverb>=I + +Add C<\macroname> to verbatim inline search (default: myverb). + +=item B<--clean>=I|I|I|I|I + +Removes specific block text in F file (default: doc). + +=item B<--zip> + +Compress files generated in C<.zip> format. + +=item B<--tar> + +Compress files generated in C<.tar.gz> format. + +=item B<--srcenv> + +Create files with only code of environments. + +=item B<--subenv> + +Create standalone files for environments. + +=item B<--shell> + +Enable C<\write18{SHELL COMMAND}>. + +=item B<--latex> + +Using CdvipsEps2pdf> for compiler F and C for compiler +F. + +=item B<--dvips> + +Using CdvipsEps2pdf> for compiler F and CdvipsEps2pdf> for +compiler F. + +=item B<--dvilua> + +Using CdvipsEps2pdf> for compiler F and C for +compiler F. + +=item B<--dvipdf> + +Using Cdvipdfmx> for compiler F and Cdvipdfmx> for compiler +F. + +=item B<--xetex> + +Using C for compiler F and F. + +=item B<--luatex> + +Using C for compiler F and F. + +=item B<--arara> + +Use C for compiler F and F. + +=item B<--latexmk> + +Using C for compiler F file. + +=item B<--norun> + +Run script, but no create images files. + +=item B<--nopdf> + +Don't create a C<.pdf> image files. + +=item B<--nocrop> + +Don't run I. + +=item B<--extrenv>=I + +Add new environments to extract. + +=item B<--skipenv>=I + +Skip some default environments to extract. + +=item B<--verbenv>=I + +Add new verbatim environments. + +=item B<--writenv>=I + +Add new verbatim write environments. + +=item B<--deltenv>=I + +Delete environments in F file. + +=back + +=head1 EXAMPLE + +B --latex -e -p --subenv -o test-out.ltx test-in.ltx + +Create a C<./images> directory (if it doesn't exist) with all extracted +environments converted to C<.pdf>, C<.eps>, C<.png> and I +files, a file F with all extracted environments +and the file F with all environments converted to +C<\includegraphics> using CdvipsEps2pdf> and I +package for F and C for F. + +=head1 DOCUMENTATION + +For full documentation use: + +texdoc B + +=head1 ISSUES AND REPORTS + +B : L + +B: L + +=head1 AUTHOR + +Pablo González Luengo, I. + +=head1 COPYRIGHT AND LICENSE + +Copyright 2013-2021 Pablo González, I. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +=head1 SEE ALSO + +gs(1), dvips(1), ps2pdf(1), pdfcrop(1), pdftops(1), pdftocairo(1), pdftoppm(1) + +=cut + diff --git a/support/ltximg/script/ltximg.pl b/support/ltximg/script/ltximg.pl deleted file mode 100644 index 7e703a7bf5..0000000000 --- a/support/ltximg/script/ltximg.pl +++ /dev/null @@ -1,3009 +0,0 @@ -#!/usr/bin/env perl -use v5.26; - -############################# LICENCE ################################## -# This program is free software; you can redistribute it and/or modify # -# it under the terms of the GNU General Public License as published by # -# the Free Software Foundation; either version 3 of the License, or # -# (at your option) any later version. # -# # -# This program is distributed in the hope that it will be useful, but # -# WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # -# General Public License for more details. # -######################################################################## - -use Getopt::Long qw(:config bundling_values require_order no_ignore_case); -use File::Spec::Functions qw(catfile devnull); -use File::Basename; -use Archive::Tar; -use Data::Dumper; -use FileHandle; -use IO::Compress::Zip qw(:all); -use File::Path qw(remove_tree); -use File::Temp qw(tempdir); -use POSIX qw(strftime); -use File::Copy; -use File::Find; -use Env qw(PATH); -use autodie; -use Config; -use Cwd; -use if $^O eq 'MSWin32', 'Win32'; -use if $^O eq 'MSWin32', 'Win32::Console::ANSI'; # need for color :) -use Term::ANSIColor; - -### Directory for work and temp files -my $tempDir = tempdir( CLEANUP => 1); -my $workdir = cwd; - -### Script identification -my $scriptname = 'ltximg'; -my $program = 'LTXimg'; -my $nv = 'v1.9'; -my $date = '2020-08-22'; -my $copyright = <<"END_COPYRIGHT" ; -[$date] (c) 2013-2020 by Pablo Gonzalez, pablgonzyahoo.com -END_COPYRIGHT - -my $title = "$program $nv $copyright"; - -### Log vars -my $LogFile = "$scriptname.log"; -my $LogWrite; -my $LogTime = strftime("%y/%m/%d %H:%M:%S", localtime); - -### Default values -my $skiptag = 'noltximg'; # internal tag for regex -my $extrtag = 'ltximg'; # internal tag for regex -my @extr_env_tmp; # save extract environments -my @skip_env_tmp; # save skip environments -my @verb_env_tmp; # save verbatim environments -my @verw_env_tmp; # save verbatim write environments -my @delt_env_tmp; # save delete environments in output file -my @clean; # clean document options -my $outfile = 0; # write output file -my $outsrc = 0; # write standalone files -my $PSTexa = 0; # run extract PSTexample environments -my $STDenv = 0; # run extract standart environments -my $verbose = 0; # verbose info -my $gscmd; # ghostscript executable name -my $write18; # storing write18 for compiler in TeXLive and MikTeX -my $log = 0; # log file -my @currentopt; # storing current options for log file - -### Hash to store options for Getopt::Long and log file -my %opts_cmd; -$opts_cmd{string}{prefix} = 'fig'; -$opts_cmd{string}{dpi} = '150'; -$opts_cmd{string}{runs} = '1'; -$opts_cmd{string}{margin} = '0'; -$opts_cmd{string}{imgdir} = 'images'; -$opts_cmd{string}{myverb} = 'myverb'; -$opts_cmd{clean} = 'doc'; - -### Error in command line -sub errorUsage { - my $msg = shift; - die color('red').'* Error!!: '.color('reset').$msg. - " (run $scriptname --help for more information)\n"; - return; -} - -### Extended error messages -sub exterr { - chomp(my $msg_errno = $!); - chomp(my $msg_extended_os_error = $^E); - if ($msg_errno eq $msg_extended_os_error) { - $msg_errno; - } - else { - "$msg_errno/$msg_extended_os_error"; - } -} - -### Funtion uniq -sub uniq { - my %seen; - return grep !$seen{$_}++, @_; -} - -### Funtion array_minus -sub array_minus(\@\@) { - my %e = map{ $_ => undef } @{$_[1]}; - return grep !exists $e{$_}, @{$_[0]}; -} - -### Funtion to create hash begin -> BEGIN, end -> END -sub crearhash { - my %cambios; - for my $aentra(@_){ - for my $initend (qw(begin end)) { - $cambios{"\\$initend\{$aentra"} = "\\\U$initend\E\{$aentra"; - } - } - return %cambios; -} - -### Print colored info in screen -sub Infocolor { - my $type = shift; - my $info = shift; - if ($type eq 'Running') { - print color('cyan'), '* ', color('reset'), color('green'), - "$type: ", color('reset'), color('cyan'), "$info\r\n", color('reset'); - } - if ($type eq 'Warning') { - print color('bold red'), "* $type: ", color('reset'), - color('yellow'), "$info\r\n", color('reset'); - } - if ($type eq 'Finish') { - print color('cyan'), '* ', color('reset'), color('magenta'), - "$type!: ", color('reset'), color('green'), "$info\r\n",color('reset'); - } - return; -} - -### Write Log line and print msg (common) -sub Infoline { - my $msg = shift; - my $now = strftime("%y/%m/%d %H:%M:%S", localtime); - if ($log) { $LogWrite->print(sprintf "[%s] * %s\n", $now, $msg); } - say $msg; - return; -} - -### Write Log line (no print msg and time stamp) -sub Logline { - my $msg = shift; - if ($log) { $LogWrite->print("$msg\n"); } - return; -} - -### Write Log line (time stamp) -sub Log { - my $msg = shift; - my $now = strftime("%y/%m/%d %H:%M:%S", localtime); - if ($log) { $LogWrite->print(sprintf "[%s] * %s\n", $now, $msg); } - return; -} - -### Write array env in Log -sub Logarray { - my ($env_ref) = @_; - my @env_tmp = @{ $env_ref }; # dereferencing and copying each array - if ($log) { - if (@env_tmp) { - my $tmp = join "\n", map { qq/* $_/ } @env_tmp; - print {$LogWrite} "$tmp\n"; - } - else { - print {$LogWrite} "Not found\n"; - } - } - return; -} - -### Extended print info for execute system commands using $ command -sub Logrun { - my $msg = shift; - my $now = strftime("%y/%m/%d %H:%M:%S", localtime); - if ($log) { $LogWrite->print(sprintf "[%s] \$ %s\n", $now, $msg); } - return; -} - -### Capture and execute system commands -sub RUNOSCMD { - my $cmdname = shift; - my $argcmd = shift; - my $showmsg = shift; - my $captured = "$cmdname $argcmd"; - Logrun($captured); - if ($showmsg eq 'show') { - if ($verbose) { - Infocolor('Running', $captured); - } - else{ Infocolor('Running', $cmdname); } - } - if ($showmsg eq 'only' and $verbose) { - Infocolor('Running', $captured); - } - # Run system system command - $captured = qx{$captured}; - if ($log) { $LogWrite->print($captured); } - if ($? == -1) { - my $errorlog = "* Error!!: ".$cmdname." failed to execute (%s)!\n"; - my $errorprint = "* Error!!: ".color('reset').$cmdname." failed to execute (%s)!\n"; - if ($log) { $LogWrite->print(sprintf $errorlog, exterr); } - print STDERR color('red'); - die sprintf $errorprint, exterr; - } elsif ($? & 127) { - my $errorlog = "* Error!!: ".$cmdname." died with signal %d!\n"; - my $errorprint = "* Error!!: ".color('reset').$cmdname." died with signal %d!\n"; - if ($log) { $LogWrite->print(sprintf $errorlog, ($? & 127)); } - print STDERR color('red'); - die sprintf $errorprint, ($? & 127); - } elsif ($? != 0 ) { - my $errorlog = "* Error!!: ".$cmdname." exited with error code %d!\n"; - my $errorprint = "* Error!!: ".color('reset').$cmdname." exited with error code %d!\n"; - if ($log) { $LogWrite->print(sprintf $errorlog, $? >> 8); } - print STDERR color('red'); - die sprintf $errorprint, $? >> 8; - } - if ($verbose) { print $captured; } - return; -} - -### Help for command line -sub usage { -find_ghostscript(); - -my $usage = <<"END_OF_USAGE"; -${title}Description - LTXimg is a "perl" script that automates the process of extracting and - converting "environments" provided by tikz, pstricks and other packages - from LaTeX file to image formats and "standalone" files using ghostscript - and poppler-utils. Generates a one file with only extracted environments - and other with all extracted environments converted to \\includegraphics. - -Syntax -\$ ltximg [] [--] . - - If used without [] the extracted environments are converted - to pdf image format and saved in "./images" directory using pdflatex - and preview package for process . - -Default environments extract - preview pspicture tikzpicture pgfpicture psgraph postscript PSTexample - -Options - Options that accept a value require either a blank space or = between - the option and the value. Multiple short options can be bundling and - if the last option takes a comma separated list you need -- at the end. - Relative or absolute paths for directories and files is not supported. - - [default] --h, --help Display command line help and exit [off] --v, --version Display current version ($nv) and exit [off] --V, --verbose Verbose printing information [off] --l, --log Write .log file with debug information [off] --t, --tif Create .tif files using ghostscript [$gscmd] --b, --bmp Create .bmp files using ghostscript [$gscmd] --j, --jpg Create .jpg files using ghostscript [$gscmd] --p, --png Create .png files using ghostscript [$gscmd] --e, --eps Create .eps files using poppler-utils [pdftops] --s, --svg Create .svg files using poppler-utils [pdftocairo] --P, --ppm Create .ppm files using poppler-utils [pdftoppm] --g, --gray Gray scale for images using ghostscript [off] --f, --force Capture "\\psset" and "\\tikzset" to extract [off] --n, --noprew Create images files without "preview" package [off] --r , --runs - Set the number of times the compiler will run - on the input file for environment extraction [1] --d , --dpi - Dots per inch resolution for images [150] --m , --margins - Set margins in bp for pdfcrop [0] --o , --output - Create output file [off] ---imgdir Set name of directory to save images/files [images] ---prefix Set prefix append to each generated files [fig] ---myverb Add "\\macroname" to verbatim inline search [myverb] ---clean (doc|pst|tkz|all|off) - Removes specific block text in output file [doc] ---zip Compress files generated in .zip [off] ---tar Compress files generated in .tar.gz [off] ---srcenv Create files with only code of environments [off] ---subenv Create standalone files for environments [off] ---shell Enable \\write18\{SHELL COMMAND\} [off] ---latex Using latex>dvips>ps2pdf for compiler input - and pdflatex for compiler output [off] ---dvips Using latex>dvips>ps2pdf for compiler input - and latex>dvips>ps2pdf for compiler output [off] ---dvilua Using dvilualatex>dvips>ps2pdf for compiler - input and lualatex for compiler output [off] ---dvipdf Using latex>dvipdfmx for compiler input and - latex>dvipdfmx for compiler output [off] ---xetex Using xelatex for compiler input and output [off] ---luatex Using lualatex for compiler input and output [off] ---arara Use arara for compiler input and output [off] ---latexmk Using latexmk for compiler output file [off] ---norun Run script, but no create images files [off] ---nopdf Don't create a ".pdf" image files [off] ---nocrop Don't run pdfcrop [off] ---extrenv Add new environments to extract [empty] ---skipenv Skip some default environments to extract [empty] ---verbenv Add new verbatim environments [empty] ---writenv Add new verbatim write environments [empty] ---deltenv Delete environments in output file [empty] - -Example -\$ ltximg --latex -e -p --subenv --imgdir mypics -o test-out test-in.ltx - - Create a "./mypics" directory (if it doesn't exist) with all extracted - environments converted to images (.pdf, .eps, .png) and standalone files - (.ltx), a file "test-in-fig-all.ltx" with all extracted environments and - the file "test-out.ltx" with all environments converted to \\includegraphics - using latex>dvips>ps2pdf and preview package for and pdflatex - for . - -Documentation -For full documentation use: -\$ texdoc ltximg - -Issues and reports -Repository : https://github.com/pablgonz/ltximg -Bug tracker : https://github.com/pablgonz/ltximg/issues -END_OF_USAGE -print $usage; -exit 0; -} - -### Getopt configuration -my $result=GetOptions ( -# image options - 'b|bmp' => \$opts_cmd{image}{bmp}, # gs - 't|tif' => \$opts_cmd{image}{tif}, # gs - 'j|jpg' => \$opts_cmd{image}{jpg}, # gs - 'p|png' => \$opts_cmd{image}{png}, # gs - 's|svg' => \$opts_cmd{image}{svg}, # pdftocairo - 'e|eps' => \$opts_cmd{image}{eps}, # pdftops - 'P|ppm' => \$opts_cmd{image}{ppm}, # pdftoppm -# compilers - 'arara' => \$opts_cmd{compiler}{arara}, # arara compiler - 'xetex' => \$opts_cmd{compiler}{xetex}, # xelatex compiler - 'latex' => \$opts_cmd{compiler}{latex}, # latex compiler - 'latexmk' => \$opts_cmd{compiler}{latexmk}, # latex compiler - 'dvips' => \$opts_cmd{compiler}{dvips}, # dvips compiler - 'dvipdf' => \$opts_cmd{compiler}{dvipdf}, # dvipdfmx compiler - 'dvilua' => \$opts_cmd{compiler}{dvilua}, # dvilualatex compiler - 'luatex' => \$opts_cmd{compiler}{luatex}, # lualatex compiler -# bolean - 'zip' => \$opts_cmd{boolean}{zip}, # zip images dir - 'tar' => \$opts_cmd{boolean}{tar}, # tar images dir - 'shell' => \$opts_cmd{boolean}{shell}, # set write18 for compiler - 'nopdf' => \$opts_cmd{boolean}{nopdf}, # no pdf image format - 'norun' => \$opts_cmd{boolean}{norun}, # no run compiler - 'nocrop' => \$opts_cmd{boolean}{nocrop}, # no run pdfcrop - 'subenv' => \$opts_cmd{boolean}{subenv}, # subfile environments (bolean) - 'srcenv' => \$opts_cmd{boolean}{srcenv}, # source files (bolean) - 'g|gray' => \$opts_cmd{boolean}{gray}, # gray (boolean) - 'f|force' => \$opts_cmd{boolean}{force}, # force (boolean) - 'n|noprew' => \$opts_cmd{boolean}{noprew}, # no preview (boolean) -# string - 'd|dpi=i' => \$opts_cmd{string}{dpi}, # positive integer < 2500 - 'r|runs=i' => \$opts_cmd{string}{runs}, # positive integer 1,2,3 - 'm|margins=i' => \$opts_cmd{string}{margins}, # integer - 'extrenv=s{1,9}' => \@extr_env_tmp, # extract environments - 'skipenv=s{1,9}' => \@skip_env_tmp, # skip environments - 'verbenv=s{1,9}' => \@verb_env_tmp, # verbatim environments - 'writenv=s{1,9}' => \@verw_env_tmp, # verbatim write environments - 'deltenv=s{1,9}' => \@delt_env_tmp, # delete environments - 'o|output=s{1}' => \$opts_cmd{string}{output}, # output file name (string) - 'imgdir=s{1}' => \$opts_cmd{string}{imgdir}, # images dir name - 'myverb=s{1}' => \$opts_cmd{string}{myverb}, # \myverb inline (string) - 'prefix=s{1}' => \$opts_cmd{string}{prefix}, # prefix - 'clean=s{1}' => \$opts_cmd{clean}, # clean output file -# internal - 'h|help' => \$opts_cmd{internal}{help}, # help - 'v|version' => \$opts_cmd{internal}{version}, # version - 'l|log' => \$log, # write log file - 'V|verbose' => \$verbose, # verbose mode - ) or do { $log = 0 ; die usage(0); }; - -### Open log file -if ($log) { - if (!defined $ARGV[0]) { errorUsage('Input filename missing'); } - my $tempname = $ARGV[0]; - $tempname =~ s/\.(tex|ltx)$//; - if ($LogFile eq "$tempname.log") { $LogFile = "$scriptname-log.log"; } - $LogWrite = FileHandle->new("> $LogFile"); -} - -### Init ltximg.log file -Log("The script $scriptname $nv was started in $workdir"); -Log("Creating the temporary directory $tempDir"); - -### Make ENV safer (perldoc perlsec) -delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; - -### The next code it's part of pdfcrop (adapted from TexLive 2014) -# Windows detection -my $Win = 0; -if ($^O =~ /mswin32/i) { $Win = 1; } - -my $archname = $Config{'archname'}; -$archname = 'unknown' unless defined $Config{'archname'}; - -# Get ghostscript command name -sub find_ghostscript { - if ($log) { - Log('General information about the Perl instalation and operating system'); - print {$LogWrite} "* Perl executable: $^X\n"; - if ($] < 5.006) { - print {$LogWrite} "* Perl version: $]\n"; - } - else { - printf {$LogWrite} "* Perl version: v%vd\n", $^V; - } - if (defined &ActivePerl::BUILD) { - printf {$LogWrite} "* Perl product: ActivePerl, build %s\n", ActivePerl::BUILD(); - } - printf {$LogWrite} "* Pointer size: $Config{'ptrsize'}\n"; - printf {$LogWrite} "* Pipe support: %s\n", - (defined $Config{'d_pipe'} ? 'yes' : 'no'); - printf {$LogWrite} "* Fork support: %s\n", - (defined $Config{'d_fork'} ? 'yes' : 'no'); - } - my $system = 'unix'; - $system = 'win' if $^O =~ /mswin32/i; - $system = 'msys' if $^O =~ /msys/i; - $system = 'cygwin' if $^O =~ /cygwin/i; - $system = 'miktex' if defined $ENV{'TEXSYSTEM'} and - $ENV{'TEXSYSTEM'} =~ /miktex/i; - if ($log) { - print {$LogWrite} "* OS name: $^O\n"; - print {$LogWrite} "* Arch name: $archname\n"; - if ($^O eq 'MSWin32') { - my $tmp = Win32::GetOSName(); - print {$LogWrite} "* System: $tmp\n"; - } - else { print {$LogWrite} "* System: $system\n"; } - } - Log('Trying to locate the executable for Ghostscript'); - my %candidates = ( - 'unix' => [qw|gs|], - 'win' => [qw|gswin32c|], - 'msys' => [qw|gswin64c gswin32c|], - 'cygwin' => [qw|gs|], - 'miktex' => [qw|mgs gswin32c|], - ); - if ($system eq 'win' or $system eq 'miktex') { - if ($archname =~ /mswin32-x64/i) { - my @a = (); - foreach my $name (@{$candidates{$system}}) { - push @a, 'gswin64c' if $name eq 'gswin32c'; - push @a, $name; - } - $candidates{$system} = \@a; - } - } - my %exe = ( - 'unix' => q{}, - 'win' => '.exe', - 'msys' => '.exe', - 'cygwin' => '.exe', - 'miktex' => '.exe', - ); - my $candidates_ref = $candidates{$system}; - my $exe = $Config{'_exe'}; - $exe = $exe{$system} unless defined $exe; - my @path = File::Spec->path(); - my $found = 0; - foreach my $candidate (@$candidates_ref) { - foreach my $dir (@path) { - my $file = File::Spec->catfile($dir, "$candidate$exe"); - if (-x $file) { - $gscmd = $candidate; - $found = 1; - if ($log) { print {$LogWrite} "* Found ($candidate): $file\n"; } - last; - } - if ($log) { print {$LogWrite} "* Not found ($candidate): $file\n"; } - } - last if $found; - } - if (not $found and $Win and $system ne 'msys') { - $found = SearchRegistry(); - } - if (not $found and $system eq 'msys') { - $found = Searchbyregquery(); - } - if ($found) { - if ($log) { print {$LogWrite} "* Autodetected ghostscript command: $gscmd\n"; } - } - else { - $gscmd = $$candidates_ref[0]; - if ($log) { print {$LogWrite} "* Default ghostscript command: $gscmd\n"; } - } -} - -sub SearchRegistry { - my $found = 0; - # The module Win32::TieRegistry not aviable in cygwin/msys - eval 'use Win32::TieRegistry qw|KEY_READ REG_SZ|'; - if ($@) { - if ($log) { - print {$LogWrite} "* Registry lookup for Ghostscript failed:\n"; - my $msg = $@; - $msg =~ s/\s+$//; - foreach (split /\r?\n/, $msg) { - print {$LogWrite} " $_\n"; - } - } - return $found; - } - my $open_params = {Access => KEY_READ(), Delimiter => q{/}}; - my $key_name_software = 'HKEY_LOCAL_MACHINE/SOFTWARE/'; - my $current_key = $key_name_software; - my $software = new Win32::TieRegistry $current_key, $open_params; - if (not $software) { - if ($log) { - print {$LogWrite} "* Cannot find or access registry key `$current_key'!\n"; - } - return $found; - } - if ($log) { print {$LogWrite} "* Search registry at `$current_key'.\n"; } - my %list; - foreach my $key_name_gs (grep /Ghostscript/i, $software->SubKeyNames()) { - $current_key = "$key_name_software$key_name_gs/"; - if ($log) { print {$LogWrite} "* Registry entry found: $current_key\n"; } - my $key_gs = $software->Open($key_name_gs, $open_params); - if (not $key_gs) { - if ($log) { print {$LogWrite} "* Cannot open registry key `$current_key'!\n"; } - next; - } - foreach my $key_name_version ($key_gs->SubKeyNames()) { - $current_key = "$key_name_software$key_name_gs/$key_name_version/"; - if ($log) { print {$LogWrite} "* Registry entry found: $current_key\n"; } - if (not $key_name_version =~ /^(\d+)\.(\d+)$/) { - if ($log) { print {$LogWrite} " The sub key is not a version number!\n"; } - next; - } - my $version_main = $1; - my $version_sub = $2; - $current_key = "$key_name_software$key_name_gs/$key_name_version/"; - my $key_version = $key_gs->Open($key_name_version, $open_params); - if (not $key_version) { - if ($log) { print {$LogWrite} "* Cannot open registry key `$current_key'!\n"; } - next; - } - $key_version->FixSzNulls(1); - my ($value, $type) = $key_version->GetValue('GS_DLL'); - if ($value and $type == REG_SZ()) { - if ($log) { print {$LogWrite} " GS_DLL = $value\n"; } - $value =~ s|([\\/])([^\\/]+\.dll)$|$1gswin32c.exe|i; - my $value64 = $value; - $value64 =~ s/gswin32c\.exe$/gswin64c.exe/; - if ($archname =~ /mswin32-x64/i and -f $value64) { - $value = $value64; - } - if (-f $value) { - if ($log) { print {$LogWrite} "EXE found: $value\n"; } - } - else { - if ($log) { print {$LogWrite} "EXE not found!\n"; } - next; - } - my $sortkey = sprintf '%02d.%03d %s', - $version_main, $version_sub, $key_name_gs; - $list{$sortkey} = $value; - } - else { - if ($log) { print {$LogWrite} "Missing key `GS_DLL' with type `REG_SZ'!\n"; } - } - } - } - foreach my $entry (reverse sort keys %list) { - $gscmd = $list{$entry}; - if ($log) { print {$LogWrite} "* Found (via registry): $gscmd\n"; } - $found = 1; - last; - } - return $found; -} # end GS search registry - -### This part is only necessary if you're using Git on windows and don't -### have gs configured in PATH. Git for windows don't have a Win32::TieRegistry -### module for perl (is not supported in the current versions of msys). -sub Searchbyregquery { - my $found = 0; - my $gs_regkey; - my $opt_reg = '//s //v'; - if ($log) { print {$LogWrite} "* Search Ghostscript in Windows registry under mingw/msys:\n";} - $gs_regkey = qx{reg query "HKLM\\Software\\GPL Ghostscript" $opt_reg GS_DLL}; - if ($? == 0) { - if ($log) { print {$LogWrite} "* Registry entry found for GS_DLL (64 bits version)\n";} - } - else { - $gs_regkey = qx{reg query "HKLM\\Software\\Wow6432Node\\GPL Ghostscript" $opt_reg GS_DLL}; - if ($? == 0) { - if ($log) { print {$LogWrite} "* Registry entry found for GS_DLL (32 bits version)\n";} - } - } - my ($gs_find) = $gs_regkey =~ m/(?:\s* GS_DLL \s* REG_SZ \s*) (.+?)(?:\.dll.+?\R)/s; - if ($gs_find) { - my ($gs_vol, $gs_path, $gs_ver) = $gs_find =~ m/ - (\w{1})(?:\:) # volumen - (.+?) # path to executable - (?:\\gsdll) # LIB - (\d{2}) # Version - /xs; - # Adjust - $gs_vol = lc($gs_vol); - $gs_path = '/'.$gs_vol.$gs_path; - $gs_path =~ s|\\|/|gmsxi; - # Add to PATH - if ($log) { print {$LogWrite} "* Add $gs_path to PATH for current session\n"; } - $PATH .= ":$gs_path"; - # Set executable - $gscmd = 'gswin'.$gs_ver.'c'; - if ($log) { print {$LogWrite} "* Found (via reg query): $gscmd\n"; } - $found = 1; - } - if ($@) { - if ($log) { - print {$LogWrite} "* Registry lookup for Ghostscript by reg query failed:\n"; - my $msg = $@; - $msg =~ s/\s+$//; - foreach (split /\r?\n/, $msg) { - print {$LogWrite} " $_\n"; - } - } - return $found; - } - return $found; -} - -### Call GS -find_ghostscript(); - -### Windows need suport space in path -if ($Win and $gscmd =~ /\s/) { $gscmd = "\"$gscmd\"";} - -### Help -if (defined $opts_cmd{internal}{help}) { - usage(1); - exit 0; -} - -### Version -if (defined $opts_cmd{internal}{version}) { - print $title; - exit 0; -} - -### Check from command line -@ARGV > 0 or errorUsage('Input filename missing'); -@ARGV < 2 or errorUsage('Unknown option or too many input files'); - -### Check extention -my @SuffixList = ('.tex', '.ltx'); -my ($name, $path, $ext) = fileparse($ARGV[0], @SuffixList); -if ($ext eq '.tex' or $ext eq '.ltx') { - $ext = $ext; -} -else { - errorUsage('Invalid or empty extention for input file'); -} - -### Read in memory, need [:crlf] for old windows files -Log("Read input file $name$ext in memory"); -open my $INPUTfile, '<:crlf', "$name$ext"; - my $ltxfile; - { - local $/; - $ltxfile = <$INPUTfile>; - } -close $INPUTfile; - -### Set tmp random number for and others -my $tmp = int(rand(10000)); - -### Identification message in terminal -print $title; - -### Remove white space and '=' in array captured from command line -s/^\s*(\=):?|\s*//mg foreach @extr_env_tmp; -s/^\s*(\=):?|\s*//mg foreach @skip_env_tmp; -s/^\s*(\=):?|\s*//mg foreach @verb_env_tmp; -s/^\s*(\=):?|\s*//mg foreach @verw_env_tmp; -s/^\s*(\=):?|\s*//mg foreach @delt_env_tmp; - -### Split comma separte list options from command line -@extr_env_tmp = split /,/,join q{},@extr_env_tmp; -@skip_env_tmp = split /,/,join q{},@skip_env_tmp; -@verb_env_tmp = split /,/,join q{},@verb_env_tmp; -@verw_env_tmp = split /,/,join q{},@verw_env_tmp; -@delt_env_tmp = split /,/,join q{},@delt_env_tmp; - -### Validate environments options from comand line -if (grep /(^\-|^\.).*?/, @extr_env_tmp) { - Log('Error!!: Invalid argument for --extrenv, some argument from list begin with -'); - errorUsage('Invalid argument for --extrenv option'); -} -if (grep /(^\-|^\.).*?/, @skip_env_tmp) { - Log('Error!!: Invalid argument for --skipenv, some argument from list begin with -'); - errorUsage('Invalid argument for --skipenv option'); -} -if (grep /(^\-|^\.).*?/, @verb_env_tmp) { - Log('Error!!: Invalid argument for --verbenv, some argument from list begin with -'); - errorUsage('Invalid argument for --verbenv option'); -} -if (grep /(^\-|^\.).*?/, @verw_env_tmp) { - Log('Error!!: Invalid argument for --writenv, some argument from list begin with -'); - errorUsage('Invalid argument for --writenv option'); -} -if (grep /(^\-|^\.).*?/, @delt_env_tmp) { - Log('Error!!: Invalid argument for --deltenv, some argument from list begin with -'); - errorUsage('Invalid argument for --deltenv option'); -} - -### Default environment to extract -my @extr_tmp = qw ( - preview postscript tikzpicture pgfpicture pspicture psgraph PSTexample - ); -push @extr_env_tmp, @extr_tmp; - -### Default verbatim environment -my @verb_tmp = qw ( - Example CenterExample SideBySideExample PCenterExample PSideBySideExample - verbatim Verbatim BVerbatim LVerbatim SaveVerbatim PSTcode - LTXexample tcblisting spverbatim minted listing lstlisting - alltt comment chklisting verbatimtab listingcont boxedverbatim - demo sourcecode xcomment pygmented pyglist program programl - programL programs programf programsc programt - ); -push @verb_env_tmp, @verb_tmp; - -### Default verbatim write environment -my @verbw_tmp = qw ( - scontents filecontents tcboutputlisting tcbexternal tcbwritetmp extcolorbox extikzpicture - VerbatimOut verbatimwrite filecontentsdef filecontentshere filecontentsdefmacro - filecontentsdefstarred filecontentsgdef filecontentsdefmacro filecontentsgdefmacro - ); -push @verw_env_tmp, @verbw_tmp; - -######################################################################## -# One problem that can arise is the filecontents environment, this can # -# contain a complete document and be anywhere, before dividing we will # -# make some replacements for this and comment lines # -######################################################################## - -### Create a Regex for verbatim write environment -@verw_env_tmp = uniq(@verw_env_tmp); -my $tmpverbw = join q{|}, map { quotemeta } sort { length $a <=> length $b } @verw_env_tmp; -$tmpverbw = qr/$tmpverbw/x; -my $tmp_verbw = qr { - ( - (?: - \\begin\{$tmpverbw\*?\} - (?: - (?>[^\\]+)| - \\ - (?!begin\{$tmpverbw\*?\}) - (?!end\{$tmpverbw\*?\})| - (?-1) - )* - \\end\{$tmpverbw\*?\} - ) - ) - }x; - -### A pre-regex for comment lines -my $tmpcomment = qr/^ \s* \%+ .+? $ /mx; - -### Hash for replace in verbatim's and comment lines -my %document = ( - '\begin{document}' => '\BEGIN{document}', - '\end{document}' => '\END{document}', - '\documentclass' => '\DOCUMENTCLASS', - '\pagestyle{' => '\PAGESTYLE{', - '\thispagestyle{' => '\THISPAGESTYLE{', - ); - -### Changes in for verbatim write and comment lines -while ($ltxfile =~ / $tmp_verbw | $tmpcomment /pgmx) { - my ($pos_inicial, $pos_final) = ($-[0], $+[0]); - my $encontrado = ${^MATCH}; - while (my($busco, $cambio) = each %document) { - $encontrado =~ s/\Q$busco\E/$cambio/g; - } - substr $ltxfile, $pos_inicial, $pos_final-$pos_inicial, $encontrado; - pos ($ltxfile) = $pos_inicial + length $encontrado; -} - -### Now, split input file in $atbegindoc and contain % ltximg : -my ($atbegindoc, $document) = $ltxfile =~ m/\A (\s* .*? \s*) (\\documentclass.*)\z/msx; - -### Capture options in preamble of -# % ltximg : extrenv : {extrenv1, extrenv2, ... , extrenvn} -# % ltximg : skipenv : {skipenv1, skipenv2, ... , skipenvn} -# % ltximg : verbenv : {verbwrt1, verbwrt2, ... , verbwrtn} -# % ltximg : writenv : {verbwrt1, verbwrt2, ... , verbwrtn} -# % ltximg : deltenv : {deltenv1, deltenv2, ... , deltenvn} -# % ltximg : options : {opt1=arg, opt2=arg, ... , booleans} - -my $readoptfile = qr/ - ^ %+ \s* ltximg (?&SEPARADOR) (?(?&CLAVE)) (?&SEPARADOR) \{ (?(?&ARGUMENTOS)) \} - (?(DEFINE) - (? \w+ ) - (? .+? ) - (? \s* : \s* ) - ) -/mx; - -### Search options in and store in %opts_file -my %opts_file; -while ($atbegindoc =~ /$readoptfile/g) { - my ($clave, $argumentos) = @+{qw(clave argumentos)}; - my @argumentos = split /\s*,\s*?/, $argumentos; - for (@argumentos) { s/^ \s* | \s* $//gx; } - if ($clave eq 'options') { - for my $argumento (@argumentos) { - if ($argumento =~ /(?\S+) \s* = \s* (?\S+)/x) { - $opts_file{$clave}{$+{'key'}} = $+{'valor'}; - } - else { - $opts_file{$clave}{$argumento} = 1; - } - } - } - else { - push @{ $opts_file{ $clave } }, @argumentos; - } -} - -### Process options from -if(%opts_file) { - Infocolor('Warning', "Found options for script in $name$ext"); - # Search and extract options from - Log("Searching options for script in $name$ext"); - if (exists $opts_file{extrenv}) { - Log("Found \% ltximg\: extrenv\: \{...\} in $name$ext"); - if (grep /(^\-|^\.).*?/, @{$opts_file{extrenv}}) { - Log('Error!!: Invalid argument for % ltximg: extrenv: {...}, some argument from list begin with -'); - errorUsage('Invalid argument in % ltximg: extrenv: {...}'); - } - Logarray(\@{$opts_file{extrenv}}); - push @extr_env_tmp, @{$opts_file{extrenv}}; - } - # Add skipenv options from - if (exists $opts_file{skipenv}) { - Log("Found \% ltximg\: skipenv\: \{...\} in $name$ext"); - if (grep /(^\-|^\.).*?/, @{$opts_file{skipenv}}) { - Log('Error!!: Invalid argument for % ltximg: skipenv: {...}, some argument from list begin with -'); - errorUsage('Invalid argument in % ltximg: skipenv: {...}'); - } - Logarray(\@{$opts_file{skipenv}}); - push @skip_env_tmp, @{$opts_file{skipenv}}; - } - # Add verbenv options from - if (exists $opts_file{verbenv}) { - Log("Found \% ltximg\: verbenv\: \{...} in $name$ext"); - if (grep /(^\-|^\.).*?/, @{$opts_file{verbenv}}) { - Log('Error!!: Invalid argument for % ltximg: verbenv: {...}, some argument from list begin with -'); - errorUsage('Invalid argument in % ltximg: verbenv: {...}'); - } - Logarray(\@{ $opts_file{verbenv}}); - push @verb_env_tmp, @{$opts_file{verbenv}}; - } - # Add writenv options from - if (exists $opts_file{writenv}) { - Log("Found \% ltximg\: writenv\: \{...\} in $name$ext"); - if (grep /(^\-|^\.).*?/, @{ $opts_file{writenv}}) { - Log('Error!!: Invalid argument for % ltximg: writenv: {...}, some argument from list begin with -'); - errorUsage('Invalid argument in % ltximg: writenv: {...}'); - } - Logarray(\@{ $opts_file{writenv}}); - push @verw_env_tmp, @{$opts_file{writenv}}; - } - # Add deltenv options from - if (exists $opts_file{deltenv}) { - Log("Found \% ltximg\: deltenv\: \{...\} in $name$ext"); - if (grep /(^\-|^\.).*?/, @{$opts_file{deltenv}}) { - Log('Error!!: Invalid argument for % ltximg: deltenv: {...}, some argument from list begin with -'); - errorUsage('Invalid argument in % ltximg: deltenv: {...}'); - } - Logarray(\@{ $opts_file{deltenv}}); - push @delt_env_tmp, @{$opts_file{deltenv}}; - } - # Add all other options from - if (exists $opts_file{options}) { - Log("Found \% ltximg\: options\: \{...\} in $name$ext"); - # Add compilers from - for my $opt (qw(arara xetex luatex latex dvips dvipdf dvilua latexmk)) { - if (exists $opts_file{options}{$opt}) { - Log("Found [$opt] compiler option in $name$ext"); - $opts_cmd{compiler}{$opt} = 1; - } - } - # Add image options - for my $opt (qw(eps ppm svg png jpg bmp tif)) { - if (exists $opts_file{options}{$opt}) { - Log("Found [$opt] image option in $name$ext"); - $opts_cmd{image}{$opt} = 1; - } - } - # Add boolean options - for my $opt (qw(shell nopdf norun nocrop srcenv subenv zip tar gray force noprew)) { - if (exists $opts_file{options}{$opt}) { - Log("Found [$opt] option in $name$ext"); - $opts_cmd{boolean}{$opt} = 1; - } - } - # Add string options - for my $opt (qw(dpi myverb margins prefix imgdir output runs)) { - if (exists $opts_file{options}{$opt}) { - Log("Found [$opt = $opts_file{options}{$opt}] in $name$ext"); - $opts_cmd{string}{$opt} = $opts_file{options}{$opt}; - } - } - # Add clean option - for my $opt (qw(doc off pst tkz all)) { - if ($opts_file{options}{clean} eq "$opt" ) { - Log("Found [clean = $opt] in $name$ext"); - $opts_cmd{clean} = $opt; - } - } - } -} - -### Validate --dpi -if( $opts_cmd{string}{dpi} <= 0 or $opts_cmd{string}{dpi} >= 2500) { - Log('Error!!: Invalid argument for --dpi, argument out of range'); - errorUsage('Invalid argument for --dpi option'); -} - -### Validate --runs -if( $opts_cmd{string}{runs} <= 0 or $opts_cmd{string}{runs} >= 3) { - Log('Error!!: Invalid argument for --runs, argument out of range'); - errorUsage('Invalid argument for --runs option'); -} - -### Check --arara and others compilers -if ($opts_cmd{compiler}{arara}) { - # Search others compilers options - for my $opt (qw(xetex luatex latex dvips dvipdf dvilua latexmk)) { - if (defined $opts_cmd{compiler}{$opt}) { - Log("Error!!: Options --arara and --$opt are mutually exclusive"); - errorUsage("Options --arara and --$opt are mutually exclusive"); - } - } -} - -### Check --srcenv and --subenv option -if ($opts_cmd{boolean}{srcenv} && $opts_cmd{boolean}{subenv}) { - Log('Error!!: Options --srcenv and --subenv are mutually exclusive'); - errorUsage('Options --srcenv and --subenv are mutually exclusive'); -} - -### If --srcenv or --subenv option are OK activate write -if ($opts_cmd{boolean}{srcenv}) { - $outsrc = 1; - $opts_cmd{boolean}{subenv} = undef; -} -if ($opts_cmd{boolean}{subenv}) { - $outsrc = 1; - $opts_cmd{boolean}{srcenv} = undef; -} - -### Add pdf image format if --nopdf -if (!$opts_cmd{boolean}{nopdf}) { - $opts_cmd{image}{pdf} = 1; -} - -### Store defined image formats in $format -my $format = join q{, },grep { defined $opts_cmd{image}{$_} } keys %{$opts_cmd{image}}; - -### Write defined image format in log file -if (!$opts_cmd{boolean}{norun}) { - Log("Defined image formats for creating: $format"); -} - -### Check --norun and no images type -if (!$opts_cmd{boolean}{norun} and $format eq q{}) { - Log('Error!!: Option --nopdf need --norun or an image option'); - errorUsage('Option --nopdf need --norun or an image option'); -} - -### Check --dvips and no eps image type -if ($opts_cmd{compiler}{dvips} and !$opts_cmd{image}{eps} and !$opts_cmd{boolean}{norun}) { - Log('Error!!: Option --dvips need --eps'); - errorUsage('Option --dvips need --eps'); -} - -### Validate myverb = macro option -if (defined $opts_cmd{string}{myverb}) { - if ($opts_cmd{string}{myverb} =~ /^(?:\\|\-).+?/) { - Log('Error!!: Invalid argument for --myverb option, argument begin with - or \ '); - errorUsage('Invalid argument for --myverb'); - } - else { Log("Set myverb = $opts_cmd{string}{myverb}"); } -} - -### Validate imgdir = string option -if (defined $opts_cmd{string}{imgdir}) { - if ($opts_cmd{string}{imgdir} =~ /^(?:\\|\-).+?/) { - Log('Error!!: Invalid argument for --imgdir option, argument begin with -, \ or /'); - errorUsage('Invalid argument for --imgdir'); - } - else { Log("Set imgdir = $opts_cmd{string}{imgdir}"); } -} - -### Validate clean -my %clean = map { $_ => 1 } @clean; -$clean{doc} = 1; # by default clean = doc - -### Pass $opts_cmd{clean} to $clean{$opt} -for my $opt (qw(doc off pst tkz all)) { - if ($opts_cmd{clean} eq "$opt") { - $clean{$opt} = 1; - push @currentopt, "--clean=$opt"; - } -} - -### Activate clean options for script -if ($clean{pst} or $clean{tkz}) { $clean{doc} = 1; } -if ($clean{all}) { @clean{qw(pst doc tkz)} = (1) x 3; } -if ($clean{off}) { undef %clean; } - -### Validating the name and save extension -my $outext; -if (defined $opts_cmd{string}{output}) { - Log('Validating name and extension for output file'); - # Capture and split - my ($outname, $outpath, $tmpext) = fileparse($opts_cmd{string}{output}, @SuffixList); - if ($outname =~ /(^\-|^\.).*?/) { - Log('The name of output file begin with dash -'); - errorUsage("$opts_cmd{string}{output} it is not a valid name for output file"); - } - if ($tmpext eq q{}) { # Check and set extension - Log("Set extension for output file to $ext"); - $outext = $ext; - } - else { - Log("Set extension for output file to $tmpext"); - $outext = $tmpext; - } - if ($outname eq $name) { # Check name - Log("The name of the output file must be different that $name"); - Infoline("Changing the output file name to $name-out"); - $opts_cmd{string}{output} = "$name-out"; - } - else { - Log("Set name of the output file to $outname"); - $opts_cmd{string}{output} = $outname; - } - # If output name are ok, then $outfile = 1 - $outfile = 1; -} - -### Storing the current options of script in array for ltximg.log file -my @allopt = qw (arara xetex luatex latex dvips dvipdf dvilua latexmk - shell nopdf norun nocrop srcenv subenv zip tar gray force - noprew eps ppm svg png jpg bmp tif dpi myverb margins - prefix imgdir output runs - ); - -for my $opt (@allopt) { - if (defined $opts_cmd{boolean}{$opt}) { - push @currentopt, "--$opt"; - } - if (defined $opts_cmd{compiler}{$opt}) { - push @currentopt, "--$opt"; - } - if (defined $opts_cmd{image}{$opt}) { - push @currentopt, "--$opt"; - } - if (defined $opts_cmd{string}{$opt}) { - push @currentopt, "--$opt=$opts_cmd{string}{$opt}" - } -} - -### Write all options in ltximg.log file -@currentopt = sort { length $a <=> length $b } @currentopt; -Log('The script will execute the following options:'); -Logarray(\@currentopt); - -### Rules to capture for regex -my $braces = qr/ (?:\{)(.+?)(?:\}) /msx; -my $braquet = qr/ (?:\[)(.+?)(?:\]) /msx; -my $no_corchete = qr/ (?:\[ .*? \])? /msx; - -### Array for capture new verbatim environments defined in input file -my @new_verb = qw ( - newtcblisting DeclareTCBListing ProvideTCBListing NewTCBListing - lstnewenvironment NewListingEnvironment NewProgram specialcomment - includecomment DefineVerbatimEnvironment newverbatim newtabverbatim - ); - -### Regex to capture names for new verbatim environments from input file -my $newverbenv = join q{|}, map { quotemeta} sort { length $a <=> length $b } @new_verb; -$newverbenv = qr/\b(?:$newverbenv) $no_corchete $braces/msx; - -### Array for capture new verbatim write environments defined in input file -my @new_verb_write = qw ( - renewtcbexternalizetcolorbox renewtcbexternalizeenvironment - newtcbexternalizeenvironment newtcbexternalizetcolorbox newenvsc - ); - -### Regex to capture names for new verbatim write environments from input file -my $newverbwrt = join q{|}, map { quotemeta} sort { length $a <=> length $b } @new_verb_write; -$newverbwrt = qr/\b(?:$newverbwrt) $no_corchete $braces/msx; - -### Regex to capture MINTED related environments -my $mintdenv = qr/\\ newminted $braces (?:\{.+?\}) /x; -my $mintcenv = qr/\\ newminted $braquet (?:\{.+?\}) /x; -my $mintdshrt = qr/\\ newmint $braces (?:\{.+?\}) /x; -my $mintcshrt = qr/\\ newmint $braquet (?:\{.+?\}) /x; -my $mintdline = qr/\\ newmintinline $braces (?:\{.+?\}) /x; -my $mintcline = qr/\\ newmintinline $braquet (?:\{.+?\}) /x; - -### Filter input file, now $ltxfile is pass to $filecheck -Log("Filter $name$ext \(remove % and comments\)"); -my @filecheck = $ltxfile; -s/%.*\n//mg foreach @filecheck; # del comments -s/^\s*|\s*//mg foreach @filecheck; # del white space -my $filecheck = join q{}, @filecheck; - -### Search verbatim and verbatim write environments -Log("Search verbatim and verbatim write environments in $name$ext"); - -### Search new verbatim write names in -my @newv_write = $filecheck =~ m/$newverbwrt/xg; -if (@newv_write) { - Log("Found new verbatim write environments in $name$ext"); - Logarray(\@newv_write); - push @verw_env_tmp, @newv_write; -} - -### Search new verbatim environments in (for) -my @verb_input = $filecheck =~ m/$newverbenv/xg; -if (@verb_input) { - Log("Found new verbatim environments in $name$ext"); - Logarray(\@verb_input); - push @verb_env_tmp, @verb_input; -} - -### Search \newminted{$mintdenv}{options} in , need add "code" (for) -my @mint_denv = $filecheck =~ m/$mintdenv/xg; -if (@mint_denv) { - Log("Found \\newminted\{envname\} in $name$ext"); - # Append "code" - $mintdenv = join "\n", map { qq/$_\Qcode\E/ } @mint_denv; - @mint_denv = split /\n/, $mintdenv; - Logarray(\@mint_denv); - push @verb_env_tmp, @mint_denv; -} - -### Search \newminted[$mintcenv]{lang} in (for) -my @mint_cenv = $filecheck =~ m/$mintcenv/xg; -if (@mint_cenv) { - Log("Found \\newminted\[envname\] in $name$ext"); - Logarray(\@mint_cenv); - push @verb_env_tmp, @mint_cenv; -} - -### Remove repetead again :) -@verb_env_tmp = uniq(@verb_env_tmp); - -### Capture verbatim inline macros in input file -Log("Search verbatim macros in $name$ext"); - -### Store all minted inline/short in @mintline -my @mintline; - -### Search \newmint{$mintdshrt}{options} in (while) -my @mint_dshrt = $filecheck =~ m/$mintdshrt/xg; -if (@mint_dshrt) { - Log("Found \\newmint\{macroname\} (short) in $name$ext"); - Logarray(\@mint_dshrt); - push @mintline, @mint_dshrt; -} - -### Search \newmint[$mintcshrt]{lang}{options} in (while) -my @mint_cshrt = $filecheck =~ m/$mintcshrt/xg; -if (@mint_cshrt) { - Log("Found \\newmint\[macroname\] (short) in $name$ext"); - Logarray(\@mint_cshrt); - push @mintline, @mint_cshrt; -} - -### Search \newmintinline{$mintdline}{options} in (while) -my @mint_dline = $filecheck =~ m/$mintdline/xg; -if (@mint_dline) { - Log("Found \\newmintinline\{macroname\} in $name$ext"); - # Append "inline" - $mintdline = join "\n", map { qq/$_\Qinline\E/ } @mint_dline; - @mint_dline = split /\n/, $mintdline; - Logarray(\@mint_dline); - push @mintline, @mint_dline; -} - -### Search \newmintinline[$mintcline]{lang}{options} in (while) -my @mint_cline = $filecheck =~ m/$mintcline/xg; -if (@mint_cline) { - Log("Found \\newmintinline\[macroname\] in $name$ext"); - Logarray(\@mint_cline); - push @mintline, @mint_cline; -} - -### Add standart mint, mintinline and lstinline -my @mint_tmp = qw(mint mintinline lstinline); - -### Join all inline verbatim macros captured -push @mintline, @mint_tmp; -@mintline = uniq(@mintline); - -### Create a regex using @mintline -my $mintline = join q{|}, map { quotemeta } sort { length $a <=> length $b } @mintline; -$mintline = qr/\b(?:$mintline)/x; - -### Reserved words in verbatim inline (while) -my %changes_in = ( - '%<*ltximg>' => '%<*LTXIMG>', - '%' => '%', - '%<*noltximg>' => '%<*NOLTXIMG>', - '%' => '%', - '%<*remove>' => '%<*REMOVE>', - '%' => '%', - '\psset' => '\PSSET', - '\tikzset' => '\TIKZSET', - '\pspicture' => '\TRICKS', - '\endpspicture' => '\ENDTRICKS', - '\pgfpicture' => '\PGFTRICKS', - '\endpgfpicture' => '\ENDPGFTRICKS', - '\tikzpicture' => '\TKZTRICKS', - '\endtikzpicture' => '\ENDTKZTRICKS', - '\psgraph' => '\PSGRAPHTRICKS', - '\endpsgraph' => '\ENDPSGRAPHTRICKS', - '\usepackage' => '\USEPACKAGE', - '{graphicx}' => '{GRAPHICX}', - '\graphicspath{' => '\GRAPHICSPATH{', - ); - -### Hash to replace \begin and \end in verbatim inline -my %init_end = ( - '\begin{' => '\BEGIN{', - '\end{' => '\END{', - ); - -### Join changes in new hash (while) for verbatim inline -my %cambios = (%changes_in,%init_end); - -### Variables and constantes -my $no_del = "\0"; -my $del = $no_del; - -### Rules -my $llaves = qr/\{ .+? \} /x; -my $no_llaves = qr/(?: $llaves )? /x; -my $corchetes = qr/\[ .+? \] /x; -my $delimitador = qr/\{ (?.+?) \} /x; -my $scontents = qr/Scontents [*]? $no_corchete /ix; -my $verb = qr/(?:((spv|(?:q|f)?v|V)erb|$opts_cmd{string}{myverb})[*]?) /ix; -my $lst = qr/(?:(lst|pyg)inline)(?!\*) $no_corchete /ix; -my $mint = qr/(?: $mintline |SaveVerb) (?!\*) $no_corchete $no_llaves $llaves /ix; -my $no_mint = qr/(?: $mintline) (?!\*) $no_corchete /ix; -my $marca = qr/\\ (?:$verb | $lst |$scontents | $mint |$no_mint) (?:\s*)? (\S) .+? \g{-1} /sx; -my $comentario = qr/^ \s* \%+ .+? $ /mx; -my $definedel = qr/\\ (?: DefineShortVerb | lstMakeShortInline| MakeSpecialShortVerb ) [*]? $no_corchete $delimitador /ix; -my $indefinedel = qr/\\ (?: (Undefine|Delete)ShortVerb | lstDeleteShortInline) $llaves /ix; - -Log('Making changes to inline/multiline verbatim before extraction'); - -### Changes in input file for verbatim inline/multiline -while ($document =~ - / $marca - | $comentario - | $definedel - | $indefinedel - | $del .+? $del - /pgmx) { - my ($pos_inicial, $pos_final) = ($-[0], $+[0]); - my $encontrado = ${^MATCH}; - if ($encontrado =~ /$definedel/) { - $del = $+{del}; - $del = "\Q$+{del}" if substr($del,0,1) ne '\\'; - } - elsif ($encontrado =~ /$indefinedel/) { - $del = $no_del; - } - else { - while (my($busco, $cambio) = each %cambios) { - $encontrado =~ s/\Q$busco\E/$cambio/g; - } - substr $document, $pos_inicial, $pos_final-$pos_inicial, $encontrado; - pos ($document) = $pos_inicial + length $encontrado; - } -} - -### Change "escaped braces" to (this label is not the one in the document) -$document =~ s/\\[{]//g; -$document =~ s/\\[}]//g; - -### Regex for verbatim inline/multiline with braces {...} -my $nestedbr = qr / ( [{] (?: [^{}]++ | (?-1) )*+ [}] ) /x; -my $fvextra = qr /\\ (?: (Save|Esc)Verb [*]?) $no_corchete /x; -my $mintedbr = qr /\\ (?:$mintline|pygment) (?!\*) $no_corchete $no_llaves /x; -my $tcbxverb = qr /\\ (?: tcboxverb [*]?| Scontents [*]? |$opts_cmd{string}{myverb} [*]?|lstinline) $no_corchete /x; -my $verb_brace = qr / (?:$tcbxverb|$mintedbr|$fvextra) (?:\s*)? $nestedbr /x; - -### Change \verb*{code} for verbatim inline/multiline -while ($document =~ /$verb_brace/pgmx) { - my ($pos_inicial, $pos_final) = ($-[0], $+[0]); - my $encontrado = ${^MATCH}; - while (my($busco, $cambio) = each %cambios) { - $encontrado =~ s/\Q$busco\E/$cambio/g; - } - substr $document, $pos_inicial, $pos_final-$pos_inicial, $encontrado; - pos ($document) = $pos_inicial + length $encontrado; -} - -### We recovered the escaped braces -$document =~ s//\\{/g; -$document =~ s//\\}/g; - -### Reverse changes for extract and output file -my %changes_out = ( - '\PSSET' => '\psset', - '\TIKZSET' => '\tikzset', - '\TRICKS' => '\pspicture', - '\ENDTRICKS' => '\endpspicture', - '\PGFTRICKS' => '\pgfpicture', - '\ENDPGFTRICKS' => '\endpgfpicture', - '\TKZTRICKS' => '\tikzpicture', - '\ENDTKZTRICKS' => '\endtikzpicture', - '\PSGRAPHTRICKS' => '\psgraph', - '\ENDPSGRAPHTRICKS' => '\endpsgraph', - '\USEPACKAGE' => '\usepackage', - '{GRAPHICX}' => '{graphicx}', - '\GRAPHICSPATH{' => '\graphicspath{', - '\BEGIN{' => '\begin{', - '\END{' => '\end{', - '\DOCUMENTCLASS' => '\documentclass', - '\PAGESTYLE{' => '\pagestyle{', - '\THISPAGESTYLE{' => '\thispagestyle{', - ); - -### Reverse tags, need back in all file to extract -my %reverse_tag = ( - '%<*LTXIMG>' => '%<*ltximg>', - '%' => '%', - '%<*NOLTXIMG>' => '%<*noltximg>', - '%' => '%', - '%<*REMOVE>' => '%<*remove>', - '%' => '%', - ); - -### First we do some security checks to ensure that they are verbatim and -### verbatim write environments are unique and disjointed -@verb_env_tmp = array_minus(@verb_env_tmp, @verw_env_tmp); #disjointed -my @verbatim = uniq(@verb_env_tmp); -my %verbatim = crearhash(@verbatim); - -Log('The environments that are considered verbatim:'); -Logarray(\@verbatim); - -### Create a Regex for verbatim standart environment -my $verbatim = join q{|}, map { quotemeta } sort { length $a <=> length $b } @verbatim; -$verbatim = qr/$verbatim/x; -my $verb_std = qr { - ( - (?: - \\begin\{$verbatim\*?\} - (?: - (?>[^\\]+)| - \\ - (?!begin\{$verbatim\*?\}) - (?!end\{$verbatim\*?\})| - (?-1) - )* - \\end\{$verbatim\*?\} - ) - ) - }x; - -### Verbatim write -@verw_env_tmp = array_minus(@verw_env_tmp, @verb_env_tmp); #disjointed -my @verbatim_w = uniq(@verw_env_tmp); -my %verbatim_w = crearhash(@verbatim_w); - -Log('The environments that are considered verbatim write:'); -Logarray(\@verbatim_w); - -### Create a Regex for verbatim write environment -my $verbatim_w = join q{|}, map { quotemeta } sort { length $a <=> length $b } @verbatim_w; -$verbatim_w = qr/$verbatim_w/x; -my $verb_wrt = qr { - ( - (?: - \\begin\{$verbatim_w\*?\} - (?: - (?>[^\\]+)| - \\ - (?!begin\{$verbatim_w\*?\}) - (?!end\{$verbatim_w\*?\})| - (?-1) - )* - \\end\{$verbatim_w\*?\} - ) - ) - }x; - -### Check skip environments -my @skipped; -if (@skip_env_tmp) { - my %envcheck = map { $_ => 1 } @skip_env_tmp; - if (exists $envcheck{PSTexample}) { - Log('The [PSTexample] environment is not allowed for skipping'); - @skip_env_tmp = grep !/PSTexample/, @skip_env_tmp; - } - if (exists $envcheck{preview}) { - Log('The [preview] environment is not allowed for skipping'); - @skip_env_tmp = grep !/preview/, @skip_env_tmp; - } - # Valid environments for skip - for my $skip (qw(pspicture tikzpicture pgfpicture psgraph postscript)) { - if (exists $envcheck{$skip}) { - push @skipped,$skip; - } - } -} - -### List of environments to be skiped from extraction -@skipped = uniq(@skip_env_tmp); -Log('The environments that will be skiped for extraction:'); -Logarray(\@skipped); - -### Create a Regex for skip environment -my $skipenv = join q{|}, map { quotemeta } sort { length $a <=> length $b } @skipped; -$skipenv = qr/$skipenv/x; -my $skip_env = qr { - ( - (?: - \\begin\{$skipenv\*?\} - (?: - (?>[^\\]+)| - \\ - (?!begin\{$skipenv\*?\}) - (?!end\{$skipenv\*?\})| - (?-1) - )* - \\end\{$skipenv\*?\} - ) - ) - }x; - -### Check reserved environments -my %envcheck = map { $_ => 1 } @extr_env_tmp; - -if (exists $envcheck{document}) { - Log('The [document] environment is allowed for extraction'); - @extr_env_tmp = grep !/document/, @extr_env_tmp; -} -if (exists $envcheck{nopreview}) { - Log('The [nopreview] environment is allowed for extraction'); - @extr_env_tmp = grep !/nopreview/, @extr_env_tmp; -} - -### An array with all environments to extract, including nopreview -my @extract_env = qw(nopreview); -push @extract_env,@extr_env_tmp; - -### Some oprations for skip environments -@extract_env = array_minus(@extract_env, @skip_env_tmp); -@extract_env = uniq(@extract_env); - -### Hash for regex -my %extract_env = crearhash(@extract_env); - -Log('The environments that will be searched for extraction:'); -my @real_extract_env = grep !/nopreview/, @extract_env; -Logarray(\@real_extract_env); - -### Create a regex to extract environments -my $environ = join q{|}, map { quotemeta } sort { length $a <=> length $b } @extract_env; -$environ = qr/$environ/x; -my $extr_tmp = qr { - ( - (?: - \\begin\{$environ\*?\} - (?: - (?>[^\\]+)| - \\ - (?!begin\{$environ\*?\}) - (?!end\{$environ\*?\})| - (?-1) - )* - \\end\{$environ\*?\} - ) - ) - }x; - -### Check delete environments -if (@delt_env_tmp) { - my %envcheck = map { $_ => 1 } @delt_env_tmp; - if (exists $envcheck{document}) { - Log('The [document] environment is not allowed for delete'); - @delt_env_tmp = grep !/document/, @delt_env_tmp; - } -} - -### An array of environments to be removed in -my @delete_env = uniq(@delt_env_tmp); -my %delete_env = crearhash(@delete_env); - -Log('The environments that will be removed in output file:'); -Logarray(\@delete_env); - -### Create a Regex for delete environment in -my $delenv = join q{|}, map { quotemeta } sort { length $a <=> length $b } @delete_env; -$delenv = qr/$delenv/x; -my $delt_env = qr { - ( - (?: - \\begin\{$delenv\*?\} - (?: - (?>[^\\]+)| - \\ - (?!begin\{$delenv\*?\}) - (?!end\{$delenv\*?\})| - (?-1) - )* - \\end\{$delenv\*?\} - ) - ) - }x; - - -######################################################################## -# In this first part the script only detects verbatim environments and # -# verbatim write don't distinguish between which ones are extracted, # -# that's done in a second pass. # -######################################################################## - -Log('Making changes to verbatim and verbatim write environments before extraction'); - -### First, revert %<*TAGS> to %<*tags> in all document -my $ltxtags = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %reverse_tag; -$document =~ s/^($ltxtags)/$reverse_tag{$1}/gmsx; - -### Create an array with the temporary extraction list, no verbatim environments -my @extract_tmp = array_minus(@extract_env, @verb_env_tmp); -@extract_tmp = array_minus(@extract_tmp, @verw_env_tmp); -@extract_tmp = uniq(@extract_tmp); -my %extract_tmp = crearhash(@extract_tmp); - -### Hash and Regex for changes, this "regex" is re-used in ALL script -my %replace = (%verbatim, %extract_tmp, %changes_in, %document); # revert tags again :) -my $find = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %replace; - -### We go line by line and make the changes in verbatim's envoronments (/p for ${^MATCH}) -while ($document =~ /$verb_wrt | $verb_std /pgmx) { - my ($pos_inicial, $pos_final) = ($-[0], $+[0]); - my $encontrado = ${^MATCH}; - if ($encontrado =~ /$verb_wrt/) { - $encontrado =~ s/($find)/$replace{$1}/g; - substr $document, $pos_inicial, $pos_final-$pos_inicial, $encontrado; - pos ($document) = $pos_inicial + length $encontrado; - } - if ($encontrado =~ /$verb_std/) { - %replace = (%verbatim_w, %extract_tmp, %changes_in, %document); - $find = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %replace; - $encontrado =~ s/($find)/$replace{$1}/g; - substr $document, $pos_inicial, $pos_final-$pos_inicial, $encontrado; - pos ($document) = $pos_inicial + length $encontrado; - } -} - -### Now split document -my ($preamble,$bodydoc,$enddoc) = $document =~ m/\A (.+?) (\\begin\{document\} .+?)(\\end\{document\}.*)\z/msx; - -### Internal for mark verbatim and verbatim write environments -my $dtxverb = "verbatim$tmp"; - -### Match , if they're matched, we turn them :) -my @tag_extract = $bodydoc =~ m/(?:^\%<\*ltximg>.+?\%<\/ltximg>)/gmsx; -my @tag_noextract = $bodydoc =~ m/(?:^\%<\*noltximg>.+?\%<\/noltximg>)/gmsx; - -if (@tag_extract) { - Log('Pass extract tags %<*ltximg> ... % to \begin{preview} ... \end{preview}'); - $bodydoc =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - ^\%<\*$extrtag>(.+?)\%<\/$extrtag>/\\begin\{preview\}$1\\end\{preview\}/gmsx; -} -if (@tag_noextract) { - Log('Pass no extract tags %<*noltximg> ... % to \begin{nopreview} ... \end{nopreview}'); - $bodydoc =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - ^\%<\*$skiptag>(.+?)\%<\/$skiptag>/\\begin\{nopreview\}$1\\end\{nopreview\}/gmsx; -} - -######################################################################## -# We now make the real changes for environment extraction. Since we # -# don't know what kind of environments are passed, need to redefine # -# all regex to make the changes. # -######################################################################## - -my @new_verb_tmp = array_minus(@verbatim, @extract_env); -$verbatim = join q{|}, map { quotemeta } sort { length $a <=> length $b } @new_verb_tmp; -$verbatim = qr/$verbatim/x; -$verb_std = qr { - ( - (?: - \\begin\{$verbatim\*?\} - (?: - (?>[^\\]+)| - \\ - (?!begin\{$verbatim\*?\}) - (?!end\{$verbatim\*?\})| - (?-1) - )* - \\end\{$verbatim\*?\} - ) - ) - }x; - -my @new_verbw_tmp = array_minus(@verbatim_w, @extract_env); -$verbatim_w = join q{|}, map { quotemeta } sort { length $a <=> length $b } @new_verbw_tmp; -$verbatim_w = qr/$verbatim_w/x; -$verb_wrt = qr { - ( - (?: - \\begin\{$verbatim_w\*?\} - (?: - (?>[^\\]+)| - \\ - (?!begin\{$verbatim_w\*?\}) - (?!end\{$verbatim_w\*?\})| - (?-1) - )* - \\end\{$verbatim_w\*?\} - ) - ) - }x; - -### Regex using hash -%replace = (%extract_env); -$find = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %replace; - -### We go line by line and make the changes (/p for ${^MATCH}) -while ($bodydoc =~ /$verb_wrt | $verb_std /pgmx) { - my ($pos_inicial, $pos_final) = ($-[0], $+[0]); - my $encontrado = ${^MATCH}; - $encontrado =~ s/($find)/$replace{$1}/g; - substr $bodydoc, $pos_inicial, $pos_final-$pos_inicial, $encontrado; - pos ($bodydoc) = $pos_inicial + length $encontrado; -} - -### Now put a internal dtxmark in no extraction/replace environments -Log("Pass verbatim write environments to %<*$dtxverb> ... %"); -$bodydoc =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - ($verb_wrt)/\%<\*$dtxverb>$1\%<\/$dtxverb>/gmsx; -$preamble =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - ($verb_wrt)/\%<\*$dtxverb>$1\%<\/$dtxverb>/gmsx; -$atbegindoc =~ s/($verb_wrt)/\%<\*$dtxverb>$1\%<\/$dtxverb>/gmsx; - -Log("Pass verbatim environments to %<*$dtxverb> ... %"); -$bodydoc =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - ($verb_std)/\%<\*$dtxverb>$1\%<\/$dtxverb>/gmsx; -$preamble =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - ($verb_std)/\%<\*$dtxverb>$1\%<\/$dtxverb>/gmsx; -$atbegindoc =~ s/($verb_std)/\%<\*$dtxverb>$1\%<\/$dtxverb>/gmsx; - -### Check plain TeX syntax -my %plainsyntax = map { $_ => 1 } @extract_env; # anon hash - -if (exists $plainsyntax{pspicture}) { - Log('Convert plain \pspicture to LaTeX syntax [skip in PSTexample]'); - $bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - \\begin\{PSTexample\}.+?\\end\{PSTexample\}(*SKIP)(*F)| - \\pspicture(\*)?(.+?)\\endpspicture/\\begin\{pspicture$1\}$2\\end\{pspicture$1\}/gmsx; -} - -if (exists $plainsyntax{psgraph}) { - Log('Convert plain \psgraph to LaTeX syntax [skip in PSTexample]'); - $bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - \\begin\{PSTexample\}.+?\\end\{PSTexample\}(*SKIP)(*F)| - \\psgraph(\*)?(.+?)\\endpsgraph/\\begin\{psgraph$1\}$2\\end\{psgraph$1\}/gmsx; -} - -if (exists $plainsyntax{tikzpicture}) { - Log('Convert plain \tikzpicture to LaTeX syntax'); - $bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - \\tikzpicture(.+?)\\endtikzpicture/\\begin{tikzpicture}$1\\end{tikzpicture}/gmsx; -} - -if (exists $plainsyntax{pgfpicture}) { - Log('Convert plain \pgfpicture to LaTeX syntax'); - $bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - \\pgfpicture(.+?)\\endpgfpicture/\\begin{pgfpicture}$1\\end{pgfpicture}/gmsx; -} - -### Force mode for pstricks/psgraph/tikzpiture -if ($opts_cmd{boolean}{force}) { - if (exists $plainsyntax{pspicture} or exists $plainsyntax{psgraph}) { - Log('Try to capture \psset{...} for pstricks environments [force mode]'); - $bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - \\begin\{PSTexample\}.+?\\end\{PSTexample\}(*SKIP)(*F)| - \\begin\{postscript\}.+?\\end\{postscript\}(*SKIP)(*F)| - (? - (?:\\psset\{(?:\{.*?\}|[^\{])*\}.+?)? # if exist ...save - \\begin\{(? pspicture\*?| psgraph)\} .+? \\end\{\k\} - ) - /\\begin\{preview\}$+{code}\\end\{preview\}/gmsx; - } - if (exists $plainsyntax{tikzpicture}) { - Log('Try to capture \tikzset{...} for tikzpicture environments [force mode]'); - $bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - \\begin\{postscript\}.+?\\end\{postscript\}(*SKIP)(*F)| - (? - (?:\\tikzset\{(?:\{.*?\}|[^\{])*\}.+?)? # if exist ...save - \\begin\{(? tikzpicture)\} .+? \\end\{\k\} - ) - /\\begin\{preview\}$+{code}\\end\{preview\}/gmsx; - } -} - -Log('Pass skip environments to \begin{nopreview} ... \end{nopreview}'); -$bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - \\begin\{PSTexample\}.+?\\end\{PSTexample\}(*SKIP)(*F)| - ($skip_env)/\\begin\{nopreview\}$1\\end\{nopreview\}/gmsx; - -### Pass all captured environments in body \begin{preview} ... \end{preview} -Log('Pass all captured environments to \begin{preview} ... \end{preview}'); -$bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - ($extr_tmp)/\\begin\{preview\}$1\\end\{preview\}/gmsx; - -######################################################################## -# All environments are now classified: # -# Extraction -> \begin{preview} ... \end{preview} # -# No Extraction -> \begin{nopreview} ... \end{nopreview} # -# Verbatim's -> %<\*$dtxverb> ... <\/$dtxverb> # -######################################################################## - -### The %<*remove> ... % tags need a special treatment :) -$bodydoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - ^(\%<(?:\*|\/))(remove)(\>)/$1$2$tmp$3/gmsx; -$preamble =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - ^(\%<(?:\*|\/))(remove)(\>)/$1$2$tmp$3/gmsx; -$atbegindoc =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - \\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \\begin\{preview\}.+?\\end\{preview\}(*SKIP)(*F)| - ^(\%<(?:\*|\/))(remove)(\>)/$1$2$tmp$3/gmsx; - -### Pass \begin{preview} ... \end{preview} to \START{preview} ... \STOP{preview} -### Pass \begin{nopreview} ... \end{nopreview} to \START{nopreview} ... \STOP{nopreview} -$bodydoc =~ s/\\begin\{((no)?preview)\}/\\START\{$1\}/gmsx; -$bodydoc =~ s/\\end\{((no)?preview)\}/\\STOP\{$1\}/gmsx; - -### We restore the changes of all environments in body -my @lineas = split /\n/, $bodydoc; -my $NEWDEL; -for (@lineas) { - %replace = (%changes_out); - $find = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %replace; - if (/\\START\{((no)?preview)(?{ $NEWDEL = "\Q$^N" })\}/ .. /\\STOP\{$NEWDEL\}/) { - s/($find)/$replace{$1}/msgx; - } - if (/\%<\*($dtxverb)(?{ $NEWDEL = "\Q$^N" })>/ .. /\%<\/$NEWDEL>/) { - s/($find)/$replace{$1}/msgx; - } -} -$bodydoc = join "\n", @lineas; - -### We restore the changes of all environments in preamble -while ($preamble =~ /\%<\*$dtxverb>(.+?)\%<\/$dtxverb>/pgmsx) { - %cambios = (%changes_out); - my ($pos_inicial, $pos_final) = ($-[0], $+[0]); - my $encontrado = ${^MATCH}; - while (my($busco, $cambio) = each %cambios) { - $encontrado =~ s/\Q$busco\E/$cambio/msxg; - } - substr $preamble, $pos_inicial, $pos_final-$pos_inicial, $encontrado; - pos ($preamble) = $pos_inicial + length $encontrado; -} - -### Set wraped environments for extraction -my $wrapping = "$scriptname$tmp"; -Log("Set up the environment [$wrapping] to encapsulate the extraction"); - -### Set vars for match/regex -my $BP = "\\\\begin\{$wrapping\}"; -my $EP = "\\\\end\{$wrapping\}"; -my $BE = '\\\\begin\{PSTexample\}'; -my $EE = '\\\\end\{PSTexample\}'; - -### Wrap environments for extraction -Log("Pass all captured environments to \\begin{$wrapping} ... \\end{$wrapping}"); -$bodydoc =~ s/\\START\{preview\} - (?.+? ) - \\STOP\{preview\} - /\\begin\{$wrapping\}$+{code}\\end\{$wrapping\}/gmsx; - -$bodydoc =~ s/\\START\{nopreview\} - (?.+? ) - \\STOP\{nopreview\} - /\\begin\{nopreview\}\%$tmp$+{code}\\end\{nopreview\}\%$tmp/gmsx; - -### We put back ltximg tags :) -$bodydoc =~ s/($ltxtags)/$reverse_tag{$1}/gmsx; -$preamble =~ s/($ltxtags)/$reverse_tag{$1}/gmsx; - -### First search PSTexample environments for extract -my @exa_extract = $bodydoc =~ m/(?:\\begin\{$wrapping\})($BE.+?$EE)(?:\\end\{$wrapping\})/gmsx; -my $exaNo = scalar @exa_extract; - -### Set vars for log and print in terminal -my $envEXA = $exaNo > 1 ? 'PSTexample environments' : 'PSTexample environment'; -my $fileEXA = $exaNo > 1 ? 'files' : 'file'; - -### Check if PSTexample environment found -if ($exaNo!=0) { - $PSTexa = 1; - Log("Found $exaNo $envEXA in $name$ext"); - my $figNo = 1; - for my $item (@exa_extract) { - Logline("%##### PSTexample environment captured number $figNo ######%"); - Logline($item); - $figNo++; - } - # Add [graphic={[...]...}] to \begin{PSTexample}[...] - Log('Append [graphic={[...]...}] to \begin{PSTexample}[...]'); - $figNo = 1; - while ($bodydoc =~ /\\begin\{$wrapping\}(\s*)?\\begin\{PSTexample\}(\[.+?\])?/gsm) { - my $swpl_grap = "graphic=\{\[scale=1\]$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-exa"; - my $corchetes = $1; - my ($pos_inicial, $pos_final) = ($-[1], $+[1]); - if (not $corchetes) { $pos_inicial = $pos_final = $+[0]; } - if (not $corchetes or $corchetes =~ /\[\s*\]/) { - $corchetes = "[$swpl_grap-$figNo}]"; - } - else { $corchetes =~ s/\]/,$swpl_grap-$figNo}]/; } - substr($bodydoc, $pos_inicial, $pos_final - $pos_inicial) = $corchetes; - pos($bodydoc) = $pos_inicial + length $corchetes; - } - continue { $figNo++; } - Log('Pass PSTexample environments to \begin{nopreview} ... \end{nopreview}'); - $bodydoc =~ s/\\begin\{$wrapping\} - (?\\begin\{PSTexample\} .+? \\end\{PSTexample\}) - \\end\{$wrapping\} - /\\begin\{nopreview\}\%$tmp$+{code}\\end\{nopreview\}\%$tmp/gmsx; -} - -### Second search standart environments for extract -my @env_extract = $bodydoc =~ m/(?<=$BP)(.+?)(?=$EP)/gms; -my $envNo = scalar @env_extract; - -### Set vars for log and print in terminal -my $envSTD = $envNo > 1 ? 'standard environments' : 'standard environment'; -my $fileSTD = $envNo > 1 ? 'files' : 'file'; - -### If any standard environments found -if ($envNo!=0) { - $STDenv = 1; - Log("Found $envNo $envSTD in $name$ext"); - my $figNo = 1; - for my $item (@env_extract) { - Logline("%##### Standard environment captured number $figNo ######%"); - Logline($item); - $figNo++; - } -} - -### Run script process only if any enviroment found in -if ($envNo == 0 and $exaNo == 0) { - errorUsage("$scriptname can not find any environment to extract in $name$ext"); -} - -### Set directory to save generated files, need full path for goog log :) -my $imgdirpath = File::Spec->rel2abs($opts_cmd{string}{imgdir}); - -if (-e $opts_cmd{string}{imgdir}) { - Infoline("The generated files will be saved in $imgdirpath"); -} -else { - Infoline("Creating the directory $imgdirpath to save the generated files"); - Infocolor('Running', "mkdir $imgdirpath"); - Logline("[perl] mkdir($opts_cmd{string}{imgdir},0744)"); - mkdir $opts_cmd{string}{imgdir},0744 or errorUsage("Can't create the directory $opts_cmd{string}{imgdir}"); -} - -### Set compiler -my $compiler = $opts_cmd{compiler}{xetex} ? 'xelatex' - : $opts_cmd{compiler}{luatex} ? 'lualatex' - : $opts_cmd{compiler}{latex} ? 'latex' - : $opts_cmd{compiler}{dvips} ? 'latex' - : $opts_cmd{compiler}{dvilua} ? 'dvilualatex' - : $opts_cmd{compiler}{dvipdf} ? 'latex' - : $opts_cmd{compiler}{arara} ? 'arara' - : 'pdflatex' - ; - -if (!$opts_cmd{boolean}{norun}) { - if ($compiler eq 'arara') { - Log("The file will be processed using $compiler, no ducks will be harmed in this process"); - } - else { Log("The file will be processed using $compiler"); } -} - -### Set option for pdfcrop (last version of pdfcrop https://github.com/ho-tex/pdfcrop) -my $opt_crop = $opts_cmd{compiler}{xetex} ? "--xetex --margins $opts_cmd{string}{margin}" - : $opts_cmd{compiler}{luatex} ? "--luatex --margins $opts_cmd{string}{margin}" - : $opts_cmd{compiler}{latex} ? "--margins $opts_cmd{string}{margin}" - : "--pdftex --margins $opts_cmd{string}{margin}" - ; - -### Set options for preview packpage -my $opt_prew = $opts_cmd{compiler}{xetex} ? 'xetex,' - : $opts_cmd{compiler}{latex} ? q{} - : $opts_cmd{compiler}{dvipdf} ? q{} - : $opts_cmd{compiler}{dvips} ? q{} - : $opts_cmd{compiler}{dvilua} ? q{} - : 'pdftex,' - ; - -######################################################################## -# One problem with using arara is that we don't know what the file is # -# really compiled with, this affects [preview] and [pdfcrop]. # -######################################################################## - -### Try to capture arara:compiler in preamble of -my @arara_engines = qw (latex pdflatex lualatex xelatex luahbtex); -my $arara_engines = join q{|}, map { quotemeta} sort { length $a <=> length $b } @arara_engines; -$arara_engines = qr/\b(?:$arara_engines)/x; -my $arara_rule = qr /^(?:\%\s{1}arara[:]\s{1}) ($arara_engines) /msx; - -### Set options for [compiler], [preview] and [pdfcrop] -if ($compiler eq 'arara') { - Log('Trying to detect some suported [engine] in the rules of arara'); - my @engine = $atbegindoc =~ m/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)|$arara_rule/msx; - my %engine = map { $_ => 1 } @engine; # anon hash - if (exists $engine{latex}) { - Log('The [latex] engine was found in arara rule'); - # Set options for [preview] and [pdfcrop] - $opt_crop = "--margins $opts_cmd{string}{margin}"; - $opt_prew = q{}; - } - elsif (exists $engine{lualatex} or exists $engine{luahbtex}) { - Log('The [lualatex] engine was found in arara rule'); - # Set options for [preview] and [pdfcrop] - $opt_crop = "--luatex --margins $opts_cmd{string}{margin}"; - $opt_prew = 'pdftex,'; - } - elsif (exists $engine{xelatex}) { - Log('The [xelatex] engine was found in arara rule'); - # Set options for [preview] and [pdfcrop] - $opt_crop = "--xetex --margins $opts_cmd{string}{margin}"; - $opt_prew = 'xetex,'; - } - elsif (exists($engine{pdflatex})) { - Log('The [pdflatex] engine was found in arara rule'); - # Set options for [preview] and [pdfcrop] - $opt_crop = "--pdftex --margins $opts_cmd{string}{margin}"; - $opt_prew = 'pdftex,'; - } - else { - Log('No supported [engine] could be detected, default values will be used'); - # Set options for [preview] and [pdfcrop] - $opt_crop = "--pdftex --margins $opts_cmd{string}{margin}"; - $opt_prew = 'pdftex,'; - } -} - -### Message in command line for compiler -my $msg_compiler = $opts_cmd{compiler}{xetex} ? 'xelatex' - : $opts_cmd{compiler}{luatex} ? 'lualatex' - : $opts_cmd{compiler}{latex} ? 'latex>dvips>ps2pdf' - : $opts_cmd{compiler}{dvips} ? 'latex>dvips>ps2pdf' - : $opts_cmd{compiler}{dvilua} ? 'dvilualatex>dvips>ps2pdf' - : $opts_cmd{compiler}{dvipdf} ? 'latex>dvipdfmx' - : $opts_cmd{compiler}{arara} ? 'arara' - : 'pdflatex' - ; - -### Set write18 for compiler -if ($opts_cmd{boolean}{shell}) { - $write18 = '-shell-escape'; - $write18 = '--enable-write18' if defined $ENV{'TEXSYSTEM'} and $ENV{'TEXSYSTEM'} =~ /miktex/i; -} -else { - $write18 = '-no-shell-escape'; - $write18 = '--disable-write18' if defined $ENV{'TEXSYSTEM'} and $ENV{'TEXSYSTEM'} =~ /miktex/i; -} - -### Set options for compiler -my $opt_compiler = $opts_cmd{compiler}{arara} ? '--log' - : "$write18 -interaction=nonstopmode -recorder" - ; - -if (!$opts_cmd{boolean}{norun}) { - Log("The options '$opt_compiler' will be passed to [$compiler]"); -} - -### Set -q for system command line (gs, poppler-utils, dvips, dvipdfmx) -my $quiet = $verbose ? q{} - : '-q' - ; - -### Set options for ghostscript in command line -my %opt_gs_dev = ( - pdf => '-dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=pdfwrite', - gray => '-dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sColorConversionStrategy=Gray -sProcessColorModel=DeviceGray', - png => "-dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=pngalpha -r$opts_cmd{string}{dpi}", - bmp => "-dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=bmp32b -r$opts_cmd{string}{dpi}", - jpg => "-dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=jpeg -r$opts_cmd{string}{dpi} -dJPEGQ=100 -dGraphicsAlphaBits=4 -dTextAlphaBits=4", - tif => "-dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=tiff32nc -r$opts_cmd{string}{dpi}", - ); - -### Set executable from poppler-utils -my %cmd_poppler = ( - eps => "pdftops", - ppm => "pdftoppm", - svg => "pdftocairo", - ); - -### Set options for poppler-utils -my %opt_poppler = ( - eps => "$quiet -eps", - ppm => "$quiet -r $opts_cmd{string}{dpi}", - svg => "$quiet -svg", - ); - -### Copy preamble and body for temp file with all environments -my $atbeginout = $atbegindoc; -my $preamout = $preamble; -my $tmpbodydoc = $bodydoc; - -### Match \pagestyle and \thispagestyle in preamble -my $style_page = qr /(?:\\)(?:this)?(?:pagestyle\{) (.+?) (?:\})/x; -my @style_page = $preamout =~ m/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| $style_page/gmsx; -my %style_page = map { $_ => 1 } @style_page; # anon hash - -### Seting \pagestyle{empty} for subfiles and process -if (@style_page) { - if (!exists $style_page{empty}) { - Log("Replacing page style for generated files"); - $preamout =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - (\\(this)?pagestyle)(?:\{.+?\})/$1\{empty\}/gmsx; - } -} -else { - Log('Add \pagestyle{empty} for generated files'); - $preamout = $preamout."\\pagestyle\{empty\}\n"; -} - -#### Remove wraped postscript environments provide by pst-pdf, auto-pst-pdf, auto-pst-pdf-lua pkgs -Log("Convert postscript environments to \\begin\{$wrapping\} ... \\end\{$wrapping\} for standalone files"); -$tmpbodydoc =~ s/(?:$BP)(?:\\begin\{postscript\})(?:\s*\[ [^]]*? \])? - (?.+?) - (?:\\end\{postscript\}) - (?:$EP) - /\\begin\{$wrapping\}$+{code}\\end\{$wrapping\}/gmsx; - -### We created a preamble for standalone files -my $sub_prea = "$atbeginout$preamout".'\begin{document}'; - -### Revert changes -$sub_prea =~ s/\%<\*$dtxverb>\s*(.+?)\s*\%<\/$dtxverb>/$1/gmsx; -%replace = (%changes_out); -$find = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %replace; -$sub_prea =~ s/($find)/$replace{$1}/g; -$sub_prea =~ s/(remove$tmp)/remove/g; - -### Write standalone files for environments -if ($outsrc) { - my $src_name = "$name-$opts_cmd{string}{prefix}-"; - my $srcNo = 1; - if ($opts_cmd{boolean}{srcenv}) { - Log('Extract source code of all captured environments without preamble'); - if ($STDenv) { - if (-e "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-1$ext") { - Log("Recreating $envNo $fileSTD [$ext] with source code for $envSTD in $imgdirpath"); - print "Recreating $envNo $fileSTD ", color('magenta'), "[$ext]", - color('reset'), " with source code for $envSTD\r\n"; - } - else { - Log("Creating $envNo $fileSTD [$ext] with source code for $envSTD in $imgdirpath"); - print "Creating $envNo $fileSTD ", color('magenta'), "[$ext]", - color('reset'), " with source code for $envSTD\r\n"; - } - # Write files - while ($tmpbodydoc =~ m/$BP\s*(?.+?)\s*$EP/gms) { - open my $outexasrc, '>', "$opts_cmd{string}{imgdir}/$src_name$srcNo$ext"; - print {$outexasrc} $+{'env_src'}; - close $outexasrc; - } - continue { $srcNo++; } - } - if ($PSTexa) { - if (-e "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-exa-1$ext") { - Log("Recreating $exaNo $fileEXA [$ext] with source code for $envEXA in $imgdirpath"); - print "Recreating $exaNo $fileEXA ", color('magenta'), "[$ext]", - color('reset'), " with source code for $envEXA\r\n"; - } - else { - Log("Creating $exaNo $fileEXA [$ext] with source code for $envEXA in $imgdirpath"); - print "Creating $exaNo $fileEXA ", color('magenta'), "[$ext]", - color('reset'), " with source code for $envEXA\r\n"; - } - # Write files - while ($tmpbodydoc =~ m/$BE\[.+?(?$opts_cmd{string}{imgdir}\/.+?-\d+)\}\]\s*(?.+?)\s*$EE/gms) { - open my $outstdsrc, '>', "$+{'pst_exa_name'}$ext"; - print {$outstdsrc} $+{'exa_src'}; - close $outstdsrc; - } - } - } - if ($opts_cmd{boolean}{subenv}) { - Log('Extract source code of all captured environments with preamble'); - if ($STDenv) { - if (-e "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-1$ext") { - Log("Recreating a $envNo standalone $fileSTD [$ext] for $envSTD in $imgdirpath"); - print "Recreating a $envNo standalone $fileSTD ", color('magenta'), "[$ext]", - color('reset'), " for $envSTD\r\n"; - } - else { - Log("Creating a $envNo standalone $fileSTD [$ext] for $envSTD in $imgdirpath"); - print "Creating a $envNo standalone $fileSTD ", color('magenta'), "[$ext]", - color('reset'), " for $envSTD\r\n"; - } - # Write files - while ($tmpbodydoc =~ m/$BP(?:\s*)?(?.+?)(?:\s*)?$EP/gms) { - open my $outstdfile, '>', "$opts_cmd{string}{imgdir}/$src_name$srcNo$ext"; - print {$outstdfile} "$sub_prea\n$+{'env_src'}\n\\end\{document\}"; - close $outstdfile; - } - continue { $srcNo++; } - } - if ($PSTexa) { - if (-e "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-exa-1$ext") { - Log("Recreating a $exaNo standalone $fileEXA [$ext] for $envEXA in $imgdirpath"); - print "Recreating a $exaNo standalone $fileEXA ", color('magenta'), "[$ext]", - color('reset'), " for $envEXA\r\n"; - } - else { - Log("Creating a $exaNo standalone $fileEXA [$ext] for $envEXA in $imgdirpath"); - print "Creating a $exaNo standalone $fileEXA ", color('magenta'), "[$ext]", - color('reset'), " for $envEXA\r\n"; - } - # Write files - while ($tmpbodydoc =~ m/$BE\[.+?(?$opts_cmd{string}{imgdir}\/.+?-\d+)\}\]\s*(?.+?)\s*$EE/gms) { - open my $outexafile, '>', "$+{'pst_exa_name'}$ext"; - print {$outexafile} "$sub_prea\n$+{'exa_src'}\n\\end\{document\}"; - close $outexafile; - } - } - } -} - -### Store options for preview and pst-pdf (add at begin document) -my $previewpkg = <<"EXTRA"; -\\PassOptionsToPackage\{inactive\}\{pst-pdf\}% -\\AtBeginDocument\{% -\\RequirePackage\[inactive\]\{pst-pdf\}% -\\RequirePackage\[${opt_prew}active,tightpage\]\{preview\}% -\\renewcommand\\PreviewBbAdjust\{-60pt -60pt 60pt 60pt\}\}% -EXTRA - -### Store options for pst-pdf (add at begin document) -my $pstpdfpkg = <<'EXTRA'; -\PassOptionsToPackage{inactive}{pst-pdf} -\AtBeginDocument{% -\RequirePackage[inactive]{pst-pdf}}% -EXTRA - -### First match preview package in preamble (prevent option clash) -my $REQPACK = quotemeta'\RequirePackage'; -my $USEPACK = quotemeta'\usepackage'; -my $CORCHETES = qr/\[ [^]]*? \]/x; - -my $PALABRAS = qr/\b (?: preview )/x; -my $FAMILIA = qr/\{ \s* $PALABRAS (?: \s* [,] \s* $PALABRAS )* \s* \}(\%*)?/x; - -Log('Remove preview package (if found) in preamble [memory]'); -$preamout =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - ^ $USEPACK (?: $CORCHETES )? $FAMILIA \s*//msxg; -$preamout =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - (?: ^ $USEPACK \{ | \G) [^}]*? \K (,?) \s* $PALABRAS (\s*) (,?) /$1 and $3 ? ',' : $1 ? $2 : ''/gemsx; -$preamout =~ s/^\\usepackage\{\}(?:[\t ]*(?:\r?\n|\r))+/\n/gmsx; - -### Remove %<*$dtxverb> ... % in tmpbodydoc and preamout -$tmpbodydoc =~ s/\%<\*$dtxverb>(.+?)\%<\/$dtxverb>/$1/gmsx; -$preamout =~ s/\%<\*$dtxverb>(.+?)\%<\/$dtxverb>/$1/gmsx; -$atbeginout =~ s/\%<\*$dtxverb>(.+?)\%<\/$dtxverb>/$1/gmsx; - -### Adjust nopreview environments -$tmpbodydoc =~ s/\\begin\{nopreview\}\%$tmp - (? .+?) - \\end\{nopreview\}\%$tmp - /\\begin\{nopreview\}\n$+{code}\n\\end\{nopreview\}\n/gmsx; - -### Adjust $wrapping environments (need \n after close for some environments, like a Verbatim) -$tmpbodydoc =~ s/\\begin\{$wrapping\} - (?.+?) - \\end\{$wrapping\} - /\\begin\{$wrapping\}\n$+{code}\n\\end\{$wrapping\}/gmsx; - -### Reverse changes for temporary file with all env (no in -exa file) -$tmpbodydoc =~ s/($find)/$replace{$1}/g; -$tmpbodydoc =~ s/(\%$tmp)//g; -$tmpbodydoc =~ s/(remove$tmp)/remove/g; -$preamout =~ s/($find)/$replace{$1}/g; -$atbeginout =~ s/(remove$tmp)/remove/g; -$atbeginout =~ s/($find)/$replace{$1}/g; - -### We created a preamble for individual files with all environments -$sub_prea = $opts_cmd{boolean}{noprew} ? "$atbeginout$pstpdfpkg$preamout".'\begin{document}' - : "$atbeginout$previewpkg$preamout" - ; - -### Create a one file with "all" PSTexample environments extracted -if ($PSTexa) { - @exa_extract = undef; - Log("Adding packages to $name-$opts_cmd{string}{prefix}-exa-$tmp$ext"); - Logline($pstpdfpkg); - Log('Convert plain Tex syntax for pspicture and psgraph to LaTeX syntax in PSTexample environments'); - while ($tmpbodydoc =~ m/$BE\[.+? $opts_cmd{string}{imgdir}\/.+?-\d+\}\] .+?$EE/pgsmx ) { # search - my ($pos_inicial, $pos_final) = ($-[0], $+[0]); - my $encontrado = ${^MATCH}; - $encontrado =~ s/\\pspicture(\*)?(.+?)\\endpspicture/\\begin\{pspicture$1\}$2\\end\{pspicture$1\}/gmsx; - $encontrado =~ s/\\psgraph(\*)?(.+?)\\endpsgraph/\\begin\{psgraph$1\}$2\\end\{psgraph$1\}/gmsx; - substr $tmpbodydoc, $pos_inicial, $pos_final-$pos_inicial, $encontrado; - pos ($tmpbodydoc) = $pos_inicial + length $encontrado; - } - # Write files - Infoline("Creating $name-$opts_cmd{string}{prefix}-exa-$tmp$ext with $exaNo $envEXA extracted"); - while ($tmpbodydoc =~ m/$BE\[.+? $opts_cmd{string}{imgdir}\/.+?-\d+\}\](?.+?)$EE/gmsx ) { # search - push @exa_extract, $+{'exa_src'}."\\newpage\n"; - open my $allexaenv, '>', "$name-$opts_cmd{string}{prefix}-exa-$tmp$ext"; - print {$allexaenv} "$atbeginout$pstpdfpkg$preamout".'\begin{document}'."@exa_extract"."\\end\{document\}"; - close $allexaenv; - } - # Remove [graphic={...}] in PSTexample example environments - $tmpbodydoc =~ s/($BE)(?:\[graphic=\{\[scale=1\]$opts_cmd{string}{imgdir}\/.+?-\d+\}\])/$1/gmsx; - $tmpbodydoc =~ s/($BE\[.+?)(?:,graphic=\{\[scale=1\]$opts_cmd{string}{imgdir}\/.+?-\d+\})(\])/$1$2/gmsx; - # Moving and renaming - if ($opts_cmd{boolean}{norun}) { - Infoline("Moving and renaming $name-$opts_cmd{string}{prefix}-exa-$tmp$ext to $name-$opts_cmd{string}{prefix}-exa-all$ext"); - if (-e "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-exa-all$ext") { - Infocolor('Warning', "The file [$name-$opts_cmd{string}{prefix}-exa-all$ext] already exists and will be rewritten"); - Log("Rewriting the file $name-$opts_cmd{string}{prefix}-exa-all$ext in $imgdirpath"); - } - else { - Log("Writing the file $name-$opts_cmd{string}{prefix}-exa-all$ext in $imgdirpath"); - } - if ($verbose) { - Infocolor('Running', "mv $workdir/$name-$opts_cmd{string}{prefix}-exa-$tmp$ext $imgdirpath/$name-$opts_cmd{string}{prefix}-exa-all$ext"); - } - else { - Infocolor('Running', "mv $name-$opts_cmd{string}{prefix}-exa-$tmp$ext ./$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-exa-all$ext"); - } - Logline("[perl] move($workdir/$name-$opts_cmd{string}{prefix}-exa-$tmp$ext, $imgdirpath/$name-$opts_cmd{string}{prefix}-exa-all$ext)"); - move("$workdir/$name-$opts_cmd{string}{prefix}-exa-$tmp$ext", "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-exa-all$ext") - or die "* Error!!: Couldn't be renamed $name-$opts_cmd{string}{prefix}-exa-$tmp$ext to ./$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-exa-all$ext"; - } -} - -### Create a one file with "all" standard environments extracted -if ($STDenv) { - if ($opts_cmd{boolean}{noprew}) { - Log("Creating $name-$opts_cmd{string}{prefix}-$tmp$ext with $envNo $envSTD extracted [no preview]"); - print "Creating $name-$opts_cmd{string}{prefix}-$tmp$ext with $envNo $envSTD extracted", - color('magenta'), " [no preview]\r\n",color('reset'); - } - else { - Log("Creating $name-$opts_cmd{string}{prefix}-$tmp$ext with $envNo $envSTD extracted [preview]"); - print "Creating $name-$opts_cmd{string}{prefix}-$tmp$ext with $envNo $envSTD extracted", - color('magenta'), " [preview]\r\n",color('reset'); - } - open my $allstdenv, '>', "$name-$opts_cmd{string}{prefix}-$tmp$ext"; - if ($opts_cmd{boolean}{noprew}) { - my @env_extract; - while ($tmpbodydoc =~ m/(?:$BP)(?.+?)(?:$EP)/gms) { - push @env_extract, $+{'env_src'}."\\newpage\n"; - } - Log("Adding packages to $name-$opts_cmd{string}{prefix}-$tmp$ext"); - Logline($pstpdfpkg); - print {$allstdenv} $sub_prea."@env_extract"."\\end{document}"; - } - else { - Log("Adding packages to $name-$opts_cmd{string}{prefix}-$tmp$ext"); - Logline($previewpkg); - Log("Convert $wrapping to preview environments in $name-$opts_cmd{string}{prefix}-$tmp$ext"); - # Convert $wrapping to preview environments - $tmpbodydoc =~ s/\\begin\{$wrapping\}(?.+?)\\end\{$wrapping\} - /\\begin\{preview\}$+{code}\\end\{preview\}\n/gmsx; - print {$allstdenv} $sub_prea.$tmpbodydoc."\n\\end{document}"; - } - close $allstdenv; - if ($opts_cmd{boolean}{norun}) { - # Moving and renaming - Infoline("Moving and renaming $name-$opts_cmd{string}{prefix}-$tmp$ext to $name-$opts_cmd{string}{prefix}-all$ext"); - if (-e "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-all$ext") { - Infocolor('Warning', "The file [$name-$opts_cmd{string}{prefix}-all$ext] already exists and will be rewritten"); - Log("Rewriting the file $name-$opts_cmd{string}{prefix}-all$ext in $imgdirpath"); - } - else { - Log("Writing the file $name-$opts_cmd{string}{prefix}-all$ext in $imgdirpath"); - } - if ($verbose) { - Infocolor('Running', "mv $workdir/$name-$opts_cmd{string}{prefix}-$tmp$ext $imgdirpath/$name-$opts_cmd{string}{prefix}-all$ext"); - } - else { - Infocolor('Running', "mv $name-$opts_cmd{string}{prefix}-$tmp$ext ./$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-all$ext"); - } - Logline("[perl] move($workdir/$name-$opts_cmd{string}{prefix}-$tmp$ext, $imgdirpath/$name-$opts_cmd{string}{prefix}-all$ext)"); - move("$workdir/$name-$opts_cmd{string}{prefix}-$tmp$ext", "$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-all$ext") - or die "* Error!!: Couldn't be renamed $name-$opts_cmd{string}{prefix}-$tmp$ext to ./$opts_cmd{string}{imgdir}/$name-$opts_cmd{string}{prefix}-all$ext"; - } -} - -### Compiler and generate PDF files -if (!$opts_cmd{boolean}{norun}) { -Log('Generate a PDF file with all captured environments'); -my @compiler = (1..$opts_cmd{string}{runs}); -opendir (my $DIR, $workdir); - while (readdir $DIR) { - if (/(?$name-$opts_cmd{string}{prefix}(-exa)?)(?-$tmp$ext)/) { - Log("Compiling the file $+{name}$+{type} using [$msg_compiler]"); - print "Compiling the file $+{name}$+{type} using ", color('magenta'), "[$msg_compiler]\r\n",color('reset'); - for (@compiler){ - RUNOSCMD("$compiler $opt_compiler","$+{name}$+{type}",'show'); - } - # Compiling file using latex>dvips>ps2pdf - if ($compiler eq 'dvips' or $compiler eq 'latex' or $compiler eq 'dvilualatex') { - RUNOSCMD("dvips $quiet -Ppdf", "-o $+{name}-$tmp.ps $+{name}-$tmp.dvi",'show'); - RUNOSCMD("ps2pdf -sPDFSETTINGS=prepress -sAutoRotatePages=None", "$+{name}-$tmp.ps $+{name}-$tmp.pdf",'show'); - } - # Compiling file using latex>dvipdfmx - if ($compiler eq 'dvipdf') { - RUNOSCMD("dvipdfmx $quiet", "$+{name}-$tmp.dvi",'show'); - } - # Moving and renaming temp files with source code - Infoline("Moving and renaming $+{name}$+{type} to $+{name}-all$ext"); - if (-e "$opts_cmd{string}{imgdir}/$+{name}-all$ext") { - Infocolor('Warning', "The file [$+{name}-all$ext] already exists and will be rewritten"); - Log("Rewriting the file $+{name}-all$ext with all source for environments in $imgdirpath"); - } - else { - Log("Writing the file $+{name}-all$ext with all source for environments in $imgdirpath"); - } - if ($verbose){ - Infocolor('Running', "mv $workdir/$+{name}$+{type} $imgdirpath/$+{name}-all$ext"); - } - else { - Infocolor('Running', "mv $+{name}$+{type} ./$opts_cmd{string}{imgdir}/$+{name}-all$ext"); - } - Logline("[perl] move($workdir/$+{name}$+{type}, $imgdirpath/$+{name}-all$ext)"); - move("$workdir/$+{name}$+{type}", "$opts_cmd{string}{imgdir}/$+{name}-all$ext") - or die "* Error!!: Couldn't be renamed $+{name}$+{type} to $opts_cmd{string}{imgdir}/$+{name}-all$ext"; - # pdfcrop - if (!$opts_cmd{boolean}{nocrop}) { - Infoline("Cropping the file $+{name}-$tmp.pdf"); - RUNOSCMD("pdfcrop $opt_crop", "$+{name}-$tmp.pdf $+{name}-$tmp.pdf",'show'); - } - # gray - if ($opts_cmd{boolean}{gray}) { - Infoline("Creating the file $+{name}-all.pdf [gray] in $tempDir"); - RUNOSCMD("$gscmd $quiet $opt_gs_dev{gray} ","-o $tempDir/$+{name}-all.pdf $workdir/$+{name}-$tmp.pdf",'show'); - } - else { - Infoline("Creating the file $+{name}-all.pdf in $tempDir"); - if ($verbose){ - Infocolor('Running', "mv $workdir/$+{name}-$tmp.pdf $tempDir/$+{name}-all.pdf"); - } - else { Infocolor('Running', "mv $+{name}-$tmp.pdf $tempDir/$+{name}-all.pdf"); } - # Renaming pdf file - Logline("[perl] move($workdir/$+{name}-$tmp.pdf, $tempDir/$+{name}-all.pdf)"); - move("$workdir/$+{name}-$tmp.pdf", "$tempDir/$+{name}-all.pdf") - or die "* Error!!: Couldn't be renamed $+{name}-$tmp.pdf to $tempDir/$+{name}-all.pdf"; - } - } - } -closedir $DIR; -} - -### Create image formats in separate files -if (!$opts_cmd{boolean}{norun}) { - Log("Creating the image formats: $format, working on $tempDir"); - opendir(my $DIR, $tempDir); - while (readdir $DIR) { - # PDF/PNG/JPG/BMP/TIFF format suported by ghostscript - if (/(?$name-$opts_cmd{string}{prefix}(-exa)?)(?-all\.pdf)/) { - for my $var (qw(pdf png jpg bmp tif)) { - if (defined $opts_cmd{image}{$var}) { - Log("Generating format [$var] from file $+{name}$+{type} in $imgdirpath using $gscmd"); - print 'Generating format', color('blue'), " [$var] ", color('reset'),"from file $+{name}$+{type}\r\n"; - RUNOSCMD("$gscmd $quiet $opt_gs_dev{$var} ", "-o $workdir/$opts_cmd{string}{imgdir}/$+{name}-%1d.$var $tempDir/$+{name}$+{type}",'show'); - } - } - } - # EPS/PPM/SVG format suported by poppler-utils - if (/(?$name-$opts_cmd{string}{prefix}-exa)(?-all\.pdf)/) { # pst-exa package - for my $var (qw(eps ppm svg)) { - if (defined $opts_cmd{image}{$var}) { - Log("Generating format [$var] from file $+{name}$+{type} in $imgdirpath using $cmd_poppler{$var}"); - print 'Generating format', color('blue'), " [$var] ", color('reset'),"from file $+{name}$+{type}\r\n"; - if (!$verbose){ - Infocolor('Running', "$cmd_poppler{$var} $opt_poppler{$var}"); - } - for (my $epsNo = 1; $epsNo <= $exaNo; $epsNo++) { - RUNOSCMD("$cmd_poppler{$var} $opt_poppler{$var}", "-f $epsNo -l $epsNo $tempDir/$+{name}$+{type} $workdir/$opts_cmd{string}{imgdir}/$+{name}-$epsNo.$var",'only'); - } - } - } - } - if (/(?$name-$opts_cmd{string}{prefix})(?-all\.pdf)/) { - for my $var (qw(eps ppm svg)) { - if (defined $opts_cmd{image}{$var}) { - Log("Generating format [$var] from file $+{name}$+{type} in $imgdirpath using $cmd_poppler{$var}"); - print 'Generating format', color('blue'), " [$var] ", color('reset'),"from file $+{name}$+{type}\r\n"; - if (!$verbose){ - Infocolor('Running', "$cmd_poppler{$var} $opt_poppler{$var}"); - } - for (my $epsNo = 1; $epsNo <= $envNo; $epsNo++) { - RUNOSCMD("$cmd_poppler{$var} $opt_poppler{$var}", "-f $epsNo -l $epsNo $tempDir/$+{name}$+{type} $workdir/$opts_cmd{string}{imgdir}/$+{name}-$epsNo.$var",'only'); - } - } - } - } - } # close while - closedir $DIR; - # Renaming PPM image files - if (defined $opts_cmd{image}{ppm}) { - Log("Renaming [ppm] images in $imgdirpath"); - if ($verbose){ - print 'Renaming', color('blue'), " [ppm] ", color('reset'),"images in $imgdirpath\r\n"; - } - opendir(my $DIR, $opts_cmd{string}{imgdir}); - while (readdir $DIR) { - if (/(?$name-$opts_cmd{string}{prefix}(-exa)?-\d+\.ppm)(?-\d+)(?\.ppm)/) { - if ($verbose){ - Infocolor('Running', "mv $+{name}$+{sep}$+{ppm} $+{name}"); - } - Logline("[perl] move($imgdirpath/$+{name}$+{sep}$+{ppm}, $imgdirpath/$+{name})"); - move("$opts_cmd{string}{imgdir}/$+{name}$+{sep}$+{ppm}", "$opts_cmd{string}{imgdir}/$+{name}") - or die "* Error!!: Couldn't be renamed $+{name}$+{sep}$+{ppm} to $+{name}"; - } - } - closedir $DIR; - } -} # close run - -### Constant -my $findgraphicx = 'true'; - -### Add $atbegindoc to $preamble -$preamble = "$atbegindoc$preamble"; - -### Replacing the extracted environments with \\includegraphics -if ($outfile) { - my @tag_remove_preamble = $preamble =~ m/(?:^\%<\*remove$tmp>.+?\%<\/remove$tmp>)/gmsx; - if (@tag_remove_preamble) { - Log("Removing the content between <*remove> ... tags in preamble for $opts_cmd{string}{output}$outext"); - $preamble =~ s/^\%<\*remove$tmp>\s*(.+?)\s*\%<\/remove$tmp>(?:[\t ]*(?:\r?\n|\r))?+//gmsx; - } - Log("Convert standard extracted environments to \\includegraphics for $opts_cmd{string}{output}$outext"); - my $grap = "\\includegraphics[scale=1]{$name-$opts_cmd{string}{prefix}-"; - my $close = '}'; - my $imgNo = 1; - $bodydoc =~ s/$BP.+?$EP/$grap@{[$imgNo++]}$close/msg; -} - -### pst-exa package -my $pstexa = qr/(?:\\ usepackage) \[\s*(.+?)\s*\] (?:\{\s*(pst-exa)\s*\} ) /x; -my @pst_exa; -my %pst_exa; - -### Search pst-exa package -@pst_exa = $preamble =~ m/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)|$pstexa/gmsx; -%pst_exa = map { $_ => 1 } @pst_exa; - -### If found comment and adjust path for graphic files -if (@pst_exa and $outfile) { - Log("Comment pst-exa package in preamble for $opts_cmd{string}{output}$outext"); - $findgraphicx = 'false'; - $preamble =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - (\\usepackage\[)\s*(swpl|tcb)\s*(\]\{pst-exa\})/\%$1$2,pdf$3/msxg; - if (exists $pst_exa{tcb}) { - Log("Suport for \\usepackage[tcb,pdf]\{pst-exa\} for $opts_cmd{string}{output}$outext"); - $bodydoc =~ s/(graphic=\{)\[(scale=\d*)\]($opts_cmd{string}{imgdir}\/$name-$opts_cmd{string}{prefix}-exa-\d*)\}/$1$2\}\{$3\}/gsmx; - } -} - -### Regex for clean file (pst) in preamble -$PALABRAS = qr/\b (?: pst-\w+ | pstricks (?: -add | -pdf )? | psfrag |psgo |vaucanson-g| auto-pst-pdf(?: -lua )? )/x; -$FAMILIA = qr/\{ \s* $PALABRAS (?: \s* [,] \s* $PALABRAS )* \s* \}(\%*)?/x; - -### Clean PST content in preamble -if ($clean{pst} and $outfile) { - Log("Remove pstricks packages in preamble for $opts_cmd{string}{output}$outext"); - $preamble =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - ^ $USEPACK (?: $CORCHETES )? $FAMILIA \s*//msxg; - $preamble =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - (?: ^ $USEPACK \{ | \G) [^}]*? \K (,?) \s* $PALABRAS (\s*) (,?) /$1 and $3 ? ',' : $1 ? $2 : ''/gemsx; - if (@pst_exa) { - Log("Uncomment pst-exa package in preamble for $opts_cmd{string}{output}$outext"); - $preamble =~ s/(?:\%)(\\usepackage\[\s*)(swpl|tcb)(,pdf\s*\]\{pst-exa\})/$1$2$3/msxg; - } - Log("Remove \\psset\{...\} in preamble for $opts_cmd{string}{output}$outext"); - $preamble =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - \\psset\{(?:\{.*?\}|[^\{])*\}(?:[\t ]*(?:\r?\n|\r))+//gmsx; - Log("Remove \\SpecialCoor in preamble for $opts_cmd{string}{output}$outext"); - $preamble =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - \\SpecialCoor(?:[\t ]*(?:\r?\n|\r))+//gmsx; - Log("Remove empty lines in preamble for $opts_cmd{string}{output}$outext"); - $preamble =~ s/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)| - ^\\usepackage\{\}(?:[\t ]*(?:\r?\n|\r))+/\n/gmsx; -} - -### To be sure that the package graphicx and \graphicspath is in the main -### document and not in a verbatim write environment we make the changes -my %tmpreplace = ( - 'graphicx' => 'TMPGRAPHICXTMP', - 'graphicspath' => 'TMPGRAPHICSPATHTMP', -); -my $findtmp = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %tmpreplace; - -### We go line by line and make the changes [need /p for ${^MATCH}] -while ($preamble =~ /\%<\*$dtxverb>(.+?)\%<\/$dtxverb> | $tmpcomment /pgmsx) { - my ($pos_inicial, $pos_final) = ($-[0], $+[0]); - my $encontrado = ${^MATCH}; - $encontrado =~ s/($findtmp)/$tmpreplace{$1}/g; - substr $preamble, $pos_inicial, $pos_final-$pos_inicial, $encontrado; - pos ($preamble) = $pos_inicial + length $encontrado; -} - -### Now we're trying to capture \graphicspath{...} -my $graphicspath= qr/\\ graphicspath \{ ((?: $llaves )+) \}/ix; -my @graphicspath; -@graphicspath = $preamble =~ m/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)|($graphicspath)/gmsx; - -if (@graphicspath and $outfile) { - Log("Found \\graphicspath in preamble for $opts_cmd{string}{output}$outext"); - $findgraphicx = 'false'; - while ($preamble =~ /$graphicspath /pgmx) { - my ($pos_inicial, $pos_final) = ($-[0], $+[0]); - my $encontrado = ${^MATCH}; - if ($encontrado =~ /$graphicspath/) { - my $argumento = $1; - if ($argumento !~ /\{$opts_cmd{string}{imgdir}\/\}/) { - $argumento .= "\{$opts_cmd{string}{imgdir}/\}"; - my $cambio = "\\graphicspath{$argumento}"; - substr $preamble, $pos_inicial, $pos_final-$pos_inicial, $cambio; - pos($preamble) = $pos_inicial + length $cambio; - } - } - } -} - -### Possible packages that load graphicx -my @pkgcandidates = qw ( - rotating epsfig lyluatex xunicode parsa xepersian-hm gregoriotex teixmlslides - teixml fotex hvfloat pgfplots grfpaste gmbase hep-paper postage schulealt - schule utfsym cachepic abc doclicense rotating epsfig semtrans mgltex - graphviz revquantum mpostinl cmpj cmpj2 cmpj3 chemschemex register papercdcase - flipbook wallpaper asyprocess draftwatermark rutitlepage dccpaper-base - nbwp-manual mandi fmp toptesi isorot pinlabel cmll graphicx-psmin ptmxcomp - countriesofeurope iodhbwm-templates fgruler combinedgraphics pax pdfpagediff - psfragx epsdice perfectcut upmethodology-fmt ftc-notebook tabvar vtable - teubner pas-cv gcard table-fct pdfpages keyfloat pdfscreen showexpl simplecd - ifmslide grffile reflectgraphics markdown bclogo tikz-page pst-uml realboxes - musikui csbulobalka lwarp mathtools sympytex mpgraphics miniplot.sty:77 - dottex pdftricks2 feupphdteses tex4ebook axodraw2 hagenberg-thesis dlfltxb - hu-berlin-bundle draftfigure quicktype endofproofwd euflag othelloboard - pdftricks unswcover breqn pdfswitch latex-make figlatex repltext etsvthor - cyber xcookybooky xfrac mercatormap chs-physics-report tikzscale ditaa - pst-poker gmp CJKvert asypictureb hletter tikz-network powerdot-fuberlin - skeyval gnuplottex plantslabels fancytooltips ieeepes pst-vectorian - phfnote overpic xtuformat stubs graphbox ucs pdfwin metalogo mwe - inline-images asymptote UNAMThesis authorarchive amscdx pst-pdf adjustbox - trimclip fixmetodonotes incgraph scanpages pst-layout alertmessage - svg quiz2socrative realhats autopdf egplot decorule figsize tikzexternal - pgfcore frontespizio textglos graphicx tikz tcolorbox pst-exa - ); - -my $pkgcandidates = join q{|}, map { quotemeta } sort { length $a <=> length $b } @pkgcandidates; -$pkgcandidates = qr/$pkgcandidates/x; -my @graphicxpkg; - -### Now we're trying to capture graphicx package -@graphicxpkg = $preamble =~ m/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)|($pkgcandidates)/gmsx; -if (@graphicxpkg and $outfile and $findgraphicx ne 'false') { - Log("Found graphicx package in preamble for $opts_cmd{string}{output}$outext"); - $findgraphicx = 'false'; -} - -### Revert changes in preamble for temp -my %tmpoutreplace = ( - 'TMPGRAPHICXTMP' => 'graphicx', - 'TMPGRAPHICSPATHTMP' => 'graphicspath', -); - -%replace = (%changes_out,%tmpoutreplace); -$find = join q{|}, map {quotemeta} sort { length $a <=> length $b } keys %replace; - -### Capture graphicx.sty in .log of LaTeX file -if ($findgraphicx ne 'false' and $outfile) { - Log("Couldn't capture the graphicx package for $opts_cmd{string}{output}$ext in preamble"); - my $ltxlog; - my @graphicx; - my $null = devnull(); - # Copy preamble and revert changes - my $preambletmp = $preamble; - $preambletmp =~ s/($find)/$replace{$1}/g; - $preambletmp =~ s/\%<\*$dtxverb>(.+?)\%<\/$dtxverb>/$1/gmsx; - Log("Creating $name-$opts_cmd{string}{prefix}-$tmp$ext [only preamble]"); - if ($verbose) { say "Creating [$name-$opts_cmd{string}{prefix}-$tmp$ext] with only preamble"; } - open my $OUTfile, '>', "$name-$opts_cmd{string}{prefix}-$tmp$ext"; - print {$OUTfile} "$preambletmp\n\\stop"; - close $OUTfile; - # Set compiler - if ($opts_cmd{compiler}{arara}) { - my @engine = $atbegindoc =~ m/\%<\*$dtxverb> .+?\%<\/$dtxverb>(*SKIP)(*F)|$arara_rule/msx; - my %engine = map { $_ => 1 } @engine; - if (%engine) { - for my $var (@arara_engines) { - if (defined $engine{$var}) { - Log("Found engine [$var] for arara"); - $compiler = $var; - } - } - } - else { - Log("Not detected engine for arara, use default [pdflatex]"); - $compiler = 'pdflatex'; - } - } - if ($opts_cmd{compiler}{latex}) { $compiler = 'pdflatex'; } - if ($opts_cmd{compiler}{dvilua}) { $compiler = 'lualatex'; } - # Compiling file - RUNOSCMD("$compiler $write18 -interaction=batchmode", "$name-$opts_cmd{string}{prefix}-$tmp$ext >$null", 'only'); - # Restore arara compiler - if ($opts_cmd{compiler}{arara}) { $compiler = 'arara'; } - Log("Search graphicx package in $name-$opts_cmd{string}{prefix}-$tmp.log"); - open my $LaTeXlog, '<', "$name-$opts_cmd{string}{prefix}-$tmp.log"; - { - local $/; - $ltxlog = <$LaTeXlog>; - } - close $LaTeXlog; - # Try to capture graphicx - @graphicx = $ltxlog =~ m/.+? (graphicx\.sty)/xg; - if (@graphicx) { - Log("Found graphicx package in $name-$opts_cmd{string}{prefix}-$tmp.log"); - } - else { - Log("Not found graphicx package in $name-$opts_cmd{string}{prefix}-$tmp.log"); - Log("Add \\usepackage\{graphicx\} to preamble of $opts_cmd{string}{output}$outext"); - $preamble= "$preamble\\usepackage\{graphicx\}\n"; - } -} - -### Add last lines -if ($outfile) { - if (!@graphicspath) { - Log("Not found \\graphicspath in preamble for $opts_cmd{string}{output}$outext"); - Log("Add \\graphicspath\{\{$opts_cmd{string}{imgdir}/\}\} to preamble for $opts_cmd{string}{output}$ext"); - $preamble= "$preamble\\graphicspath\{\{$opts_cmd{string}{imgdir}/\}\}\n"; - } - Log("Add \\usepackage\{grfext\} to preamble for $opts_cmd{string}{output}$ext"); - $preamble = "$preamble\\usepackage\{grfext\}\n"; - Log("Add \\PrependGraphicsExtensions\*\{\.pdf\} to preamble for $opts_cmd{string}{output}$ext"); - $preamble = "$preamble\\PrependGraphicsExtensions\*\{\.pdf\}"; - $preamble =~ s/\%<\*$dtxverb>\s*(.+?)\s*\%<\/$dtxverb>/$1/gmsx; - $preamble =~ s/^\\usepackage\{\}(?:[\t ]*(?:\r?\n|\r))+/\n/gmsx; - $preamble =~ s/^(?:[\t ]*(?:\r?\n|\r))?+//gmsx; -} - -### We remove environments from the -if (%delete_env and $outfile) { - Log("Remove environments in body of $opts_cmd{string}{output}$ext"); - %replace = (%delete_env); - $find = join q{|}, map { quotemeta } sort { length $a <=> length $b } keys %replace; - # We must prevent eliminating somewhere wrong - # We re-create the regular expressions to make the changes - my @new_verb_tmp = array_minus(@verbatim, @delete_env); - $verbatim = join q{|}, map { quotemeta } sort { length $a <=> length $b } @new_verb_tmp; - $verbatim = qr/$verbatim/x; - $verb_std = qr { - ( - (?: - \\begin\{$verbatim\*?\} - (?: - (?>[^\\]+)| - \\ - (?!begin\{$verbatim\*?\}) - (?!end\{$verbatim\*?\})| - (?-1) - )* - \\end\{$verbatim\*?\} - ) - ) - }x; - - my @new_verbw_tmp = array_minus(@verbatim_w, @delete_env); - $verbatim_w = join q{|}, map { quotemeta } sort { length $a <=> length $b } @new_verbw_tmp; - $verbatim_w = qr/$verbatim_w/x; - $verb_wrt = qr { - ( - (?: - \\begin\{$verbatim_w\*?\} - (?: - (?>[^\\]+)| - \\ - (?!begin\{$verbatim_w\*?\}) - (?!end\{$verbatim_w\*?\})| - (?-1) - )* - \\end\{$verbatim_w\*?\} - ) - ) - }x; - while ($bodydoc =~ /$verb_wrt | $verb_std /pgmx) { - my ($pos_inicial, $pos_final) = ($-[0], $+[0]); - my $encontrado = ${^MATCH}; - $encontrado =~ s/($find)/$replace{$1}/g; - substr $bodydoc, $pos_inicial, $pos_final-$pos_inicial, $encontrado; - pos ($bodydoc) = $pos_inicial + length $encontrado; - } - # Now remove - $bodydoc =~ s/($delt_env)(?:[\t ]*(?:\r?\n|\r))?+//gmsx; -} - -### Create a -if ($outfile) { - # Options for out_file (add $end to outfile) - my $out_file = $clean{doc} ? "$preamble\n$bodydoc\n\\end\{document\}" - : "$preamble\n$bodydoc\n$enddoc" - ; - # Clean \psset{...} content in - if ($clean{pst}) { - $out_file =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \%<\*$dtxverb> .+? \%<\/$dtxverb>(*SKIP)(*F)| - \\psset\{(?:\{.*?\}|[^\{])*\}(?:[\t ]*(?:\r?\n|\r))?+//gmsx; - } - # Clean \tikzset{...} content in - if ($clean{tkz}) { - $out_file =~ s/\\begin\{nopreview\}.+?\\end\{nopreview\}(*SKIP)(*F)| - \%<\*$dtxverb> .+? \%<\/$dtxverb>(*SKIP)(*F)| - \\tikzset\{(?:\{.*?\}|[^\{])*\}(?:[\t ]*(?:\r?\n|\r))?+//gmsx; - } - # Revert all changes in outfile - $out_file =~ s/\\begin\{nopreview\}\%$tmp\s*(.+?)\s*\\end\{nopreview\}\%$tmp/$1/gmsx; - my @tag_remove_outfile = $out_file =~ m/(?:^\%<\*remove$tmp>.+?\%<\/remove$tmp>)/gmsx; - if (@tag_remove_outfile) { - Log("Removing the content between <*remove> ... tags in all $opts_cmd{string}{output}$outext"); - $out_file =~ s/^\%<\*remove$tmp>\s*(.+?)\s*\%<\/remove$tmp>(?:[\t ]*(?:\r?\n|\r))?+//gmsx; - } - # Remove internal mark for verbatim and verbatim write environments - $out_file =~ s/\%<\*$dtxverb>\s*(.+?)\s*\%<\/$dtxverb>/$1/gmsx; - %replace = (%changes_out); - $find = join q{|}, map {quotemeta} sort { length $a <=> length $b } keys %replace; - $out_file =~ s/($find)/$replace{$1}/g; - if (-e "$opts_cmd{string}{output}$outext") { - Log("Rewriting the file $opts_cmd{string}{output}$outext in $workdir"); - Infocolor('Warning', "The file [$opts_cmd{string}{output}$outext] already exists and will be rewritten"); - } - else{ - Infoline("Creating the file $opts_cmd{string}{output}$outext"); - Log("Write the file $opts_cmd{string}{output}$outext in $workdir"); - } - # Write - open my $OUTfile, '>', "$opts_cmd{string}{output}$outext"; - print {$OUTfile} $out_file; - close $OUTfile; -} - -### Set compiler for process -$compiler = $opts_cmd{compiler}{xetex} ? 'xelatex' - : $opts_cmd{compiler}{luatex} ? 'lualatex' - : $opts_cmd{compiler}{dvips} ? 'latex' - : $opts_cmd{compiler}{dvilua} ? 'lualatex' - : $opts_cmd{compiler}{dvipdf} ? 'latex' - : $opts_cmd{compiler}{arara} ? 'arara' - : $opts_cmd{compiler}{latexmk} ? 'latexmk' - : 'pdflatex' - ; - -### Set options for latexmk -my $ltxmkopt = $opts_cmd{compiler}{xetex} ? "-pdfxe -silent -xelatex=\"xelatex $write18 -recorder %O %S\"" - : $opts_cmd{compiler}{luatex} ? "-pdflua -silent -lualatex=\"lualatex $write18 -recorder %O %S\"" - : $opts_cmd{compiler}{dvilua} ? "-pdflua -silent -lualatex=\"lualatex $write18 -recorder %O %S\"" - : $opts_cmd{compiler}{dvips} ? "-pdfps -silent -latex=\"latex $write18 -recorder %O %S\"" - : $opts_cmd{compiler}{dvipdf} ? "-pdfdvi -silent -latex=\"latex $write18 -recorder %O %S\"" - : "-pdf -silent -pdflatex=\"pdflatex $write18 -recorder %O %S\"" - ; - -### Set options for compiler -$opt_compiler = $opts_cmd{compiler}{arara} ? '--log' - : $opts_cmd{compiler}{latexmk} ? "$ltxmkopt" - : "$write18 -interaction=nonstopmode -recorder" - ; - -### Message in command line for compiler -$msg_compiler = $opts_cmd{compiler}{xetex} ? 'xelatex' - : $opts_cmd{compiler}{luatex} ? 'lualatex' - : $opts_cmd{compiler}{latex} ? 'pdflatex' - : $opts_cmd{compiler}{dvips} ? 'latex>dvips>ps2pdf' - : $opts_cmd{compiler}{dvilua} ? 'lualatex' - : $opts_cmd{compiler}{dvipdf} ? 'latex>dvipdfmx' - : $opts_cmd{compiler}{arara} ? 'arara' - : 'latexmk' - ; - -### Now set message for latexmk -if ($opts_cmd{compiler}{latexmk}) { - $msg_compiler = 'latexmk'; -} - -### Compiling -if (!$opts_cmd{boolean}{norun} and $outfile) { - Log("Compiling the file $opts_cmd{string}{output}$outext using [$msg_compiler]"); - print "Compiling the file $opts_cmd{string}{output}$outext using ", color('magenta'), "[$msg_compiler]\r\n",color('reset'); - RUNOSCMD("$compiler $opt_compiler", "$opts_cmd{string}{output}$outext",'show'); - # Compiling using dvips>ps2pdf - if ($opts_cmd{compiler}{dvips}) { - RUNOSCMD("dvips $quiet -Ppdf", "$opts_cmd{string}{output}.dvi",'show'); - RUNOSCMD("ps2pdf -sPDFSETTINGS=prepress -sAutoRotatePages=None", "$opts_cmd{string}{output}.ps $opts_cmd{string}{output}.pdf", 'show'); - } - # Compiling using latex>dvipdfmx - if ($opts_cmd{compiler}{dvipdf}) { - RUNOSCMD("dvipdfmx $quiet", "$opts_cmd{string}{output}.dvi", 'show'); - } -} - -### Remove temporary files -my @tmpfiles; -my @protected = qw(); -my $flsline = 'OUTPUT'; -my @flsfile; - -### Protect generated files -if (defined $opts_cmd{string}{output}) { - push @protected, "$opts_cmd{string}{output}$outext", "$opts_cmd{string}{output}.pdf"; -} - -### Find files -find(\&aux_files, $workdir); -sub aux_files{ - my $findtmpfiles = $_; - if (-f $findtmpfiles && $findtmpfiles =~ m/$name-$opts_cmd{string}{prefix}(-exa)?-$tmp.+?$/) { # search - push @tmpfiles, $_; - } - return; -} - -### Add if exists -if (-e 'arara.log') { - push @flsfile, 'arara.log'; -} -if (-e "$name-$opts_cmd{string}{prefix}-$tmp.fls") { - push @flsfile, "$name-$opts_cmd{string}{prefix}-$tmp.fls"; -} -if (-e "$name-$opts_cmd{string}{prefix}-exa-$tmp.fls") { - push @flsfile, "$name-$opts_cmd{string}{prefix}-exa-$tmp.fls"; -} -if (-e "$opts_cmd{string}{output}.fls") { - push @flsfile, "$opts_cmd{string}{output}.fls"; -} - -### Read .fls file -for my $filename(@flsfile){ - open my $RECtmp, '<', $filename; - push @tmpfiles, grep /^$flsline/,<$RECtmp>; - close $RECtmp; -} -foreach (@tmpfiles) { s/^$flsline\s+|\s+$//g; } -push @tmpfiles, @flsfile; -@tmpfiles = uniq(@tmpfiles); -@tmpfiles = array_minus(@tmpfiles, @protected); - -Log('The files that will be deleted are:'); -Logarray(\@tmpfiles); - -### Remove only if exist -if (@tmpfiles) { - Infoline("Remove temporary files created in $workdir"); - foreach my $tmpfiles (@tmpfiles) { - move($tmpfiles, $tempDir); - } -} - -### Find dirs created by minted -my @deldirs; -my $mintdir = "\_minted\-$name-$opts_cmd{string}{prefix}-$tmp"; -my $mintdirexa = "\_minted\-$name-$opts_cmd{string}{prefix}-exa-$tmp"; -if (-e $mintdir) { push @deldirs, $mintdir; } -if (-e $mintdirexa) { push @deldirs, $mintdirexa; } - -Log('The directory that will be deleted are:'); -Logarray(\@deldirs); - -### Remove only if exist -if (@deldirs) { - Infoline("Remove temporary directories created by minted in $workdir"); - foreach my $deldirs (@deldirs) { - remove_tree($deldirs); - } -} - -### Compress ./images with all generated files -my $archivetar; -if ($opts_cmd{boolean}{zip} or $opts_cmd{boolean}{tar}) { - my $stamp = strftime("%Y-%m-%d", localtime); - $archivetar = "$opts_cmd{string}{imgdir}-$stamp"; - - my @savetozt; - find(\&zip_tar, $opts_cmd{string}{imgdir}); - sub zip_tar{ - my $filesto = $_; - if (-f $filesto && $filesto =~ m/$name-$opts_cmd{string}{prefix}-.+?$/) { # search - push @savetozt, $File::Find::name; - } - return; - } - Log("The files are compress found in $imgdirpath are:"); - Logarray(\@savetozt); - if ($opts_cmd{boolean}{zip}) { - if (-e "$archivetar.zip") { - Infocolor('Warning', "The file [$archivetar.zip] already exists and will be rewritten"); - Log("Rewriting the file $archivetar.zip in $workdir"); - } - else{ - print "Creating the file ", color('magenta'), "[$archivetar.zip]", - color('reset'), " with generate files in ./$opts_cmd{string}{imgdir}\r\n"; - Log("Writen the file $archivetar.tar.gz in $workdir"); - } - zip \@savetozt => "$archivetar.zip"; - } - if ($opts_cmd{boolean}{tar}) { - if (-e "$archivetar.tar.gz") { - Infocolor('Warning', "The file [$archivetar.tar.gz] already exists and will be rewritten"); - Log("Rewriting the file $archivetar.tar.gz in $workdir"); - } - else{ - print "Creating the file ", color('magenta'), "[$archivetar.tar.gz]", - color('reset'), " with generate files in ./$opts_cmd{string}{imgdir}\r\n"; - Log("Writen the file $archivetar.tar.gz in $workdir"); - } - my $imgdirtar = Archive::Tar->new(); - $imgdirtar->add_files(@savetozt); - $imgdirtar->write( "$archivetar.tar.gz" , 9 ); - } -} - -### End script process -if (!$opts_cmd{boolean}{norun} and ($opts_cmd{boolean}{srcenv} or $opts_cmd{boolean}{subenv})) { - Log("The image files: $format and generated files are in $imgdirpath"); -} -if (!$opts_cmd{boolean}{norun} and (!$opts_cmd{boolean}{srcenv} and !$opts_cmd{boolean}{subenv})) { - Log("The image files: $format are in $imgdirpath"); -} -if ($opts_cmd{boolean}{norun} and ($opts_cmd{boolean}{srcenv} or $opts_cmd{boolean}{subenv})) { - Log("The generated files are in $imgdirpath"); -} -if ($outfile) { Log("The file $opts_cmd{string}{output}$ext are in $workdir"); } - -Infocolor('Finish', "The execution of $scriptname has been successfully completed"); - -Log("The execution of $scriptname has been successfully completed"); - -__END__ -- cgit v1.2.3