summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Johnson <ajohnson@redneon.com>2017-10-22 08:07:49 +1030
committerAdrian Johnson <ajohnson@redneon.com>2017-10-22 08:42:36 +1030
commite1a02b180d804887980c111c1f9780bed44b96a6 (patch)
treecca69a484e92389b20ef60f31fb697e61b7ce774
parent4ae7f411c865a25b577faea58e5fda6f4e9e1172 (diff)
downloadcairo-e1a02b180d804887980c111c1f9780bed44b96a6.tar.gz
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.
-rw-r--r--doc/public/cairo-sections.txt2
-rw-r--r--src/Makefile.sources16
-rw-r--r--src/cairo-pdf-surface-private.h2
-rw-r--r--src/cairo-pdf-surface.c263
-rw-r--r--src/cairo-ps-surface.c200
-rw-r--r--src/cairo-surface.c21
-rw-r--r--src/cairo-tag-attributes-private.h15
-rw-r--r--src/cairo-tag-attributes.c80
-rw-r--r--src/cairo.h2
-rw-r--r--test/ccitt.g32
-rw-r--r--test/mime-data.c56
-rw-r--r--test/reference/mime-data.base.argb32.ref.pngbin243 -> 272 bytes
-rw-r--r--test/reference/mime-data.base.rgb24.ref.pngbin243 -> 272 bytes
-rw-r--r--test/reference/mime-data.pdf.ref.pngbin7563 -> 8205 bytes
-rw-r--r--test/reference/mime-data.ps.ref.pngbin4705 -> 5386 bytes
-rw-r--r--test/reference/mime-data.ref.pngbin243 -> 272 bytes
-rw-r--r--test/reference/mime-data.script.ref.pngbin2130 -> 2175 bytes
-rw-r--r--test/reference/mime-data.svg.ref.pngbin6437 -> 6513 bytes
18 files changed, 609 insertions, 50 deletions
diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index 7b04ae7b3..40c214834 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 89417ac86..cc2194f3e 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 a84ea9573..98f0cfdda 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 9e1547eac..cb887119f 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 e34f656cf..62b19e4af 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 35c63d7b8..459b84c9e 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 a127abc97..30bb48ed9 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 b3d08f6f7..64173402d 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 32fc88b17..671be5a89 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 000000000..b5ef99e3d
--- /dev/null
+++ b/test/ccitt.g3
@@ -0,0 +1,2 @@
+F#Z#І(ԍ b#GG:#hҜ3Bд#B.1P1é": *ՈVx6o^ֿNZ7D{_Jd{kkf+ L j؏c_P(p2({(sxЂB}(}
+(pDu(pQ \ No newline at end of file
diff --git a/test/mime-data.c b/test/mime-data.c
index c744f5c9b..e6d1405bf 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 4bc007c8a..03a0247a3 100644
--- a/test/reference/mime-data.base.argb32.ref.png
+++ b/test/reference/mime-data.base.argb32.ref.png
Binary files differ
diff --git a/test/reference/mime-data.base.rgb24.ref.png b/test/reference/mime-data.base.rgb24.ref.png
index 4bc007c8a..03a0247a3 100644
--- a/test/reference/mime-data.base.rgb24.ref.png
+++ b/test/reference/mime-data.base.rgb24.ref.png
Binary files differ
diff --git a/test/reference/mime-data.pdf.ref.png b/test/reference/mime-data.pdf.ref.png
index 76c17f8de..a669c8f2b 100644
--- a/test/reference/mime-data.pdf.ref.png
+++ b/test/reference/mime-data.pdf.ref.png
Binary files differ
diff --git a/test/reference/mime-data.ps.ref.png b/test/reference/mime-data.ps.ref.png
index 7ec7d9b2c..bf834020a 100644
--- a/test/reference/mime-data.ps.ref.png
+++ b/test/reference/mime-data.ps.ref.png
Binary files differ
diff --git a/test/reference/mime-data.ref.png b/test/reference/mime-data.ref.png
index 4bc007c8a..03a0247a3 100644
--- a/test/reference/mime-data.ref.png
+++ b/test/reference/mime-data.ref.png
Binary files differ
diff --git a/test/reference/mime-data.script.ref.png b/test/reference/mime-data.script.ref.png
index 07691b101..e48618033 100644
--- a/test/reference/mime-data.script.ref.png
+++ b/test/reference/mime-data.script.ref.png
Binary files differ
diff --git a/test/reference/mime-data.svg.ref.png b/test/reference/mime-data.svg.ref.png
index a4bbb1b6c..1889c6e8d 100644
--- a/test/reference/mime-data.svg.ref.png
+++ b/test/reference/mime-data.svg.ref.png
Binary files differ