[cairo-commit] 2 commits - doc/public src/cairo.h src/cairo-pdf-surface.c src/cairo-pdf-surface-private.h src/cairo-ps-surface.c src/cairo-surface.c src/cairo-tag-attributes.c src/cairo-tag-attributes-private.h src/Makefile.sources test/ccitt.g3 test/mime-data.c test/reference

Adrian Johnson ajohnson at kemper.freedesktop.org
Sun Oct 22 00:07:40 UTC 2017


 doc/public/cairo-sections.txt                |    2 
 src/Makefile.sources                         |   16 +
 src/cairo-pdf-surface-private.h              |    2 
 src/cairo-pdf-surface.c                      |  231 ++++++++++++++++++---------
 src/cairo-ps-surface.c                       |  227 ++++++++++++++++++++++++--
 src/cairo-surface.c                          |   21 ++
 src/cairo-tag-attributes-private.h           |   15 +
 src/cairo-tag-attributes.c                   |   80 +++++++++
 src/cairo.h                                  |    2 
 test/ccitt.g3                                |    2 
 test/mime-data.c                             |   56 ++++++
 test/reference/mime-data.base.argb32.ref.png |binary
 test/reference/mime-data.base.rgb24.ref.png  |binary
 test/reference/mime-data.pdf.ref.png         |binary
 test/reference/mime-data.ps.ref.png          |binary
 test/reference/mime-data.ref.png             |binary
 test/reference/mime-data.script.ref.png      |binary
 test/reference/mime-data.svg.ref.png         |binary
 18 files changed, 554 insertions(+), 100 deletions(-)

New commits:
commit 87dfd0c16f4fa798c1f72612a2e070fca8547ad2
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 22 08:45:45 2017 +1030

    Allow mime image to be different size to cairo image
    
    Previously it was assumed the mime image size is the same as the cairo
    image surface size. When using the 1 bpp formats (CCITT, JBIG2),
    creating a cairo image of the same size will have very large memory
    requirements and in some case may exceed the pixman image size
    limits. In these cases it is useful to allow the mime image to have a
    different resolution to the cairo image and in the PDF/PS output scale
    the mime image to be the same physical size as the cairo image.
    
    In PDF, this is easy as all PDF images are scaled to 1x1 unit and the
    CTM is used to scale the image to the required size. The PS surface
    has been changed to also scale images to 1x1 and use the CTM to get
    the required size.

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index cb887119..fa40bc30 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1403,105 +1403,12 @@ _cairo_pdf_surface_release_source_image_from_pattern (cairo_pdf_surface_t
 }
 
 static cairo_int_status_t
-_get_jbig2_image_info (cairo_surface_t		 *source,
-		       cairo_image_info_t	 *info)
-{
-    const unsigned char *mime_data;
-    unsigned long mime_data_length;
-
-    cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JBIG2,
-				 &mime_data, &mime_data_length);
-    if (mime_data == NULL)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    return _cairo_image_info_get_jbig2_info (info, mime_data, mime_data_length);
-}
-
-static cairo_int_status_t
-_get_jpx_image_info (cairo_surface_t		 *source,
-		     cairo_image_info_t		*info)
-{
-    const unsigned char *mime_data;
-    unsigned long mime_data_length;
-
-    cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JP2,
-				 &mime_data, &mime_data_length);
-    if (mime_data == NULL)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    return _cairo_image_info_get_jpx_info (info, mime_data, mime_data_length);
-}
-
-static cairo_int_status_t
-_get_jpeg_image_info (cairo_surface_t		 *source,
-		      cairo_image_info_t	 *info)
-{
-    const unsigned char *mime_data;
-    unsigned long mime_data_length;
-
-    cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
-				 &mime_data, &mime_data_length);
-    if (mime_data == NULL)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    return _cairo_image_info_get_jpeg_info (info, mime_data, mime_data_length);
-}
-
-static cairo_int_status_t
-_get_ccitt_image_info (cairo_surface_t		 *source,
-		       int                       *width,
-		       int                       *height)
-{
-    cairo_status_t status;
-    const unsigned char *ccitt_data;
-    unsigned long ccitt_data_len;
-    const unsigned char *ccitt_params_string;
-    unsigned long ccitt_params_string_len;
-    char *params;
-    cairo_ccitt_params_t ccitt_params;
-
-    cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_CCITT_FAX,
-				 &ccitt_data, &ccitt_data_len);
-    if (unlikely (source->status))
-	return source->status;
-    if (ccitt_data == NULL)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
-				 &ccitt_params_string, &ccitt_params_string_len);
-    if (unlikely (source->status))
-	return source->status;
-    if (ccitt_params_string == NULL)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    /* ensure params_string is null terminated */
-    params = malloc (ccitt_params_string_len + 1);
-    memcpy (params, ccitt_params_string, ccitt_params_string_len);
-    params[ccitt_params_string_len] = 0;
-    status = _cairo_tag_parse_ccitt_params (params, &ccitt_params);
-    if (unlikely(status))
-	return source->status;
-
-    free (params);
-
-    if (ccitt_params.columns <= 0 || ccitt_params.rows <= 0)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    *width = ccitt_params.columns;
-    *height = ccitt_params.rows;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
 _get_source_surface_extents (cairo_surface_t         *source,
 			     cairo_rectangle_int_t   *extents,
 			     cairo_bool_t            *bounded,
 			     cairo_bool_t            *subsurface)
 {
     cairo_int_status_t status;
-    cairo_image_info_t info;
-    int width, height;
 
     *bounded = TRUE;
     *subsurface = FALSE;
@@ -1534,37 +1441,6 @@ _get_source_surface_extents (cairo_surface_t         *source,
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    extents->x = 0;
-    extents->y = 0;
-
-    status = _get_jbig2_image_info (source, &info);
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
-	extents->width = info.width;
-	extents->height = info.height;
-	return status;
-    }
-
-    status = _get_jpx_image_info (source, &info);
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
-	extents->width = info.width;
-	extents->height = info.height;
-	return status;
-    }
-
-    status = _get_jpeg_image_info (source, &info);
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
-	extents->width = info.width;
-	extents->height = info.height;
-	return status;
-    }
-
-    status = _get_ccitt_image_info (source, &width, &height);
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
-	extents->width = width;
-	extents->height = height;
-	return status;
-    }
-
     if (! _cairo_surface_get_extents (source, extents))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 62b19e4a..905ee2c8 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -2754,7 +2754,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t    *surface,
 	}
 
 	_cairo_output_stream_printf (surface->stream,
-				     "    /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
+				     "    /ImageMatrix [ %d 0 0 %d 0 %d ] def\n"
 				     "  end\n"
 				     "  /MaskDict 8 dict def\n"
 				     "     MaskDict begin\n"
@@ -2764,14 +2764,18 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t    *surface,
 				     "    /Interpolate %s def\n"
 				     "    /BitsPerComponent 1 def\n"
 				     "    /Decode [ 1 0 ] def\n"
-				     "    /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
+				     "    /ImageMatrix [ %d 0 0 %d 0 %d ] def\n"
 				     "  end\n"
 				     "end\n"
 				     "image\n",
+				     ps_image->width,
+				     -ps_image->height,
 				     ps_image->height,
 				     ps_image->width,
 				     ps_image->height,
 				     interpolate,
+				     ps_image->width,
+				     -ps_image->height,
 				     ps_image->height);
     } else {
 	if (!stencil_mask) {
@@ -2808,9 +2812,11 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t    *surface,
 	}
 
 	_cairo_output_stream_printf (surface->stream,
-				     "  /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
+				     "  /ImageMatrix [ %d 0 0 %d 0 %d ] def\n"
 				     "end\n"
 				     "%s%s\n",
+				     ps_image->width,
+				     -ps_image->height,
 				     ps_image->height,
 				     surface->use_string_datasource ? "" : "cairo_",
 				     stencil_mask ? "imagemask" : "image");
@@ -2936,9 +2942,11 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t    *surface,
     }
 
     _cairo_output_stream_printf (surface->stream,
-				 "  /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
+				 "  /ImageMatrix [ %d 0 0 %d 0 %d ] def\n"
 				 "end\n"
 				 "%simage\n",
+				 info.width,
+				 -info.height,
 				 info.height,
 				 surface->use_string_datasource ? "" : "cairo_");
 
