Skip to content

Commit

Permalink
Add dither APIs
Browse files Browse the repository at this point in the history
Adds:

* Dither
* Pattern.set_dither
* Pattern.get_dither

See pygobject#335
  • Loading branch information
lazka committed Sep 26, 2023
1 parent 2b5f361 commit ff59afb
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 0 deletions.
64 changes: 64 additions & 0 deletions cairo/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,45 @@ class ColorMode(_IntEnum):
in color.
"""

class Dither(_IntEnum):
"""
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.
:class:`Dither` 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.
.. versionadded:: 1.25 Only available with cairo 1.18.0+
"""

NONE: "Dither" = ...
"""
No dithering.
"""

DEFAULT: "Dither" = ...
"""
Default choice at cairo compile time. Currently NONE.
"""

FAST: "Dither" = ...
"""
Fastest dithering algorithm supported by the backend
"""

GOOD: "Dither" = ...
"""
An algorithm with smoother dithering than FAST
"""

BEST: "Dither" = ...
"""
Best algorithm available in the backend
"""

class HintStyle(_IntEnum):
"""
These constants specify the type of hinting to do on font outlines.
Expand Down Expand Up @@ -1293,6 +1332,26 @@ class Pattern:
:class:`Context.set_source`.
"""

def get_dither(self) -> Dither:
"""
:returns: the current dithering mode.
Gets the current dithering mode, as set by :meth:`Pattern.set_dither`.
.. versionadded:: 1.25.0 Only available with cairo 1.18.0+
"""

def set_dither(self, dither: Dither) -> None:
"""
:param dither: a :class:`Dither` 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.
.. versionadded:: 1.25.0 Only available with cairo 1.18.0+
"""

class Glyph(Tuple[int, float, float]):
"""
The :class:`Glyph` holds information about a single glyph when drawing or
Expand Down Expand Up @@ -5809,3 +5868,8 @@ PDF_OUTLINE_FLAG_ITALIC = PDFOutlineFlags.ITALIC
COLOR_MODE_DEFAULT = ColorMode.DEFAULT
COLOR_MODE_NO_COLOR = ColorMode.NO_COLOR
COLOR_MODE_COLOR = ColorMode.COLOR
DITHER_NONE = Dither.NONE
DITHER_DEFAULT = Dither.DEFAULT
DITHER_FAST = Dither.FAST
DITHER_GOOD = Dither.GOOD
DITHER_BEST = Dither.BEST
12 changes: 12 additions & 0 deletions cairo/enums.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ DEFINE_ENUM(ScriptMode)
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 17, 8)
DEFINE_ENUM(ColorMode)
#endif
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 18, 0)
DEFINE_ENUM(Dither)
#endif

#undef DEFINE_ENUM

Expand Down Expand Up @@ -527,6 +530,15 @@ init_enums (PyObject *module) {
CONSTANT(ColorMode, COLOR_MODE, COLOR);
#endif

#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 18, 0)
ENUM(Dither)
CONSTANT(Dither, DITHER, NONE);
CONSTANT(Dither, DITHER, DEFAULT);
CONSTANT(Dither, DITHER, FAST);
CONSTANT(Dither, DITHER, GOOD);
CONSTANT(Dither, DITHER, BEST);
#endif

#undef ENUM
#undef CONSTANT

Expand Down
34 changes: 34 additions & 0 deletions cairo/pattern.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,36 @@ pattern_set_filter (PycairoPattern *o, PyObject *args) {
Py_RETURN_NONE;
}

#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 18, 0)
static PyObject *
pattern_get_dither (PycairoPattern *o, PyObject *ignored) {
cairo_dither_t dither;

Py_BEGIN_ALLOW_THREADS;
dither = cairo_pattern_get_dither (o->pattern);
Py_END_ALLOW_THREADS;

RETURN_INT_ENUM (Dither, dither);
}

static PyObject *
pattern_set_dither (PycairoPattern *o, PyObject *args) {
cairo_dither_t dither;
int dither_arg;

if (!PyArg_ParseTuple (args, "i:Pattern.set_dither", &dither_arg))
return NULL;

dither = (cairo_dither_t)dither_arg;

Py_BEGIN_ALLOW_THREADS;
cairo_pattern_set_dither (o->pattern, dither);
Py_END_ALLOW_THREADS;

Py_RETURN_NONE;
}
#endif

static PyMethodDef pattern_methods[] = {
/* methods never exposed in a language binding:
* cairo_pattern_destroy()
Expand All @@ -182,6 +212,10 @@ static PyMethodDef pattern_methods[] = {
{"set_matrix", (PyCFunction)pattern_set_matrix, METH_VARARGS },
{"get_filter", (PyCFunction)pattern_get_filter, METH_NOARGS },
{"set_filter", (PyCFunction)pattern_set_filter, METH_VARARGS },
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 18, 0)
{"get_dither", (PyCFunction)pattern_get_dither, METH_NOARGS },
{"set_dither", (PyCFunction)pattern_set_dither, METH_VARARGS },
#endif
{NULL, NULL, 0, NULL},
};

Expand Down
3 changes: 3 additions & 0 deletions cairo/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,9 @@ DECL_ENUM(ScriptMode)
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 17, 8)
DECL_ENUM(ColorMode)
#endif
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 18, 0)
DECL_ENUM(Dither)
#endif

/* Use to disable deprecation warnings temporarily */
#ifdef _MSC_VER
Expand Down
4 changes: 4 additions & 0 deletions docs/reference/enums.rst
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,9 @@ as constants on the module level. See :ref:`legacy_constants`.
:undoc-members:

.. autoclass:: ColorMode
:members:
:undoc-members:

.. autoclass:: Dither
:members:
:undoc-members:
4 changes: 4 additions & 0 deletions tests/test_enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ def test_aliases():
# cairo 1.17.8+
types_.append(cairo.ColorMode)

if hasattr(cairo, "Dither"):
# cairo 1.18.0+
types_.append(cairo.Dither)

def get_prefix(t):
name = t.__name__
# special case..
Expand Down
9 changes: 9 additions & 0 deletions tests/test_pattern.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,12 @@ def test_pattern_filter():
def test_surface_pattern():
with pytest.raises(TypeError):
cairo.SurfacePattern(object())


@pytest.mark.skipif(not hasattr(cairo.Pattern, "set_dither"),
reason="too old cairo")
def test_pattern_dither():
pattern = cairo.SolidPattern(1, 2, 3)
pattern.get_dither() == cairo.Dither.DEFAULT
pattern.set_dither(cairo.Dither.BEST)
assert pattern.get_dither() == cairo.Dither.BEST

0 comments on commit ff59afb

Please sign in to comment.