PS/PDF: Set image Interpolation flag

If the filter mode is anything other than DEFAILT, FAST or NEAREST set the
Interpolate flag in the image dictionary so that a smoothing filter is
applied when rasterising the vector file.

As we have no control over the implementation of the Interpolate filter
(the PS/PDF specifications leave it undefined) we need to capture the
output of poppler/GS and update our reference images. (For a couple of
tests, the filtering is irrelevant so for those we set the filter to
NEAREST.)

Note that GhostScript's Interpolate filter does not work on rotated images
(and a variety of other transformations) so several of the PS reference
images have use nearest-neighbour sampling instead of a bilinear filter.
This commit is contained in:
Adrian Johnson 2008-04-05 13:32:51 +10:30 committed by Chris Wilson
parent 2c53bdb82a
commit 05fce5bced
52 changed files with 98 additions and 30 deletions

View file

@ -1411,9 +1411,10 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface,
/* Emit image data into the given surface, providing a resource that
* can be used to reference the data in image_ret. */
static cairo_status_t
_cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
cairo_image_surface_t *image,
cairo_pdf_resource_t *image_ret)
_cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
cairo_image_surface_t *image,
cairo_pdf_resource_t *image_ret,
cairo_filter_t filter)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
char *rgb;
@ -1422,6 +1423,7 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
int i, x, y;
cairo_pdf_resource_t smask = {0}; /* squelch bogus compiler warning */
cairo_bool_t need_smask;
const char *interpolate;
/* These are the only image formats we currently support, (which
* makes things a lot simpler here). This is enforced through
@ -1486,11 +1488,25 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
need_smask = TRUE;
}
switch (filter) {
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;
}
#define IMAGE_DICTIONARY " /Type /XObject\n" \
" /Subtype /Image\n" \
" /Width %d\n" \
" /Height %d\n" \
" /ColorSpace /DeviceRGB\n" \
" /Interpolate %s\n" \
" /BitsPerComponent 8\n"
if (need_smask)
@ -1500,13 +1516,15 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
IMAGE_DICTIONARY
" /SMask %d 0 R\n",
image->width, image->height,
interpolate,
smask.id);
else
status = _cairo_pdf_surface_open_stream (surface,
NULL,
TRUE,
IMAGE_DICTIONARY,
image->width, image->height);
image->width, image->height,
interpolate);
if (status)
goto CLEANUP_RGB;
@ -1537,7 +1555,7 @@ _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface,
if (status)
goto BAIL;
status = _cairo_pdf_surface_emit_image (surface, image, resource);
status = _cairo_pdf_surface_emit_image (surface, image, resource, pattern->base.filter);
if (status)
goto BAIL;

View file

@ -1863,7 +1863,8 @@ _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface,
static cairo_status_t
_cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
cairo_image_surface_t *image,
cairo_operator_t op)
cairo_operator_t op,
cairo_filter_t filter)
{
cairo_status_t status;
unsigned char *data, *data_compressed;
@ -1874,10 +1875,24 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
cairo_bool_t use_mask;
uint32_t *pixel;
int bit;
const char *interpolate;
if (image->base.status)
return image->base.status;
switch (filter) {
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;
}
transparency = _cairo_image_analyze_transparency (image);
/* PostScript can not represent the alpha channel, so we blend the
@ -1998,10 +2013,12 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
" /ImageType 1 def\n"
" /Width %d def\n"
" /Height %d def\n"
" /Interpolate %s def\n"
" /BitsPerComponent 8 def\n"
" /Decode [ 0 1 0 1 0 1 ] def\n",
image->width,
image->height);
image->height,
interpolate);
if (surface->use_string_datasource) {
_cairo_output_stream_printf (surface->stream,
@ -2024,6 +2041,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
" /ImageType 1 def\n"
" /Width %d def\n"
" /Height %d def\n"
" /Interpolate %s def\n"
" /BitsPerComponent 1 def\n"
" /Decode [ 1 0 ] def\n"
" /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
@ -2033,6 +2051,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
image->height,
image->width,
image->height,
interpolate,
image->height);
} else {
_cairo_output_stream_printf (surface->stream,
@ -2059,9 +2078,11 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
}
_cairo_output_stream_printf (surface->stream,
" /Interpolate %s def\n"
" /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
"end\n"
"image\n",
interpolate,
opaque_image->height);
}
@ -2246,7 +2267,8 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
status = _cairo_ps_surface_emit_meta_surface (surface,
meta_surface);
} else {
status = _cairo_ps_surface_emit_image (surface, surface->image, op);
status = _cairo_ps_surface_emit_image (surface, surface->image,
op, pattern->base.filter);
}
return status;

View file

@ -359,8 +359,14 @@ REFERENCE_IMAGES = \
close-path-ps2-ref.png \
close-path-ps3-ref.png \
composite-integer-translate-over-ref.png \
composite-integer-translate-over-ps2-ref.png \
composite-integer-translate-over-ps3-ref.png \
composite-integer-translate-over-repeat-ref.png \
composite-integer-translate-over-repeat-ps2-ref.png \
composite-integer-translate-over-repeat-ps3-ref.png \
composite-integer-translate-source-ref.png \
composite-integer-translate-source-ps2-ref.png \
composite-integer-translate-source-ps3-ref.png \
copy-path-ps2-ref.png \
copy-path-ps3-ref.png \
copy-path-ref.png \
@ -432,7 +438,11 @@ REFERENCE_IMAGES = \
extend-reflect-ps2-ref.png \
extend-reflect-ps3-ref.png \
extend-repeat-ref.png \
extend-repeat-ps2-ref.png \
extend-repeat-ps3-ref.png \
extend-repeat-similar-ref.png \
extend-repeat-similar-ps2-ref.png \
extend-repeat-similar-ps3-ref.png \
fallback-resolution-ppi37.5x37.5-ref.png \
fallback-resolution-ppi37.5x72-ref.png \
fallback-resolution-ppi37.5x75-ref.png \
@ -584,6 +594,8 @@ REFERENCE_IMAGES = \
huge-pattern-pdf-ref.png \
huge-pattern-pdf-rgb24-ref.png \
image-surface-source-ref.png \
image-surface-source-ps2-ref.png \
image-surface-source-ps3-ref.png \
infinite-join-ref.png \
infinite-join-ps2-ref.png \
infinite-join-ps3-ref.png \
@ -869,18 +881,20 @@ REFERENCE_IMAGES = \
stroke-ctm-caps-ps2-ref.png \
stroke-ctm-caps-ps3-ref.png \
surface-pattern-big-scale-down-ref.png \
surface-pattern-pdf-argb32-ref.png \
surface-pattern-ps2-argb32-ref.png \
surface-pattern-ps3-argb32-ref.png \
surface-pattern-pdf-ref.png \
surface-pattern-ps2-ref.png \
surface-pattern-ps3-ref.png \
surface-pattern-ref.png \
surface-pattern-scale-down-pdf-argb32-ref.png \
surface-pattern-scale-down-ps2-argb32-ref.png \
surface-pattern-scale-down-ps3-argb32-ref.png \
surface-pattern-scale-down-pdf-argb24-ref.png \
surface-pattern-scale-down-pdf-rgb24-ref.png \
surface-pattern-scale-down-ps2-ref.png \
surface-pattern-scale-down-ps3-ref.png \
surface-pattern-scale-down-ref.png \
surface-pattern-scale-down-quartz-ref.png \
surface-pattern-scale-up-pdf-argb32-ref.png \
surface-pattern-scale-up-ps2-argb32-ref.png \
surface-pattern-scale-up-ps3-argb32-ref.png \
surface-pattern-scale-up-pdf-rgb24-ref.png \
surface-pattern-scale-up-ps2-ref.png \
surface-pattern-scale-up-ps3-ref.png \
surface-pattern-scale-up-ref.png \
surface-pattern-svg12-ref.png \
surface-pattern-svg11-ref.png \
@ -964,6 +978,8 @@ REFERENCE_IMAGES = \
unbounded-operator-quartz-rgb24-ref.png \
xlib-expose-event-ref.png \
xlib-surface-source-ref.png \
xlib-surface-source-ps2-ref.png \
xlib-surface-source-ps3-ref.png \
zero-alpha-ref.png
EXTRA_DIST += \
@ -1023,10 +1039,7 @@ $(REFERENCE_IMAGES)
# on cairo_traps_t after strokes.
# Test case should also be expanded to hit special-case
# tessellators as well.
# surface-pattern* - old bugs in pixman, but fails PS/PDF due to lack of
# /Interpolate support - which causes a half-pixel
# shift in GS (and consequently virtually every
# image/fallback-image using test to FAIL).
# surface-pattern-big...- Strange, unexplained results for SVG/PS.
XFAIL_TESTS = \
alpha-similar$(EXEEXT) \
big-line$(EXEEXT) \
@ -1039,10 +1052,7 @@ fallback-resolution$(EXEEXT) \
long-lines$(EXEEXT) \
self-copy-overlap$(EXEEXT) \
self-intersecting$(EXEEXT) \
surface-pattern$(EXEEXT) \
surface-pattern-big-scale-down$(EXEEXT) \
surface-pattern-scale-down$(EXEEXT) \
surface-pattern-scale-up$(EXEEXT) \
$(NULL)
# Any test that doesn't generate a log file goes here
@ -1289,7 +1299,6 @@ check-ref-dups:
check-ref-missing:
@cd "$(srcdir)"; \
REFS=`git ls-files "*-ref.png"`; \
test x = "x$$REFS" && REFS=`ls *-ref.png`; \
ret=true; \
missing=""; \
for i in $$REFS; do \
@ -1302,6 +1311,19 @@ check-ref-missing:
echo "Missing: $$missing"; \
ret=false; \
fi >&2; \
if $$ret; then \
REFS=`ls *-ref.png`; \
for i in $$REFS; do \
echo "" $(REFERENCE_IMAGES) "" | grep -sq " $$i " || missing="$$missing $$i" ; \
done ; \
if test -n "$$missing"; then \
echo "*** Error: Sanity check failed"; \
echo "Some local reference files are not included in the distribution or been added to git."; \
echo "You probably need to add these to git and Makefile.am's REFERENCE_IMAGES."; \
echo "Missing: $$missing"; \
ret=false; \
fi >&2; \
fi >&2; \
missing=""; \
for i in $(REFERENCE_IMAGES); do \
echo "" $$REFS "" | grep -sq " $$i " || missing="$$missing $$i" ; \

View file

@ -54,6 +54,7 @@ draw (cairo_t *cr, int width, int height)
CAIRO_FORMAT_ARGB32, 12, 4, 48);
cairo_set_source_surface (cr, mask, 0, 0);
cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
cairo_surface_destroy (mask);
cairo_paint (cr);

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -88,6 +88,7 @@ draw (cairo_t *cr, int width, int height)
free (filename);
cairo_set_source_surface (cr, surface, 0, 0);
cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
cairo_paint (cr);
cairo_surface_destroy (surface);

View file

@ -72,6 +72,7 @@ draw (cairo_t *cr, int width, int height)
free (filename);
cairo_set_source_surface (cr, surface, 0, 0);
cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
cairo_paint (cr);
cairo_surface_destroy (surface);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 B

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -34,8 +34,7 @@ static cairo_test_draw_function_t draw;
static const cairo_test_t test = {
"surface-pattern-scale-down",
"Test scaled-down transformed not-repeated surface patterns"
"\nFails xlib backend (with argb32) with inexplicable alpha in result",
"Test scaled-down transformed not-repeated surface patterns",
SIZE, SIZE,
draw
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,011 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,011 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 4 KiB

View file

@ -24,6 +24,9 @@
* Author: Behdad Esfahbod <behdad@behdad.org>
*/
/* Exhibits nasty behaviour with GS due as their /Interpolate implementation
* does not function for rotated images. */
#include <math.h>
#include "cairo-test.h"
#include <stdio.h>
@ -34,8 +37,7 @@ static cairo_test_draw_function_t draw;
static const cairo_test_t test = {
"surface-pattern-scale-up",
"Test scaled-up transformed not-repeated surface patterns"
"\nFails xlib backend (with argb32) with inexplicable alpha in result",
"Test scaled-up transformed not-repeated surface patterns",
SIZE, SIZE,
draw
};

View file

@ -30,12 +30,14 @@
#define SIZE 140
/* Not GhostScript does not support /Interpolate on rotated images, so the PS
* output looks terrible, but is a known issue. */
static cairo_test_draw_function_t draw;
static const cairo_test_t test = {
"surface-pattern",
"Test transformed repeated surface patterns"
"\nExhibiting a strange (very minor) failure in ps backend with device-offset",
"Test transformed repeated surface patterns",
SIZE, SIZE,
draw
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B