@@ -3077,9 +3085,11 @@ _cairo_ps_surface_emit_ccitt_image (cairo_ps_surface_t   *surface,
 				 " >> /CCITTFaxDecode filter\n");
 
     _cairo_output_stream_printf (surface->stream,
-				 "  /ImageMatrix [ 1 0 0 -1 0 %d ]\n"
+				 "  /ImageMatrix [ %d 0 0 %d 0 %d ]\n"
 				 ">>\n"
 				 "%s%s\n",
+				 ccitt_params.columns,
+				 -ccitt_params.rows,
 				 ccitt_params.rows,
 				 surface->use_string_datasource ? "" : "cairo_",
 				 stencil_mask ? "imagemask" : "image");
@@ -3407,6 +3417,7 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t     *surface,
     {
 	cairo_matrix_translate (&ps_p2d, 0.0, src_surface_extents.height);
 	cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
+	cairo_matrix_scale (&ps_p2d, src_surface_extents.width, src_surface_extents.height);
     }
 
     if (! _cairo_matrix_is_identity (&ps_p2d)) {
@@ -3545,6 +3556,14 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t      *surface,
 				 pattern_extents.x, pattern_extents.y,
 				 pattern_extents.width, pattern_extents.height);
 
+
+    if (((cairo_surface_pattern_t *)pattern)->surface->type != CAIRO_SURFACE_TYPE_RECORDING)
+    {
+	_cairo_output_stream_printf (surface->stream,
+				     "[ %d 0 0 %d 0 0 ] concat\n",
+				     pattern_extents.width, pattern_extents.height);
+    }
+
     old_use_string_datasource = surface->use_string_datasource;
     surface->use_string_datasource = TRUE;
     if (op == CAIRO_OPERATOR_SOURCE) {
commit e1a02b180d804887980c111c1f9780bed44b96a6
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 22 08:07:49 2017 +1030

    Add CCITT_FAX mime type for PDF and PS surfaces
    
    This completes the full set of PDF/PS image filters allowing image
    data to be passed though without decompressing then recompresssing in
    a less efficient format.
    
    The difficulty with CCITT_FAX is it needs some decoding parameters
    that are not stored inside the image data. This is achieved by using
    an additional mime type CCITT_FAX_PARAMS that contains the params in
    key=value format.

diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index 7b04ae7b..40c21483 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -242,6 +242,8 @@ cairo_device_observer_stroke_elapsed
 <SECTION>
 <FILE>cairo-surface</FILE>
 CAIRO_HAS_MIME_SURFACE
+CAIRO_MIME_TYPE_CCITT_FAX
+CAIRO_MIME_TYPE_CCITT_FAX_PARAMS
 CAIRO_MIME_TYPE_JBIG2
 CAIRO_MIME_TYPE_JBIG2_GLOBAL
 CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 89417ac8..cc2194f3 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -264,8 +264,16 @@ cairo_egl_sources =
 cairo_glx_sources =
 cairo_wgl_sources =
 
-_cairo_pdf_operators_private = cairo-pdf-operators-private.h cairo-pdf-shading-private.h
-_cairo_pdf_operators_sources = cairo-pdf-operators.c cairo-pdf-shading.c
+_cairo_pdf_operators_private = \
+	cairo-pdf-operators-private.h \
+	cairo-pdf-shading-private.h \
+	cairo-tag-attributes-private.h \
+	$(NULL)
+_cairo_pdf_operators_sources = \
+	cairo-pdf-operators.c \
+	cairo-pdf-shading.c \
+	cairo-tag-attributes.c \
+	$(NULL)
 cairo_private += $(_cairo_pdf_operators_private)
 cairo_sources += $(_cairo_pdf_operators_sources)
 
@@ -279,8 +287,8 @@ _cairo_deflate_stream_sources = cairo-deflate-stream.c
 cairo_sources += $(_cairo_deflate_stream_sources)
 
 cairo_pdf_headers = cairo-pdf.h
-cairo_pdf_private = cairo-pdf-surface-private.h cairo-tag-stack-private.h cairo-tag-attributes-private.h
-cairo_pdf_sources = cairo-pdf-surface.c cairo-pdf-interchange.c cairo-tag-stack.c cairo-tag-attributes.c
+cairo_pdf_private = cairo-pdf-surface-private.h cairo-tag-stack-private.h
+cairo_pdf_sources = cairo-pdf-surface.c cairo-pdf-interchange.c cairo-tag-stack.c
 
 cairo_svg_headers = cairo-svg.h
 cairo_svg_private = cairo-svg-surface-private.h
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index a84ea957..98f0cfdd 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -84,7 +84,7 @@ typedef struct _cairo_pdf_source_surface_entry {
     cairo_bool_t bounded;
     cairo_rectangle_int_t extents;
 
-    /* Union of source extents requried for all operations using this source */
+    /* Union of source extents required for all operations using this source */
     cairo_rectangle_int_t required_extents;
 } cairo_pdf_source_surface_entry_t;
 
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 9e1547ea..cb887119 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -134,19 +134,62 @@
  * The following mime types are supported: %CAIRO_MIME_TYPE_JPEG,
  * %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_UNIQUE_ID,
  * %CAIRO_MIME_TYPE_JBIG2, %CAIRO_MIME_TYPE_JBIG2_GLOBAL,
- * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID.
+ * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID,
+ * %CAIRO_MIME_TYPE_CCITT_FAX, %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS.
  *
+ * # JBIG2 Images #
  * JBIG2 data in PDF must be in the embedded format as described in
  * ISO/IEC 11544. Image specific JBIG2 data must be in
  * %CAIRO_MIME_TYPE_JBIG2.  Any global segments in the JBIG2 data
  * (segments with page association field set to 0) must be in
  * %CAIRO_MIME_TYPE_JBIG2_GLOBAL. The global data may be shared by
  * multiple images. All images sharing the same global data must set
- * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID to a unique identifer. At least
+ * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID to a unique identifier. At least
  * one of the images must provide the global data using
  * %CAIRO_MIME_TYPE_JBIG2_GLOBAL. The global data will only be
- * embedded once but shared by all JBIG2 images with the same
+ * embedded once and shared by all JBIG2 images with the same
  * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID.
+ *
+ * # CCITT Fax Images # {#ccitt}
+ * The %CAIRO_MIME_TYPE_CCITT_FAX mime data requires a number of decoding
+ * parameters These parameters are specified using %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS.
+ *
+ * %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS mime data must contain a string of the form
+ * "param1=value1 param2=value2 ...".
+ *
+ * @Columns: [required] An integer specifying the width of the image in pixels.
+ *
+ * @Rows: [required] An integer specifying the height of the image in scan lines.
+ *
+ * @K: [optional] An integer identifying the encoding scheme used. < 0
+ * is 2 dimensional Group 4, = 0 is Group3 1 dimensional, > 0 is mixed 1
+ * and 2 dimensional encoding. Default is 0.
+ *
+ * @EndOfLine: [optional] If true end-of-line bit patterns are present. Default is false.
+ *
+ * @EncodedByteAlign: [optional] If true the end of line is padded
+ * with 0 bits so the next line begins on a byte boundary. Default is false.
+ *
+ * @EndOfBlock: [optional] If true the data contains an end-of-block pattern. Default is true.
+ *
+ * @BlackIs1: [optional] If true 1 bits are black pixels. Default is false.
+ *
+ * @DamagedRowsBeforeError: [optional] An integer specifying the
+ * number of damages rows tolerated before an error occurs. Default is 0.
+ *
+ * Boolean values may be "true" or "false", or 1 or 0.
+ *
+ * These parameters are the same as the CCITTFaxDecode parameters in the
+ * [PostScript Language Reference](https://www.adobe.com/products/postscript/pdfs/PLRM.pdf)
+ * and [Portable Document Format (PDF)](https://www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf).
+ * Refer to these documents for further details.
+ *
+ * An example %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS string is:
+ *
+ * <programlisting>
+ * "Columns=10230 Rows=40000 K=1 EndOfLine=true EncodedByteAlign=1 BlackIs1=false"
+ * </programlisting>
+ *
  **/
 
 static cairo_bool_t
@@ -184,6 +227,8 @@ static const char *_cairo_pdf_supported_mime_types[] =
     CAIRO_MIME_TYPE_JBIG2,
     CAIRO_MIME_TYPE_JBIG2_GLOBAL,
     CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID,
+    CAIRO_MIME_TYPE_CCITT_FAX,
+    CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
     NULL
 };
 
@@ -1359,44 +1404,93 @@ _cairo_pdf_surface_release_source_image_from_pattern (cairo_pdf_surface_t
 
 static cairo_int_status_t
 _get_jbig2_image_info (cairo_surface_t		 *source,
-		       cairo_image_info_t	 *info,
-		       const unsigned char	**mime_data,
-		       unsigned long		 *mime_data_length)
+		       cairo_image_info_t	 *info)
 {
+    const unsigned char *mime_data;
+    unsigned long mime_data_length;
+
     cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JBIG2,
-				 mime_data, mime_data_length);
-    if (*mime_data == NULL)
+				 &mime_data, &mime_data_length);
+    if (mime_data == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    return _cairo_image_info_get_jbig2_info (info, *mime_data, *mime_data_length);
+    return _cairo_image_info_get_jbig2_info (info, mime_data, mime_data_length);
 }
 
 static cairo_int_status_t
 _get_jpx_image_info (cairo_surface_t		 *source,
-		     cairo_image_info_t		*info,
-		     const unsigned char	**mime_data,
-		     unsigned long		 *mime_data_length)
+		     cairo_image_info_t		*info)
 {
+    const unsigned char *mime_data;
+    unsigned long mime_data_length;
+
     cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JP2,
-				 mime_data, mime_data_length);
-    if (*mime_data == NULL)
+				 &mime_data, &mime_data_length);
+    if (mime_data == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    return _cairo_image_info_get_jpx_info (info, *mime_data, *mime_data_length);
+    return _cairo_image_info_get_jpx_info (info, mime_data, mime_data_length);
 }
 
 static cairo_int_status_t
 _get_jpeg_image_info (cairo_surface_t		 *source,
-		      cairo_image_info_t	 *info,
-		      const unsigned char	**mime_data,
-		      unsigned long		 *mime_data_length)
+		      cairo_image_info_t	 *info)
 {
+    const unsigned char *mime_data;
+    unsigned long mime_data_length;
+
     cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
-				 mime_data, mime_data_length);
-    if (*mime_data == NULL)
+				 &mime_data, &mime_data_length);
+    if (mime_data == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    return _cairo_image_info_get_jpeg_info (info, *mime_data, *mime_data_length);
+    return _cairo_image_info_get_jpeg_info (info, mime_data, mime_data_length);
+}
+
+static cairo_int_status_t
+_get_ccitt_image_info (cairo_surface_t		 *source,
+		       int                       *width,
+		       int                       *height)
+{
+    cairo_status_t status;
+    const unsigned char *ccitt_data;
+    unsigned long ccitt_data_len;
+    const unsigned char *ccitt_params_string;
+    unsigned long ccitt_params_string_len;
+    char *params;
+    cairo_ccitt_params_t ccitt_params;
+
+    cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_CCITT_FAX,
+				 &ccitt_data, &ccitt_data_len);
+    if (unlikely (source->status))
+	return source->status;
+    if (ccitt_data == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
+				 &ccitt_params_string, &ccitt_params_string_len);
+    if (unlikely (source->status))
+	return source->status;
+    if (ccitt_params_string == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    /* ensure params_string is null terminated */
+    params = malloc (ccitt_params_string_len + 1);
+    memcpy (params, ccitt_params_string, ccitt_params_string_len);
+    params[ccitt_params_string_len] = 0;
+    status = _cairo_tag_parse_ccitt_params (params, &ccitt_params);
+    if (unlikely(status))
+	return source->status;
+
+    free (params);
+
+    if (ccitt_params.columns <= 0 || ccitt_params.rows <= 0)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    *width = ccitt_params.columns;
+    *height = ccitt_params.rows;
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
@@ -1407,8 +1501,7 @@ _get_source_surface_extents (cairo_surface_t         *source,
 {
     cairo_int_status_t status;
     cairo_image_info_t info;
-    const unsigned char *mime_data;
-    unsigned long mime_data_length;
+    int width, height;
 
     *bounded = TRUE;
     *subsurface = FALSE;
@@ -1444,27 +1537,34 @@ _get_source_surface_extents (cairo_surface_t         *source,
     extents->x = 0;
     extents->y = 0;
 
-    status = _get_jbig2_image_info (source, &info, &mime_data, &mime_data_length);
+    status = _get_jbig2_image_info (source, &info);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
 	extents->width = info.width;
 	extents->height = info.height;
 	return status;
     }
 
-    status = _get_jpx_image_info (source, &info, &mime_data, &mime_data_length);
+    status = _get_jpx_image_info (source, &info);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
 	extents->width = info.width;
 	extents->height = info.height;
 	return status;
     }
 
-    status = _get_jpeg_image_info (source, &info, &mime_data, &mime_data_length);
+    status = _get_jpeg_image_info (source, &info);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
 	extents->width = info.width;
 	extents->height = info.height;
 	return status;
     }
 
+    status = _get_ccitt_image_info (source, &width, &height);
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
+	extents->width = width;
+	extents->height = height;
+	return status;
+    }
+
     if (! _cairo_surface_get_extents (source, extents))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
