From: Enrico Forestieri Date: Mon, 27 Apr 2015 19:37:26 +0000 (+0200) Subject: Use pdftocairo (if available) for instant preview. X-Git-Tag: 2.2.0alpha1~954 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=c9b553fd2f6d7a13da41dd43475005556b5a4c0d;p=features.git Use pdftocairo (if available) for instant preview. If pdftocairo is detected, it is used for generating bitmaps in the legacy method route in preference to ghostscript. This is justified by the fact that the conversion is 4 to 5 times faster and the quality of the generated images is superior. --- diff --git a/lib/scripts/legacy_lyxpreview2ppm.py b/lib/scripts/legacy_lyxpreview2ppm.py index e6d5371de2..c9c3081af9 100644 --- a/lib/scripts/legacy_lyxpreview2ppm.py +++ b/lib/scripts/legacy_lyxpreview2ppm.py @@ -42,6 +42,8 @@ # * gs; # * pdflatex (optional); # * pnmcrop (optional). +# * pdftocairo (optional). +# * epstopdf (optional). # preview.sty is part of the preview-latex project # http://preview-latex.sourceforge.net/ @@ -56,11 +58,11 @@ # [legacy_conversion_step2] # 2) Call dvips to create one PS file for each DVI page # [legacy_conversion_step3] -# 3) If dvips fails look for PDF and call gs to produce bitmaps -# 4) Otherwise call gs on each PostScript file to produce bitmaps +# 3) If dvips fails look for PDF and call pdftocairo or gs to produce bitmaps +# 4) Otherwise call pdftocairo or gs on each PostScript file to produce bitmaps # [legacy_conversion_pdflatex] # 5) Keep track of pages on which gs failed and pass them to pdflatex -# 6) Call gs on the PDF output from pdflatex to produce bitmaps +# 6) Call pdftocairo or gs on the PDF output from pdflatex to produce bitmaps # 7) Extract and write to file (or return to lyxpreview2bitmap) # metrics from both methods (standard and pdflatex) @@ -74,6 +76,8 @@ # is required in certain cases, if hyperref is active for instance, # (step 5, 6). # If possible, dvipng should be used, as it's much faster. +# If possible, the script will use pdftocairo instead of gs, +# as it's much faster and gives better results. import glob, os, pipes, re, string, sys @@ -229,6 +233,7 @@ def legacy_latex_file(latex_file, fg_color, bg_color): \definecolor{bg}{rgb}{%s} \pagecolor{bg} \usepackage[%s,tightpage]{preview} +\IfFileExists{lmodern.sty}{\usepackage{lmodern}}{\usepackage{ae,aecomp}} \makeatletter \g@addto@macro\preview{\begingroup\color{bg}\special{ps::clippath fill}\color{fg}} \g@addto@macro\endpreview{\endgroup} @@ -307,8 +312,8 @@ def legacy_conversion_step1(latex_file, dpi, output_format, fg_color, bg_color, # Creates a new LaTeX file from the original with pages specified in # failed_pages, pass it through pdflatex and updates the metrics # from the standard legacy route -def legacy_conversion_pdflatex(latex_file, failed_pages, legacy_metrics, gs, - gs_device, gs_ext, alpha, resolution, output_format): +def legacy_conversion_pdflatex(latex_file, failed_pages, legacy_metrics, + use_pdftocairo, conv, gs_device, gs_ext, alpha, resolution, output_format): # Search for pdflatex executable pdflatex = find_exe(["pdflatex"]) @@ -323,16 +328,30 @@ def legacy_conversion_pdflatex(latex_file, failed_pages, legacy_metrics, gs, pdflatex_status, pdflatex_stdout = run_latex(pdflatex, pdf_latex_file) pdf_file = latex_file_re.sub(".pdf", pdf_latex_file) - - # GhostScript call to produce bitmaps - gs_call = '%s -dNOPAUSE -dBATCH -dSAFER -sDEVICE=%s ' \ - '-sOutputFile="%s%%d.%s" ' \ - '-dGraphicsAlphaBit=%d -dTextAlphaBits=%d ' \ - '-r%f "%s"' \ - % (gs, gs_device, latex_file_re.sub("", pdf_latex_file), \ - gs_ext, alpha, alpha, resolution, pdf_file) - gs_status, gs_stdout = run_command(gs_call) - if gs_status: + latex_file_root = latex_file_re.sub("", pdf_latex_file) + + # Converter call to produce bitmaps + if use_pdftocairo: + conv_call = '%s -png -transp -r %d "%s" "%s"' \ + % (conv, resolution, pdf_file, latex_file_root) + conv_status, conv_stdout = run_command(conv_call) + if not conv_status: + seqnum_re = re.compile("-([0-9]+)") + for name in glob.glob("%s-*.png" % latex_file_root): + match = seqnum_re.search(name) + if match != None: + new_name = seqnum_re.sub(str(int(match.group(1))), name) + os.rename(name, new_name) + else: + conv_call = '%s -dNOPAUSE -dBATCH -dSAFER -sDEVICE=%s ' \ + '-sOutputFile="%s%%d.%s" ' \ + '-dGraphicsAlphaBit=%d -dTextAlphaBits=%d ' \ + '-r%f "%s"' \ + % (conv, gs_device, latex_file_root, \ + gs_ext, alpha, alpha, resolution, pdf_file) + conv_status, conv_stdout = run_command(conv_call) + + if conv_status: # Give up! warning("Some pages failed with all the possible routes") else: @@ -371,17 +390,27 @@ def legacy_conversion_step2(latex_file, dpi, output_format, skipMetrics = False) # Either latex and dvips have been run and we have a ps file, or -# pdflatex has been run and we have a pdf file. Proceed with gs. +# pdflatex has been run and we have a pdf file. Proceed with pdftocairo or gs. def legacy_conversion_step3(latex_file, dpi, output_format, dvips_failed, skipMetrics = False): # External programs used by the script. gs = find_exe_or_terminate(["gswin32c", "gswin64c", "gs"]) pnmcrop = find_exe(["pnmcrop"]) + pdftocairo = find_exe(["pdftocairo"]) + epstopdf = find_exe(["epstopdf"]) + use_pdftocairo = pdftocairo != None and output_format == "png" + if use_pdftocairo: + conv = pdftocairo + else: + conv = gs # Files to process pdf_file = latex_file_re.sub(".pdf", latex_file) ps_file = latex_file_re.sub(".ps", latex_file) - # Extract resolution data for gs from the log file. + # The latex file name without extension + latex_file_root = latex_file_re.sub("", latex_file) + + # Extract resolution data for the converter from the log file. log_file = latex_file_re.sub(".log", latex_file) resolution = extract_resolution(log_file, dpi) @@ -406,48 +435,76 @@ def legacy_conversion_step3(latex_file, dpi, output_format, dvips_failed, skipMe # Generate the bitmap images if dvips_failed: # dvips failed, maybe there's a PDF, try to produce bitmaps - gs_call = '%s -dNOPAUSE -dBATCH -dSAFER -sDEVICE=%s ' \ - '-sOutputFile="%s%%d.%s" ' \ - '-dGraphicsAlphaBit=%d -dTextAlphaBits=%d ' \ - '-r%f "%s"' \ - % (gs, gs_device, latex_file_re.sub("", latex_file), \ - gs_ext, alpha, alpha, resolution, pdf_file) - - gs_status, gs_stdout = run_command(gs_call) - if gs_status: - error("Failed: %s %s" % (os.path.basename(gs), ps_file)) + if use_pdftocairo: + conv_call = '%s -png -transp -r %d "%s" "%s"' \ + % (pdftocairo, resolution, pdf_file, latex_file_root) + + conv_status, conv_stdout = run_command(conv_call) + if not conv_status: + seqnum_re = re.compile("-([0-9]+)") + for name in glob.glob("%s-*.png" % latex_file_root): + match = seqnum_re.search(name) + if match != None: + new_name = seqnum_re.sub(str(int(match.group(1))), name) + os.rename(name, new_name) + else: + conv_call = '%s -dNOPAUSE -dBATCH -dSAFER -sDEVICE=%s ' \ + '-sOutputFile="%s%%d.%s" ' \ + '-dGraphicsAlphaBit=%d -dTextAlphaBits=%d ' \ + '-r%f "%s"' \ + % (gs, gs_device, latex_file_root, \ + gs_ext, alpha, alpha, resolution, pdf_file) + + conv_status, conv_stdout = run_command(conv_call) + + if conv_status: + error("Failed: %s %s" % (os.path.basename(conv), pdf_file)) else: - # Model for calling gs on each file - gs_call = '%s -dNOPAUSE -dBATCH -dSAFER -sDEVICE=%s ' \ - '-sOutputFile="%s%%d.%s" ' \ - '-dGraphicsAlphaBit=%d -dTextAlphaBits=%d ' \ - '-r%f "%%s"' \ - % (gs, gs_device, latex_file_re.sub("", latex_file), \ - gs_ext, alpha, alpha, resolution) + # Model for calling the converter on each file + if use_pdftocairo and epstopdf != None: + conv_call = '%s -png -transp -singlefile -r %d "%%s.pdf" "%s%%d"' \ + % (pdftocairo, resolution, latex_file_root) + else: + conv_call = '%s -dNOPAUSE -dBATCH -dSAFER -sDEVICE=%s ' \ + '-sOutputFile="%s%%d.%s" ' \ + '-dGraphicsAlphaBit=%d -dTextAlphaBits=%d ' \ + '-r%f "%%s"' \ + % (gs, gs_device, latex_file_root, \ + gs_ext, alpha, alpha, resolution) i = 0 # Collect all the PostScript files (like *.001, *.002, ...) - ps_files = glob.glob("%s.[0-9][0-9][0-9]" % latex_file_re.sub("", latex_file)) + ps_files = glob.glob("%s.[0-9][0-9][0-9]" % latex_file_root) ps_files.sort() - # Call GhostScript for each file + # Call the converter for each file for file in ps_files: i = i + 1 progress("Processing page %s, file %s" % (i, file)) - gs_status, gs_stdout = run_command(gs_call % (i, file)) - if gs_status: - # gs failed, keep track of this - warning("Ghostscript failed on page %s, file %s" % (i, file)) + if use_pdftocairo and epstopdf != None: + 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_status, conv_stdout = run_command(conv_call % (i, file)) + + if conv_status: + # The converter failed, keep track of this + warning("%s failed on page %s, file %s" % (conv_name, i, file)) failed_pages.append(i) # Pass failed pages to pdflatex if len(failed_pages) > 0: - legacy_conversion_pdflatex(latex_file, failed_pages, legacy_metrics, gs, - gs_device, gs_ext, alpha, resolution, output_format) + legacy_conversion_pdflatex(latex_file, failed_pages, legacy_metrics, + use_pdftocairo, conv, gs_device, gs_ext, alpha, resolution, + output_format) - # Crop the images - if pnmcrop != None: - crop_files(pnmcrop, latex_file_re.sub("", latex_file)) + # Crop the ppm images + if pnmcrop != None and output_format == "ppm": + crop_files(pnmcrop, latex_file_root) # Allow to skip .metrics creation for custom management # (see the dvipng method)