[Top][All Lists]
[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?
____________________________________________________________
output-ps.scm
Description: Text Data
- reducing ps file size (please comment),
Mark Polesky <=