@@ -3182,6 +3282,113 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t              *surface,
 }
 
 static cairo_int_status_t
+_cairo_pdf_surface_emit_ccitt_image (cairo_pdf_surface_t              *surface,
+				     cairo_surface_t	             *source,
+				     cairo_pdf_source_surface_entry_t *surface_entry)
+{
+    cairo_status_t status;
+    const unsigned char *ccitt_data;
+    unsigned long ccitt_data_len;
+    const unsigned char *ccitt_params_string;
+    unsigned long ccitt_params_string_len;
+    char *params, *p, *end;
+    cairo_ccitt_params_t ccitt_params;
+    char buf[300];
+
+    cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_CCITT_FAX,
+				 &ccitt_data, &ccitt_data_len);
+    if (unlikely (source->status))
+	return source->status;
+    if (ccitt_data == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
+				 &ccitt_params_string, &ccitt_params_string_len);
+    if (unlikely (source->status))
+	return source->status;
+    if (ccitt_params_string == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    /* ensure params_string is null terminated */
+    params = malloc (ccitt_params_string_len + 1);
+    memcpy (params, ccitt_params_string, ccitt_params_string_len);
+    params[ccitt_params_string_len] = 0;
+    status = _cairo_tag_parse_ccitt_params (params, &ccitt_params);
+    if (unlikely(status))
+	return source->status;
+
+    free (params);
+
+    p = buf;
+    *p = 0;
+    end = buf + sizeof(buf) - 1;
+    p += snprintf (p, end - p, "/Columns %d /Rows %d /K %d",
+				 ccitt_params.columns,
+				 ccitt_params.rows,
+				 ccitt_params.k);
+    if (ccitt_params.end_of_line)
+	p += snprintf (p, end - p, " /EndOfLine true");
+
+    if (ccitt_params.encoded_byte_align)
+	p += snprintf (p, end - p, " /EncodedByteAlign true");
+
+    if (!ccitt_params.end_of_block)
+	p += snprintf (p, end - p, " /EndOfBlock false");
+
+    if (ccitt_params.black_is_1)
+	p += snprintf (p, end - p, " /BlackIs1 true");
+
+    if (ccitt_params.damaged_rows_before_error > 0) {
+	p += snprintf (p, end - p, " /DamagedRowsBeforeError %d",
+		       ccitt_params.damaged_rows_before_error);
+    }
+
+    if (surface_entry->stencil_mask) {
+	status = _cairo_pdf_surface_open_stream (surface,
+						 &surface_entry->surface_res,
+						 FALSE,
+						 "   /Type /XObject\n"
+						 "   /Subtype /Image\n"
+						 "   /ImageMask true\n"
+						 "   /Width %d\n"
+						 "   /Height %d\n"
+						 "   /Interpolate %s\n"
+						 "   /BitsPerComponent 1\n"
+						 "   /Decode [1 0]\n"
+						 "   /Filter /CCITTFaxDecode\n"
+						 "   /DecodeParms << %s >> ",
+						 ccitt_params.columns,
+						 ccitt_params.rows,
+						 surface_entry->interpolate ? "true" : "false",
+						 buf);
+    } else {
+	status = _cairo_pdf_surface_open_stream (surface,
+						 &surface_entry->surface_res,
+						 FALSE,
+						 "   /Type /XObject\n"
+						 "   /Subtype /Image\n"
+						 "   /Width %d\n"
+						 "   /Height %d\n"
+						 "   /ColorSpace /DeviceGray\n"
+						 "   /BitsPerComponent 1\n"
+						 "   /Interpolate %s\n"
+						 "   /Filter /CCITTFaxDecode\n"
+						 "   /DecodeParms << %s >> ",
+						 ccitt_params.columns,
+						 ccitt_params.rows,
+						 surface_entry->interpolate ? "true" : "false",
+						 buf);
+    }
+    if (unlikely (status))
+	return status;
+
+    _cairo_output_stream_write (surface->output, ccitt_data, ccitt_data_len);
+    status = _cairo_pdf_surface_close_stream (surface);
+
+    return status;
+}
+
+static cairo_int_status_t
 _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t        *surface,
 				       cairo_pdf_source_surface_t *source)
 {
@@ -3201,6 +3408,10 @@ _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t        *surface,
 	status = _cairo_pdf_surface_emit_jpeg_image (surface, source->surface, source->hash_entry);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
+
+	status = _cairo_pdf_surface_emit_ccitt_image (surface, source->surface, source->hash_entry);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
     }
 
     if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index e34f656c..62b19e4a 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -77,6 +77,7 @@
 #include "cairo-output-stream-private.h"
 #include "cairo-type3-glyph-surface-private.h"
 #include "cairo-image-info-private.h"
