mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-08 20:48:03 +02:00
Enable access to the pixman dithering path
Newer versions of Pixman allow choosing the dithering format.
This commit is contained in:
parent
7380d3dd7d
commit
e6ab85712c
13 changed files with 201 additions and 3 deletions
|
|
@ -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
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ");
|
||||
|
|
|
|||
|
|
@ -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 */ \
|
||||
}
|
||||
|
|
|
|||
33
src/cairo.h
33
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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
53
test/dithergradient.c
Normal file
53
test/dithergradient.c
Normal file
|
|
@ -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 <marc@jeanmougin.fr>
|
||||
*/
|
||||
|
||||
#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)
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
BIN
test/reference/dithergradient.image.argb32.ref.png
Normal file
BIN
test/reference/dithergradient.image.argb32.ref.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
test/reference/dithergradient.image.rgb24.ref.png
Normal file
BIN
test/reference/dithergradient.image.rgb24.ref.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
test/reference/dithergradient.image16.rgb24.ref.png
Normal file
BIN
test/reference/dithergradient.image16.rgb24.ref.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Loading…
Add table
Reference in a new issue