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.
This commit is contained in:
Adrian Johnson 2017-10-22 08:45:45 +10:30
parent e1a02b180d
commit 87dfd0c16f
2 changed files with 24 additions and 129 deletions

View file

@ -1402,97 +1402,6 @@ _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,
@ -1500,8 +1409,6 @@ _get_source_surface_extents (cairo_surface_t *source,
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;

View file

@ -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) {