+#include "cairo-tag-attributes-private.h"
 
 #include <stdio.h>
 #include <ctype.h>
@@ -105,6 +106,13 @@
  *
  * The PostScript surface is used to render cairo graphics to Adobe
  * PostScript files and is a multi-page vector surface backend.
+ *
+ * The following mime types are supported: %CAIRO_MIME_TYPE_JPEG,
+ * %CAIRO_MIME_TYPE_UNIQUE_ID,
+ * %CAIRO_MIME_TYPE_CCITT_FAX, %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS.
+ *
+ * The %CAIRO_MIME_TYPE_CCITT_FAX and %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS mime types
+ * are documented in [CCITT Fax Images][ccitt].
  **/
 
 /**
@@ -146,6 +154,8 @@ static const char * _cairo_ps_level_strings[CAIRO_PS_LEVEL_LAST] =
 static const char *_cairo_ps_supported_mime_types[] =
 {
     CAIRO_MIME_TYPE_JPEG,
+    CAIRO_MIME_TYPE_CCITT_FAX,
+    CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
     NULL
 };
 
@@ -2440,6 +2450,28 @@ _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t    *surface,
     return status;
 }
 
+static const char *
+get_interpolate (cairo_filter_t	filter)
+{
+    const char *interpolate;
+
+    switch (filter) {
+	default:
+	case CAIRO_FILTER_GOOD:
+	case CAIRO_FILTER_BEST:
+	case CAIRO_FILTER_BILINEAR:
+	    interpolate = "true";
+	    break;
+	case CAIRO_FILTER_FAST:
+	case CAIRO_FILTER_NEAREST:
+	case CAIRO_FILTER_GAUSSIAN:
+	    interpolate = "false";
+	break;
+    }
+
+    return interpolate;
+}
+
 static cairo_status_t
 _cairo_ps_surface_emit_image (cairo_ps_surface_t    *surface,
 			      cairo_image_surface_t *image_surf,
@@ -2493,20 +2525,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t    *surface,
             goto bail0;
     }
     ps_image = image;
-
-    switch (filter) {
-    default:
-    case CAIRO_FILTER_GOOD:
-    case CAIRO_FILTER_BEST:
-    case CAIRO_FILTER_BILINEAR:
-	interpolate = "true";
-	break;
-    case CAIRO_FILTER_FAST:
-    case CAIRO_FILTER_NEAREST:
-    case CAIRO_FILTER_GAUSSIAN:
-	interpolate = "false";
-	break;
-    }
+    interpolate = get_interpolate (filter);
 
     if (stencil_mask) {
 	use_mask = FALSE;
@@ -2827,8 +2846,7 @@ bail0:
 static cairo_status_t
 _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t    *surface,
 				   cairo_surface_t	 *source,
-				   int                    width,
-				   int                    height)
+				   cairo_filter_t	  filter)
 {
     cairo_status_t status;
     const unsigned char *mime_data;
@@ -2895,11 +2913,13 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t    *surface,
 				 "  /Width %d def\n"
 				 "  /Height %d def\n"
 				 "  /BitsPerComponent %d def\n"
+				 "  /Interpolate %s def\n"
 				 "  /Decode [ %s ] def\n",
 				 colorspace,
 				 info.width,
 				 info.height,
 				 info.bits_per_component,
+				 get_interpolate (filter),
                                  decode);
 
     if (surface->use_string_datasource) {
@@ -2936,6 +2956,148 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t    *surface,
 }
 
 static cairo_status_t
+_cairo_ps_surface_emit_ccitt_image (cairo_ps_surface_t   *surface,
+				    cairo_surface_t	 *source,
+				    cairo_filter_t	  filter,
+				    cairo_bool_t          stencil_mask)
+{
+    cairo_status_t status;
+    const unsigned char *ccitt_data;
+    unsigned long ccitt_data_len;
+    const unsigned char *ccitt_params_string;
+    unsigned long ccitt_params_string_len;
+    char *params;
+    cairo_ccitt_params_t ccitt_params;
+
+    cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_CCITT_FAX,
+				 &ccitt_data, &ccitt_data_len);
+    if (unlikely (source->status))
+	return source->status;
+    if (ccitt_data == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
+				 &ccitt_params_string, &ccitt_params_string_len);
+    if (unlikely (source->status))
+	return source->status;
+    if (ccitt_params_string == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    /* ensure params_string is null terminated */
+    params = malloc (ccitt_params_string_len + 1);
+    memcpy (params, ccitt_params_string, ccitt_params_string_len);
+    params[ccitt_params_string_len] = 0;
+    status = _cairo_tag_parse_ccitt_params (params, &ccitt_params);
+    if (unlikely(status))
+	return source->status;
+
+    free (params);
+
+    if (ccitt_params.columns <= 0 || ccitt_params.rows <= 0)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (surface->use_string_datasource) {
+	/* Emit the image data as a base85-encoded string which will
+	 * be used as the data source for the image operator later. */
+	_cairo_output_stream_printf (surface->stream,
+				     "/CairoImageData [\n");
+
+	status = _cairo_ps_surface_emit_base85_string (surface,
+						       ccitt_data,
+						       ccitt_data_len,
+						       CAIRO_PS_COMPRESS_NONE,
+						       TRUE);
+	if (unlikely (status))
+	    return status;
+
+	_cairo_output_stream_printf (surface->stream,
+				     "] def\n");
+	_cairo_output_stream_printf (surface->stream,
+				     "/CairoImageDataIndex 0 def\n");
+    } else {
+	_cairo_output_stream_printf (surface->stream,
+				     "/cairo_ascii85_file currentfile /ASCII85Decode filter def\n");
+    }
+
+    if (!stencil_mask) {
+	_cairo_output_stream_printf (surface->stream,
+				     "/DeviceGray setcolorspace\n");
+    }
+
+    _cairo_output_stream_printf (surface->stream,
+				 "<<\n"
+				 "  /ImageType 1\n"
+				 "  /Width %d\n"
+				 "  /Height %d\n"
+				 "  /BitsPerComponent 1\n"
+				 "  /Interpolate %s\n"
+				 "  /Decode [ 0 1 ]\n",
+				 ccitt_params.columns,
+				 ccitt_params.rows,
+				 get_interpolate (filter));
+
+    if (surface->use_string_datasource) {
+	_cairo_output_stream_printf (surface->stream,
+				     "  /DataSource {\n"
+				     "    CairoImageData CairoImageDataIndex get\n"
+				     "    /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
+				     "    CairoImageDataIndex CairoImageData length 1 sub gt\n"
+				     "     { /CairoImageDataIndex 0 def } if\n"
+				     "  } /ASCII85Decode filter");
+    } else {
+	_cairo_output_stream_printf (surface->stream,
+				     "  /DataSource cairo_ascii85_file");
+    }
+
+    _cairo_output_stream_printf (surface->stream,
+				 " << /Columns %d /Rows %d /K %d",
+				 ccitt_params.columns,
+				 ccitt_params.rows,
+				 ccitt_params.k);
+
+    if (ccitt_params.end_of_line)
+	_cairo_output_stream_printf (surface->stream, " /EndOfLine true");
+
+    if (ccitt_params.encoded_byte_align)
+	_cairo_output_stream_printf (surface->stream, " /EncodedByteAlign true");
+
+    if (!ccitt_params.end_of_block)
+	_cairo_output_stream_printf (surface->stream, " /EndOfBlock false");
+
+    if (ccitt_params.black_is_1)
+	_cairo_output_stream_printf (surface->stream, " /BlackIs1 true");
+
+    if (ccitt_params.damaged_rows_before_error > 0) {
+	_cairo_output_stream_printf (surface->stream,
+				     " /DamagedRowsBeforeError %d",
+				     ccitt_params.damaged_rows_before_error);
+    }
+
+    _cairo_output_stream_printf (surface->stream,
+				 " >> /CCITTFaxDecode filter\n");
+
+    _cairo_output_stream_printf (surface->stream,
+				 "  /ImageMatrix [ 1 0 0 -1 0 %d ]\n"
+				 ">>\n"
+				 "%s%s\n",
+				 ccitt_params.rows,
+				 surface->use_string_datasource ? "" : "cairo_",
+				 stencil_mask ? "imagemask" : "image");
+
+    if (!surface->use_string_datasource) {
+	/* Emit the image data as a base85-encoded string which will
+	 * be used as the data source for the image operator. */
+	status = _cairo_ps_surface_emit_base85_string (surface,
+						       ccitt_data,
+						       ccitt_data_len,
+						       CAIRO_PS_COMPRESS_NONE,
+						       FALSE);
+    }
+
+    return status;
+}
+
+static cairo_status_t
 _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t          *surface,
 					  cairo_surface_t             *recording_surface,
 					  const cairo_rectangle_int_t *recording_extents,
