[cairo-commit] 3 commits - src/cairo-deflate-stream.c src/cairo-output-stream-private.h src/cairo-pdf-surface.c src/Makefile.am

Carl Worth cworth at kemper.freedesktop.org
Wed Jan 17 13:28:15 PST 2007


 src/Makefile.am                   |    1 
 src/cairo-deflate-stream.c        |  142 ++++++++++++++++++++++++++++++++++++++
 src/cairo-output-stream-private.h |    4 +
 src/cairo-pdf-surface.c           |   70 ++++++++++++++----
 4 files changed, 202 insertions(+), 15 deletions(-)

New commits:
diff-tree b02b86da5c6c82f9b653698f8480855a35777155 (from 7f246462eb3cc2576387755fa2d554394e86225c)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Sep 24 00:55:20 2006 +0930

    PDF: Compress the content stream
    
    Use cairo-deflate-stream to compress all content streams emitted by the
    PDF surface.

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index d290059..ec98345 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 @@ emit_image (cairo_pdf_surface_t		*surfac
 
     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"
@@ -1942,7 +1968,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",
@@ -1997,7 +2023,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",
diff-tree 7f246462eb3cc2576387755fa2d554394e86225c (from b3440e85305af4f5ceef9437af7c26d3232dc55a)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Sep 24 00:52:01 2006 +0930

    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.

diff --git a/src/Makefile.am b/src/Makefile.am
index 5206d3f..5983867 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -177,6 +177,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 */
diff-tree b3440e85305af4f5ceef9437af7c26d3232dc55a (from 5c2136ea7c3aea1ae90b46b0dd645a4e1b5cc9a1)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Sep 24 00:48:36 2006 +0930

    PDF: Use Td where possible instead of Tm for positioning glyphs
    
    This avoids emitting the font matrix for every single glyph.

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 821ea5f..d290059 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -2726,6 +2726,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;
 
@@ -2741,6 +2742,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,
@@ -2748,22 +2755,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,


More information about the cairo-commit mailing list