[cairo] [PATCH] PS/PDF improve efficiency of text output

Behdad Esfahbod behdad at behdad.org
Sun Sep 24 19:02:06 PDT 2006


Hi Adrian,

Thanks for yet another excellent patch set.

I like to propose new API, cairo_surface_[sg]et_compression_level().
They take/return an integer value between 0 and 9, inclusive.  With 0,
no compression is performed as much as possible, while 1 to 9 are simply
passed to libpng and zlib to be used as compression levels.  The default
level is 6, like gzip.

What do people think about this?  The main motivation is to have public
API to get human-readable PS/PDF output.

behdad


On Sat, 2006-09-23 at 12:55 -0400, Adrian Johnson wrote:
> The PDF and PS backends are very inefficient at printing text. These
> patches remove some of the redundancy and help to reduce the size of the
> PS and PDF files generated by cairo.
> 
> The first patch makes the PS show glyphs function look for strings of
> glyphs from the same subset and use either the xshow, yshow, or xyshow
> PS operator to print the glyphs depending on whether the glyphs are
> horizontal, vertical, or neither.
> 
> The PDF show glyphs function emits the text matrix for every glyph
> displayed as this is the only way to specify an absolute position.
> There is a 'x y Td' PDF operator that multiplies the text matrix by a
> translation matrix created from the x and y operands. The second patch
> will, for the simple case where the text matrix is a diagonal matrix,
> use the Td operator for positioning glyphs.
> 
> The third patch adds a new stream filter type that compresses the stream
> using the zlib deflate method.
> 
> The fourth patch uses the deflate stream in the PDF backend when
> emitting the content stream. This could be further extended to compress
> all PDF streams including replacing the compress_dup() function with the
> deflate stream.
> 
> Testing the PDF backend with a paragraph of text showed that currently
> the content stream averages 45 bytes per glyph. These patches reduce
> that to an average of 1.6 bytes per glyph.
> 
> I mentioned previously that I am getting a large number of make test
> failures despite trying different library versions. How do I resolve
> this apparent conflict between "don't commit until make test passes" and
> the inability to get make test to pass for the latest git master on my
> machine?
> 
> plain text document attachment
> (0001-PS-Use-xshow-yshow-xyshow-for-strings-of-glyphs.txt)
> >From 6bcc67f1df6d4301e616fa6d4711c73fd4c5795e Mon Sep 17 00:00:00 2001
> From: Adrian Johnson <ajohnson at redneon.com>
> Date: Sun, 24 Sep 2006 00:46:43 +0930
> Subject: [PATCH] PS: Use xshow/yshow/xyshow for strings of glyphs
> 
> Optimize show glyphs by looking for strings of glyphs from the same subset
> and use the xyshow operator to display. As a further optimization the xshow
> and yshow operators are used for displaying horizontal and vertical text.
> ---
>  src/cairo-ps-surface.c |   97 +++++++++++++++++++++++++++++++++++++++++++-----
>  1 files changed, 86 insertions(+), 11 deletions(-)
> 
> diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
> index 7403b0e..d9c5d9c 100644
> --- a/src/cairo-ps-surface.c
> +++ b/src/cairo-ps-surface.c
> @@ -2089,6 +2089,15 @@ _cairo_ps_surface_fill (void		*abstract_
>      return status;
>  }
>  
> +/* This size keeps the length of the hex encoded string of glyphs
> + * within 80 columns. */
> +#define MAX_GLYPHS_PER_SHOW  36
> +
> +typedef struct _cairo_ps_glyph_id {
> +    unsigned int subset_id;
> +    unsigned int glyph_id;
> +} cairo_ps_glyph_id_t;
> +
>  static cairo_int_status_t
>  _cairo_ps_surface_show_glyphs (void		     *abstract_surface,
>  			       cairo_operator_t	      op,
> @@ -2100,9 +2109,12 @@ _cairo_ps_surface_show_glyphs (void		   
>      cairo_ps_surface_t *surface = abstract_surface;
>      cairo_output_stream_t *stream = surface->stream;
>      unsigned int current_subset_id = -1;
> -    unsigned int font_id, subset_id, subset_glyph_index;
> +    unsigned int font_id;
> +    cairo_ps_glyph_id_t *glyph_ids;
>      cairo_status_t status;
> -    int i;
> +    int i, j, last, end;
> +    cairo_bool_t vertical, horizontal;
> +    cairo_output_stream_t *word_wrap;
>  
>      if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
>  	return _analyze_operation (surface, op, source);
> @@ -2114,35 +2126,98 @@ _cairo_ps_surface_show_glyphs (void		   
>  
>      if (num_glyphs)
>  	emit_pattern (surface, source, 0, 0);
> +    else
> +        return CAIRO_STATUS_SUCCESS;
> +
> +    glyph_ids = malloc (num_glyphs*sizeof(cairo_ps_glyph_id_t));
> +    if (glyph_ids == NULL)
> +        return CAIRO_STATUS_NO_MEMORY;
>  
>      for (i = 0; i < num_glyphs; i++) {
>  	status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
>  						       scaled_font, glyphs[i].index,
> -						       &font_id, &subset_id, &subset_glyph_index);
> +						       &font_id,
> +                                                       &(glyph_ids[i].subset_id),
> +                                                       &(glyph_ids[i].glyph_id));
>  	if (status)
> -	    return status;
> +	    goto fail;
> +    }
>  
> -	if (subset_id != current_subset_id) {
> +    i = 0;
> +    while (i < num_glyphs) {
> +        if (glyph_ids[i].subset_id != current_subset_id) {
>  	    _cairo_output_stream_printf (surface->stream,
>  					 "/CairoFont-%d-%d findfont\n"
>  					 "[ %f %f %f %f 0 0 ] makefont\n"
>  					 "setfont\n",
>  					 font_id,
> -					 subset_id,
> +					 glyph_ids[i].subset_id,
>  					 scaled_font->scale.xx,
>  					 scaled_font->scale.yx,
>  					 -scaled_font->scale.xy,
>  					 -scaled_font->scale.yy);
> -	    current_subset_id = subset_id;
> +	    current_subset_id = glyph_ids[i].subset_id;
>  	}
>  
> -	_cairo_output_stream_printf (surface->stream,
> -				     "%f %f M <%02x> S\n",
> -				     glyphs[i].x, glyphs[i].y,
> -				     subset_glyph_index);
> +        _cairo_output_stream_printf (stream, "%f %f M\n",  glyphs[i].x, glyphs[i].y);
> +
> +        horizontal = TRUE;
> +        vertical = TRUE;
> +        end = num_glyphs;
> +        if (end - i > MAX_GLYPHS_PER_SHOW)
> +            end = i + MAX_GLYPHS_PER_SHOW;
> +        last = end - 1;
> +        for (j = i; j < end - 1; j++) {
> +            if ((glyphs[j].y != glyphs[j + 1].y))
> +                horizontal = FALSE;
> +            if ((glyphs[j].x != glyphs[j + 1].x))
> +                vertical = FALSE;
> +            if (glyph_ids[j].subset_id != glyph_ids[j + 1].subset_id) {
> +                last = j;
> +                break;
> +            }
> +        }
> +
> +        if (i == last) {
> +            _cairo_output_stream_printf (surface->stream, "<%02x> S\n", glyph_ids[i].glyph_id);
> +        } else {
> +            word_wrap = _word_wrap_stream_create (surface->stream, 79);
> +            _cairo_output_stream_printf (word_wrap, "<");
> +            for (j = i; j <= last; j++)
> +                _cairo_output_stream_printf (word_wrap, "%02x", glyph_ids[j].glyph_id);
> +            _cairo_output_stream_printf (word_wrap, ">\n[");
> +
> +            for (j = i + 1; j <= last; j++) {
> +                if (horizontal) {
> +                    _cairo_output_stream_printf (word_wrap,
> +                                                 "%f ", glyphs[j].x - glyphs[j - 1].x);
> +                } else if (vertical) {
> +                    _cairo_output_stream_printf (word_wrap,
> +                                                 "%f ", glyphs[j].y - glyphs[j - 1].y);
> +                } else {
> +                    _cairo_output_stream_printf (word_wrap,
> +                                                 "%f %f ",
> +                                                 glyphs[j].x - glyphs[j - 1].x,
> +                                                 glyphs[j].y - glyphs[j - 1].y);
> +                }
> +            }
> +            if (horizontal)
> +                _cairo_output_stream_printf (word_wrap, "] xshow\n");
> +            else if (vertical)
> +                _cairo_output_stream_printf (word_wrap, "] yshow\n");
> +            else
> +                _cairo_output_stream_printf (word_wrap, "] xyshow\n");
> +            _cairo_output_stream_destroy (word_wrap);
> +        }
> +        i = last + 1;
>      }
>  
> +    free (glyph_ids);
>      return _cairo_output_stream_get_status (surface->stream);
> +
> +fail:
> +    free (glyph_ids);
> +    return status;
>  }
>  
>  static void
> plain text document attachment
> (0002-PDF-Use-Td-where-possible-instead-of-Tm-for-positioning-glyphs.txt)
> >From 406b480cfecdd46580dc70b3e4c5ca78c830a402 Mon Sep 17 00:00:00 2001
> From: Adrian Johnson <ajohnson at redneon.com>
> Date: Sun, 24 Sep 2006 00:48:36 +0930
> Subject: [PATCH] PDF: Use Td where possible instead of Tm for positioning glyphs
> 
> This avoids emitting the font matrix for every single glyph.
> ---
>  src/cairo-pdf-surface.c |   38 ++++++++++++++++++++++++++------------
>  1 files changed, 26 insertions(+), 12 deletions(-)
> 
> diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
> index 6106284..e14c50c 100644
> --- a/src/cairo-pdf-surface.c
> +++ b/src/cairo-pdf-surface.c
> @@ -2618,6 +2618,7 @@ _cairo_pdf_surface_show_glyphs (void			*
>      cairo_pdf_surface_t *surface = abstract_surface;
>      unsigned int current_subset_id = (unsigned int)-1;
>      unsigned int font_id, subset_id, subset_glyph_index;
> +    cairo_bool_t diagonal;
>      cairo_status_t status;
>      int i;
>  
> @@ -2633,6 +2634,12 @@ _cairo_pdf_surface_show_glyphs (void			*
>      _cairo_output_stream_printf (surface->output,
>  				 "BT\r\n");
>  
> +    if (scaled_font->scale.xy == 0.0 &&
> +        scaled_font->scale.yx == 0.0)
> +        diagonal = TRUE;
> +    else
> +        diagonal = FALSE;
> +
>      for (i = 0; i < num_glyphs; i++) {
>  	status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
>  						       scaled_font, glyphs[i].index,
> @@ -2640,22 +2647,29 @@ _cairo_pdf_surface_show_glyphs (void			*
>  	if (status)
>  	    return status;
>  
> -	if (subset_id != current_subset_id) {
> +	if (subset_id != current_subset_id)
>  	    _cairo_output_stream_printf (surface->output,
>  					 "/CairoFont-%d-%d 1 Tf\r\n",
>  					 font_id, subset_id);
> -	    current_subset_id = subset_id;
> -	}
>  
> -	_cairo_output_stream_printf (surface->output,
> -				     "%f %f %f %f %f %f Tm <%02x> Tj\r\n",
> -				     scaled_font->scale.xx,
> -				     scaled_font->scale.yx,
> -				     -scaled_font->scale.xy,
> -				     -scaled_font->scale.yy,
> -				     glyphs[i].x,
> -				     glyphs[i].y,
> -				     subset_glyph_index);
> +        if (subset_id != current_subset_id || !diagonal) {
> +            _cairo_output_stream_printf (surface->output,
> +                                         "%f %f %f %f %f %f Tm <%02x> Tj\r\n",
> +                                         scaled_font->scale.xx,
> +                                         scaled_font->scale.yx,
> +                                         -scaled_font->scale.xy,
> +                                         -scaled_font->scale.yy,
> +                                         glyphs[i].x,
> +                                         glyphs[i].y,
> +                                         subset_glyph_index);
> +	    current_subset_id = subset_id;
> +        } else {
> +            _cairo_output_stream_printf (surface->output,
> +                                         "%f %f Td <%02x> Tj\r\n",
> +                                         (glyphs[i].x - glyphs[i-1].x)/scaled_font->scale.xx,
> +                                         (glyphs[i].y - glyphs[i-1].y)/scaled_font->scale.yy,
> +                                         subset_glyph_index);
> +        }
>      }
>  
>      _cairo_output_stream_printf (surface->output,
> plain text document attachment (0003-Add-cairo-deflate-stream.c.txt)
> >From f2b27cea6a1e610c957e00d7907641467ac6e705 Mon Sep 17 00:00:00 2001
> From: Adrian Johnson <ajohnson at redneon.com>
> Date: Sun, 24 Sep 2006 00:52:01 +0930
> Subject: [PATCH] Add cairo-deflate-stream.c
> 
> Add a new stream type that compresses the stream using the zlib deflate method.
> This is intended for use by the PDF surface.
> ---
>  src/Makefile.am                   |    1 
>  src/cairo-deflate-stream.c        |  142 +++++++++++++++++++++++++++++++++++++
>  src/cairo-output-stream-private.h |    4 +
>  3 files changed, 147 insertions(+), 0 deletions(-)
> 
> diff --git a/src/Makefile.am b/src/Makefile.am
> index a0e30ee..ae4301f 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -175,6 +175,7 @@ libcairo_la_SOURCES =				\
>  	cairo-clip-private.h			\
>  	cairo-color.c				\
>  	cairo-debug.c				\
> +	cairo-deflate-stream.c			\
>  	cairo-fixed.c				\
>  	cairo-font.c				\
>  	cairo-font-options.c			\
> diff --git a/src/cairo-deflate-stream.c b/src/cairo-deflate-stream.c
> new file mode 100644
> index 0000000..816f5c5
> --- /dev/null
> +++ b/src/cairo-deflate-stream.c
> @@ -0,0 +1,142 @@
> +/* cairo_deflate_stream.c: Output stream abstraction
> + *
> + * Copyright © 2006 Adrian Johnson
> + *
> + * 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 cairo_output_stream.c as distributed with the
> + *   cairo graphics library.
> + *
> + * The Initial Developer of the Original Code is Adrian Johnson.
> + *
> + * Author(s):
> + *	Adrian Johnson <ajohnson at redneon.com>
> + */
> +
> +#include "cairoint.h"
> +#include "cairo-output-stream-private.h"
> +#include <zlib.h>
> +
> +#define BUFFER_SIZE 16384
> +
> +typedef struct _cairo_deflate_stream {
> +    cairo_output_stream_t  base;
> +    cairo_output_stream_t *output;
> +    z_stream               zlib_stream;
> +    unsigned char          input_buf[BUFFER_SIZE];
> +    unsigned char          output_buf[BUFFER_SIZE];
> +} cairo_deflate_stream_t;
> +
> +static void
> +cairo_deflate_stream_deflate (cairo_deflate_stream_t *stream, cairo_bool_t flush)
> +{
> +    int ret;
> +    cairo_bool_t finished;
> +
> +    do {
> +        ret = deflate (&stream->zlib_stream, flush ? Z_FINISH : Z_NO_FLUSH);
> +        if (flush || stream->zlib_stream.avail_out == 0)
> +        {
> +            _cairo_output_stream_write (stream->output,
> +                                        stream->output_buf,
> +                                        BUFFER_SIZE - stream->zlib_stream.avail_out);
> +            stream->zlib_stream.next_out = stream->output_buf;
> +            stream->zlib_stream.avail_out = BUFFER_SIZE;
> +        }
> +
> +        finished = TRUE;
> +        if (stream->zlib_stream.avail_in != 0)
> +            finished = FALSE;
> +        if (flush && ret != Z_STREAM_END)
> +            finished = FALSE;
> +
> +    } while (!finished);
> +
> +    stream->zlib_stream.next_in = stream->input_buf;
> +}
> +
> +static cairo_status_t
> +_cairo_deflate_stream_write (cairo_output_stream_t *base,
> +                             const unsigned char   *data,
> +                             unsigned int	    length)
> +{
> +    cairo_deflate_stream_t *stream = (cairo_deflate_stream_t *) base;
> +    unsigned int count;
> +    const unsigned char *p = data;
> +
> +    while (length) {
> +        count = length;
> +        if (count > BUFFER_SIZE - stream->zlib_stream.avail_in)
> +            count = BUFFER_SIZE - stream->zlib_stream.avail_in;
> +        memcpy (stream->input_buf + stream->zlib_stream.avail_in, p, count);
> +        p += count;
> +        stream->zlib_stream.avail_in += count;
> +        length -= count;
> +
> +        if (stream->zlib_stream.avail_in == BUFFER_SIZE)
> +            cairo_deflate_stream_deflate (stream, FALSE);
> +    }
> +
> +    return _cairo_output_stream_get_status (stream->output);
> +}
> +
> +static cairo_status_t
> +_cairo_deflate_stream_close (cairo_output_stream_t *base)
> +{
> +    cairo_deflate_stream_t *stream = (cairo_deflate_stream_t *) base;
> +
> +    cairo_deflate_stream_deflate (stream, TRUE);
> +    deflateEnd (&stream->zlib_stream);
> +
> +    return _cairo_output_stream_get_status (stream->output);
> +}
> +
> +cairo_output_stream_t *
> +_cairo_deflate_stream_create (cairo_output_stream_t *output)
> +{
> +    cairo_deflate_stream_t *stream;
> +
> +    stream = malloc (sizeof (cairo_deflate_stream_t));
> +    if (stream == NULL)
> +	return (cairo_output_stream_t *) &cairo_output_stream_nil;
> +
> +    _cairo_output_stream_init (&stream->base,
> +			       _cairo_deflate_stream_write,
> +			       _cairo_deflate_stream_close);
> +    stream->output = output;
> +
> +    stream->zlib_stream.zalloc = Z_NULL;
> +    stream->zlib_stream.zfree  = Z_NULL;
> +    stream->zlib_stream.opaque  = Z_NULL;
> +
> +    if (deflateInit (&stream->zlib_stream, Z_DEFAULT_COMPRESSION) != Z_OK)
> +	return (cairo_output_stream_t *) &cairo_output_stream_nil;
> +
> +    stream->zlib_stream.next_in = stream->input_buf;
> +    stream->zlib_stream.avail_in = 0;
> +    stream->zlib_stream.next_out = stream->output_buf;
> +    stream->zlib_stream.avail_out = BUFFER_SIZE;
> +
> +    return &stream->base;
> +}
> diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h
> index 913fb60..d68fbb4 100644
> --- a/src/cairo-output-stream-private.h
> +++ b/src/cairo-output-stream-private.h
> @@ -159,4 +159,8 @@ _cairo_memory_stream_length (cairo_outpu
>  cairo_private cairo_output_stream_t *
>  _cairo_base85_stream_create (cairo_output_stream_t *output);
>  
> +/* cairo_deflate_stream.c */
> +cairo_private cairo_output_stream_t *
> +_cairo_deflate_stream_create (cairo_output_stream_t *output);
> +
>  #endif /* CAIRO_OUTPUT_STREAM_PRIVATE_H */
> plain text document attachment
> (0004-PDF-Compress-the-content-stream.txt)
> >From ab2caf88477caec8f4219589bd1f2311d5a5ea15 Mon Sep 17 00:00:00 2001
> From: Adrian Johnson <ajohnson at redneon.com>
> Date: Sun, 24 Sep 2006 00:55:20 +0930
> Subject: [PATCH] PDF: Compress the content stream
> 
> Use cairo-deflate-stream to compress all content streams emitted by the
> PDF surface.
> ---
>  src/cairo-pdf-surface.c |   32 +++++++++++++++++++++++++++++---
>  1 files changed, 29 insertions(+), 3 deletions(-)
> 
> diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
> index e14c50c..ea22686 100644
> --- a/src/cairo-pdf-surface.c
> +++ b/src/cairo-pdf-surface.c
> @@ -129,6 +129,8 @@ typedef struct _cairo_pdf_surface {
>  	cairo_pdf_resource_t self;
>  	cairo_pdf_resource_t length;
>  	long start_offset;
> +        cairo_bool_t compressed;
> +        cairo_output_stream_t *old_output;
>      } current_stream;
>  
>      cairo_bool_t has_clip;
> @@ -146,8 +148,9 @@ _cairo_pdf_surface_clear (cairo_pdf_surf
>  
>  static cairo_pdf_resource_t
>  _cairo_pdf_surface_open_stream (cairo_pdf_surface_t	*surface,
> +                                cairo_bool_t             compressed,
>  				const char		*fmt,
> -				...) CAIRO_PRINTF_FORMAT(2, 3);
> +				...) CAIRO_PRINTF_FORMAT(3, 4);
>  static void
>  _cairo_pdf_surface_close_stream (cairo_pdf_surface_t	*surface);
>  
> @@ -456,6 +459,7 @@ _cairo_pdf_surface_clear (cairo_pdf_surf
>  
>  static cairo_pdf_resource_t
>  _cairo_pdf_surface_open_stream (cairo_pdf_surface_t	*surface,
> +                                cairo_bool_t             compressed,
>  				const char		*fmt,
>  				...)
>  {
> @@ -464,12 +468,16 @@ _cairo_pdf_surface_open_stream (cairo_pd
>      surface->current_stream.active = TRUE;
>      surface->current_stream.self = _cairo_pdf_surface_new_object (surface);
>      surface->current_stream.length = _cairo_pdf_surface_new_object (surface);
> +    surface->current_stream.compressed = compressed;
>  
>      _cairo_output_stream_printf (surface->output,
>  				 "%d 0 obj\r\n"
>  				 "<< /Length %d 0 R\r\n",
>  				 surface->current_stream.self.id,
>  				 surface->current_stream.length.id);
> +    if (compressed)
> +        _cairo_output_stream_printf (surface->output,
> +                                     "   /Filter /FlateDecode\r\n");
>  
>      if (fmt != NULL) {
>  	va_start (ap, fmt);
> @@ -483,6 +491,11 @@ _cairo_pdf_surface_open_stream (cairo_pd
>  
>      surface->current_stream.start_offset = _cairo_output_stream_get_position (surface->output);
>  
> +    if (compressed) {
> +        surface->current_stream.old_output = surface->output;
> +        surface->output = _cairo_deflate_stream_create (surface->output);
> +    }
> +
>      return surface->current_stream.self;
>  }
>  
> @@ -494,6 +507,13 @@ _cairo_pdf_surface_close_stream (cairo_p
>      if (! surface->current_stream.active)
>  	return;
>  
> +    if (surface->current_stream.compressed) {
> +        _cairo_output_stream_destroy (surface->output);
> +        surface->output = surface->current_stream.old_output;
> +        _cairo_output_stream_printf (surface->output,
> +                                     "\r\n");
> +    }
> +
>      length = _cairo_output_stream_get_position (surface->output) -
>  	surface->current_stream.start_offset;
>      _cairo_output_stream_printf (surface->output,
> @@ -577,6 +597,7 @@ _cairo_pdf_surface_resume_content_stream
>      cairo_pdf_resource_t stream;
>  
>      stream = _cairo_pdf_surface_open_stream (surface,
> +                                             TRUE,
>  					     "   /Type /XObject\r\n"
>  					     "   /Subtype /Form\r\n"
>  					     "   /BBox [ 0 0 %f %f ]\r\n",
> @@ -593,6 +614,7 @@ _cairo_pdf_surface_start_page (void *abs
>      cairo_pdf_resource_t stream;
>  
>      stream = _cairo_pdf_surface_open_stream (surface,
> +                                             TRUE,
>  					     "   /Type /XObject\r\n"
>  					     "   /Subtype /Form\r\n"
>  					     "   /BBox [ 0 0 %f %f ]\r\n",
> @@ -680,6 +702,7 @@ emit_smask (cairo_pdf_surface_t		*surfac
>      }
>  
>      *stream_ret = _cairo_pdf_surface_open_stream (surface,
> +                                                  FALSE,
>  						  "   /Type /XObject\r\n"
>  						  "   /Subtype /Image\r\n"
>  						  "   /Width %d\r\n"
> @@ -789,12 +812,14 @@ #define IMAGE_DICTIONARY	"   /Type /XObj
>  
>      if (need_smask)
>  	*image_ret = _cairo_pdf_surface_open_stream (surface,
> +                                                     FALSE,
>  						     IMAGE_DICTIONARY
>  						     "   /SMask %d 0 R\r\n",
>  						     image->width, image->height,
>  						     smask.id);
>      else
>  	*image_ret = _cairo_pdf_surface_open_stream (surface,
> +                                                     FALSE,
>  						     IMAGE_DICTIONARY,
>  						     image->width, image->height);
>  
> @@ -928,6 +953,7 @@ emit_surface_pattern (cairo_pdf_surface_
>      cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
>  
>      stream = _cairo_pdf_surface_open_stream (surface,
> +                                             FALSE,
>  					     "   /BBox [0 0 %d %d]\r\n"
>  					     "   /XStep %d\r\n"
>  					     "   /YStep %d\r\n"
> @@ -1837,7 +1863,7 @@ _cairo_pdf_surface_emit_outline_glyph (c
>      if (status)
>  	return status;
>  
> -    *glyph_ret = _cairo_pdf_surface_open_stream (surface, NULL);
> +    *glyph_ret = _cairo_pdf_surface_open_stream (surface, FALSE, NULL);
>  
>      _cairo_output_stream_printf (surface->output,
>  				 "0 0 %f %f %f %f d1\r\n",
> @@ -1892,7 +1918,7 @@ _cairo_pdf_surface_emit_bitmap_glyph (ca
>  	    return cairo_surface_status (&image->base);
>      }
>  
> -    *glyph_ret = _cairo_pdf_surface_open_stream (surface, NULL);
> +    *glyph_ret = _cairo_pdf_surface_open_stream (surface, FALSE, NULL);
>  
>      _cairo_output_stream_printf (surface->output,
>  				 "0 0 %f %f %f %f d1\r\n",
> _______________________________________________
> cairo mailing list
> cairo at cairographics.org
> http://cairographics.org/cgi-bin/mailman/listinfo/cairo
-- 
behdad
http://behdad.org/

"Commandment Three says Do Not Kill, Amendment Two says Blood Will Spill"
        -- Dan Bern, "New American Language"



More information about the cairo mailing list