@@ -3078,7 +3240,11 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t          *surface,
     {
 	cairo_surface_t *surf = ((cairo_surface_pattern_t *) source_pattern)->surface;
 
-	status = _cairo_ps_surface_emit_jpeg_image (surface, surf, src_surface_extents->width, src_surface_extents->height);
+	status = _cairo_ps_surface_emit_jpeg_image (surface, surf, source_pattern->filter);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
+
+	status = _cairo_ps_surface_emit_ccitt_image (surface, surf, source_pattern->filter, stencil_mask);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
     }
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 35c63d7b..459b84c9 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1225,6 +1225,24 @@ _cairo_mime_data_destroy (void *ptr)
 }
 
 /**
+ * CAIRO_MIME_TYPE_CCITT_FAX:
+ *
+ * Group 3 or Group 4 CCITT facsimile encoding (International
+ * Telecommunication Union, Recommendations T.4 and T.6.)
+ *
+ * Since: 1.16
+ **/
+
+/**
+ * CAIRO_MIME_TYPE_CCITT_FAX_PARAMS:
+ *
+ * Decode parameters for Group 3 or Group 4 CCITT facsimile encoding.
+ * See [CCITT Fax Images][ccitt].
+ *
+ * Since: 1.16
+ **/
+
+/**
  * CAIRO_MIME_TYPE_JBIG2:
  *
  * Joint Bi-level Image Experts Group image coding standard (ISO/IEC 11544).
@@ -1314,7 +1332,8 @@ _cairo_mime_data_destroy (void *ptr)
  * The recognized MIME types are the following: %CAIRO_MIME_TYPE_JPEG,
  * %CAIRO_MIME_TYPE_PNG, %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_URI,
  * %CAIRO_MIME_TYPE_UNIQUE_ID, %CAIRO_MIME_TYPE_JBIG2,
- * %CAIRO_MIME_TYPE_JBIG2_GLOBAL, %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID.
+ * %CAIRO_MIME_TYPE_JBIG2_GLOBAL, %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID,
+ * %CAIRO_MIME_TYPE_CCITT_FAX, %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS.
  *
  * See corresponding backend surface docs for details about which MIME
  * types it can handle. Caution: the associated MIME data will be
diff --git a/src/cairo-tag-attributes-private.h b/src/cairo-tag-attributes-private.h
index a127abc9..30bb48ed 100644
--- a/src/cairo-tag-attributes-private.h
+++ b/src/cairo-tag-attributes-private.h
@@ -68,10 +68,25 @@ typedef struct _cairo_dest_attrs {
     cairo_bool_t internal;
 } cairo_dest_attrs_t;
 
+typedef struct _cairo_ccitt_params {
+    int columns;
+    int rows;
+    int k;
+    cairo_bool_t end_of_line;
+    cairo_bool_t encoded_byte_align;
+    cairo_bool_t end_of_block;
+    cairo_bool_t black_is_1;
+    int damaged_rows_before_error;
+} cairo_ccitt_params_t;
+
+
 cairo_private cairo_int_status_t
 _cairo_tag_parse_link_attributes (const char *attributes, cairo_link_attrs_t *link_attrs);
 
 cairo_private cairo_int_status_t
 _cairo_tag_parse_dest_attributes (const char *attributes, cairo_dest_attrs_t *dest_attrs);
 
+cairo_private cairo_int_status_t
+_cairo_tag_parse_ccitt_params (const char *attributes, cairo_ccitt_params_t *dest_attrs);
+
 #endif /* CAIRO_TAG_ATTRIBUTES_PRIVATE_H */
