📄 cairo-ps-surface.c
字号:
/* cairo - a vector graphics library with display and print output * * Copyright © 2003 University of Southern California * Copyright © 2005 Red Hat, Inc * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * (the "LGPL") or, at your option, under the terms of the Mozilla * Public License Version 1.1 (the "MPL"). If you do not alter this * notice, a recipient may use your version of this file under either * the MPL or the LGPL. * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. * * The Original Code is the cairo graphics library. * * The Initial Developer of the Original Code is University of Southern * California. * * Contributor(s): * Carl D. Worth <cworth@cworth.org> * Kristian Høgsberg <krh@redhat.com> * Keith Packard <keithp@keithp.com> */#include "cairoint.h"#include "cairo-ps.h"#include "cairo-ps-test.h"#include "cairo-scaled-font-subsets-private.h"#include "cairo-paginated-surface-private.h"#include "cairo-meta-surface-private.h"#include "cairo-ft-private.h"#include "cairo-output-stream-private.h"#include <time.h>#include <zlib.h>static const cairo_surface_backend_t cairo_ps_surface_backend;static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend;typedef struct cairo_ps_surface { cairo_surface_t base; /* Here final_stream corresponds to the stream/file passed to * cairo_ps_surface_create surface is built. Meanwhile stream is a * temporary stream in which the file output is built, (so that * the header can be built and inserted into the target stream * before the contents of the temporary stream are copied). */ cairo_output_stream_t *final_stream; FILE *tmpfile; cairo_output_stream_t *stream; double width; double height; double max_width; double max_height; int num_pages; cairo_paginated_mode_t paginated_mode; cairo_scaled_font_subsets_t *font_subsets; cairo_array_t dsc_header_comments; cairo_array_t dsc_setup_comments; cairo_array_t dsc_page_setup_comments; cairo_array_t *dsc_comment_target;} cairo_ps_surface_t;#define PS_SURFACE_MAX_GLYPHS_PER_FONT 256/* A word wrap stream can be used as a filter to do word wrapping on * top of an existing output stream. The word wrapping is quite * simple, using isspace to determine characters that separate * words. Any word that will cause the column count exceeed the given * max_column will have a '\n' character emitted before it. * * The stream is careful to maintain integrity for words that cross * the boundary from one call to write to the next. * * Note: This stream does not guarantee that the output will never * exceed max_column. In particular, if a single word is larger than * max_column it will not be broken up. */typedef struct _word_wrap_stream { cairo_output_stream_t base; cairo_output_stream_t *output; int max_column; int column; cairo_bool_t last_write_was_space;} word_wrap_stream_t;static int_count_word_up_to (const unsigned char *s, int length){ int word = 0; while (length--) { if (! isspace (*s++)) word++; else return word; } return word;}static cairo_status_t_word_wrap_stream_write (cairo_output_stream_t *base, const unsigned char *data, unsigned int length){ word_wrap_stream_t *stream = (word_wrap_stream_t *) base; cairo_bool_t newline; int word; while (length) { if (isspace (*data)) { newline = (*data == '\n' || *data == '\r'); if (! newline && stream->column >= stream->max_column) { _cairo_output_stream_printf (stream->output, "\n"); stream->column = 0; } _cairo_output_stream_write (stream->output, data, 1); data++; length--; if (newline) stream->column = 0; else stream->column++; stream->last_write_was_space = TRUE; } else { word = _count_word_up_to (data, length); /* Don't wrap if this word is a continuation of a word * from a previous call to write. */ if (stream->column + word >= stream->max_column && stream->last_write_was_space) { _cairo_output_stream_printf (stream->output, "\n"); stream->column = 0; } _cairo_output_stream_write (stream->output, data, word); data += word; length -= word; stream->column += word; stream->last_write_was_space = FALSE; } } return _cairo_output_stream_get_status (stream->output);}static cairo_status_t_word_wrap_stream_close (cairo_output_stream_t *base){ word_wrap_stream_t *stream = (word_wrap_stream_t *) base; return _cairo_output_stream_get_status (stream->output);}static cairo_output_stream_t *_word_wrap_stream_create (cairo_output_stream_t *output, int max_column){ word_wrap_stream_t *stream; stream = malloc (sizeof (word_wrap_stream_t)); if (stream == NULL) return (cairo_output_stream_t *) &cairo_output_stream_nil; _cairo_output_stream_init (&stream->base, _word_wrap_stream_write, _word_wrap_stream_close); stream->output = output; stream->max_column = max_column; stream->column = 0; stream->last_write_was_space = FALSE; return &stream->base;}typedef struct _ps_path_info { cairo_ps_surface_t *surface; cairo_output_stream_t *stream; cairo_line_cap_t line_cap; cairo_point_t last_move_to_point; cairo_bool_t has_sub_path;} ps_path_info_t;static cairo_status_t_cairo_ps_surface_path_move_to (void *closure, cairo_point_t *point){ ps_path_info_t *path_info = closure; path_info->last_move_to_point = *point; path_info->has_sub_path = FALSE; _cairo_output_stream_printf (path_info->stream, "%f %f moveto ", _cairo_fixed_to_double (point->x), _cairo_fixed_to_double (point->y)); return CAIRO_STATUS_SUCCESS;}static cairo_status_t_cairo_ps_surface_path_line_to (void *closure, cairo_point_t *point){ ps_path_info_t *path_info = closure; if (path_info->line_cap != CAIRO_LINE_CAP_ROUND && ! path_info->has_sub_path && point->x == path_info->last_move_to_point.x && point->y == path_info->last_move_to_point.y) { return CAIRO_STATUS_SUCCESS; } path_info->has_sub_path = TRUE; _cairo_output_stream_printf (path_info->stream, "%f %f lineto ", _cairo_fixed_to_double (point->x), _cairo_fixed_to_double (point->y)); return CAIRO_STATUS_SUCCESS;}static cairo_status_t_cairo_ps_surface_path_curve_to (void *closure, cairo_point_t *b, cairo_point_t *c, cairo_point_t *d){ ps_path_info_t *path_info = closure; path_info->has_sub_path = TRUE; _cairo_output_stream_printf (path_info->stream, "%f %f %f %f %f %f curveto ", _cairo_fixed_to_double (b->x), _cairo_fixed_to_double (b->y), _cairo_fixed_to_double (c->x), _cairo_fixed_to_double (c->y), _cairo_fixed_to_double (d->x), _cairo_fixed_to_double (d->y)); return CAIRO_STATUS_SUCCESS;}static cairo_status_t_cairo_ps_surface_path_close_path (void *closure){ ps_path_info_t *path_info = closure; if (path_info->line_cap != CAIRO_LINE_CAP_ROUND && ! path_info->has_sub_path) { return CAIRO_STATUS_SUCCESS; } _cairo_output_stream_printf (path_info->stream, "closepath\n"); return CAIRO_STATUS_SUCCESS;}/* The line cap value is needed to workaround the fact that PostScript * semnatics for stroking degenerate sub-paths do not match cairo * semantics. (PostScript draws something for any line cap value, * while cairo draws something only for round caps). * * When using this function to emit a path to be filled, rather than * stroked, simply pass CAIRO_LINE_CAP_ROUND which will guarantee that * the stroke workaround will not modify the path being emitted. */static cairo_status_t_cairo_ps_surface_emit_path (cairo_ps_surface_t *surface, cairo_output_stream_t *stream, cairo_path_fixed_t *path, cairo_line_cap_t line_cap){ cairo_output_stream_t *word_wrap; cairo_status_t status; ps_path_info_t path_info; word_wrap = _word_wrap_stream_create (stream, 79); path_info.surface = surface; path_info.stream = word_wrap; path_info.line_cap = line_cap; status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, _cairo_ps_surface_path_move_to, _cairo_ps_surface_path_line_to, _cairo_ps_surface_path_curve_to, _cairo_ps_surface_path_close_path, &path_info); _cairo_output_stream_destroy (word_wrap); return status;}static void_cairo_ps_surface_emit_header (cairo_ps_surface_t *surface){ time_t now; char **comments; int i, num_comments; now = time (NULL); _cairo_output_stream_printf (surface->final_stream, "%%!PS-Adobe-3.0\n" "%%%%Creator: cairo (http://cairographics.org)\n" "%%%%CreationDate: %s" "%%%%Pages: %d\n" "%%%%BoundingBox: %d %d %d %d\n", ctime (&now), surface->num_pages, 0, 0, (int) ceil (surface->max_width), (int) ceil (surface->max_height)); _cairo_output_stream_printf (surface->final_stream, "%%%%DocumentData: Clean7Bit\n" "%%%%LanguageLevel: 2\n"); num_comments = _cairo_array_num_elements (&surface->dsc_header_comments); comments = _cairo_array_index (&surface->dsc_header_comments, 0); for (i = 0; i < num_comments; i++) { _cairo_output_stream_printf (surface->final_stream, "%s\n", comments[i]); free (comments[i]); comments[i] = NULL; } _cairo_output_stream_printf (surface->final_stream, "%%%%EndComments\n"); _cairo_output_stream_printf (surface->final_stream, "%%%%BeginProlog\n" "/C{curveto}bind def\n" "/F{fill}bind def\n" "/G{setgray}bind def\n" "/L{lineto}bind def\n" "/M{moveto}bind def\n" "/P{closepath}bind def\n" "/R{setrgbcolor}bind def\n" "/S{show}bind def\n" "%%%%EndProlog\n"); num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments); if (num_comments) { _cairo_output_stream_printf (surface->final_stream, "%%%%BeginSetup\n"); comments = _cairo_array_index (&surface->dsc_setup_comments, 0); for (i = 0; i < num_comments; i++) { _cairo_output_stream_printf (surface->final_stream, "%s\n", comments[i]); free (comments[i]); comments[i] = NULL; } _cairo_output_stream_printf (surface->final_stream, "%%%%EndSetup\n"); }}static cairo_status_t_cairo_ps_surface_emit_type1_font_subset (cairo_ps_surface_t *surface, cairo_scaled_font_subset_t *font_subset){ cairo_type1_subset_t subset; cairo_status_t status; int length; char name[64]; snprintf (name, sizeof name, "CairoFont-%d-%d", font_subset->font_id, font_subset->subset_id); status = _cairo_type1_subset_init (&subset, name, font_subset); if (status) return status; /* FIXME: Figure out document structure convention for fonts */ _cairo_output_stream_printf (surface->final_stream, "%% _cairo_ps_surface_emit_type1_font_subset\n"); length = subset.header_length + subset.data_length + subset.trailer_length; _cairo_output_stream_write (surface->final_stream, subset.data, length); _cairo_type1_subset_fini (&subset); return CAIRO_STATUS_SUCCESS;}static cairo_status_t_cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface, cairo_scaled_font_subset_t *font_subset){ cairo_truetype_subset_t subset; cairo_status_t status; int i; status = _cairo_truetype_subset_init (&subset, font_subset); if (status) return status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -