[cairo] PDF Backend for cairo

Carl Worth cworth at cworth.org
Mon Nov 29 12:52:55 PST 2004


On Mon, 29 Nov 2004 14:59:09 -0500, =?ISO-8859-1?Q?Kristian_H=F8gsberg?= wrote:
> I've been working on a PDF backend for cairo over the weekend, and at 
> this point I think it's appropriate post a snapshot of the current code. 

Fantastic! It's great to see more progress continuing on this front.

>    http://people.redhat.com/krh/cairo-pdf/snippets.pdf

And this is coming along quite well already.

I haven't looked at the details of the patch yet, but when I do, (or
someone else reviews them carefully), we should get them into
CVS. There's no need to risk having this work performed a third
time.

> Right now the PDF backends only render the trapezoids cairo passes it 
> after tesselation.  PDF has the same curve_to and line_to operators as 
> cairo has and could do stroking and filling if it was passed the 
> highlevel path instead of the tesselation output.  I think this could be 
> acheived by adding stroke_path() and fill_path() function pointers to 
> the cairo_surface_backend_t struct, something along these lines:

I think this seems quite reasonable, and will likely help out with some
of the file size issues as well as slow performance and seams we've seen
in some PDF viewers already.

However, if we are going to rely on PDF tessellation, I want to make
sure we understand it well enough to guarantee we get high-quality
results.

For example, Keith and I played with PostScript a while back and without
too much effort we came up with the attached test case that gives a
"wrong" result on every implementation we had available at the time.

This is a hand-crafted PostScript file that is simply a single wide
spline that turns very sharply, (an equivalent thinner spline is also
drawn to make it more obvious what it happening).

When I view this in gs, gv, ggv, a large portion of what should be a
smooth contour near the top of the figure is instead approximated with
three linear segments. And the error in this approximation is much
greater than the flatness of 0.5 that is explicitly set in the file.

I saw similar results by printing this file directly to a PostScript
printer.

The ugly result appears consistent with an implementation that first
flattens the path to within the flatness value and then strokes the
resulting piecewise-linear path. I'm not 100% sure that the PostScript
specification requires the stroke operator to be implemented this way,
but the description of the flattenpath operator certainly suggests that
this is the case:

	The flattening of curves to straight line segments
	is done automatically when a path is used to control
	painting (for example, by stroke, fill, eofill, or
	clip). Only rarely does a program need to flatten a
	path explicitly (see pathbbox).

And regardless of whether this is a specification or implementation
bug, it appears to be widespread in PostScript implementations.  One
thing that needs to be tested is whether PDF implementations share the
same bug.

The spline stroking algorithm in cairo was carefully selected to
prevent these kinds of problems. I don't want output from cairo to
trigger this bug in downstream libraries/programs/etc.

The current approach of never relying on downstream tessellation does
prevent this problem. So, before we start using downstream
tessellation we need to characterize when they can be trusted. With
the particular case demonstrated above, it should be fairly simple to
design a function of the current line width and the tolerance value
(cairo's equivalent to the flatness parameter), that returns whether
or not the downstream tessellator can be trusted. If so, it can be
used, and otherwise, cairo should fall back to internal tessellation.

I think that should still give the benefits of external tessellation
for most stroke operations, (since the line width is typically small).

> where [ gstate ] means that the current line cap, line join, line width, 
> fill rule etc should be passed to the backend.  I'm not sure what the 
> best approach would be: either just pass the relevant part of the state 
> in the call or let the backend query the gstate object directly. 

Yeah, these backend interface functions get ugly because so many
parameters are needed. Note that this is exactly the defect that
cairo's graphics-state-based model avoids in its own public interface.

>                                    This could be worked around by 
> storing a hash of the image data with the resource ID, but I was 
> thinking about adding a generation field to the surface.  Everytime the 
> surface is altered the generation is increased, making it easy for 
> backends to determine if it safe to reuse previous resources.

I like the idea of a generation field in the surface. We will also
need something similar when we add a public function to allow the user
to indicate that the surface contents have been modified outside of
cairo's control, (though in that case, we may provide a region-based
interface).

-Carl

-------------- next part --------------
A non-text attachment was scrubbed...
Name: badspline.eps
Type: application/postscript
Size: 428 bytes
Desc: not available
Url : http://lists.freedesktop.org/archives/cairo/attachments/20041129/ddbf9ec3/badspline.eps


More information about the cairo mailing list