1#!/usr/bin/python3 2# 3# Modify reStructuredText 'image' directives by adding a percentage 'width' 4# attribute so that the images are scaled to fit on the page when the document 5# is renderd to LaTeX, and add a center alignment. 6# 7# Also convert references to PNG images to use PDF files generated from SVG 8# files if available. 9# 10# Without the explicit size specification, the images are ridiculously huge and 11# most extend far off the right side of the page. 12# 13# Copyright (C) 2009 Colin D Bennett 14# 15# This program is free software; you can redistribute it and/or modify 16# it under the terms of the GNU General Public License as published by 17# the Free Software Foundation; either version 2 of the License, or 18# (at your option) any later version. 19# 20# This program is distributed in the hope that it will be useful, 21# but WITHOUT ANY WARRANTY; without even the implied warranty of 22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23# GNU General Public License for more details. 24# 25# You should have received a copy of the GNU General Public License 26# along with this program; if not, write to the Free Software 27# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 28 29import os 30import re 31import shutil 32import sys 33from sys import argv 34from subprocess import call 35 36verbose = False 37 38IMAGE_DIRECTIVE_PATTERN = re.compile(u'^..\\s+image::\\s+(.*)\\`\\s+$') 39DIRECTIVE_ELEMENT_PATTERN = re.compile(u'^\\s+:[^:]+:\\s+') 40 41class Converter(object): 42 def __init__(self, srcdir, destdir): 43 self.srcdir = srcdir 44 self.destdir = destdir 45 46 # Process .txt files in sourcedir, generating output in destdir. 47 def process_files(self): 48 for filename in os.listdir(self.srcdir): 49 # Process all text files in the current directory. 50 if filename.endswith('.txt'): 51 inpath = os.path.join(self.srcdir, filename) 52 outpath = os.path.join(self.destdir, filename) 53 self._process_file(inpath, outpath) 54 55 def _process_file(self, inpath, outpath): 56 infile = open(inpath, 'r') 57 outfile = open(outpath, 'w') 58 foundimg = False 59 for line in infile: 60 if foundimg and DIRECTIVE_ELEMENT_PATTERN.match(line) is None: 61 if verbose: 62 print('Fixing image directive') 63 # The preceding image directive has no elements. 64 outfile.write(' :width: 85%\n') 65 outfile.write(' :align: center\n') 66 foundimg = False 67 68 image_fixer = ImageFixer(self.srcdir, self.destdir) 69 image_fixer_lambda = lambda match: image_fixer.substitute_pdf_image(match) 70 line = IMAGE_DIRECTIVE_PATTERN.sub(image_fixer_lambda, line) 71 directive_match = IMAGE_DIRECTIVE_PATTERN.match(line) 72 if directive_match is not None: 73 image_src = directive_match.group(1) 74 if verbose: 75 print(('Image ' + image_src + ' in ' + filename 76 + ': ' + line.strip())) 77 78 foundimg = True 79 outfile.write(line) 80 outfile.close() 81 infile.close() 82 83class ImageFixer(object): 84 def __init__(self, srcdir, destdir): 85 self.srcdir = srcdir 86 self.destdir = destdir 87 88 def substitute_pdf_image(self, match): 89 prefix = match.string[:match.start(1)] 90 newname = self.convert_image_to_pdf(match.group(1)) 91 suffix = match.string[match.end(1):] 92 return prefix + newname + suffix 93 94 def replace_extension(self, path, newext): 95 if path.endswith(newext): 96 raise Exception("File '" + path + "' already has extension '" 97 + newext + "'") 98 dot = path.rfind('.') 99 if dot == -1: 100 return path + newext 101 else: 102 return path[:dot] + newext 103 104 # Possibly use an SVG alternative to a PNG image, converting the SVG image 105 # to a PDF first. Whether or not a conversion is made, the image to use is 106 # written to the destination directory and the path to use in the RST # 107 # source is returned. 108 def convert_image_to_pdf(self, filename): 109 # Make the directory structure for the image in the destination dir. 110 image_dirname = os.path.dirname(filename) 111 if image_dirname: 112 image_dirpath = os.path.join(self.destdir, image_dirname) 113 if not os.path.exists(image_dirpath): 114 os.mkdir(image_dirpath) 115 116 # Decide how to handle this image. 117 if filename.endswith('.png'): 118 # See if there is a vector alternative. 119 svgfile = self.replace_extension(filename, '.svg') 120 svgpath = os.path.join(self.srcdir, svgfile) 121 if os.path.exists(svgpath): 122 if verbose: 123 print('Using SVG alternative to PNG') 124 # Convert SVG to PDF with Inkscape. 125 pdffile = self.replace_extension(filename, '.pdf') 126 pdfpath = os.path.join(self.destdir, pdffile) 127 if call(['/usr/bin/inkscape', 128 '--export-pdf=' + pdfpath, svgpath]) != 0: 129 raise Exception("Conversion to pdf failed") 130 return pdffile 131 132 # No conversion, just copy the file. 133 srcpath = os.path.join(self.srcdir, filename) 134 destpath = os.path.join(self.destdir, filename) 135 shutil.copyfile(srcpath, destpath) 136 return filename 137 138if __name__ == '__main__': 139 IN_DIR_OPT = '--in-dir=' 140 OUT_DIR_OPT = '--out-dir=' 141 srcdir = None 142 destdir = None 143 144 if len(argv) < 2: 145 print(('Usage: ' + argv[0] + ' ' + IN_DIR_OPT + 'INDIR ' 146 + OUT_DIR_OPT + 'OUTDIR')) 147 print() 148 print('This will convert all .txt files in INDIR into file in OUTDIR') 149 print('while adjusting the use of images and possibly converting SVG') 150 print('images to PDF files so LaTeX can include them.') 151 sys.exit(1) 152 153 for arg in argv[1:]: 154 if arg == '-v' or arg == '--verbose': 155 verbose = True 156 elif arg.startswith(IN_DIR_OPT): 157 srcdir = arg[len(IN_DIR_OPT):] 158 elif arg.startswith(OUT_DIR_OPT): 159 destdir = arg[len(OUT_DIR_OPT):] 160 else: 161 print(('Invalid argument ' + arg)) 162 sys.exit(1) 163 164 if srcdir is None or destdir is None: 165 print(('Please specify the ' + IN_DIR_OPT + ' and ' 166 + OUT_DIR_OPT + ' options.')) 167 sys.exit(1) 168 169 if not os.path.exists(destdir): 170 os.mkdir(destdir) 171 Converter(srcdir, destdir).process_files() 172 173# vim: set ts=4 sw=4 et: 174