diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/cairo-gstate.c | 9 | ||||
-rw-r--r-- | src/cairo-image-surface.c | 18 | ||||
-rw-r--r-- | src/cairo-ps-surface.c | 377 | ||||
-rw-r--r-- | src/cairo-surface.c | 15 | ||||
-rw-r--r-- | src/cairo-xlib-surface.c | 7 | ||||
-rw-r--r-- | src/cairo.c | 9 | ||||
-rw-r--r-- | src/cairo.h | 49 | ||||
-rw-r--r-- | src/cairo_gstate.c | 9 | ||||
-rw-r--r-- | src/cairo_image_surface.c | 18 | ||||
-rw-r--r-- | src/cairo_ps_surface.c | 377 | ||||
-rw-r--r-- | src/cairo_surface.c | 15 | ||||
-rw-r--r-- | src/cairo_xlib_surface.c | 7 | ||||
-rw-r--r-- | src/cairoint.h | 16 |
14 files changed, 912 insertions, 15 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index e90b0fa3..8ff927be 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,6 +18,7 @@ libcairo_la_SOURCES = \ cairo_path_stroke.c \ cairo_pen.c \ cairo_polygon.c \ + cairo_ps_surface.c \ cairo_slope.c \ cairo_spline.c \ cairo_surface.c \ diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 7b9fdd59..8405c32c 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -1345,6 +1345,15 @@ _cairo_gstate_fill (cairo_gstate_t *gstate) } cairo_status_t +_cairo_gstate_show_page (cairo_gstate_t *gstate) +{ + if (gstate->surface == NULL) + return CAIRO_STATUS_NO_TARGET_SURFACE; + + return _cairo_surface_show_page (gstate->surface); +} + +cairo_status_t _cairo_gstate_clip (cairo_gstate_t *gstate) { cairo_status_t status; diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 908e4342..ffd03d0b 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -251,9 +251,16 @@ _cairo_image_surface_set_matrix (cairo_image_surface_t *surface, } static cairo_status_t -_cairo_image_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +_cairo_image_abstract_surface_set_filter (void *abstract_surface, cairo_filter_t filter) { cairo_image_surface_t *surface = abstract_surface; + + return _cairo_image_surface_set_filter (surface, filter); +} + +cairo_status_t +_cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter) +{ IcFilter ic_filter; switch (filter) { @@ -414,6 +421,12 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator, return CAIRO_STATUS_SUCCESS; } +static cairo_int_status_t +_cairo_image_surface_show_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_create_similar, _cairo_image_abstract_surface_destroy, @@ -421,9 +434,10 @@ static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_get_image, _cairo_image_surface_set_image, _cairo_image_abstract_surface_set_matrix, - _cairo_image_surface_set_filter, + _cairo_image_abstract_surface_set_filter, _cairo_image_abstract_surface_set_repeat, _cairo_image_surface_composite, _cairo_image_surface_fill_rectangles, _cairo_image_surface_composite_trapezoids, + _cairo_image_surface_show_page }; diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c new file mode 100644 index 00000000..f78c0ff3 --- /dev/null +++ b/src/cairo-ps-surface.c @@ -0,0 +1,377 @@ +/* + * Copyright © 2003 University of Southern California + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth <cworth@isi.edu> + */ + +#include "cairoint.h" + +#include <time.h> +#include <zlib.h> + +static const cairo_surface_backend_t cairo_ps_surface_backend; + +void +cairo_set_target_ps (cairo_t *cr, + FILE *file, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + cairo_surface_t *surface; + + surface = cairo_ps_surface_create (file, + width_inches, height_inches, + x_pixels_per_inch, y_pixels_per_inch); + + cairo_set_target_surface (cr, surface); + + /* cairo_set_target_surface takes a reference, so we must destroy ours */ + cairo_surface_destroy (surface); +} + +typedef struct cairo_ps_surface { + cairo_surface_t base; + + /* PS-specific fields */ + FILE *file; + + double width_inches; + double height_inches; + double x_ppi; + double y_ppi; + + cairo_image_surface_t *image; +} cairo_ps_surface_t; + +cairo_surface_t * +cairo_ps_surface_create (FILE *file, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + cairo_ps_surface_t *surface; + int width, height; + cairo_color_t transparent; + + surface = malloc (sizeof (cairo_ps_surface_t)); + if (surface == NULL) + return NULL; + + _cairo_surface_init (&surface->base, &cairo_ps_surface_backend); + + surface->file = file; + + surface->width_inches = width_inches; + surface->height_inches = height_inches; + surface->x_ppi = x_pixels_per_inch; + surface->y_ppi = x_pixels_per_inch; + + width = (int) (x_pixels_per_inch * width_inches + 1.0); + height = (int) (y_pixels_per_inch * height_inches + 1.0); + + surface->image = (cairo_image_surface_t *) + cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + if (surface->image == NULL) { + free (surface); + return NULL; + } + + _cairo_color_init (&transparent); + _cairo_color_set_rgb (&transparent, 0., 0., 0.); + _cairo_color_set_alpha (&transparent, 0.); + _cairo_surface_fill_rectangle (&surface->image->base, + CAIRO_OPERATOR_SRC, + &transparent, 0, 0, width, height); + + return &surface->base; +} + +static cairo_surface_t * +_cairo_ps_surface_create_similar (void *abstract_src, + cairo_format_t format, + int width, + int height) +{ + return NULL; +} + +static void +_cairo_ps_surface_destroy (void *abstract_surface) +{ + cairo_ps_surface_t *surface = abstract_surface; + + cairo_surface_destroy (&surface->image->base); + + free (surface); +} + +/* XXX: We should re-work this interface to return both X/Y ppi values. */ +static double +_cairo_ps_surface_pixels_per_inch (void *abstract_surface) +{ + cairo_ps_surface_t *surface = abstract_surface; + + return surface->y_ppi; +} + +static cairo_image_surface_t * +_cairo_ps_surface_get_image (void *abstract_surface) +{ + cairo_ps_surface_t *surface = abstract_surface; + + cairo_surface_reference (&surface->image->base); + + return surface->image; +} + +static cairo_status_t +_cairo_ps_surface_set_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_ps_surface_t *surface = abstract_surface; + + if (image == surface->image) + return CAIRO_STATUS_SUCCESS; + + /* XXX: Need to call _cairo_image_surface_set_image here, but it's + not implemented yet. */ + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_status_t +_cairo_ps_surface_set_matrix (void *abstract_surface, + cairo_matrix_t *matrix) +{ + cairo_ps_surface_t *surface = abstract_surface; + + return _cairo_image_surface_set_matrix (surface->image, matrix); +} + +static cairo_status_t +_cairo_ps_surface_set_filter (void *abstract_surface, + cairo_filter_t filter) +{ + cairo_ps_surface_t *surface = abstract_surface; + + return _cairo_image_surface_set_filter (surface->image, filter); +} + +static cairo_status_t +_cairo_ps_surface_set_repeat (void *abstract_surface, + int repeat) +{ + cairo_ps_surface_t *surface = abstract_surface; + + return _cairo_image_surface_set_repeat (surface->image, repeat); +} + +static cairo_int_status_t +_cairo_ps_surface_composite (cairo_operator_t operator, + cairo_surface_t *generic_src, + cairo_surface_t *generic_mask, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_ps_surface_fill_rectangles (void *abstract_surface, + cairo_operator_t operator, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_ps_surface_composite_trapezoids (cairo_operator_t operator, + cairo_surface_t *generic_src, + void *abstract_dst, + int x_src, + int y_src, + cairo_trapezoid_t *traps, + int num_traps) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_ps_surface_show_page (void *abstract_surface) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_ps_surface_t *surface = abstract_surface; + int width = surface->image->width; + int height = surface->image->height; + FILE *file = surface->file; + + int i, x, y; + time_t now = time (0); + + cairo_surface_t *white_surface; + char *bgr, *compressed; + long bgr_size, compressed_size; + + cairo_color_t white; + + bgr_size = 3 * width * height; + bgr = malloc (bgr_size); + if (bgr == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto BAIL0; + } + + compressed_size = (int) (1.0 + 1.1 * bgr_size); + compressed = malloc (compressed_size); + if (compressed == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto BAIL1; + } + + /* PostScript can not represent the alpha channel, so we blend the + current image over a white RGB surface to eliminate it. */ + white_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1); + if (white_surface == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto BAIL2; + } + + _cairo_color_init (&white); + _cairo_surface_fill_rectangle (white_surface, + CAIRO_OPERATOR_SRC, + &white, + 0, 0, 1, 1); + cairo_surface_set_repeat (white_surface, 1); + _cairo_surface_composite (CAIRO_OPERATOR_OVER_REVERSE, + white_surface, + NULL, + &surface->image->base, + 0, 0, + 0, 0, + 0, 0, + width, height); + + i = 0; + for (y = 0; y < height; y++) { + char *line = surface->image->data + y * surface->image->stride; + for (x = 0; x < width; x++) { + unsigned char *pixel = (unsigned char *) line + x * 4; + bgr[i++] = *(pixel+2); + bgr[i++] = *(pixel+1); + bgr[i++] = *(pixel); + } + } + + compress (compressed, &compressed_size, bgr, bgr_size); + + /* Document header */ + fprintf (file, + "%%!PS-Adobe-3.0\n" + "%%%%Creator: Cairo (http://cairographics.org)\n"); + fprintf (file, + "%%%%CreationDate: %s", + ctime (&now)); + fprintf (file, + "%%%%Copyright: 2003 Carl Worth and Keith Packard\n"); + fprintf (file, + "%%%%BoundingBox: %d %d %d %d\n", + 0, 0, (int) (surface->width_inches * 72.0), (int) (surface->height_inches * 72.0)); + fprintf (file, + "%%%%DocumentData: Clean7Bit\n" + "%%%%LanguageLevel: 3\n"); + fprintf (file, + "%%%%Pages: %d\n", + 1); + fprintf (file, + "%%%%Orientation: Portrait\n" + "%%%%EndComments\n"); + + /* Page header */ + fprintf (file, "%%%%Page: %d\n", 1); + + fprintf (file, "gsave\n"); + + /* Image header goop */ + fprintf (file, "%g %g translate\n", 0.0, surface->width_inches * 72.0); + fprintf (file, "%g %g scale\n", 72.0 / surface->x_ppi, 72.0 / surface->y_ppi); + fprintf (file, "/DeviceRGB setcolorspace\n"); + fprintf (file, "<<\n"); + fprintf (file, " /ImageType 1\n"); + fprintf (file, " /Width %d\n", width); + fprintf (file, " /Height %d\n", height); + fprintf (file, " /BitsPerComponent 8\n"); + fprintf (file, " /Decode [ 0 1 0 1 0 1 ]\n"); + fprintf (file, " /DataSource currentfile /FlateDecode filter\n"); + fprintf (file, " /ImageMatrix [ 1 0 0 -1 0 1 ]\n"); + fprintf (file, ">>\n"); + fprintf (file, "image\n"); + + /* Compressed image data */ + fwrite (compressed, 1, compressed_size, file); + + fprintf (file, "showpage\n"); + + fprintf (file, "grestore\n"); + + /* Page footer */ + fprintf (file, "%%%%EndPage\n"); + + /* Document footer */ + fprintf (file, "%%%%EOF\n"); + + cairo_surface_destroy (white_surface); + BAIL2: + free (compressed); + BAIL1: + free (bgr); + BAIL0: + return status; +} + +static const cairo_surface_backend_t cairo_ps_surface_backend = { + _cairo_ps_surface_create_similar, + _cairo_ps_surface_destroy, + _cairo_ps_surface_pixels_per_inch, + _cairo_ps_surface_get_image, + _cairo_ps_surface_set_image, + _cairo_ps_surface_set_matrix, + _cairo_ps_surface_set_filter, + _cairo_ps_surface_set_repeat, + _cairo_ps_surface_composite, + _cairo_ps_surface_fill_rectangles, + _cairo_ps_surface_composite_trapezoids, + _cairo_ps_surface_show_page +}; diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 41baabec..0e847eae 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -334,3 +334,18 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator, return status; } +cairo_status_t +_cairo_surface_show_page (cairo_surface_t *surface) +{ + cairo_int_status_t status; + + status = surface->backend->show_page (surface); + /* It's fine if some backends just don't support this. */ + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + return CAIRO_STATUS_SUCCESS; + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} + diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 41ab48bd..9d705150 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -556,7 +556,11 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, return CAIRO_STATUS_SUCCESS; } - +static cairo_int_status_t +_cairo_xlib_surface_show_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_create_similar, @@ -570,6 +574,7 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_composite, _cairo_xlib_surface_fill_rectangles, _cairo_xlib_surface_composite_trapezoids, + _cairo_xlib_surface_show_page }; cairo_surface_t * diff --git a/src/cairo.c b/src/cairo.c index 77220cbf..e80fd6cd 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -584,6 +584,15 @@ cairo_fill (cairo_t *cr) } void +cairo_show_page (cairo_t *cr) +{ + if (cr->status) + return; + + cr->status = _cairo_gstate_show_page (cr->gstate); +} + +void cairo_clip (cairo_t *cr) { if (cr->status) diff --git a/src/cairo.h b/src/cairo.h index 8a64d3fb..1944aaa7 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -29,6 +29,7 @@ #define _CAIRO_H_ #include <ic.h> +#include <stdio.h> #ifdef _CAIROINT_H_ #include <slim_export.h> @@ -90,6 +91,14 @@ cairo_set_target_image (cairo_t *cr, int height, int stride); +void +cairo_set_target_ps (cairo_t *cr, + FILE *file, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch); + typedef enum cairo_operator { CAIRO_OPERATOR_CLEAR, CAIRO_OPERATOR_SRC, @@ -286,6 +295,9 @@ cairo_stroke (cairo_t *cr); extern void __external_linkage cairo_fill (cairo_t *cr); +void +cairo_show_page (cairo_t *cr); + /* Clipping */ extern void __external_linkage cairo_clip (cairo_t *cr); @@ -497,15 +509,18 @@ cairo_status (cairo_t *cr); extern const char * __external_linkage cairo_status_string (cairo_t *cr); -/* Surface mainpulation */ - +/* Surface manipulation */ +/* XXX: We may want to rename this function in light of the new + virtualized surface backends... */ extern cairo_surface_t * __external_linkage -cairo_surface_create_for_image (char *data, - cairo_format_t format, - int width, - int height, - int stride); - +cairo_surface_create_for_image (char *data, + cairo_format_t format, + int width, + int height, + int stride); + +/* XXX: I want to remove this function, (replace with + cairo_set_target_scratch or similar). */ extern cairo_surface_t * __external_linkage cairo_surface_create_similar (cairo_surface_t *other, cairo_format_t format, @@ -523,6 +538,9 @@ extern cairo_status_t __external_linkage cairo_surface_clip_restore (cairo_surface_t *surface); extern cairo_status_t __external_linkage +cairo_surface_clip_begin (cairo_surface_t *surface); + +extern cairo_status_t __external_linkage cairo_surface_clip_rectangle (cairo_surface_t *surface, int x, int y, int width, int height); @@ -530,12 +548,15 @@ cairo_surface_clip_rectangle (cairo_surface_t *surface, /* XXX: Note: The current Render/Ic implementations don't do the right thing with repeat when the surface has a non-identity matrix. */ +/* XXX: Rework this as a cairo function with an enum: cairo_set_pattern_extend */ extern cairo_status_t __external_linkage cairo_surface_set_repeat (cairo_surface_t *surface, int repeat); +/* XXX: Rework this as a cairo function: cairo_set_pattern_transform */ extern cairo_status_t __external_linkage cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix); +/* XXX: Rework this as a cairo function: cairo_current_pattern_transform */ extern cairo_status_t __external_linkage cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix); @@ -547,6 +568,7 @@ typedef enum cairo_filter { CAIRO_FILTER_BILINEAR, } cairo_filter_t; +/* XXX: Rework this as a cairo function: cairo_set_pattern_filter */ extern cairo_status_t __external_linkage cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter); @@ -564,8 +586,19 @@ cairo_image_surface_create_for_data (char *data, int height, int stride); +/* PS-surface functions */ + +cairo_surface_t * +cairo_ps_surface_create (FILE *file, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch); + /* Matrix functions */ +/* XXX: Rename all of these to cairo_transform_t */ + extern cairo_matrix_t * __external_linkage cairo_matrix_create (void); diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c index 7b9fdd59..8405c32c 100644 --- a/src/cairo_gstate.c +++ b/src/cairo_gstate.c @@ -1345,6 +1345,15 @@ _cairo_gstate_fill (cairo_gstate_t *gstate) } cairo_status_t +_cairo_gstate_show_page (cairo_gstate_t *gstate) +{ + if (gstate->surface == NULL) + return CAIRO_STATUS_NO_TARGET_SURFACE; + + return _cairo_surface_show_page (gstate->surface); +} + +cairo_status_t _cairo_gstate_clip (cairo_gstate_t *gstate) { cairo_status_t status; diff --git a/src/cairo_image_surface.c b/src/cairo_image_surface.c index 908e4342..ffd03d0b 100644 --- a/src/cairo_image_surface.c +++ b/src/cairo_image_surface.c @@ -251,9 +251,16 @@ _cairo_image_surface_set_matrix (cairo_image_surface_t *surface, } static cairo_status_t -_cairo_image_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +_cairo_image_abstract_surface_set_filter (void *abstract_surface, cairo_filter_t filter) { cairo_image_surface_t *surface = abstract_surface; + + return _cairo_image_surface_set_filter (surface, filter); +} + +cairo_status_t +_cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter) +{ IcFilter ic_filter; switch (filter) { @@ -414,6 +421,12 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator, return CAIRO_STATUS_SUCCESS; } +static cairo_int_status_t +_cairo_image_surface_show_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_create_similar, _cairo_image_abstract_surface_destroy, @@ -421,9 +434,10 @@ static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_get_image, _cairo_image_surface_set_image, _cairo_image_abstract_surface_set_matrix, - _cairo_image_surface_set_filter, + _cairo_image_abstract_surface_set_filter, _cairo_image_abstract_surface_set_repeat, _cairo_image_surface_composite, _cairo_image_surface_fill_rectangles, _cairo_image_surface_composite_trapezoids, + _cairo_image_surface_show_page }; diff --git a/src/cairo_ps_surface.c b/src/cairo_ps_surface.c new file mode 100644 index 00000000..f78c0ff3 --- /dev/null +++ b/src/cairo_ps_surface.c @@ -0,0 +1,377 @@ +/* + * Copyright © 2003 University of Southern California + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth <cworth@isi.edu> + */ + +#include "cairoint.h" + +#include <time.h> +#include <zlib.h> + +static const cairo_surface_backend_t cairo_ps_surface_backend; + +void +cairo_set_target_ps (cairo_t *cr, + FILE *file, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + cairo_surface_t *surface; + + surface = cairo_ps_surface_create (file, + width_inches, height_inches, + x_pixels_per_inch, y_pixels_per_inch); + + cairo_set_target_surface (cr, surface); + + /* cairo_set_target_surface takes a reference, so we must destroy ours */ + cairo_surface_destroy (surface); +} + +typedef struct cairo_ps_surface { + cairo_surface_t base; + + /* PS-specific fields */ + FILE *file; + + double width_inches; + double height_inches; + double x_ppi; + double y_ppi; + + cairo_image_surface_t *image; +} cairo_ps_surface_t; + +cairo_surface_t * +cairo_ps_surface_create (FILE *file, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + cairo_ps_surface_t *surface; + int width, height; + cairo_color_t transparent; + + surface = malloc (sizeof (cairo_ps_surface_t)); + if (surface == NULL) + return NULL; + + _cairo_surface_init (&surface->base, &cairo_ps_surface_backend); + + surface->file = file; + + surface->width_inches = width_inches; + surface->height_inches = height_inches; + surface->x_ppi = x_pixels_per_inch; + surface->y_ppi = x_pixels_per_inch; + + width = (int) (x_pixels_per_inch * width_inches + 1.0); + height = (int) (y_pixels_per_inch * height_inches + 1.0); + + surface->image = (cairo_image_surface_t *) + cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + if (surface->image == NULL) { + free (surface); + return NULL; + } + + _cairo_color_init (&transparent); + _cairo_color_set_rgb (&transparent, 0., 0., 0.); + _cairo_color_set_alpha (&transparent, 0.); + _cairo_surface_fill_rectangle (&surface->image->base, + CAIRO_OPERATOR_SRC, + &transparent, 0, 0, width, height); + + return &surface->base; +} + +static cairo_surface_t * +_cairo_ps_surface_create_similar (void *abstract_src, + cairo_format_t format, + int width, + int height) +{ + return NULL; +} + +static void +_cairo_ps_surface_destroy (void *abstract_surface) +{ + cairo_ps_surface_t *surface = abstract_surface; + + cairo_surface_destroy (&surface->image->base); + + free (surface); +} + +/* XXX: We should re-work this interface to return both X/Y ppi values. */ +static double +_cairo_ps_surface_pixels_per_inch (void *abstract_surface) +{ + cairo_ps_surface_t *surface = abstract_surface; + + return surface->y_ppi; +} + +static cairo_image_surface_t * +_cairo_ps_surface_get_image (void *abstract_surface) +{ + cairo_ps_surface_t *surface = abstract_surface; + + cairo_surface_reference (&surface->image->base); + + return surface->image; +} + +static cairo_status_t +_cairo_ps_surface_set_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_ps_surface_t *surface = abstract_surface; + + if (image == surface->image) + return CAIRO_STATUS_SUCCESS; + + /* XXX: Need to call _cairo_image_surface_set_image here, but it's + not implemented yet. */ + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_status_t +_cairo_ps_surface_set_matrix (void *abstract_surface, + cairo_matrix_t *matrix) +{ + cairo_ps_surface_t *surface = abstract_surface; + + return _cairo_image_surface_set_matrix (surface->image, matrix); +} + +static cairo_status_t +_cairo_ps_surface_set_filter (void *abstract_surface, + cairo_filter_t filter) +{ + cairo_ps_surface_t *surface = abstract_surface; + + return _cairo_image_surface_set_filter (surface->image, filter); +} + +static cairo_status_t +_cairo_ps_surface_set_repeat (void *abstract_surface, + int repeat) +{ + cairo_ps_surface_t *surface = abstract_surface; + + return _cairo_image_surface_set_repeat (surface->image, repeat); +} + +static cairo_int_status_t +_cairo_ps_surface_composite (cairo_operator_t operator, + cairo_surface_t *generic_src, + cairo_surface_t *generic_mask, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_ps_surface_fill_rectangles (void *abstract_surface, + cairo_operator_t operator, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_ps_surface_composite_trapezoids (cairo_operator_t operator, + cairo_surface_t *generic_src, + void *abstract_dst, + int x_src, + int y_src, + cairo_trapezoid_t *traps, + int num_traps) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_ps_surface_show_page (void *abstract_surface) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_ps_surface_t *surface = abstract_surface; + int width = surface->image->width; + int height = surface->image->height; + FILE *file = surface->file; + + int i, x, y; + time_t now = time (0); + + cairo_surface_t *white_surface; + char *bgr, *compressed; + long bgr_size, compressed_size; + + cairo_color_t white; + + bgr_size = 3 * width * height; + bgr = malloc (bgr_size); + if (bgr == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto BAIL0; + } + + compressed_size = (int) (1.0 + 1.1 * bgr_size); + compressed = malloc (compressed_size); + if (compressed == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto BAIL1; + } + + /* PostScript can not represent the alpha channel, so we blend the + current image over a white RGB surface to eliminate it. */ + white_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1); + if (white_surface == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto BAIL2; + } + + _cairo_color_init (&white); + _cairo_surface_fill_rectangle (white_surface, + CAIRO_OPERATOR_SRC, + &white, + 0, 0, 1, 1); + cairo_surface_set_repeat (white_surface, 1); + _cairo_surface_composite (CAIRO_OPERATOR_OVER_REVERSE, + white_surface, + NULL, + &surface->image->base, + 0, 0, + 0, 0, + 0, 0, + width, height); + + i = 0; + for (y = 0; y < height; y++) { + char *line = surface->image->data + y * surface->image->stride; + for (x = 0; x < width; x++) { + unsigned char *pixel = (unsigned char *) line + x * 4; + bgr[i++] = *(pixel+2); + bgr[i++] = *(pixel+1); + bgr[i++] = *(pixel); + } + } + + compress (compressed, &compressed_size, bgr, bgr_size); + + /* Document header */ + fprintf (file, + "%%!PS-Adobe-3.0\n" + "%%%%Creator: Cairo (http://cairographics.org)\n"); + fprintf (file, + "%%%%CreationDate: %s", + ctime (&now)); + fprintf (file, + "%%%%Copyright: 2003 Carl Worth and Keith Packard\n"); + fprintf (file, + "%%%%BoundingBox: %d %d %d %d\n", + 0, 0, (int) (surface->width_inches * 72.0), (int) (surface->height_inches * 72.0)); + fprintf (file, + "%%%%DocumentData: Clean7Bit\n" + "%%%%LanguageLevel: 3\n"); + fprintf (file, + "%%%%Pages: %d\n", + 1); + fprintf (file, + "%%%%Orientation: Portrait\n" + "%%%%EndComments\n"); + + /* Page header */ + fprintf (file, "%%%%Page: %d\n", 1); + + fprintf (file, "gsave\n"); + + /* Image header goop */ + fprintf (file, "%g %g translate\n", 0.0, surface->width_inches * 72.0); + fprintf (file, "%g %g scale\n", 72.0 / surface->x_ppi, 72.0 / surface->y_ppi); + fprintf (file, "/DeviceRGB setcolorspace\n"); + fprintf (file, "<<\n"); + fprintf (file, " /ImageType 1\n"); + fprintf (file, " /Width %d\n", width); + fprintf (file, " /Height %d\n", height); + fprintf (file, " /BitsPerComponent 8\n"); + fprintf (file, " /Decode [ 0 1 0 1 0 1 ]\n"); + fprintf (file, " /DataSource currentfile /FlateDecode filter\n"); + fprintf (file, " /ImageMatrix [ 1 0 0 -1 0 1 ]\n"); + fprintf (file, ">>\n"); + fprintf (file, "image\n"); + + /* Compressed image data */ + fwrite (compressed, 1, compressed_size, file); + + fprintf (file, "showpage\n"); + + fprintf (file, "grestore\n"); + + /* Page footer */ + fprintf (file, "%%%%EndPage\n"); + + /* Document footer */ + fprintf (file, "%%%%EOF\n"); + + cairo_surface_destroy (white_surface); + BAIL2: + free (compressed); + BAIL1: + free (bgr); + BAIL0: + return status; +} + +static const cairo_surface_backend_t cairo_ps_surface_backend = { + _cairo_ps_surface_create_similar, + _cairo_ps_surface_destroy, + _cairo_ps_surface_pixels_per_inch, + _cairo_ps_surface_get_image, + _cairo_ps_surface_set_image, + _cairo_ps_surface_set_matrix, + _cairo_ps_surface_set_filter, + _cairo_ps_surface_set_repeat, + _cairo_ps_surface_composite, + _cairo_ps_surface_fill_rectangles, + _cairo_ps_surface_composite_trapezoids, + _cairo_ps_surface_show_page +}; diff --git a/src/cairo_surface.c b/src/cairo_surface.c index 41baabec..0e847eae 100644 --- a/src/cairo_surface.c +++ b/src/cairo_surface.c @@ -334,3 +334,18 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator, return status; } +cairo_status_t +_cairo_surface_show_page (cairo_surface_t *surface) +{ + cairo_int_status_t status; + + status = surface->backend->show_page (surface); + /* It's fine if some backends just don't support this. */ + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + return CAIRO_STATUS_SUCCESS; + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} + diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c index 41ab48bd..9d705150 100644 --- a/src/cairo_xlib_surface.c +++ b/src/cairo_xlib_surface.c @@ -556,7 +556,11 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, return CAIRO_STATUS_SUCCESS; } - +static cairo_int_status_t +_cairo_xlib_surface_show_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_create_similar, @@ -570,6 +574,7 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_composite, _cairo_xlib_surface_fill_rectangles, _cairo_xlib_surface_composite_trapezoids, + _cairo_xlib_surface_show_page }; cairo_surface_t * diff --git a/src/cairoint.h b/src/cairoint.h index b672e2eb..d100a067 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -353,6 +353,9 @@ typedef struct cairo_surface_backend { int ySrc, cairo_trapezoid_t *traps, int num_traps); + + cairo_int_status_t + (*show_page) (void *surface); } cairo_surface_backend_t; struct cairo_matrix { @@ -709,6 +712,9 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate); extern cairo_status_t __internal_linkage _cairo_gstate_fill (cairo_gstate_t *gstate); +cairo_status_t +_cairo_gstate_show_page (cairo_gstate_t *gstate); + extern cairo_status_t __internal_linkage _cairo_gstate_clip (cairo_gstate_t *gstate); @@ -956,6 +962,9 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator, cairo_trapezoid_t *traps, int ntraps); +cairo_status_t +_cairo_surface_show_page (cairo_surface_t *surface); + extern double __internal_linkage _cairo_surface_pixels_per_inch (cairo_surface_t *surface); @@ -982,8 +991,13 @@ extern cairo_status_t __internal_linkage _cairo_image_surface_set_matrix (cairo_image_surface_t *surface, cairo_matrix_t *matrix); +cairo_status_t +_cairo_image_surface_set_filter (cairo_image_surface_t *surface, + cairo_filter_t filter); + extern cairo_status_t __internal_linkage -_cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat); +_cairo_image_surface_set_repeat (cairo_image_surface_t *surface, + int repeat); /* cairo_pen.c */ extern cairo_status_t __internal_linkage |