lilypond-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

reducing ps file size (please comment)


From: Mark Polesky
Subject: reducing ps file size (please comment)
Date: Tue, 7 Apr 2009 17:25:40 -0700 (PDT)

Short version: I made some changes to output-ps.scm
that can safely reduce the file size of ps files. In
a simple experiment, I was able to reduce non-binary
ps-code by up to 10%. I also don't know if anyone
cares! (: See the attachment.

- Mark


Long version (sorry this is so long):

LilyPond generates postscript files with needless precision:

1.1267 0.0000 /d
1.1950 0.0000 /n
0.9902 0.0000 /o
1.2633 0.0000 /P

But I was able to tweak output-ps.scm to generate this:

1.1267 0 /d
1.195 0 /n
0.9902 0 /o
1.2633 0 /P

The reason is that output-ps procedures generally use the
form (ly:format "~4f" x). For example:

(define (placebox x y s) 
  (ly:format "~4f ~4f moveto\n~a\n" x y s))

First I defined my own format:

(define (set-precision n)
  (if (number? n)
    (let* ((max-decimals 4)
           (k (expt 10.0 max-decimals))
           (float (/ (round (* n k))
                     k)))
      (if (integer? n)
          (inexact->exact n)
          (if (< (abs (- float (round n)))
                 (/ 0.1 k))
              (inexact->exact (round float))
              float)))
        n))
  
(define (ly:format4 string . args)
  (apply format string (map set-precision args)))

A major benefit of this format is that strings and
numbers can both be processed with "~a". So that
(ly:format4 "~a ~a" "my string" 3.14159265358979)
yields "my string 3.1416".

Then I substituted the form (ly:format4 "~a" x) where I
could. For example:

(define (placebox x y s) 
  (ly:format4 "~a ~a moveto\n~a\n" x y s))

This worked! But there remained procedures which used the
form (ly:format "~4l" list-of-args), which my ly:format4
procedure could not recognize. It seems the "~l" construct
was born around line 493 of general-scheme.cc, but since 
I'm not a C++ guy, I solved it with scheme instead.

If all args were already known, I just broke it up like so:
(ly:format4 "~a ~a ~a" arg1 arg2 arg3)

For example:
(define (dot x y radius)
  (ly:format "~4l draw_dot" (list radius x y)))

...became...
(define (dot x y radius)
  (ly:format4 "~a ~a ~a draw_dot" radius x y))


If the number of args is determined on-the-fly, I used this:
(ly:format "~{~a ~}" (map set-precision list-of-args))

So this:
(define (bezier-sandwich lst thick)
  (ly:format "~l ~4f draw_bezier_sandwich" 
            (map number-pair->string4 lst)
            thick))

...became this:
(define (bezier-sandwich lst thick)
  (ly:format4 "~{~a ~}~a draw_bezier_sandwich" 
               (map number-pair->string4 (map set-precision lst))
              thick))

____________________________________________________________


Then I compared the sizes of postscript files generated by
these two versions of output-ps.scm.

Well actually, I removed all of the binary data, ps varaiables
and music-drawing-routines.ps stuff before measuring. So each
stripped file now starts with:

%%Page: 1 1
%%BeginPageSetup
%%EndPageSetup

I used the Bach Invention no.13 from mutopia as a test file.

Here are the results (in bytes):

point-and-click off:
   original "output-ps.scm" ==> 174,137
   modified "output-ps.scm" ==> 157,515

point-and-click on:
   original "output-ps.scm" ==> 299,460
   modified "output-ps.scm" ==> 282,517

So with point-and-click off, the file size was reduced by 
almost 10% using the modified output-ps. With point-and-click
on, the size was reduced only about 5.5%.

I don't know if anybody cares about this. I've attached the
modified file.

Here are some more questions/observations.
Man, this postis long. Sorry.
____________________________________________________________

There's a procedure named glyph-string which has some 
internal parameters that I don't fully understand. Actually,
I don't need to understand them, I just would like to if 
they can safely be restricted to 4 decimal places if they 
are numbers.

Are there any numeric parameters that need to remain 
unformatted? I can't imagine why there would be. To my 
untrained eye, it looks like it would be safe to call 
ly:format4 on any arg here. 

Also, in the grob-cause procedure, I found these lines:
(music-origin (if (ly:stream-event? cause)
                  (ly:event-property cause 'origin))))
Is it okay that the if expr is missing an alternate case?
What is music-origin if (ly:stream-event? cause) ==> #f ?

____________________________________________________________


I also found 2 procedures which are *never* called anywhere in
LilyPond: str4 and char

grep "str4" and you'll see its only occurence is in 
output-ps.scm. grep "(char " - with the space - and you'll see
the function is defined twice (also in scm/output-svg.scm) but
never used again (as far as I can tell). I also checked 
"map char " but I could be missing something. I don't know how
to ignore C++ headers and files when grepping. Do we need to 
keep these?

____________________________________________________________


      

Attachment: output-ps.scm
Description: Text Data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]