From e6ab85712cfa4450da1a010828c48c3044e57af8 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Thu, 25 May 2023 18:50:38 +0200 Subject: [PATCH 1/3] Enable access to the pixman dithering path Newer versions of Pixman allow choosing the dithering format. --- doc/public/cairo-sections.txt | 3 + src/cairo-image-surface.c | 23 ++++++++ src/cairo-pattern-private.h | 2 + src/cairo-pattern.c | 46 +++++++++++++++ src/cairo-script-surface.c | 26 +++++++++ src/cairo-surface.c | 11 +++- src/cairo.h | 33 +++++++++++ src/cairoint.h | 6 ++ test/dithergradient.c | 53 ++++++++++++++++++ test/meson.build | 1 + .../dithergradient.image.argb32.ref.png | Bin 0 -> 10442 bytes .../dithergradient.image.rgb24.ref.png | Bin 0 -> 10442 bytes .../dithergradient.image16.rgb24.ref.png | Bin 0 -> 20311 bytes 13 files changed, 201 insertions(+), 3 deletions(-) create mode 100644 test/dithergradient.c create mode 100644 test/reference/dithergradient.image.argb32.ref.png create mode 100644 test/reference/dithergradient.image.rgb24.ref.png create mode 100644 test/reference/dithergradient.image16.rgb24.ref.png diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt index 81c18a2de..f6dc84813 100644 --- a/doc/public/cairo-sections.txt +++ b/doc/public/cairo-sections.txt @@ -409,6 +409,9 @@ cairo_pattern_get_type cairo_pattern_get_reference_count cairo_pattern_set_user_data cairo_pattern_get_user_data +cairo_dither_t +cairo_set_dither +cairo_get_dither
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 553e32605..047acf133 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -248,6 +248,27 @@ _pixman_format_from_masks (cairo_format_masks_t *masks, return TRUE; } +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,39,0) +/* Convenience function to convert #cairo_dither_t into #pixman_dither_t */ +pixman_dither_t +_pixman_dither_from_cairo_dither (cairo_dither_t dither) +{ + switch(dither) { + default: + case CAIRO_DITHER_NONE: + case CAIRO_DITHER_DEFAULT: + return PIXMAN_DITHER_NONE; + case CAIRO_DITHER_FAST: + return PIXMAN_DITHER_FAST; + case CAIRO_DITHER_GOOD: + return PIXMAN_DITHER_GOOD; + case CAIRO_DITHER_BEST: + return PIXMAN_DITHER_BEST; + } +} +#endif + + /* A mask consisting of N bits set to 1. */ #define MASK(N) ((1UL << (N))-1) @@ -930,6 +951,8 @@ _cairo_image_surface_paint (void *abstract_surface, const cairo_clip_t *clip) { cairo_image_surface_t *surface = abstract_surface; + pixman_dither_t pixman_dither = _pixman_dither_from_cairo_dither(source->dither); + pixman_image_set_dither (surface->pixman_image, pixman_dither); TRACE ((stderr, "%s (surface=%d)\n", __FUNCTION__, surface->base.unique_id)); diff --git a/src/cairo-pattern-private.h b/src/cairo-pattern-private.h index d061b39c4..0e69d0177 100644 --- a/src/cairo-pattern-private.h +++ b/src/cairo-pattern-private.h @@ -52,6 +52,7 @@ enum { CAIRO_PATTERN_NOTIFY_FILTER = 0x2, CAIRO_PATTERN_NOTIFY_EXTEND = 0x4, CAIRO_PATTERN_NOTIFY_OPACITY = 0x9, + CAIRO_PATTERN_NOTIFY_DITHER = 0x12, }; struct _cairo_pattern_observer { @@ -73,6 +74,7 @@ struct _cairo_pattern { cairo_extend_t extend; cairo_bool_t has_component_alpha; cairo_bool_t is_foreground_marker; + cairo_dither_t dither; cairo_matrix_t matrix; double opacity; diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 1933fb80a..23c43855c 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -77,6 +77,7 @@ static const cairo_solid_pattern_t _cairo_pattern_nil = { CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */ FALSE, /* has component alpha */ FALSE, /* is_foreground_marker */ + CAIRO_DITHER_DEFAULT, /* dither */ { 1., 0., 0., 1., 0., 0., }, /* matrix */ 1.0 /* opacity */ } @@ -94,6 +95,7 @@ static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = { CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */ FALSE, /* has component alpha */ FALSE, /* is_foreground_marker */ + CAIRO_DITHER_DEFAULT, /* dither */ { 1., 0., 0., 1., 0., 0., }, /* matrix */ 1.0 /* opacity */ } @@ -111,6 +113,7 @@ const cairo_solid_pattern_t _cairo_pattern_black = { CAIRO_EXTEND_REPEAT, /* extend */ FALSE, /* has component alpha */ FALSE, /* is_foreground_marker */ + CAIRO_DITHER_DEFAULT, /* dither */ { 1., 0., 0., 1., 0., 0., }, /* matrix */ 1.0 /* opacity */ }, @@ -129,6 +132,7 @@ const cairo_solid_pattern_t _cairo_pattern_clear = { CAIRO_EXTEND_REPEAT, /* extend */ FALSE, /* has component alpha */ FALSE, /* is_foreground_marker */ + CAIRO_DITHER_DEFAULT, /* dither */ { 1., 0., 0., 1., 0., 0., }, /* matrix */ 1.0 /* opacity */ }, @@ -147,6 +151,7 @@ const cairo_solid_pattern_t _cairo_pattern_white = { CAIRO_EXTEND_REPEAT, /* extend */ FALSE, /* has component alpha */ FALSE, /* is_foreground_marker */ + CAIRO_DITHER_DEFAULT, /* dither */ { 1., 0., 0., 1., 0., 0., }, /* matrix */ 1.0 /* opacity */ }, @@ -240,6 +245,8 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type) pattern->has_component_alpha = FALSE; pattern->is_foreground_marker = FALSE; + pattern->dither = CAIRO_DITHER_DEFAULT; + cairo_matrix_init_identity (&pattern->matrix); cairo_list_init (&pattern->observers); @@ -2090,6 +2097,45 @@ cairo_pattern_get_filter (cairo_pattern_t *pattern) return pattern->filter; } +/** + * cairo_pattern_get_dither: + * @pattern: a #cairo_pattern_t + * + * Gets the current dithering mode, as set by + * cairo_pattern_set_dither(). + * + * Return value: the current dithering mode. + * + * Since: 1.18 + **/ +cairo_dither_t +cairo_pattern_get_dither (cairo_pattern_t *pattern) +{ + return pattern->dither; +} + +/** + * cairo_pattern_set_dither: + * @pattern: a #cairo_pattern_t + * @dither: a #cairo_dither_t describing the new dithering mode + * + * Set the dithering mode of the rasterizer used for drawing shapes. + * This value is a hint, and a particular backend may or may not support + * a particular value. At the current time, only pixman is supported. + * + * Since: 1.18 + **/ +void +cairo_pattern_set_dither (cairo_pattern_t *pattern, cairo_dither_t dither) +{ + if (pattern->status) + return; + + pattern->dither = dither; + _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_DITHER); + +} + /** * cairo_pattern_set_extend: * @pattern: a #cairo_pattern_t diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c index 1175bd8f3..23d64cf93 100644 --- a/src/cairo-script-surface.c +++ b/src/cairo-script-surface.c @@ -370,6 +370,21 @@ _filter_to_string (cairo_filter_t filter) return names[filter]; } +static const char * +_dither_to_string (cairo_dither_t dither) +{ + static const char *names[] = { + "DITHER_DEFAULT", /* CAIRO_FILTER_FAST */ + "DITHER_NONE", /* CAIRO_FILTER_GOOD */ + "DITHER_FAST", /* CAIRO_FILTER_BEST */ + "DITHER_GOOD", /* CAIRO_FILTER_NEAREST */ + "DITHER_BEST", /* CAIRO_FILTER_BILINEAR */ + }; + assert (dither < ARRAY_LENGTH (names)); + return names[dither]; +} + + static const char * _fill_rule_to_string (cairo_fill_rule_t rule) { @@ -1731,6 +1746,17 @@ _emit_pattern (cairo_script_surface_t *surface, " //%s set-filter\n ", _filter_to_string (pattern->filter)); } + /* XXX need to discriminate the user explicitly setting the default */ + if (pattern->dither != CAIRO_DITHER_DEFAULT) { + if (need_newline) { + _cairo_output_stream_puts (ctx->stream, "\n "); + need_newline = FALSE; + } + + _cairo_output_stream_printf (ctx->stream, + " //%s set-dither\n ", + _dither_to_string (pattern->dither)); + } if (! is_default_extend ){ if (need_newline) { _cairo_output_stream_puts (ctx->stream, "\n "); diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 9110edb1a..d0706cbb0 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -127,13 +127,18 @@ const cairo_surface_t name = { \ NULL, /* snapshot_detach */ \ { NULL, NULL }, /* snapshots */ \ { NULL, NULL }, /* snapshot */ \ - { CAIRO_ANTIALIAS_DEFAULT, /* antialias */ \ + { /* font options begin */\ + CAIRO_ANTIALIAS_DEFAULT, /* antialias */ \ CAIRO_SUBPIXEL_ORDER_DEFAULT, /* subpixel_order */ \ CAIRO_LCD_FILTER_DEFAULT, /* lcd_filter */ \ CAIRO_HINT_STYLE_DEFAULT, /* hint_style */ \ CAIRO_HINT_METRICS_DEFAULT, /* hint_metrics */ \ - CAIRO_ROUND_GLYPH_POS_DEFAULT /* round_glyph_positions */ \ - }, /* font_options */ \ + CAIRO_ROUND_GLYPH_POS_DEFAULT, /* round_glyph_positions */ \ + NULL, /* variations */ \ + CAIRO_COLOR_MODE_DEFAULT, /* color mode */ \ + CAIRO_COLOR_PALETTE_DEFAULT, /* color palette */ \ + NULL, 0, /* custom palette */ \ + }, /* font_options end */ \ NULL, /* foreground_source */ \ FALSE, /* foreground_used */ \ } diff --git a/src/cairo.h b/src/cairo.h index f6028a243..cd529c26e 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -440,6 +440,39 @@ typedef enum _cairo_format { CAIRO_FORMAT_RGBA128F = 7 } cairo_format_t; +/** + * cairo_dither_t: + * @CAIRO_DITHER_NONE: No dithering. + * @CAIRO_DITHER_DEFAULT: Default choice at cairo compile time. Currently NONE. + * @CAIRO_DITHER_FAST: Fastest dithering algorithm supported by the backend + * @CAIRO_DITHER_GOOD: An algorithm with smoother dithering than FAST + * @CAIRO_DITHER_BEST: Best algorithm available in the backend + * + * Dither is an intentionally applied form of noise used to randomize + * quantization error, preventing large-scale patterns such as color banding + * in images (e.g. for gradients). Ordered dithering applies a precomputed + * threshold matrix to spread the errors smoothly. + * + * #cairo_dither_t is modeled on pixman dithering algorithm choice. + * As of Pixman 0.40, FAST corresponds to a 8x8 ordered bayer noise and GOOD + * and BEST use an ordered 64x64 precomputed blue noise. + * + * Since: 1.18 + **/ +#define CAIRO_HAS_DITHER +typedef enum _cairo_dither { + CAIRO_DITHER_NONE, + CAIRO_DITHER_DEFAULT, + CAIRO_DITHER_FAST, + CAIRO_DITHER_GOOD, + CAIRO_DITHER_BEST +} cairo_dither_t; + +cairo_public void +cairo_pattern_set_dither (cairo_pattern_t *pattern, cairo_dither_t dither); + +cairo_public cairo_dither_t +cairo_pattern_get_dither (cairo_pattern_t *pattern); /** * cairo_write_func_t: diff --git a/src/cairoint.h b/src/cairoint.h index c906c25c1..85636d826 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1606,6 +1606,12 @@ cairo_private cairo_bool_t _pixman_format_to_masks (pixman_format_code_t pixman_format, cairo_format_masks_t *masks); +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,39,0) +cairo_private pixman_dither_t +_pixman_dither_from_cairo_dither (cairo_dither_t dither); +#endif + + cairo_private void _cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph); diff --git a/test/dithergradient.c b/test/dithergradient.c new file mode 100644 index 000000000..112395603 --- /dev/null +++ b/test/dithergradient.c @@ -0,0 +1,53 @@ +/* + * Copyright © 2023 Marc Jeanmougin + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Marc Jeanmougin + */ + +#include "cairo-test.h" + +/* History: + * + * 2023: v3 of a patch to use pixman dithering with cairo + */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *gradient = cairo_pattern_create_linear (0, 0, width, 0); + cairo_pattern_add_color_stop_rgba (gradient, 0., 25./255, 25./255, 25./255, 1.0); + cairo_pattern_add_color_stop_rgba (gradient, 1., 45./255, 45./255, 45./255, 1.0); + + cairo_set_source (cr, gradient); + cairo_pattern_set_dither (gradient, CAIRO_DITHER_BEST); + cairo_paint (cr); + + cairo_pattern_destroy (gradient); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (dithergradient, + "Testing the creation of a dithered gradient (in argb32)", + "gradient, dither", /* keywords */ + NULL, /* requirements */ + 400, 100, + NULL, draw) diff --git a/test/meson.build b/test/meson.build index 1d76d5daa..68fcee4c1 100644 --- a/test/meson.build +++ b/test/meson.build @@ -124,6 +124,7 @@ test_sources = [ 'device-offset-fractional.c', 'device-offset-positive.c', 'device-offset-scale.c', + 'dithergradient.c', 'error-setters.c', 'extend-pad.c', 'extend-pad-border.c', diff --git a/test/reference/dithergradient.image.argb32.ref.png b/test/reference/dithergradient.image.argb32.ref.png new file mode 100644 index 0000000000000000000000000000000000000000..c44e123806d8f7ea7a85aaa5a8875f5c221c151b GIT binary patch literal 10442 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 YzYytnPDKy?d&)a!WQa5 Date: Mon, 21 Aug 2023 16:16:47 +0100 Subject: [PATCH 2/3] Make Cairo dither to Pixman dither conversion static We don't use it anywhere outside of the image surface, so there's no need to make it a project-wide private function. The name is also updated: it's a cairo function, so it should not abuse the pixman namespace. --- src/cairo-image-surface.c | 16 ++++++++-------- src/cairoint.h | 5 ----- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 047acf133..fe64cd76c 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -250,20 +250,20 @@ _pixman_format_from_masks (cairo_format_masks_t *masks, #if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,39,0) /* Convenience function to convert #cairo_dither_t into #pixman_dither_t */ -pixman_dither_t -_pixman_dither_from_cairo_dither (cairo_dither_t dither) +static pixman_dither_t +_cairo_dither_to_pixman_dither (cairo_dither_t dither) { - switch(dither) { - default: - case CAIRO_DITHER_NONE: - case CAIRO_DITHER_DEFAULT: - return PIXMAN_DITHER_NONE; + switch (dither) { case CAIRO_DITHER_FAST: return PIXMAN_DITHER_FAST; case CAIRO_DITHER_GOOD: return PIXMAN_DITHER_GOOD; case CAIRO_DITHER_BEST: return PIXMAN_DITHER_BEST; + case CAIRO_DITHER_NONE: + case CAIRO_DITHER_DEFAULT: + default: + return PIXMAN_DITHER_NONE; } } #endif @@ -951,7 +951,7 @@ _cairo_image_surface_paint (void *abstract_surface, const cairo_clip_t *clip) { cairo_image_surface_t *surface = abstract_surface; - pixman_dither_t pixman_dither = _pixman_dither_from_cairo_dither(source->dither); + pixman_dither_t pixman_dither = _cairo_dither_to_pixman_dither (source->dither); pixman_image_set_dither (surface->pixman_image, pixman_dither); TRACE ((stderr, "%s (surface=%d)\n", diff --git a/src/cairoint.h b/src/cairoint.h index 85636d826..cac7f56d4 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1606,11 +1606,6 @@ cairo_private cairo_bool_t _pixman_format_to_masks (pixman_format_code_t pixman_format, cairo_format_masks_t *masks); -#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,39,0) -cairo_private pixman_dither_t -_pixman_dither_from_cairo_dither (cairo_dither_t dither); -#endif - cairo_private void _cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font, From ac1ac72ff155b9cffdc3e51513962d34a9daebfa Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sat, 23 Sep 2023 12:15:27 +0100 Subject: [PATCH 3/3] tests: Add more dithering tests Use operator add to add the same source over and over again, to make the dithering more pronounced. --- test/dithergradient.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/test/dithergradient.c b/test/dithergradient.c index 112395603..1ad1aadc7 100644 --- a/test/dithergradient.c +++ b/test/dithergradient.c @@ -25,12 +25,8 @@ #include "cairo-test.h" -/* History: - * - * 2023: v3 of a patch to use pixman dithering with cairo - */ -static cairo_test_status_t -draw (cairo_t *cr, int width, int height) +static void +set_dither_source (cairo_t *cr, int width) { cairo_pattern_t *gradient = cairo_pattern_create_linear (0, 0, width, 0); cairo_pattern_add_color_stop_rgba (gradient, 0., 25./255, 25./255, 25./255, 1.0); @@ -38,9 +34,34 @@ draw (cairo_t *cr, int width, int height) cairo_set_source (cr, gradient); cairo_pattern_set_dither (gradient, CAIRO_DITHER_BEST); + cairo_pattern_destroy (gradient); +} + +/* History: + * + * 2023: v3 of a patch to use pixman dithering with cairo + */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + set_dither_source (cr, width); cairo_paint (cr); - cairo_pattern_destroy (gradient); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw2 (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + set_dither_source (cr, width); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (int i = 0; i < 5; i++) { + cairo_paint (cr); + } return CAIRO_TEST_SUCCESS; } @@ -51,3 +72,9 @@ CAIRO_TEST (dithergradient, NULL, /* requirements */ 400, 100, NULL, draw) +CAIRO_TEST (dithergradient2, + "Testing the creation of a dithered gradient (in argb32)", + "gradient, dither", /* keywords */ + NULL, /* requirements */ + 400, 100, + NULL, draw2)