summaryrefslogtreecommitdiff
path: root/src/cairo-ps-surface.c
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 /src/cairo-ps-surface.c
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.
Diffstat (limited to 'src/cairo-ps-surface.c')
-rw-r--r--src/cairo-ps-surface.c200
1 files changed, 183 insertions, 17 deletions
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;
}