From: Han-Wen Nienhuys Date: Wed, 5 Mar 2003 17:37:14 +0000 (+0000) Subject: * python/lilylib.py (make_page_images): add function. X-Git-Tag: release/1.7.14~6 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=42bb369cd16b8a788a0d66cdaaca6ec38dd7012b;p=lilypond.git * python/lilylib.py (make_page_images): add function. * scripts/ly2dvi.py (run_latex): include title in preview image. * scripts/lilypond-book.py (process_ly2dvi_blocks): call ly2dvi from lilypond-book for tags in HTML. * scripts/ly2dvi.py (option_definitions): add --debug option to print out environment. --- diff --git a/ChangeLog b/ChangeLog index 5d9d850226..0d136aa92a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,15 @@ 2003-03-05 Han-Wen Nienhuys + * python/lilylib.py (make_page_images): add function. + + * scripts/ly2dvi.py (run_latex): include title in preview image. + + * scripts/lilypond-book.py (process_ly2dvi_blocks): call ly2dvi + from lilypond-book for tags in HTML. + + * scripts/ly2dvi.py (option_definitions): add --debug option to + print out environment. + * input/regression/tie-chord-partial.ly: new file. 2003-03-05 Heikki Junes diff --git a/Documentation/user/appendices.itely b/Documentation/user/appendices.itely index c151df2cc3..1f594e1593 100644 --- a/Documentation/user/appendices.itely +++ b/Documentation/user/appendices.itely @@ -97,7 +97,7 @@ rules. @section The Feta font The following symbols are available in the Feta font and may be accessed directly using text markup such as -@code{g^#'(music "scripts-segno")}, see @ref{Text markup}. +@code{g^\markup @{ \musicglyph #"scripts-segno" @}}, see @ref{Text markup}. @lilypondfile[noquote,noindent]{feta16list.ly} diff --git a/Documentation/user/invoking.itexi b/Documentation/user/invoking.itexi index ea699c3f10..1f7275dcd7 100644 --- a/Documentation/user/invoking.itexi +++ b/Documentation/user/invoking.itexi @@ -214,7 +214,7 @@ developers, send a @emph{small} sample file. system libraries, whether you downloaded a binary release) @item If necessary, send a description of the bug itself. If you -include output a ly2dvi run, please use @code{--verbose} option of +include output a ly2dvi run, please use @code{--debug} option of ly2dvi. @end itemize @@ -277,8 +277,16 @@ through @code{ps2pdf} producing a PDF file. @code{\usepackage[latin1]@{inputenc@}} if you use any other non-anglosaxian characters. - @item --preview +@item --preview Also generate a picture of the first system of the score. + +@cindex preview +@cindex picture +@cindex bitmap +@cindex pixmap +@cindex thumbnail +@cindex screenshot + @item -s,--set=@var{key}=@var{val} Add @var{key}= @var{val} to the settings, overriding those specified in the files. Possible keys: @code{language}, @code{latexheaders}, @@ -286,9 +294,11 @@ in the files. Possible keys: @code{language}, @code{latexheaders}, @code{pagenumber}, @code{linewidth}, @code{orientation}, @code{textheight}. @item -v,--version -Show version information +Show version information . @item -V,--verbose -Be verbose +Be verbose. +@item --debug +Print even more information. This is useful when generating bugreports. @item -w,--warranty Show the warranty with which GNU LilyPond comes. (It comes with @strong{NO WARRANTY}!) diff --git a/Documentation/user/lilypond-book.itely b/Documentation/user/lilypond-book.itely index cd3cd356a2..be091ae181 100644 --- a/Documentation/user/lilypond-book.itely +++ b/Documentation/user/lilypond-book.itely @@ -206,12 +206,26 @@ For inline pictures, use @code{} syntax, eg. Some music in a line of text. @end example +A special feature not (yet) available in other output formats, is the +@code{} tag, for example +@example + trip.ly +@end example +This runs @file{trip.ly} through ly2dvi (See also @ref{Invoking +ly2dvi}), and substitutes a preview image in the output. The image +links to a separate HTML file, so clicking it will take the viewer to +a menu, with links to images, midi and printouts. + +@cindex ly2dvi +@cindex titling in THML +@cindex preview image +@cindex thumbnail @node Music fragment options @section Music fragment options -The commands for lilypond-book have room to specify options. These are -all of the options: +The commands for lilypond-book have room to specify options. These +are all of the options: @table @code @item eps diff --git a/Documentation/user/refman.itely b/Documentation/user/refman.itely index 905b2d2436..6fa0bd454b 100644 --- a/Documentation/user/refman.itely +++ b/Documentation/user/refman.itely @@ -3646,10 +3646,11 @@ The @code{\mark} command can also be used to put signs like coda, segno and fermatas on a barline. The trick is to use the text markup mechanism to access the fermata symbol. @lilypond[fragment,verbatim,relative=1] - c1 \mark #'(music "scripts-ufermata") + c1 \mark \markup { \musicglyph #"scripts-ufermata" } c1 @end lilypond + The problem is that marks that occur at a line break are typeset only at the beginning of the next line, opposite to what you want for the fermata. This can be corrected by the following property setting diff --git a/Documentation/user/tutorial.itely b/Documentation/user/tutorial.itely index 4350b8909e..59f147a1af 100644 --- a/Documentation/user/tutorial.itely +++ b/Documentation/user/tutorial.itely @@ -2150,13 +2150,14 @@ a collision with the slur. This could be achieved with works. We insert an empty text between the 5 and the note. The empty text pushes the fingering instruction away: @example - a^" "^#'(finger "5") + a-)^" "^\markup { \finger "5" } @end example -Lilypond tries to put fingering instructions as close to the notes as -possible. To make sure that Lilypond doesn't do that, we disguise the -fingering as text: @code{(finger "5")}. - +A fingering instruction, which would be entered as @code{^5}, is put +as close to the notes as possible, closer than the space entered to +push away the 5. Hence, the 5 is entered as a normal text, formatting +of fingering instructions. + @separate Normally one would specify all dynamics in the same voice, so that diff --git a/python/lilylib.py b/python/lilylib.py index 3f0b0e7302..49078c5ab2 100644 --- a/python/lilylib.py +++ b/python/lilylib.py @@ -99,7 +99,7 @@ underscore = _ program_version = '@TOPLEVEL_VERSION@' if program_version == '@' + 'TOPLEVEL_VERSION' + '@': - program_version = '1.7.5' + program_version = '1.7.14' def identify (port): port.write ('%s (GNU LilyPond) %s\n' % (__main__.program_name, program_version)) @@ -421,8 +421,6 @@ def make_preview (name): cmd = r'''gs -g%dx%d -sDEVICE=pnggray -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -q -sOutputFile=%s -r%d -dNOPAUSE %s %s -c quit ''' % \ (x, y, png, __main__.preview_resolution, trans_ps, preview_ps) - system (cmd) - status = system (cmd) signal = 0xf & status exit_status = status >> 8 @@ -431,3 +429,14 @@ def make_preview (name): os.unlink (png) error (_ ("Removing output file")) exit (1) + +def make_page_images (name, resolution = 90): + + """ Generate images for + all pages in the PS file NAME. NAME should be the basename + (not including the extension.). + """ + + cmd = 'gs -sDEVICE=pnggray -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -sOutputFile="%s-page%%d.png" -r%d -dNOPAUSE %s -c quit' + cmd = cmd % (name, resolution, name + '.ps') + system (cmd) diff --git a/scripts/lilypond-book.py b/scripts/lilypond-book.py index 4dbafe498d..bb217b0b93 100644 --- a/scripts/lilypond-book.py +++ b/scripts/lilypond-book.py @@ -15,13 +15,33 @@ # TODO: magnification support should also work for texinfo -> html: eg. add as option to dvips. # + +# +# This is a slightly hairy program. The general approach is as follows +# The input string is chopped up in chunks, i.e. , a list of tuples +# +# with the format (TAG_STR, MAIN_STR, OPTIONS, TODO, BASE) +# +# This list is build step by step: first ignore and verbatim commands are handled, +# delivering a list of chunks. +# +# then all chunks containing lilypnod commands are chopped up +# +# when all chunks have their final form, all bodies from lilypond blocks are +# extracted, and if applicable, written do disk and run through lilypond. +# + + # This is was the idea for handling of comments: + + # Multiline comments, @ignore .. @end ignore is scanned for # in read_doc_file, and the chunks are marked as 'ignore', so # lilypond-book will not touch them any more. The content of the # chunks are written to the output file. Also 'include' and 'input' # regex has to check if they are commented out. # + # Then it is scanned for 'lilypond', 'lilypond-file' and 'lilypond-block'. # These three regex's has to check if they are on a commented line, # % for latex, @c for texinfo. @@ -140,7 +160,9 @@ default_music_fontsize = 16 default_text_fontsize = 12 paperguru = None - +################################################################ +# Dimension handling for LaTeX. +# class LatexPaper: def __init__ (self): self.m_document_preamble = [] @@ -297,6 +319,9 @@ html_linewidths = { 'smallbook': {12: in2pt (5)}, 'letterpaper': {12: in2pt (6)}} + +################################################################ +# How to output various structures. output_dict= { @@ -460,7 +485,11 @@ def output_verbatim (body, small): return get_output (key) % body -# Warning: This uses extended regular expressions. Treat with care. +################################################################ +# Recognize special sequences in the input + + +# Warning: This uses extended regular expressions. Tread with care. # # legenda # @@ -486,6 +515,7 @@ re_dict = { 'singleline-comment': no_match, 'numcols': no_match, 'multicols': no_match, + 'ly2dvi': r'(?m)(?P[^>]+)?>\s*(?P[^<]+)\s*)', }, 'latex': { @@ -507,6 +537,8 @@ re_dict = { 'singleline-comment': r"(?m)^.*?(?P(?P^%.*$\n+))", 'numcols': r"(?P\\(?Pone|two)column)", 'multicols': r"(?P\\(?Pbegin|end)\s*{multicols}({(?P\d+)?})?)", + 'ly2dvi': no_match, + }, # why do we have distinction between @mbinclude and @include? @@ -528,6 +560,7 @@ re_dict = { 'singleline-comment': r"(?m)^.*?(?P(?P@c.*$\n+))", 'numcols': no_match, 'multicols': no_match, + 'ly2dvi': no_match, } } @@ -859,6 +892,15 @@ def make_lilypond_file (m): return [('input', get_output ('output-lilypond') % (options, content))] +def make_ly2dvi_block (m): + ''' + + Find + ''' + + return [('ly2dvi', m.group ('filename'), m.group ('options'))] + + def make_lilypond_block (m): if not g_do_music: return [] @@ -870,6 +912,7 @@ def make_lilypond_block (m): options = filter (lambda s: s != '', options) return [('lilypond', m.group ('code'), options)] + def do_columns (m): global format if format != 'latex': @@ -966,6 +1009,10 @@ def read_doc_file (filename): taken_file_names = {} + +def unique_file_name (body): + return 'lily-' + `abs (hash (body))` + def schedule_lilypond_block (chunk): '''Take the body and options from CHUNK, figure out how the real .ly should look, and what should be left MAIN_STR (meant @@ -982,7 +1029,7 @@ def schedule_lilypond_block (chunk): ## Hmm, we should hash only lilypond source, and skip the ## %options are ... ## comment line - basename = 'lily-' + `abs (hash (file_body))` + basename = unique_file_name (file_body) for o in opts: m = re.search ('filename="(.*?)"', o) if m: @@ -1001,6 +1048,7 @@ def schedule_lilypond_block (chunk): needed_filetypes.append ('png') if 'eps' in opts and not ('eps' in needed_filetypes): needed_filetypes.append ('eps') + pathbase = os.path.join (g_outdir, basename) def f (base, ext1, ext2): a = os.path.isfile (base + ext2) @@ -1062,6 +1110,9 @@ def schedule_lilypond_block (chunk): newbody = newbody + get_output (s) % {'fn': basename } return ('lilypond', newbody, opts, todo, basename) + + + def process_lilypond_blocks (chunks):#ugh rename newchunks = [] # Count sections/chapters. @@ -1075,6 +1126,106 @@ def process_lilypond_blocks (chunks):#ugh rename newchunks.append (c) return newchunks +def process_ly2dvi_blocks (chunks): + + def process_ly2dvi_block (chunk): + """ + +Run ly2dvi script on filename specified in CHUNK. +This is only supported for HTML output. + +In HTML output it will leave a download menu with ps/pdf/midi etc. in +a separate HTML file, and a title + preview in the main html file, +linking to the menu. + + """ + (tag, name, opts) = chunk + assert format == 'html' + (content, original_name) = find_file (name) + + original_name = os.path.basename (original_name) + + base = unique_file_name (content) + outname = base + '.ly' + changed = update_file (content, outname) + + preview = base + ".png" + if changed or not os.path.isfile (preview): + ly.system ('ly2dvi --preview --postscript --verbose %s ' % base) + + ly.make_page_images (base) + ly.system ('gzip -9 - < %s.ps > %s.ps.gz' % (base, base)) + + def size_str (fn): + b = os.stat(fn)[stat.ST_SIZE] + if b < 1024: + return '%d bytes' % b + elif b < (2 << 20): + return '%d kb' % (b >> 10) + else: + return '%d mb' % (b >> 20) + + exts = { + 'pdf' : "Print (PDF, %s)", + 'ps.gz' : "Print (gzipped PostScript, %s)", + 'png' : "View (PNG, %s)", + 'midi' : "Listen (MIDI, %s)", + 'ly' : "View source code (%s)", + } + + menu = '' + page_files = ly.read_pipe ('ls --color=no -1 %s-page*.png' % base) + + for p in string.split (page_files, '\n'): + p = p.strip() + if os.path.isfile (p): + sz = size_str (p) + page = re.sub ('.*page([0-9])+.*', 'View page \\1 (PNG picture, %s)\n', p) + page = page % sz + menu += '
  • %s' % (p, page) + + ext_order = ['ly', 'pdf', 'ps.gz', 'midi'] + for e in ext_order: + fn = base + '.' + e + print 'checking,' , fn + if not os.path.isfile (fn): + continue + + entry = exts[e] % size_str (fn) + + ## TODO: do something like + ## this for texinfo/latex as well ? + + menu += '
  • %s\n\n' % (fn, entry) + + + explanatory_para = """The pictures are 90dpi +anti-aliased snapshots of the printed output, in PNG format. Both PDF and PS +use scalable fonts and should look OK at any resolution.""" + + separate_menu =r''' +LilyPond example %s + +

    %s

    +

    +

    %s +

    +

      %s
    ''' % (original_name,original_name, preview, explanatory_para, menu) + + open (base + '.html','w'). write (separate_menu) + + inline_menu = '

    ' % (base, original_name, preview) + + return ('ly2dvi', inline_menu) + + newchunks = [] + for c in chunks: + if c[0] == 'ly2dvi': + c = process_ly2dvi_block (c) + newchunks.append (c) + + return newchunks + def compile_all_files (chunks): global foutn eps = [] @@ -1149,7 +1300,7 @@ def compile_all_files (chunks): def update_file (body, name): ''' - write the body if it has changed + write the body if it has changed. Return whether BODY has changed. ''' same = 0 try: @@ -1242,6 +1393,7 @@ foutn="" def do_file (input_filename): chunks = read_doc_file (input_filename) + chunks = chop_chunks (chunks, 'ly2dvi', make_ly2dvi_block, 1) chunks = chop_chunks (chunks, 'lilypond', make_lilypond, 1) chunks = chop_chunks (chunks, 'lilypond-file', make_lilypond_file, 1) chunks = chop_chunks (chunks, 'lilypond-block', make_lilypond_block, 1) @@ -1254,7 +1406,8 @@ def do_file (input_filename): #sys.exit () scan_preamble (chunks) chunks = process_lilypond_blocks (chunks) - + chunks = process_ly2dvi_blocks (chunks) + # Do It. global g_run_lilypond if g_run_lilypond: diff --git a/scripts/ly2dvi.py b/scripts/ly2dvi.py index 28cd50eebb..7b8c519955 100644 --- a/scripts/ly2dvi.py +++ b/scripts/ly2dvi.py @@ -112,6 +112,7 @@ original_dir = os.getcwd () temp_dir = os.path.join (original_dir, '%s.dir' % program_name) keep_temp_dir_p = 0 preview_resolution = 90 +debug_p = 0 ## FIXME ## ly2dvi: silly name? @@ -125,6 +126,7 @@ option_definitions = [ ('', 'd', 'dependencies', _ ("write Makefile dependencies for every input file")), ('', 'h', 'help', _ ("this help")), + ('', '', 'debug', _ ("print even more output")), (_ ("DIR"), 'I', 'include', _ ("add DIR to LilyPond's search path")), ('', 'k', 'keep', _ ("keep all output, output to directory %s.dir") % program_name), @@ -243,6 +245,8 @@ def run_lilypond (files, dep_prefix): global verbose_p if verbose_p: opts = opts + ' --verbose' + + if debug_p: ly.print_environment () cmd = string.join ((lilypond_cmd,opts, fs)) @@ -498,16 +502,14 @@ None # make a preview by rendering only the 1st line. preview_fn = outbase + '.preview.tex' f = open (preview_fn, 'w') - f.write (r''' -%s -\input lilyponddefs -\pagestyle{empty} -\begin{document} -\def\interscoreline{\endinput} -\input %s -\end{document} -''' % (global_latex_preamble (extra), outbase)) - + wfs = find_tex_files (files, extra) + s = global_latex_definition (wfs, extra) + + s = re.sub ('thispagestyle{firstpage}', r'''thispagestyle{empty}% +\\def\\interscoreline{\\endinput}''',s ) + s = re.sub ('thispagestyle{lastpage}', r'''thispagestyle{empty}% +\\def\\interscoreline{\\endinput}''',s ) + f.write (s) f.close() cmd = '%s \\\\nonstopmode \\\\input %s' % (latex_cmd, preview_fn) ly.system (cmd) @@ -545,8 +547,8 @@ None. opts = opts + ' -Ppdf -G0 -u lilypond.map' else: ly.warning (_ ('''Trying create PDF, but no PFA fonts found. -Using bitmap fonts instead. This will look poorly.''')) - +Using bitmap fonts instead. This will look bad.''')) + cmd = 'dvips %s -o%s %s' % (opts, outbase + '.ps', outbase + '.dvi') ly.system (cmd) @@ -634,6 +636,9 @@ for opt in options: targets.append ('PDF') elif o == '--keep' or o == '-k': keep_temp_dir_p = 1 + elif o == '--debug': + verbose_p = 1 + debug_p = 1 elif o == '--no-lily': lily_p = 0 elif o == '--preview':