diff --git a/src/cairo-tag-attributes.c b/src/cairo-tag-attributes.c
index b3d08f6f..64173402 100644
--- a/src/cairo-tag-attributes.c
+++ b/src/cairo-tag-attributes.c
@@ -113,6 +113,36 @@ static attribute_spec_t _link_attrib_spec[] =
     { NULL }
 };
 
+/*
+ * Required:
+ *   Columns - width of the image in pixels.
+ *   Rows    - height of the image in scan lines.
+ *
+ * Optional:
+ *   K - An integer identifying the encoding scheme used. < 0 is 2 dimensional
+ *       Group 4, = 0 is Group3 1 dimensional, > 0 is mixed 1 and 2 dimensional
+ *       encoding. Default: 0.
+ *   EndOfLine  - If true end-of-line bit patterns are present. Default: false.
+ *   EncodedByteAlign - If true the end of line is padded with 0 bits so the next
+ *                      line begins on a byte boundary. Default: false.
+ *   EndOfBlock - If true the data contains an end-of-block pattern. Default: true.
+ *   BlackIs1   - If true 1 bits are black pixels. Default: false.
+ *   DamagedRowsBeforeError - Number of damages rows tolerated before an error
+ *                            occurs. Default: 0.
+ */
+static attribute_spec_t _ccitt_params_spec[] =
+{
+    { "Columns",                ATTRIBUTE_INT },
+    { "Rows",                   ATTRIBUTE_INT },
+    { "K",                      ATTRIBUTE_INT },
+    { "EndOfLine",              ATTRIBUTE_BOOL },
+    { "EncodedByteAlign",       ATTRIBUTE_BOOL },
+    { "EndOfBlock",             ATTRIBUTE_BOOL },
+    { "BlackIs1",               ATTRIBUTE_BOOL },
+    { "DamagedRowsBeforeError", ATTRIBUTE_INT },
+    { NULL }
+};
+
 typedef union {
     cairo_bool_t b;
     int i;
@@ -569,3 +599,53 @@ _cairo_tag_parse_dest_attributes (const char *attributes, cairo_dest_attrs_t *de
 
     return status;
 }
+
+cairo_int_status_t
+_cairo_tag_parse_ccitt_params (const char *attributes, cairo_ccitt_params_t *ccitt_params)
+{
+    cairo_list_t list;
+    cairo_int_status_t status;
+    attribute_t *attr;
+
+    ccitt_params->columns = -1;
+    ccitt_params->rows = -1;
+
+    /* set defaults */
+    ccitt_params->k = 0;
+    ccitt_params->end_of_line = FALSE;
+    ccitt_params->encoded_byte_align = FALSE;
+    ccitt_params->end_of_block = TRUE;
+    ccitt_params->black_is_1 = FALSE;
+    ccitt_params->damaged_rows_before_error = 0;
+
+    cairo_list_init (&list);
+    status = parse_attributes (attributes, _ccitt_params_spec, &list);
+    if (unlikely (status))
+	goto cleanup;
+
+    cairo_list_foreach_entry (attr, attribute_t, &list, link)
+    {
+	if (strcmp (attr->name, "Columns") == 0) {
+	    ccitt_params->columns = attr->scalar.i;
+	} else if (strcmp (attr->name, "Rows") == 0) {
+	    ccitt_params->rows = attr->scalar.i;
+	} else if (strcmp (attr->name, "K") == 0) {
+	    ccitt_params->k = attr->scalar.i;
+	} else if (strcmp (attr->name, "EndOfLine") == 0) {
+	    ccitt_params->end_of_line = attr->scalar.b;
+	} else if (strcmp (attr->name, "EncodedByteAlign") == 0) {
+	    ccitt_params->encoded_byte_align = attr->scalar.b;
+	} else if (strcmp (attr->name, "EndOfBlock") == 0) {
+	    ccitt_params->end_of_block = attr->scalar.b;
+	} else if (strcmp (attr->name, "BlackIs1") == 0) {
+	    ccitt_params->black_is_1 = attr->scalar.b;
+	} else if (strcmp (attr->name, "DamagedRowsBeforeError") == 0) {
+	    ccitt_params->damaged_rows_before_error = attr->scalar.b;
+	}
+    }
+
+  cleanup:
+    free_attributes_list (&list);
+
+    return status;
+}
diff --git a/src/cairo.h b/src/cairo.h
index 32fc88b1..671be5a8 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -2453,6 +2453,8 @@ cairo_surface_set_user_data (cairo_surface_t		 *surface,
 #define CAIRO_MIME_TYPE_JBIG2 "application/x-cairo.jbig2"
 #define CAIRO_MIME_TYPE_JBIG2_GLOBAL "application/x-cairo.jbig2-global"
 #define CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID "application/x-cairo.jbig2-global-id"
+#define CAIRO_MIME_TYPE_CCITT_FAX "image/g3fax"
+#define CAIRO_MIME_TYPE_CCITT_FAX_PARAMS "application/x-cairo.ccitt.params"
 
 cairo_public void
 cairo_surface_get_mime_data (cairo_surface_t		*surface,
diff --git a/test/ccitt.g3 b/test/ccitt.g3
new file mode 100644
index 00000000..b5ef99e3
--- /dev/null
+++ b/test/ccitt.g3
@@ -0,0 +1,2 @@
+ÿþFÙÞ#Z#™¡ôІ½©à¡è(¨Ô³¼b#£†GGâ:#³hÒœ‹ºœ3‹Bд#B.‚éºù1Äã¦PåÑ1ʉé¢":*ÂôÕˆ½Vš¼x»ë6o¯žþ‡^¾Ö¿è›þN—ZÑ7 D{ÿ_ÓJ÷×d{ÿkkf+
L —j•ÿØØ؏c_þÌöPæ(p¨2‡({(sÌõxˆˆˆˆ¨‹ˆˆˆˆÎЂB}(}
+ˆ«(pDu(pQÿÿ
\ No newline at end of file
diff --git a/test/mime-data.c b/test/mime-data.c
index c744f5c9..e6d1405b 100644
--- a/test/mime-data.c
+++ b/test/mime-data.c
@@ -207,6 +207,56 @@ paint_jbig2_file (cairo_t *cr, int x, int y)
 }
 
 static cairo_test_status_t
+paint_ccitt_file (cairo_t *cr, int x, int y)
+{
+    const cairo_test_context_t *ctx = cairo_test_get_context (cr);
+    cairo_surface_t *image;
+    unsigned char *mime_data;
+    unsigned int mime_length;
+    cairo_status_t status;
+    const char *ccitt_image_filename = "ccitt.g3";
+    const char *ccitt_image_params = "Columns=200 Rows=50 K=-1";
+
+    /* Deliberately use a non-matching MIME images, so that we can identify
+     * when the MIME representation is used in preference to the plain image
+     * surface.
+     */
+
+    status = read_file (ctx, ccitt_image_filename, &mime_data, &mime_length);
+    if (status)
+	return cairo_test_status_from_status (ctx, status);
+
+    image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 50);
+
+    /* Set the CCITT image data */
+    status = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_CCITT_FAX,
+					  mime_data, mime_length,
+					  free, mime_data);
+    if (status) {
+	cairo_surface_destroy (image);
+	free (mime_data);
+	return cairo_test_status_from_status (ctx, status);
+    }
+
+    /* Set the CCITT image paramaters */
+    status = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
+					  (unsigned char *)ccitt_image_params,
+					  strlen (ccitt_image_params),
+					  NULL, NULL);
+    if (status) {
+	cairo_surface_destroy (image);
+	return cairo_test_status_from_status (ctx, status);
+    }
+
+    cairo_set_source_surface (cr, image, x, y);
+    cairo_surface_destroy (image);
+
+    cairo_paint (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+static cairo_test_status_t
 draw (cairo_t *cr, int width, int height)
 {
     const char jpg_filename[] = "jpeg.jpg";
@@ -230,6 +280,10 @@ draw (cairo_t *cr, int width, int height)
     if (status)
 	return status;
 
+    status = paint_ccitt_file (cr, 0, 250);
+    if (status)
+	return status;
+
     return CAIRO_TEST_SUCCESS;
 }
 
@@ -237,5 +291,5 @@ CAIRO_TEST (mime_data,
 	    "Check that the mime-data embedding works",
 	    "jpeg, api", /* keywords */
 	    NULL, /* requirements */
-	    200, 250,
+	    200, 300,
 	    NULL, draw)
diff --git a/test/reference/mime-data.base.argb32.ref.png b/test/reference/mime-data.base.argb32.ref.png
index 4bc007c8..03a0247a 100644
Binary files a/test/reference/mime-data.base.argb32.ref.png and b/test/reference/mime-data.base.argb32.ref.png differ
diff --git a/test/reference/mime-data.base.rgb24.ref.png b/test/reference/mime-data.base.rgb24.ref.png
index 4bc007c8..03a0247a 100644
Binary files a/test/reference/mime-data.base.rgb24.ref.png and b/test/reference/mime-data.base.rgb24.ref.png differ
diff --git a/test/reference/mime-data.pdf.ref.png b/test/reference/mime-data.pdf.ref.png
index 76c17f8d..a669c8f2 100644
Binary files a/test/reference/mime-data.pdf.ref.png and b/test/reference/mime-data.pdf.ref.png differ
diff --git a/test/reference/mime-data.ps.ref.png b/test/reference/mime-data.ps.ref.png
index 7ec7d9b2..bf834020 100644
Binary files a/test/reference/mime-data.ps.ref.png and b/test/reference/mime-data.ps.ref.png differ
diff --git a/test/reference/mime-data.ref.png b/test/reference/mime-data.ref.png
index 4bc007c8..03a0247a 100644
Binary files a/test/reference/mime-data.ref.png and b/test/reference/mime-data.ref.png differ
diff --git a/test/reference/mime-data.script.ref.png b/test/reference/mime-data.script.ref.png
index 07691b10..e4861803 100644
Binary files a/test/reference/mime-data.script.ref.png and b/test/reference/mime-data.script.ref.png differ
diff --git a/test/reference/mime-data.svg.ref.png b/test/reference/mime-data.svg.ref.png
index a4bbb1b6..1889c6e8 100644
Binary files a/test/reference/mime-data.svg.ref.png and b/test/reference/mime-data.svg.ref.png differ


More information about the cairo-commit mailing list