[cl-typesetting-devel] Reusing bits of code
Peter Seibel
peter at gigamonkeys.com
Thu Jul 14 19:06:24 UTC 2005
On Jul 8, 2005, at 9:17 PM, Peter Seibel wrote:
>
> On Jul 8, 2005, at 9:10 AM, Marc Battyani wrote:
>
>
>> You can get the "natural" size on some text content with something
>> like
>> that:
>>
>> (compute-boxes-natural-size
>> (boxes (compile-text ()
>> (with-style (:font "Times-Roman") "foo"))) #'dx)
>> 15.996
>>
>
> Okay, more puzzles. Why does this function:
>
> (defun measure-logo ()
> (let* ((big-font 48)
> (small-font 16)
> (extra-spacing 7)
> (content
> (compile-text ()
> (with-style (:font "Didot-Bold" :font-size big-font) (put-
> string "gigamonkeys")) :eol
> (vspace -2)
> (hspace 69)
> (with-style (:font "Optima-Regular" :font-size small-font)
> (loop for char across "CONSULTING" do
> (put-string (string char))
> (unless (char= char #\G)
> (typeset::add-box
> (make-instance 'typeset::h-spacing
> :dx extra-spacing
> :max-expansion extra-spacing
> :max-compression extra-spacing
> :expansibility 1.0
> :compressibility 1.0))))))))
> (values
> (typeset::compute-boxes-natural-size (boxes content)
> #'typeset::dx)
> (typeset::compute-boxes-natural-size (boxes content)
> #'typeset::dy))))
>
> return
>
> 521.12006
> 823.6001
>
> The logo is *not* bigger than a piece of 8.5x11 paper!
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.
-Peter
--
Peter Seibel * peter at gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp * http://www.gigamonkeys.com/book/
More information about the cl-typesetting-devel
mailing list