[cl-typesetting-devel] Reusing bits of code

Marc Battyani marc.battyani at fractalconcept.com
Wed Jul 20 19:55:24 UTC 2005


Peter Seibel wrote:

> On Jul 8, 2005, at 9:17 PM, Peter Seibel wrote:
>
> So, I figured this one out. Sort of. The problem is that compute-
> boxes-natural-size simply sums the values returned by the size-fn (dx
> or dy here). Which means that if you have CHAR-BOX, CHAR-BOX, :EOL,
> CHAR-BOX, CHAR-BOX the "natural" width is the sum of the widths of
> the four char-boxes even though there's a line break. Similarly, the
> height is even more off because it sums the heights of a bunch of
> boxes that are actually all in a row. Here are two functions that
> seem to more or less do what I want though I'm not sure if I've dealt
> with all the edge cases:
>
> (defun natural-width (content)
>    (loop with max-width = 0
>       with current-width = 0
>       for box in (boxes content)
>       for dx = (typeset::dx box)
>       when (eql box :eol) do (setf current-width 0)
>       do (incf current-width dx)
>       do (setf max-width (max current-width max-width))
>       finally (return max-width)))
>
> (defun natural-height (content)
>    (loop with max-height = 0
>       with total-height = 0
>       for box in (boxes content)
>       for dy = (typeset::dy box)
>       when (eql box :eol) do
>         (incf total-height (* typeset::*leading-ratio* max-height))
>         (setf max-height 0)
>       do (setf max-height (max max-height dy))
>       finally (return total-height)))
>
> This lets me write a function like this to position a block of text
> in the middle of a page at its natural size:
>
> (defun small-envelope (&optional (address *gigamonkeys*) (file "/tmp/
> small-envelope.pdf"))
>    (pdf:with-document ()
>      (pdf:with-page (:bounds (vector 0 0 *small-envelope-width*
> *small-envelope-height*))
>        (let* ((content (compile-text ()
>                 (with-style (:font "Optima-Regular" :font-size 12)
>               (paragraph ()
>                 (loop for line in address do
>                  (put-string line)
>                  (typeset::add-box :eol))))))
>           (width (natural-width content))
>           (height (natural-height content))
>           (x (/ (- *small-envelope-width* width) 2))
>           (y (- *small-envelope-height* (/ (- *small-envelope-height*
> height) 2))))
>       (draw-block content x y width height)))
>      (pdf:write-document file)))
>
> If there's an easier way to do this, I'd be glad to hear it.

The problem here is that you are only implementing a small part of the
function that cuts the content into lines. So this will work only on small
lines without any breaks. In your case, as this is what you want, it's OK.

I would rather do this:
Make a vbox with #'make-filled-vbox by giving it large dx and dy values.
Then use #'compute-boxes-natural-size with #'dy to get the height and a
reduce #'max of #'compute-boxes-natural-size on #'dx of the lines boxes.
Hum.... I'm not sure I'm very clear ;-)

Marc





More information about the cl-typesetting-devel mailing list