Try even harder to obtain an instant preview

This is a followup commit to 691fdea3 and restores the behavior of the
script as it was intended before 64e0c558, other than taking into account
possible inclusion of files that only pdflatex can process and the
possibility of multiple defined math macros.
The instant previews in the math manual now work again.
This commit is contained in:
Enrico Forestieri 2015-04-29 12:28:51 +02:00
parent ec7833272a
commit 75f7eafd65
2 changed files with 74 additions and 27 deletions

View File

@ -482,13 +482,13 @@ def legacy_conversion_step3(latex_file, dpi, output_format, dvips_failed, skipMe
i = i + 1
progress("Processing page %s, file %s" % (i, file))
if use_pdftocairo and epstopdf != None:
conv_name = "PdfToCairo"
conv_name = "pdftocairo"
conv_status, conv_stdout = run_command("%s --outfile=%s.pdf %s"
% (epstopdf, file, file))
if not conv_status:
conv_status, conv_stdout = run_command(conv_call % (file, i))
else:
conv_name = "Ghostscript"
conv_name = "ghostscript"
conv_status, conv_stdout = run_command(conv_call % (i, file))
if conv_status:
@ -498,6 +498,7 @@ def legacy_conversion_step3(latex_file, dpi, output_format, dvips_failed, skipMe
# Pass failed pages to pdflatex
if len(failed_pages) > 0:
warning("Now trying to obtain failed previews through pdflatex")
legacy_conversion_pdflatex(latex_file, failed_pages, legacy_metrics,
use_pdftocairo, conv, gs_device, gs_ext, alpha, resolution,
output_format)

View File

@ -159,18 +159,25 @@ def extract_metrics_info(dvipng_stdout):
def fix_latex_file(latex_file):
documentclass_re = re.compile("(\\\\documentclass\[)(1[012]pt,?)(.+)")
newcommandx_re = re.compile("^(\\\\newcommandx)(.+)")
tmp = mkstemp()
changed = 0
for line in open(latex_file, 'r').readlines():
match = documentclass_re.match(line)
if match != None:
changed = 1
tmp.write("%s%s\n" % (match.group(1), match.group(3)))
continue
match = newcommandx_re.match(line)
if match == None:
tmp.write(line)
continue
changed = 1
tmp.write("%s%s\n" % (match.group(1), match.group(3)))
tmp.write("\\providecommandx%s\n" % match.group(2))
if changed:
copyfileobj(tmp, open(latex_file,"wb"), 1)
@ -195,15 +202,17 @@ def convert_to_ppm_format(pngtopnm, basename):
# Returns a tuple of:
# ps_pages: list of page indexes of pages containing PS literals
# pdf_pages: list of page indexes of pages requiring running pdflatex
# page_count: total number of pages
# pages_parameter: parameter for dvipng to exclude pages with PostScript
# pages_parameter: parameter for dvipng to exclude pages with PostScript/PDF
def find_ps_pages(dvi_file):
# latex failed
# FIXME: try with pdflatex
if not os.path.isfile(dvi_file):
error("No DVI output.")
# Check for PostScript specials in the dvi, badly supported by dvipng
# Check for PostScript specials in the dvi, badly supported by dvipng,
# and inclusion of PDF/PNG/JPG files.
# This is required for correct rendering of PSTricks and TikZ
dv2dt = find_exe_or_terminate(["dv2dt"])
dv2dt_call = '%s "%s"' % (dv2dt, dvi_file)
@ -211,33 +220,47 @@ def find_ps_pages(dvi_file):
# The output from dv2dt goes to stdout
dv2dt_status, dv2dt_output = run_command(dv2dt_call)
psliteral_re = re.compile("^special[1-4] [0-9]+ '(\"|ps:)")
pdffile_re = re.compile("^special[1-4] [0-9]+ 'PSfile=.*.(pdf|png|jpg)")
# Parse the dtl file looking for PostScript specials.
# Pages using PostScript specials are recorded in ps_pages and then
# used to create a different LaTeX file for processing in legacy mode.
# Parse the dtl file looking for PostScript specials and pdflatex files.
# Pages using PostScript specials or pdflatex files are recorded in
# ps_pages or pdf_pages, respectively, and then used to create a
# different LaTeX file for processing in legacy mode.
page_has_ps = False
page_has_pdf = False
page_index = 0
ps_pages = []
pdf_pages = []
ps_or_pdf_pages = []
for line in dv2dt_output.split("\n"):
# New page
if line.startswith("bop"):
page_has_ps = False
page_has_pdf = False
page_index += 1
# End of page
if line.startswith("eop") and page_has_ps:
# We save in a list all the PostScript pages
ps_pages.append(page_index)
if line.startswith("eop") and (page_has_ps or page_has_pdf):
# We save in a list all the PostScript/PDF pages
if page_has_ps:
ps_pages.append(page_index)
else:
pdf_pages.append(page_index)
ps_or_pdf_pages.append(page_index)
if psliteral_re.match(line) != None:
# Literal PostScript special detected!
page_has_ps = True
if pdffile_re.match(line) != None:
# Inclusion of pdflatex image file detected!
page_has_pdf = True
# Create the -pp parameter for dvipng
pages_parameter = ""
if len(ps_pages) > 0 and len(ps_pages) < page_index:
# Don't process Postscript pages with dvipng by selecting the
if len(ps_or_pdf_pages) > 0 and len(ps_or_pdf_pages) < page_index:
# Don't process Postscript/PDF pages with dvipng by selecting the
# wanted pages through the -pp parameter. E.g., dvipng -pp 4-12,14,64
pages_parameter = " -pp "
skip = True
@ -246,7 +269,7 @@ def find_ps_pages(dvi_file):
# Use page ranges, as a list of pages could exceed command line
# maximum length (especially under Win32)
for index in xrange(1, page_index + 1):
if (not index in ps_pages) and skip:
if (not index in ps_or_pdf_pages) and skip:
# We were skipping pages but current page shouldn't be skipped.
# Add this page to -pp, it could stay alone or become the
# start of a range.
@ -255,7 +278,7 @@ def find_ps_pages(dvi_file):
last = index
# We're not skipping anymore
skip = False
elif (index in ps_pages) and (not skip):
elif (index in ps_or_pdf_pages) and (not skip):
# We weren't skipping but current page should be skipped
if last != index - 1:
# If the start index of the range is the previous page
@ -270,10 +293,10 @@ def find_ps_pages(dvi_file):
# Remove the trailing separator
pages_parameter = pages_parameter.rstrip(",")
# We've to manage the case in which the last page is closing a range
if (not index in ps_pages) and (not skip) and (last != index):
if (not index in ps_or_pdf_pages) and (not skip) and (last != index):
pages_parameter += "-" + str(index)
return (ps_pages, page_index, pages_parameter)
return (ps_pages, pdf_pages, page_index, pages_parameter)
def main(argv):
# Set defaults.
@ -368,7 +391,8 @@ def main(argv):
progress("Preprocess through lilypond-book: %s" % lilypond)
progress("Altering the latex file for font size and colors")
# Omit font size specification in latex file.
# Omit font size specification in latex file and make sure multiple
# defined macros are not an issue.
fix_latex_file(latex_file)
if lilypond:
@ -411,11 +435,7 @@ def main(argv):
fg_color, bg_color, latex, pdf_output)
# Compile the latex file.
latex_status, latex_stdout = run_latex(latex, latex_file, bibtex)
if latex_status:
progress("Using the legacy conversion method and pdflatex (latex failed)")
return legacy_conversion_step1(latex_file, dpi, output_format, fg_color,
bg_color, "pdflatex", True)
run_latex(latex, latex_file, bibtex)
# The dvi output file name
dvi_file = latex_file_re.sub(".dvi", latex_file)
@ -434,17 +454,22 @@ def main(argv):
error("No DVI or PDF output. %s failed." \
% (os.path.basename(latex)))
# Look for PS literals in DVI pages
# ps_pages: list of page indexes of pages containing PS literals
# Look for PS literals or inclusion of pdflatex files in DVI pages
# ps_pages: list of indexes of pages containing PS literals
# pdf_pages: list of indexes of pages requiring running pdflatex
# page_count: total number of pages
# pages_parameter: parameter for dvipng to exclude pages with PostScript
(ps_pages, page_count, pages_parameter) = find_ps_pages(dvi_file)
(ps_pages, pdf_pages, page_count, pages_parameter) = find_ps_pages(dvi_file)
# If all pages need PostScript, directly use the legacy method.
# If all pages need PostScript or pdflatex, directly use the legacy method.
if len(ps_pages) == page_count:
progress("Using the legacy conversion method (PostScript support)")
return legacy_conversion_step1(latex_file, dpi, output_format, fg_color,
bg_color, latex, pdf_output)
elif len(pdf_pages) == page_count:
progress("Using the legacy conversion method (PDF support)")
return legacy_conversion_step1(latex_file, dpi, output_format, fg_color,
bg_color, "pdflatex", True)
# Run the dvi file through dvipng.
dvipng_call = '%s -Ttight -depth -height -D %d -fg "%s" -bg "%s" %s "%s"' \
@ -483,6 +508,27 @@ def main(argv):
join_metrics_and_rename(dvipng_metrics, legacy_metrics, ps_pages,
original_bitmap, destination_bitmap)
# If some pages require running pdflatex pass them to legacy method
if len(pdf_pages) > 0:
# Create a new LaTeX file just for the snippets needing
# the legacy method
legacy_latex_file = latex_file_re.sub("_legacy.tex", latex_file)
filter_pages(latex_file, legacy_latex_file, pdf_pages)
# Pass the new LaTeX file to the legacy method
progress("Pages %s include pdflatex image files" % pdf_pages)
progress("Using the legacy conversion method (PDF support)")
legacy_status, legacy_metrics = legacy_conversion_step1(legacy_latex_file,
dpi, output_format, fg_color, bg_color, "pdflatex", True, True)
# Now we need to mix metrics data from dvipng and the legacy method
original_bitmap = latex_file_re.sub("%d." + output_format, legacy_latex_file)
destination_bitmap = latex_file_re.sub("%d." + output_format, latex_file)
# Join metrics from dvipng and legacy, and rename legacy bitmaps
join_metrics_and_rename(dvipng_metrics, legacy_metrics, pdf_pages,
original_bitmap, destination_bitmap)
# Convert images to ppm format if necessary.
if output_format == "ppm":
convert_to_ppm_format(pngtopnm, latex_file_re.sub("", latex_file))