
do you think you can use that in metapict then?

Yes an crop-automatic
would be easy to do. But we need to figure out how to render a pict to a cairo_recording_surface_t
first. The record-dc%
in racket/draw is implemented in Racket and doesn’t use cairo_recording_surface_t
.

Good news. The code of racket/draw
contains a dc-mixin
that makes it easy to make a new kind of dc%. Initial experiment turned out well. #lang racket/base
(require racket/class
racket/draw/private/syntax ; "syntax.rkt"
racket/draw/unsafe/cairo
racket/draw/private/dc ; "dc.rkt"
racket/draw/private/local ; local.rkt"
"bb.rkt"
)
(provide cairo-record-dc%)
(define dc-backend%
(class default-dc-backend%
(init [(init-x0 x0)]
[(init-y0 y0)]
[(init-w width)]
[(init-h height)])
(unless (real? init-x0)
(raise-type-error (init-name 'record-dc%) "non-real or #f" init-x0))
(unless (real? init-y0)
(raise-type-error (init-name 'record-dc%) "non-real or #f" init-y0))
(unless (and (real? init-w) (not (negative? init-w)))
(raise-type-error (init-name 'record-dc%) "nonnegative real or #f" init-w))
(unless (and (real? init-h) (not (negative? init-h)))
(raise-type-error (init-name 'record-dc%) "nonnegative real or #f" init-h))
(define width init-w)
(define height init-h)
(define x0 init-x0)
(define y0 init-y0)
(define s (cairo_recording_surface_create CAIRO_CONTENT_COLOR_ALPHA #f))
(define c (and s (cairo_create s)))
(when s (cairo_surface_destroy s)) ; decrease reference count
(define/override (ok?) (and c #t))
(define/override (get-cr) c)
(def/override (get-size)
(values width height))
(define/override (end-cr)
(cairo_surface_finish s)
(cairo_destroy c)
(set! c #f)
(set! s #f))
; keep these?
(define/override (get-pango font)
(send font get-pango))
(define/override (get-font-metrics-key sx sy)
(if (and (= sx 1.0) (= sy 1.0))
3
0))
(define/override (can-combine-text? sz)
#t)
(define/public (multiple-pages-ok?) #f)
(define/public (get-inked-extents)
(cairo_recording_surface_ink_extents s 0. 0. 10. 10.))
(super-new)))
(define cairo-record-dc% (class (dc-mixin dc-backend%)
(super-new)))
(define cr-dc (new cairo-record-dc% [x0 0.0] [y0 0.0] [width 1000.] [height 1000.]))
(require pict)
(define p (pin-over (rectangle 30 40)
20 20
(circle 15)))
(draw-pict p cr-dc 0 0)
(send cr-dc get-inked-extents)

what’s bb.rkt?

got it. it’s the file above

Nice!

This should even fix the broken bounding box for disks et al. with borders

like (disk 20 #:border-width 20)
is not well rendered in DrRacket at least, the sizes are wrong as they don’t include the border.

Nice example. I know why it happens, but need to look up whether it is intentional.

I hope it’s not, because it’s ugly

Also #:border-width 0 still draws a border…

A border width 0 means the thinnest (non-zero) possible width.

The disc is drawn as a filled circle and the outline is drawn with a pen of width 20. Only the circle is counted in the bounding box.

I can’t think the exact place in the documentation, but I consider ``` (beside (rectangle 10 10) (rectangle 10 10))

The bounding box for (rectangle 10 10) is a rectangle of width 10 and height 10. When you stroke the outline with a pen, half the ink is outside the other half is inside.

The concequence is that the edge shared by the two rectangles is only drawn once.

Well, it might be drawn twice, but it will be the same edge.

If the width of the pen was added to the bounding box, using beside would make the shared edge twice as wide.

DrRacket compensates for this by drawing “a bit more” than the bounding box.

I am not sure what a “bit more” is exactly.

Yeah, well i find this behaviour broken. A bounding box is supposed to be bounding what’s drawn. What you’re talking about is an alignment box.

When i draw a single disk with a border of size 20, i don’t want to see it cut in a square

I agree that there should have been two types of boxes in a pict.

Difficult to find a reasonable backward-compatible solution.

Personally I find the current behaviour buggy, so replacing it with the correct bounding-box behaviour would just be bug fixing, which is not considered as backward incompatibility :stuck_out_tongue:


Getting there.

nice!

Here is a single file to experiment with. I am slightly surprised that I get 39 and not 40 as the width in the example.

yes, it seems to be off by 1 pixel on that example. Weird

This shows that the cropping is always off by one: (for/list ([i (in-range 1 20)]) (crop/inked (frame (crop/inked (cc-superimpose (blank 100 100) (circle i))))))

This is odd too:

The circle of radius 1 is blank?!

looks like another bug

Maybe it is a racket-mode bug. Seems to work in DrRacket.

(for/list ([i 40 ])(frame (circle i)))
is also off by one in DrRacket

I’m doing my tests in DrRacket

and (circle 1)
is also blank, but has size 1

ah, no sometimes I can see a pixel

alignment problem?

scratch that actually. What I see is the frame

Maybe it is an off-by–0.5 error? I think Racket adds 0.5 before calling Cairo if … something.


> In addition, for pen drawing through draw-rectangle, draw-ellipse, draw-rounded-rectangle, and draw-arc, the given width and height are each decreased by 1.0 divided by the alignment scale.

(require (only-in metapict aligned smoothed unsmoothed))
(pict-width (crop/inked (aligned (disk 20 #:border-width 20))))
(pict-width (crop/inked (smoothed (disk 20 #:border-width 20))))
(pict-width (crop/inked (unsmoothed (disk 20 #:border-width 20))))
gives ``` 39

40

39 ```

ouch

I suddenly remember I wrote this note in “pict.rkt” at some point: > ;;; IMPORTANT NOTE > ;;; Remember that to set the smoothing mode to ’smoothed if you implement > ;;; new picts constructors, that use coordinates.

:slightly_smiling_face: