*** Extend preview scripts to also handle PDF output (bug 2165) ***

* src/PreviewLoader.cpp:
	- add conditions for preview with pdf output

* lib/scripts/legacy_lyxpreview2ppm.py:
	- if no dvi preview file is available, check for a PDF file
	  and process that, if found
	- also produce png output, if requested.

* lib/scripts/lyxpreview2bitmap.py:
	- if no dvi preview file is available, check for a PDF file
	  and process that, if found

*  lib/scripts/lyxpreview_tools.py:
	- move some common functions here

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@25419 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Jürgen Spitzmüller 2008-07-02 14:42:04 +00:00
parent 35e14de706
commit 01c71419d9
4 changed files with 136 additions and 54 deletions

View File

@ -56,7 +56,7 @@
import glob, os, pipes, re, string, sys
from lyxpreview_tools import copyfileobj, error, find_exe, \
find_exe_or_terminate, mkstemp, run_command
find_exe_or_terminate, make_texcolor, mkstemp, run_command, warning
# Pre-compiled regular expression.
latex_file_re = re.compile("\.tex$")
@ -168,25 +168,34 @@ def extract_resolution(log_file, dpi):
return dpi * (10.0 / fontsize) * (1000.0 / magnification)
def legacy_latex_file(latex_file, fg_color, bg_color):
use_preview_re = re.compile("(\\\\usepackage\[[^]]+)(\]{preview})")
def legacy_latex_file(latex_file, fg_color, bg_color, bg_color_gr):
use_preview_dvi_re = re.compile("(\s*\\\\usepackage\[[^]]+)(dvips\]{preview})")
use_preview_pdf_re = re.compile("(\s*\\\\usepackage\[[^]]+)(pdftex\]{preview})")
tmp = mkstemp()
success = 0
try:
for line in open(latex_file, 'r').readlines():
match = use_preview_re.match(line)
match = use_preview_dvi_re.match(line)
if match == None:
tmp.write(line)
match = use_preview_pdf_re.match(line)
if match == None:
tmp.write(line)
continue
success = 1
tmp.write(" \\usepackage{color}\n" \
" \\pagecolor[rgb]{%s}\n" \
"%s\n" \
% (bg_color_gr, match.group()))
continue
success = 1
tmp.write("%s,dvips,tightpage%s\n\n" \
"\\AtBeginDocument{\\AtBeginDvi{%%\n" \
"\\special{!userdict begin/bop-hook{//bop-hook exec\n" \
"<%s%s>{255 div}forall setrgbcolor\n" \
"clippath fill setrgbcolor}bind def end}}}\n" \
tmp.write("%stightpage,%s\n" \
" \\AtBeginDocument{\\AtBeginDvi{%%\n" \
" \\special{!userdict begin/bop-hook{//bop-hook exec\n" \
" <%s%s>{255 div}forall setrgbcolor\n" \
" clippath fill setrgbcolor}bind def end}}}\n" \
% (match.group(1), match.group(2), fg_color, bg_color))
except:
@ -226,21 +235,17 @@ def legacy_conversion(argv):
dpi = string.atoi(argv[2])
output_format = argv[3]
if output_format != "ppm":
error("This script will generate ppm format images only.")
fg_color = argv[4]
bg_color = argv[5]
bg_color_gr = make_texcolor(argv[5], True)
# External programs used by the script.
path = string.split(os.environ["PATH"], os.pathsep)
latex = find_exe_or_terminate(["pplatex", "platex", "latex2e", "latex"], path)
dvips = find_exe_or_terminate(["dvips"], path)
gs = find_exe_or_terminate(["gswin32c", "gs"], path)
pnmcrop = find_exe(["pnmcrop"], path)
path = string.split(os.environ["PATH"], os.pathsep)
latex = find_exe_or_terminate(["latex", "pplatex", "platex", "latex2e"], path)
# Move color information into the latex file.
if not legacy_latex_file(latex_file, fg_color, bg_color):
if not legacy_latex_file(latex_file, fg_color, bg_color, bg_color_gr):
error("Unable to move color info into the latex file")
# Compile the latex file.
@ -251,15 +256,29 @@ def legacy_conversion(argv):
error("%s failed to compile %s" \
% (os.path.basename(latex), latex_file))
return legacy_conversion_step2(latex_file, dpi, output_format)
def legacy_conversion_step2(latex_file, dpi, output_format):
# External programs used by the script.
path = string.split(os.environ["PATH"], os.pathsep)
dvips = find_exe_or_terminate(["dvips"], path)
gs = find_exe_or_terminate(["gswin32c", "gs"], path)
pnmcrop = find_exe(["pnmcrop"], path)
# Run the dvi file through dvips.
dvi_file = latex_file_re.sub(".dvi", latex_file)
ps_file = latex_file_re.sub(".ps", latex_file)
pdf_file = latex_file_re.sub(".pdf", latex_file)
dvips_call = '%s -o "%s" "%s"' % (dvips, ps_file, dvi_file)
dvips_failed = False
dvips_status, dvips_stdout = run_command(dvips_call)
if dvips_status != None:
error("Failed: %s %s" % (os.path.basename(dvips), dvi_file))
warning('Failed: %s %s ... looking for PDF' \
% (os.path.basename(dvips), dvi_file))
dvips_failed = True
# Extract resolution data for gs from the log file.
log_file = latex_file_re.sub(".log", latex_file)
@ -271,13 +290,27 @@ def legacy_conversion(argv):
if resolution > 150:
alpha = 2
gs_device = "png16m"
gs_ext = "png"
if output_format == "ppm":
gs_device = "pnmraw"
gs_ext = "ppm"
# Generate the bitmap images
gs_call = '%s -dNOPAUSE -dBATCH -dSAFER -sDEVICE=pnmraw ' \
'-sOutputFile="%s%%d.ppm" ' \
gs_call = '%s -dNOPAUSE -dBATCH -dSAFER -sDEVICE=%s ' \
'-sOutputFile="%s%%d.%s" ' \
'-dGraphicsAlphaBit=%d -dTextAlphaBits=%d ' \
'-r%f "%s"' \
% (gs, latex_file_re.sub("", latex_file), \
alpha, alpha, resolution, ps_file)
% (gs, gs_device, latex_file_re.sub("", latex_file), \
gs_ext, alpha, alpha, resolution, ps_file)
if dvips_failed:
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 != None:

View File

@ -47,14 +47,14 @@
import glob, os, re, string, sys
from legacy_lyxpreview2ppm import legacy_conversion
from legacy_lyxpreview2ppm import legacy_conversion, \
legacy_conversion_step2
from lyxpreview_tools import error, find_exe, \
find_exe_or_terminate, run_command
from lyxpreview_tools import copyfileobj, error, find_exe, \
find_exe_or_terminate, make_texcolor, mkstemp, run_command, warning
# Pre-compiled regular expressions.
hexcolor_re = re.compile("^[0-9a-fA-F]{6}$")
latex_file_re = re.compile("\.tex$")
@ -64,18 +64,6 @@ def usage(prog_name):
% prog_name
def make_texcolor(hexcolor):
# Test that the input string contains 6 hexadecimal chars.
if not hexcolor_re.match(hexcolor):
error("Cannot convert color '%s'" % hexcolor)
red = float(string.atoi(hexcolor[0:2], 16)) / 255.0
green = float(string.atoi(hexcolor[2:4], 16)) / 255.0
blue = float(string.atoi(hexcolor[4:6], 16)) / 255.0
return "rgb %f %f %f" % (red, green, blue)
def extract_metrics_info(dvipng_stdout, metrics_file):
metrics = open(metrics_file, 'w')
# "\[[0-9]+" can match two kinds of numbers: page numbers from dvipng
@ -117,6 +105,37 @@ def extract_metrics_info(dvipng_stdout, metrics_file):
return success
def color_pdf(latex_file, bg_color):
use_preview_pdf_re = re.compile("(\s*\\\\usepackage\[[^]]+)(pdftex\]{preview})")
tmp = mkstemp()
success = 0
try:
for line in open(latex_file, 'r').readlines():
match = use_preview_pdf_re.match(line)
if match == None:
tmp.write(line)
continue
success = 1
tmp.write(" \\usepackage{color}\n" \
" \\pagecolor[rgb]{%s}\n" \
"%s\n" \
% (bg_color, match.group()))
continue
except:
# Unable to open the file, but do nothing here because
# the calling function will act on the value of 'success'.
warning('Warning in color_pdf! Unable to open "%s"' % latex_file)
warning(`sys.exc_type` + ',' + `sys.exc_value`)
if success:
copyfileobj(tmp, open(latex_file,"wb"), 1)
return success
def convert_to_ppm_format(pngtopnm, basename):
png_file_re = re.compile("\.png$")
@ -145,30 +164,32 @@ def main(argv):
os.chdir(dir)
dpi = string.atoi(argv[3])
fg_color = make_texcolor(argv[4])
bg_color = make_texcolor(argv[5])
fg_color = make_texcolor(argv[4], False)
bg_color = make_texcolor(argv[5], False)
bg_color_gr = make_texcolor(argv[5], True)
# External programs used by the script.
path = string.split(os.environ["PATH"], os.pathsep)
latex = find_exe_or_terminate(["pplatex", "platex", "latex2e", "latex"], path)
latex = find_exe_or_terminate(["latex", "pplatex", "platex", "latex2e"], path)
# This can go once dvipng becomes widespread.
dvipng = find_exe(["dvipng"], path)
if dvipng == None:
if output_format == "ppm":
# The data is input to legacy_conversion in as similar
# as possible a manner to that input to the code used in
# LyX 1.3.x.
vec = [ argv[0], argv[2], argv[3], argv[1], argv[4], argv[5] ]
return legacy_conversion(vec)
else:
error("The old 'dvi->ps->ppm' conversion requires "
"ppm as the output format")
# The data is input to legacy_conversion in as similar
# as possible a manner to that input to the code used in
# LyX 1.3.x.
vec = [ argv[0], argv[2], argv[3], argv[1], argv[4], argv[5] ]
return legacy_conversion(vec)
pngtopnm = ""
if output_format == "ppm":
pngtopnm = find_exe_or_terminate(["pngtopnm"], path)
# Move color information for PDF into the latex file.
if not color_pdf(latex_file, bg_color_gr):
error("Unable to move color info into the latex file")
# Compile the latex file.
latex_call = '%s "%s"' % (latex, latex_file)
@ -184,8 +205,9 @@ def main(argv):
dvipng_status, dvipng_stdout = run_command(dvipng_call)
if dvipng_status != None:
error("%s failed to generate images from %s" \
warning("%s failed to generate images from %s ... looking for PDF" \
% (os.path.basename(dvipng), dvi_file))
return legacy_conversion_step2(latex_file, dpi, output_format)
# Extract metrics info from dvipng_stdout.
metrics_file = latex_file_re.sub(".metrics", latex_file)

View File

@ -11,7 +11,7 @@
# Paul A. Rubin, rubin@msu.edu.
# A repository of the following functions, used by the lyxpreview2xyz scripts.
# copyfileobj, error, find_exe, find_exe_or_terminate, mkstemp,
# copyfileobj, error, find_exe, find_exe_or_terminate, make_texcolor, mkstemp,
# run_command, warning
import os, re, string, sys, tempfile
@ -43,6 +43,22 @@ def error(message):
sys.exit(1)
def make_texcolor(hexcolor, graphics):
# Test that the input string contains 6 hexadecimal chars.
hexcolor_re = re.compile("^[0-9a-fA-F]{6}$")
if not hexcolor_re.match(hexcolor):
error("Cannot convert color '%s'" % hexcolor)
red = float(string.atoi(hexcolor[0:2], 16)) / 255.0
green = float(string.atoi(hexcolor[2:4], 16)) / 255.0
blue = float(string.atoi(hexcolor[4:6], 16)) / 255.0
if graphics:
return "%f,%f,%f" % (red, green, blue)
else:
return "rgb %f %f %f" % (red, green, blue)
def find_exe(candidates, path):
for prog in candidates:
for directory in path:

View File

@ -717,8 +717,19 @@ void PreviewLoader::Impl::dumpPreamble(odocstream & os) const
// Use the preview style file to ensure that each snippet appears on a
// fresh page.
// Also support PDF output (automatically generated e.g. when
// \usepackage[pdftex]{hyperref} is used.
os << "\n"
<< "\\usepackage[active,delayed,dvips,showlabels,lyx]{preview}\n"
<< "\\newif\\ifpdf\n"
<< "\\ifx\\pdfoutput\\undefined\n"
<< "\\else\\ifx\\pdfoutput\\relax\n"
<< "\\else\\ifnum0=\\pdfoutput\n"
<< "\\else\\pdftrue\\fi\\fi\\fi\n"
<< "\\ifpdf\n"
<< " \\usepackage[active,delayed,tightpage,showlabels,lyx,pdftex]{preview}\n"
<< "\\else\n"
<< " \\usepackage[active,delayed,showlabels,lyx,dvips]{preview}\n"
<< "\\fi\n"
<< "\n";
}