[cairo] How do you get tight bounding boxes and/or unused margins cropped for final libcairo results?

Behdad Esfahbod behdad at behdad.org
Mon Sep 10 14:01:24 PDT 2007

On Mon, 2007-09-10 at 13:40 -0700, Alan W. Irwin wrote:
> On 2007-09-10 15:42-0400 Behdad Esfahbod wrote:
> > On Mon, 2007-09-10 at 14:00 -0400, Alan W. Irwin wrote:
> >> [...]Therefore, I hope there is a general
> >> way to do this (crop [in the ImageMagick sense] unused margins from the
> >> final result) internal to libcairo that works for some/all libcairo back ends.
> >> If so, can somebody point me in the right direction?
> >
> > Hi, and welcome to cairo!
> >
> > Currently cairo surfaces need to know the size at surface creation time.
> > A common approach to fixing this chicken-egg problem is that
> > applications first create a 1x1 (or 0x0) dummy surface of the same type
> > as the final one, render to it and compute extents (using
> > cairo_stroke_extents(), cairo_fill_extents(),
> > pango_layout_get_extents(), etc), and then create the final surface at
> > the right size and render again.
> Exactly, it is a chicken-egg problem.  :-)
> I might be able to implement such a solution for our cairo devices. I guess
> it would involve storing all the cairo calls in order so they can be
> replayed.  That's actually not too bad since we don't use that large a
> variety of libcairo calls. I presume an offset to all x and y coordinates
> would also be involved for the cairo replay to fit everything inside the
> smaller rectangular area.
> What is the advantage to 1x1?  Does it make the first pass go a lot quicker
> without affecting the calculated extents?

Yes, that's the idea.

> > I can't readily think of any generic solution to this.  For PS/PDF/SVG
> > we have cairo_[ps/pdf/svg]_surface_set_size() but the docs say they
> > should only be called before any drawing operations have been performed
> > on the current page.  We can look into fixing this such that they work
> > even after drawing to the page.  It shouldn't be *that* hard to do.  But
> > this approach doesn't work for raster backends, needless to say.
> >
> > In the future we may make the cairo meta-surface public.  At that point
> > you can render to the meta-surface, measure, create final surface and
> > replay the meta surface to the final surface.
> That would be extremely useful, but meanwhile I will probably implement the
> replay scenario discussed above.  Since this appears to be a fairly common
> approach to the problem, I would appreciate it if somebody could point
> me to some sample code that does replays.

What most people do is not saving and replaying, but to just play twice.
That is, they have a function that draws to a cairo_surface_t and
calculates the extents at the same time too.  They can then do:

  surface = cairo_pdf_surface_create (filename, 1, 1);
  draw (surface, &width, &height);
  cairo_surface_destroy (surface);
  surface = cairo_pdf_surface_create (filename, width, height);
  draw (surface, NULL, NULL);
  cairo_surface_destroy (surface);

Something like that.


> Alan
> __________________________
> Alan W. Irwin
> Astronomical research affiliation with Department of Physics and Astronomy,
> University of Victoria (astrowww.phys.uvic.ca).
> Programming affiliations with the FreeEOS equation-of-state implementation
> for stellar interiors (freeeos.sf.net); PLplot scientific plotting software
> package (plplot.org); the libLASi project (unifont.org/lasi); the Loads of
> Linux Links project (loll.sf.net); and the Linux Brochure Project
> (lbproject.sf.net).
> __________________________
> Linux-powered Science
> __________________________

"Those who would give up Essential Liberty to purchase a little
 Temporary Safety, deserve neither Liberty nor Safety."
        -- Benjamin Franklin, 1759

More information about the cairo mailing list