[cairo-commit] cairo/src cairo-pdf-surface.c,1.61,1.62
Kristian Høgsberg
commit at pdx.freedesktop.org
Tue Oct 11 13:20:46 PDT 2005
Committed by: krh
Update of /cvs/cairo/cairo/src
In directory gabe:/tmp/cvs-serv21764/src
Modified Files:
cairo-pdf-surface.c
Log Message:
2005-10-11 Kristian Høgsberg <krh at redhat.com>
* src/cairo-pdf-surface.c (emit_surface_pattern),
(emit_linear_colorgradient), (emit_stiched_colorgradient),
(emit_pattern_stops):
Implement non-uniformly spaced color stops for PDF gradients.
Patch from Jens Taprogge (#4722).
Index: cairo-pdf-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-pdf-surface.c,v
retrieving revision 1.61
retrieving revision 1.62
diff -u -d -r1.61 -r1.62
--- cairo-pdf-surface.c 10 Oct 2005 16:36:39 -0000 1.61
+++ cairo-pdf-surface.c 11 Oct 2005 20:20:44 -0000 1.62
@@ -51,9 +51,6 @@
* could add generation counters to surfaces and remember the stream
* ID for a particular generation for a particular surface.
*
- * - Multi stop gradients. Need to fix support for non-regular spacing
- * using Type 3 (Stiching) Functions.
- *
* - Clipping: must be able to reset clipping
*
* - Images of other formats than 8 bit RGBA.
@@ -786,7 +783,7 @@
static cairo_status_t
emit_surface_pattern (cairo_pdf_surface_t *dst,
- cairo_surface_pattern_t *pattern)
+ cairo_surface_pattern_t *pattern)
{
cairo_pdf_document_t *document = dst->document;
cairo_output_stream_t *output = document->output_stream;
@@ -844,12 +841,15 @@
return CAIRO_STATUS_SUCCESS;
}
+
typedef struct _cairo_pdf_color_stop {
- cairo_fixed_t offset;
- int id;
- unsigned char color_char[4];
+ double offset;
+ int id;
+ unsigned int gradient_id;
+ unsigned char color_char[4];
} cairo_pdf_color_stop_t;
+
static int
_cairo_pdf_color_stop_compare (const void *elem1, const void *elem2)
{
@@ -864,60 +864,143 @@
return (s1->offset < s2->offset) ? -1 : 1;
}
-static int
-emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern)
+static unsigned int
+emit_linear_colorgradient (cairo_pdf_document_t *document,
+ cairo_pdf_color_stop_t *stop1,
+ cairo_pdf_color_stop_t *stop2)
{
- cairo_pdf_document_t *document = surface->document;
cairo_output_stream_t *output = document->output_stream;
- unsigned int function_id;
- cairo_pdf_color_stop_t *stops;
- int i;
-
- function_id = _cairo_pdf_document_new_object (document);
-
+ unsigned int function_id = _cairo_pdf_document_new_object (document);
+
_cairo_output_stream_printf (output,
"%d 0 obj\r\n"
"<< /FunctionType 0\r\n"
- " /Domain [ 0.0 1.0 ]\r\n"
- " /Size [ %d ]\r\n"
+ " /Domain [ 0 1 ]\r\n"
+ " /Size [ 2 ]\r\n"
" /BitsPerSample 8\r\n"
- " /Range [ 0.0 1.0 0.0 1.0 0.0 1.0 ]\r\n"
- " /Length %d\r\n"
+ " /Range [ 0 1 0 1 0 1 ]\r\n"
+ " /Length 6\r\n"
">>\r\n"
"stream\r\n",
- function_id,
- pattern->n_stops,
- pattern->n_stops * 3);
+ function_id);
- stops = malloc (pattern->n_stops * sizeof(cairo_pdf_color_stop_t));
- if (!stops) {
+ _cairo_output_stream_write (output, stop1->color_char, 3);
+ _cairo_output_stream_write (output, stop2->color_char, 3);
+ _cairo_output_stream_printf (output,
+ "\r\n"
+ "endstream\r\n"
+ "endobj\r\n");
+
+ return function_id;
+}
+
+
+static unsigned int
+emit_stiched_colorgradient (cairo_pdf_document_t *document,
+ unsigned int n_stops,
+ cairo_pdf_color_stop_t stops[])
+{
+ cairo_output_stream_t *output = document->output_stream;
+ unsigned int function_id;
+ unsigned int i;
+
+ /* emit linear gradients between pairs of subsequent stops... */
+ for (i = 0; i < n_stops-1; i++) {
+ stops[i].gradient_id = emit_linear_colorgradient (document,
+ &stops[i],
+ &stops[i+1]);
+ }
+
+ /* ... and stich them together */
+ function_id = _cairo_pdf_document_new_object (document);
+ _cairo_output_stream_printf (output,
+ "%d 0 obj\r\n"
+ "<< /FunctionType 3\r\n"
+ " /Domain [ 0 1 ]\r\n"
+ " /Functions [ ",
+ function_id);
+ for (i = 0; i < n_stops-1; i++)
+ _cairo_output_stream_printf (output, "%d 0 R ", stops[i].gradient_id);
+ _cairo_output_stream_printf (output,
+ "]\r\n"
+ " /Bounds [ ");
+ for (i = 1; i < n_stops-1; i++)
+ _cairo_output_stream_printf (output, "%f ", stops[i].offset);
+ _cairo_output_stream_printf (output,
+ "]\r\n"
+ " /Encode [ ");
+ for (i = 1; i < n_stops; i++)
+ _cairo_output_stream_printf (output, "0 1 ");
+ _cairo_output_stream_printf (output,
+ "]\r\n"
+ ">>\r\n"
+ "endobj\r\n");
+
+ return function_id;
+}
+
+#define COLOR_STOP_EPSILLON 1e-6
+
+static unsigned int
+emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern)
+{
+ cairo_pdf_document_t *document = surface->document;
+ unsigned int function_id;
+ cairo_pdf_color_stop_t *allstops, *stops;
+ unsigned int n_stops;
+ unsigned int i;
+
+ function_id = _cairo_pdf_document_new_object (document);
+
+ allstops = malloc ((pattern->n_stops + 2) * sizeof (cairo_pdf_color_stop_t));
+ if (allstops == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return 0;
}
+ stops = &allstops[1];
+ n_stops = pattern->n_stops;
for (i = 0; i < pattern->n_stops; i++) {
stops[i].color_char[0] = pattern->stops[i].color.red * 0xff + 0.5;
stops[i].color_char[1] = pattern->stops[i].color.green * 0xff + 0.5;
stops[i].color_char[2] = pattern->stops[i].color.blue * 0xff + 0.5;
stops[i].color_char[3] = pattern->stops[i].color.alpha * 0xff + 0.5;
- stops[i].offset = pattern->stops[i].offset;
+ stops[i].offset = _cairo_fixed_to_double (pattern->stops[i].offset);
stops[i].id = i;
}
-
+
/* sort stops in ascending order */
- qsort (stops, pattern->n_stops, sizeof (cairo_pdf_color_stop_t),
+ qsort (stops, n_stops, sizeof (cairo_pdf_color_stop_t),
_cairo_pdf_color_stop_compare);
- for (i = 0; i < pattern->n_stops; i++) {
- _cairo_output_stream_write (output, stops[i].color_char, 3);
+ /* make sure first offset is 0.0 and last offset is 1.0. (Otherwise Acrobat
+ * Reader chokes.) */
+ if (stops[0].offset > COLOR_STOP_EPSILLON) {
+ memcpy (allstops, stops, sizeof (cairo_pdf_color_stop_t));
+ stops = allstops;
+ stops[0].offset = 0.0;
+ n_stops++;
+ }
+ if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILLON) {
+ memcpy (&stops[n_stops],
+ &stops[n_stops - 1],
+ sizeof (cairo_pdf_color_stop_t));
+ stops[n_stops].offset = 1.0;
+ n_stops++;
+ }
+
+ if (n_stops == 2) {
+ /* no need for stiched function */
+ function_id = emit_linear_colorgradient (document, &stops[0], &stops[1]);
+ } else {
+ /* multiple stops: stich. XXX possible optimization: regulary spaced
+ * stops do not require stiching. XXX */
+ function_id = emit_stiched_colorgradient (document,
+ n_stops,
+ stops);
}
- free (stops);
-
- _cairo_output_stream_printf (output,
- "\r\n"
- "endstream\r\n"
- "endobj\r\n");
+ free (allstops);
return function_id;
}
More information about the cairo-commit
mailing list