#! /usr/bin/env python ################################################### # Convert each pgfornament picture to a PDF file. # # # # In fact, this script creates only a Ninja # # build file to perform the conversion. # # # # Author: Scott Pakin # ################################################### import glob import os import re import subprocess import sys import textwrap from pathlib import Path 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() def find_pgfornament_dir(): # Find the vectorian1.pgf file then return its parent's parent directory. proc = subprocess.run(['kpsewhich', '--path=$TEXINPUTS', 'vectorian1.pgf'], capture_output=True, encoding='utf-8') if proc.returncode != 0: return None fname = Path(proc.stdout.strip()) return fname.parent.parent def list_pgfornament_files(dname): '''Return a list of vectorian*.pgf numbers and a list of pgfhan*.pgf numbers.''' number_re = re.compile(r'(\d+)\.pgf') vectorian = set() for fname in (dname / "vectorian").glob('vectorian*.pgf'): match = number_re.search(str(fname)) vectorian.add(int(match[1])) pgfhan = set() for fname in (dname / "pgfhan").glob('pgfhan*.pgf'): match = number_re.search(str(fname)) pgfhan.add(int(match[1])) return sorted(vectorian), sorted(pgfhan) def construct_phony(target, deps): 'Return a phony build line.' lines = textwrap.wrap(' '.join(deps), break_long_words=False, break_on_hyphens=False, initial_indent=' ', subsequent_indent=' ') return f'build {target} : phony $\n' + ' $\n'.join(lines) + '\n' # Generate a Ninja build file for managing PDF creation. with open('pgfornament.ninja', 'w') as w: # Write a header comment. w.write('# This is a generated file. DO NOT EDIT.\n') w.write('# Edit %s instead.\n' % os.path.abspath(sys.argv[0])) # Find the pgfornament base directory. If not found, generate a # trivial Ninja file and exit. dname = find_pgfornament_dir() if dname is None: w.write('\n') w.write('build PGFORNAMENT : phony\n') sys.exit(0) # Determine what vectorian and pgfhan files to generate. vectorian, pgfhan = list_pgfornament_files(dname) # Write all rules. w.write(r''' rule write-file command = /bin/echo -e '$body' > $out description = Creating $out rule generate-mylatex command = $ cd pgfornament ; $ pdflatex --ini '&pdflatex' mylatex.ltx preloaded.tex description = Creating mylatex.fmt for faster builds rule write-vectorian-tex command = $ NUM=`echo $out | perl -ne 'm,(\d+)\.tex$$, && print "$$1\n"'` ; $ /bin/echo -e "$ \\\\documentclass{minimal}\\n$ \\\\begin{document}\\n$ \\\\newpgfornamentfamily{vectorian}\\n$ \\\\pgfornament[height=15pt,ydelta=-5pt]{$$NUM}\\n$ \\\\end{document}" > $out description = Writing $out rule write-pgfhan-tex command = $ NUM=`echo $out | perl -ne 'm,(\d+)\.tex$$, && print "$$1\n"'` ; $ /bin/echo -e "$ \\\\documentclass{minimal}\\n$ \\\\begin{document}\\n$ \\\\newpgfornamentfamily{han}\\n$ \\\\resizebox{!}{15pt}{\\\\pgfornament[height=25pt,ydelta=-5pt]{$$NUM}}\\n$ \\\\end{document}" > $out description = Writing $out rule tex-to-pdf command = $ texname="$$(basename $in)" ; $ jname="$$(basename $in .tex)-uncrop" ; $ cd pgfornament ; $ pdflatex -jobname "$$jname" '&mylatex' "$$texname" description = pdflatex $in rule crop-pdf command = pdfcrop $in $out description = Cropping $in to produce $out ########################################################################### ''') # Write build statements for creating mylatex.ltx. w.write(r''' build pgfornament/preloaded.tex : write-file body = $ \\documentclass{minimal}\n$ \\usepackage{pgfornament}\n$ \\usepackage{graphicx}\n$ \\begin{document}\n$ \\end{document} build pgfornament/mylatex.fmt pgfornament/mylatex.log : generate-mylatex pgfornament/preloaded.tex | %s %s ''' % (kpsewhich('mylatex.ltx'), kpsewhich('pgfornament.sty'))) # Write build statements for all vectorian*.tex files and all # pgfhan*.tex files. for i in vectorian: w.write(f'build pgfornament/vectorian{i}.tex : write-vectorian-tex\n') w.write('\n') for i in pgfhan: w.write(f'build pgfornament/pgfhan{i}.tex : write-pgfhan-tex\n') w.write('\n') # Write build statements to compile each LaTeX file to a PDF file. for i in vectorian: w.write(f'build pgfornament/vectorian{i}-uncrop.pdf pgfornament/vectorian{i}-uncrop.log pgfornament/vectorian{i}-uncrop.aux : tex-to-pdf pgfornament/vectorian{i}.tex | pgfornament/mylatex.fmt\n') w.write('\n') for i in pgfhan: w.write(f'build pgfornament/pgfhan{i}-uncrop.pdf pgfornament/pgfhan{i}-uncrop.log pgfornament/pgfhan{i}-uncrop.aux : tex-to-pdf pgfornament/pgfhan{i}.tex | pgfornament/mylatex.fmt\n') w.write('\n') # Write build statements to crop each PDF file. for i in vectorian: w.write(f'build pgfornament/vectorian{i}.pdf : crop-pdf pgfornament/vectorian{i}-uncrop.pdf\n') w.write('\n') for i in pgfhan: w.write(f'build pgfornament/pgfhan{i}.pdf : crop-pdf pgfornament/pgfhan{i}-uncrop.pdf\n') w.write('\n') # Write some phony build statements to aggregate all outputs. w.write(construct_phony('VECTORIAN', [f'pgfornament/vectorian{i}.pdf' for i in vectorian])) w.write('\n') w.write(construct_phony('PGFHAN', [f'pgfornament/pgfhan{i}.pdf' for i in pgfhan])) w.write('\n') w.write('build PGFORNAMENT : phony VECTORIAN PGFHAN\n')