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.
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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" ; \
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
BIN
test/composite-integer-translate-over-ps2-ref.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
test/composite-integer-translate-over-ps3-ref.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
test/composite-integer-translate-over-repeat-ps2-ref.png
Normal file
|
After Width: | Height: | Size: 448 B |
BIN
test/composite-integer-translate-over-repeat-ps3-ref.png
Normal file
|
After Width: | Height: | Size: 448 B |
BIN
test/composite-integer-translate-source-ps2-ref.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
test/composite-integer-translate-source-ps3-ref.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 200 B |
|
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 200 B |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 144 KiB |
BIN
test/extend-repeat-ps2-ref.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
test/extend-repeat-ps3-ref.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
test/extend-repeat-similar-ps2-ref.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
test/extend-repeat-similar-ps3-ref.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 173 B After Width: | Height: | Size: 556 B |
|
Before Width: | Height: | Size: 173 B After Width: | Height: | Size: 556 B |
BIN
test/image-surface-source-ps2-ref.png
Normal file
|
After Width: | Height: | Size: 376 B |
BIN
test/image-surface-source-ps3-ref.png
Normal file
|
After Width: | Height: | Size: 376 B |
|
Before Width: | Height: | Size: 268 B After Width: | Height: | Size: 332 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 14 KiB |
BIN
test/surface-pattern-pdf-ref.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
BIN
test/surface-pattern-ps2-ref.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
BIN
test/surface-pattern-ps3-ref.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
BIN
test/surface-pattern-scale-down-ps2-ref.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
BIN
test/surface-pattern-scale-down-ps3-ref.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 4.1 KiB |
BIN
test/surface-pattern-scale-up-pdf-rgb24-ref.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 1,011 B |
BIN
test/surface-pattern-scale-up-ps2-ref.png
Normal file
|
After Width: | Height: | Size: 943 B |
|
Before Width: | Height: | Size: 1,011 B |
BIN
test/surface-pattern-scale-up-ps3-ref.png
Normal file
|
After Width: | Height: | Size: 943 B |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 4 KiB |
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
BIN
test/xlib-surface-source-ps2-ref.png
Normal file
|
After Width: | Height: | Size: 376 B |
BIN
test/xlib-surface-source-ps3-ref.png
Normal file
|
After Width: | Height: | Size: 376 B |