Source code for storylines.files

# Copyright (C) 2016-2024 Jan Berges
# This program is free software under the terms of the BSD Zero Clause License.

"""Typeset TeX, rasterize PDF."""

from __future__ import division

import os
import subprocess

from .png import save, load

[docs] def goto(filename): """Go to output directory for plot typesetting. Parameters ---------- filename : str LaTeX file name including possible path. Returns ------- stem : str File name without path and extension. typ : str Desired file type (extension). home : function Function to return to previous working directory. """ head, tail = os.path.split(filename) for extension in 'tex', 'pdf', 'png': if tail.endswith('.%s' % extension): stem = tail[:-len(extension) - 1] typ = extension break else: stem = tail typ = None if head: cwd = os.getcwd() subprocess.call(['mkdir', '-p', head]) os.chdir(head) def home(): if head: os.chdir(cwd) return stem, typ, home
[docs] def typeset(stem, engine='pdflatex'): """Run typesetting engine and remove ``.aux`` and ``.log`` files. Parameters ---------- stem : str File name without path and extension (in current working directory). engine : str, default 'pdflatex' TeX typesetting engine. """ try: subprocess.call([engine, '--interaction=batchmode', '%s.tex' % stem]) for suffix in 'aux', 'log': os.remove('%s.%s' % (stem, suffix)) except OSError: print('Could not typeset %s' % stem)
[docs] def rasterize(stem, dpi=300.0, width=0, height=0, rewrite=False): """Run ``pdftoppm`` and remove ``-1`` from name of resulting PNG file. Parameters ---------- stem : str File name without path and extension (in current working directory). dpi : float, default 300.0 Image resolution in dots per inch. width, height : int, default 0 Image dimensions in pixels. If either `width` or `height` is zero, it will be determined by the aspect ratio of the image. If both are zero, they will also be determined by `dpi`. rewrite : bool, default False Rewrite resulting PNG file using StoryLines? This will remove possible metadata and may reduce the file size but currently is quite slow. """ try: args = ['-png'] if width or height: args += ['-scale-to-x', '%g' % (width or -1)] args += ['-scale-to-y', '%g' % (height or -1)] else: args += ['-r', '%g' % dpi] subprocess.call(['pdftoppm'] + args + ['%s.pdf' % stem, stem]) os.rename('%s-1.png' % stem, '%s.png' % stem) if rewrite: save('%s.png' % stem, load('%s.png' % stem)) except OSError: print('Could not rasterize %s' % stem)
[docs] def combine(filename, pdfs, columns=100, align=0.5, halign='left', pdf=False, png=False, dpi=300.0): """Arrange multiple PDFs in single file. Parameters ---------- filename : str Name of combined file. pdfs : list of str Names of PDFs to be combined. columns : int, default 100 Number of PDFs to be arranged side by side. align : float, default 0.5 Vertical alignment of PDFs, where 0, 0.5, and 1 stand for the bottom, center, and top of the individual figures. halign : str, default 'left' Horizontal alignment of PDFs. Possible values are ``'left'``, ``'center'`` and ``'right'``. pdf : bool, default False Convert resulting TeX file to PDF? Automatically set to ``True`` if `filename` ends with ``.pdf``. png : bool, default False Convert resulting PDF file to PNG? This implies `pdf`. Automatically set to ``True`` if `filename` ends with ``.png``. dpi : float, default 300.0 Image resolution in dots per inch. """ stem, typ, home = goto(filename) png = png or typ == 'png' pdf = pdf or typ == 'pdf' or png with open('%s.tex' % stem, 'w') as tex: tex.write('\\documentclass[varwidth=1189mm]{standalone}\n' '\\usepackage{graphicx}\n' '\\begin{document}\n' '\\noindent%\n') if halign == 'center': tex.write('\\centering%\n') elif halign == 'right': tex.write('\\raggedleft%\n') for n in range(len(pdfs)): nobreak = (n + 1) % columns or n + 1 == len(pdfs) tex.write('\\raisebox{-%g\\height}{\\includegraphics{{%s}.pdf}}%s\n' % (align, pdfs[n], '%' if nobreak else '\\\\[-\\lineskip]')) tex.write('\\end{document}\n') if pdf: typeset(stem) if png: rasterize(stem, dpi) home()