#! /usr/bin/env python ################################################ # Convert each figchild picture to a PDF file. # # # # Author: Scott Pakin # ################################################ import concurrent.futures import os import re import subprocess import sys def kpsewhich(fname): 'Find a filename in the TeX tree.' proc = subprocess.run(['kpsewhich', fname], capture_output=True, check=True, encoding='utf-8') return proc.stdout.strip() # Extract all commands defined by figchild.sty and the package description. desc = None commands = [] newcmd_re = re.compile(r'^\\newcommand{\\(fc\w+)\}') desc_re = re.compile(r'\\ProvidesPackage\{figchild\}\[(.*?)\]') sty = kpsewhich('figchild.sty') with open(sty) as r: for ln in r: # Extract the package description. if desc is None: match = desc_re.search(ln) if match is not None: desc = match[1] # Extract a command. match = newcmd_re.search(ln) if match is None: continue if match[1] != 'fcAlligatorB': # Undocumented and broken commands.append(match[1]) commands.sort(key=lambda s: s.lower()) # Create a fakefigchild.sty file. with open('fakefigchild.sty', 'w') as w: w.write('''\ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is a generated file. DO NOT EDIT. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ''') w.write('''\ \\NeedsTeXFormat{LaTeX2e} \\ProvidesPackage{fakefigchild}[%s] \\RequirePackage{graphicx} ''' % desc) for cmd in commands: ht = 20 if cmd == 'fcPencil': # Special case for \fcPencil, which is abnormally wide and short. ht = 5 w.write('\\DeclareRobustCommand{\\%s}{%%\n' % cmd) w.write(' \\includegraphics[height=%dpt,keepaspectratio]' '{figchild/%s}%%\n' % (ht, cmd)) w.write('}\n') w.write('\n') w.write('\\endinput\n') # Create and switch to a figchild subdirectory. try: os.mkdir('figchild') except FileExistsError: pass os.chdir('figchild') # For speed, dump a LaTeX format file with figchild preloaded. with open('preloaded.tex', 'w') as w: w.write(r''' \documentclass{minimal} \usepackage[a2paper,landscape]{geometry} \usepackage{figchild} \usepackage{graphicx} \begin{document} \end{document} '''[1:]) subprocess.run([ 'pdflatex', '--ini', '&pdflatex', 'mylatex.ltx', 'preloaded.tex' ], check=True) def run_and_return_output(cmd_line): 'Run a command line and return its combined stdout + stderr.' stdout = 'RUN: ' + ' '.join(cmd_line) + '\n' proc = subprocess.run(cmd_line, check=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout += proc.stdout.decode('utf-8') return stdout def generate_graphic(cmd): 'Generate a PDF file for a given figchild command.' stdout = f'*** PROCESSING {cmd} ***\n\n' # Create a LaTeX file. stdout += f'CREATE: {cmd}.tex\n' div = 48 if cmd == 'fcPencil': # Special case for \fcPencil, which is abnormally wide and short. div = 12 with open(cmd + '.tex', 'w') as w: w.write(r''' \documentclass{minimal} \begin{document} \newsavebox{\fig} \savebox{\fig}{\%s{1}{black}{1}} \newlength{\figheight} \settoheight{\figheight}{\usebox{\fig}} \makeatletter \edef\figscale{\expandafter\strip@pt\dimexpr\figheight / %d\relax} \makeatother \%s{1}{black}{\figscale} \end{document} '''[1:] % (cmd, div, cmd)) # Compile the LaTeX file to PDF. stdout += run_and_return_output(['pdflatex', '&mylatex', cmd + '.tex']) # Crop the PDF file. stdout += run_and_return_output(['pdfcrop', cmd + '.pdf']) # Overwrite the original PDF file with the cropped version. stdout += f'RUN: mv {cmd}-crop.pdf {cmd}.pdf\n' os.rename(f'{cmd}-crop.pdf', f'{cmd}.pdf') # Output the buffered output. stdout += '\n' print(stdout) # Concurrently process all figures. with concurrent.futures.ProcessPoolExecutor() as executor: executor.map(generate_graphic, commands)