예제 #1
0
파일: gegl.py 프로젝트: Griatch/dopey
def something():

    #MyPaint.init()

    # Create a brush, load from disk
    brush = MyPaint.Brush()
    brush_def = open("brushes/classic/brush.myb").read()
    brush.from_string(brush_def)

    # List all settings
    # TODO: Is there a better way to list all enums with GI?
    settings = [getattr(MyPaint.BrushSetting, attr) for attr in dir(MyPaint.BrushSetting) if attr.startswith("SETTING_")]
    print "Available settings: %s\n" % str(settings)

    # Get info about a given setting
    setting = MyPaint.BrushSetting.SETTING_RADIUS_LOGARITHMIC
    info = MyPaint.brush_setting_info(setting)

    # TODO: rename "def_" to "default"
    print "Setting: %s\n\t Max: %f \n\t Default: %f \n\t Min: %f" % (info.cname, info.max, info.def_, info.min)
    print "\t Name: %s\n\t Tooltip: '%s'\n" % (info.get_name(), info.get_tooltip()) # Use the getters so that i18n works

    # TODO: should be MyPaint.BrushSetting.from_cname
    # Same with MyPaint.Brush.input_from_cname
    assert (MyPaint.Brush.setting_from_cname(info.cname) == setting)

    # Get/Set current base value for the given setting
    print "Base value is: %f" % brush.get_base_value(setting)
    brush.set_base_value(setting, 2.0)
    assert brush.get_base_value(setting) ==  2.0

    # Get dynamics for given setting
    inputs = [getattr(MyPaint.BrushInput, a) for a in dir(MyPaint.BrushInput) if a.startswith('INPUT_')]
    if not brush.is_constant(setting):
        for input in inputs:
            mapping_points = brush.get_mapping_n(setting, input)
            if mapping_points > 1: # If 0, no dynamics for this input
                points = [brush.get_mapping_point(setting, input, i) for i in range(mapping_points)]
                print "Has dynamics for input %s:\n%s" % (input, str(points))


    # Create a surface to paint on
    Gegl.init(0, "")
    surface = MyPaintGegl.TiledSurface()
    s = surface.interface()

    print surface.get_buffer()

    for x, y in [(0.0, 0.0), (100.0, 100.0), (100.0, 200.0)]:
        dtime = 0.1 # XXX: Important to set correctly for speed calculations
        s.begin_atomic()
        brush.stroke_to(s, x, y, pressure=1.0, xtilt=0.0, ytilt=0.0, dtime=dtime)
        rect = s.end_atomic()
        print rect.x, rect.y, rect.width, rect.height

    Gegl.exit()
예제 #2
0
def main():

    # Parse options

    parser = argparse.ArgumentParser(description='An argparse snippet.')

    parser.add_argument("--infile",  "-i",  help="the input file",  required=True, metavar="STRING")
    parser.add_argument("--outfile", "-o",  help="the output file", required=True, metavar="STRING")

    args = parser.parse_args()
    infile = args.infile
    outfile = args.outfile

    # GEGL ######################################

    gegl.init([])

    #print(gegl.list_operations())

    # Make nodes

    node1 = gegl.Node()
    node2 = gegl.Node() # png-load
    node3 = gegl.Node() # invert
    node4 = gegl.Node() # png-save

    # Set properties

    node2.set_property("operation", "gegl:png-load")
    node2.set_property("path", infile)

    node3.set_property("operation", "gegl:invert")

    node4.set_property("operation", "gegl:png-save")
    node4.set_property("path", outfile)

    # Make the graph

    node1.add_child(node2)
    node1.add_child(node3)
    node1.add_child(node4)

    node2.connect_to("output", node3, "input")
    node3.connect_to("output", node4, "input")

    # Process

    node4.process()
예제 #3
0
    def run(self, procedure, args, data):
        runmode = args.index(0)

        if runmode == Gimp.RunMode.INTERACTIVE:
            gi.require_version('Gtk', '3.0')
            from gi.repository import Gtk
            gi.require_version('Gdk', '3.0')
            from gi.repository import Gdk

            Gimp.ui_init("palette-offset.py", False)

            dialog = Gimp.Dialog(use_header_bar=True,
                                 title=_("Exercise a goat (Python 3)"),
                                 role="goat-exercise-Python3")

            dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL)
            dialog.add_button("_Source", Gtk.ResponseType.APPLY)
            dialog.add_button("_OK", Gtk.ResponseType.OK)

            geometry = Gdk.Geometry();
            geometry.min_aspect = 0.5;
            geometry.max_aspect = 1.0;
            dialog.set_geometry_hints(None, geometry, Gdk.WindowHints.ASPECT);

            box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2)
            dialog.get_content_area().add(box)
            box.show()

            # XXX We use printf-style string for sharing the localized
            # string. You may just use recommended Python format() or
            # any style you like in your plug-ins.
            head_text=("This plug-in is an exercise in '%s' to "
                       "demo plug-in creation.\nCheck out the last "
                       "version of the source code online by clicking "
                       "the \"Source\" button." % ("Python 3"))
            label = Gtk.Label(label=head_text)
            box.pack_start(label, False, False, 1)
            label.show()

            contents = None
            # Get the file contents Python-style instead of using
            # GLib.file_get_contents() which returns bytes result, and
            # when converting to string, get newlines as text contents.
            # Rather than wasting time to figure this out, use Python
            # core API!
            with open(os.path.realpath(__file__), 'r') as f:
                contents = f.read()

            if contents is not None:
                scrolled = Gtk.ScrolledWindow()
                scrolled.set_vexpand (True)
                box.pack_start(scrolled, True, True, 1)
                scrolled.show()

                view = Gtk.TextView()
                view.set_wrap_mode(Gtk.WrapMode.WORD)
                view.set_editable(False)
                buffer = view.get_buffer()
                buffer.set_text(contents, -1)
                scrolled.add(view)
                view.show()

            while (True):
                response = dialog.run()
                if response == Gtk.ResponseType.OK:
                    dialog.destroy()
                    break
                elif response == Gtk.ResponseType.APPLY:
                    Gio.app_info_launch_default_for_uri(url, None)
                    continue
                else:
                    dialog.destroy()
                    return procedure.new_return_values(Gimp.PDBStatusType.CANCEL,
                                                       GLib.Error())

        # Parameters are not working fine yet because properties should
        # be Gimp.ImageID/Gimp.DrawableID but we can't make these with
        # pygobject. Until I figure out how to make it work, you could
        # uncomment the following lines instead of using the args value.
        #images = Gimp.image_list()
        #image_id = images[0]
        #drawable_id = Gimp.image_get_active_drawable(image_id)
        drawable_id = args.index(2)

        success, x, y, width, height = Gimp.drawable_mask_intersect(drawable_id);
        if success:
            Gegl.init(None);

            buffer = Gimp.drawable_get_buffer(drawable_id)
            shadow_buffer = Gimp.drawable_get_shadow_buffer(drawable_id)

            graph = Gegl.Node()
            input = graph.create_child("gegl:buffer-source")
            input.set_property("buffer", buffer)
            invert = graph.create_child("gegl:invert")
            output = graph.create_child("gegl:write-buffer")
            output.set_property("buffer", shadow_buffer)
            input.link(invert)
            invert.link(output)
            output.process()

            # This is extremely important in bindings, since we don't
            # unref buffers. If we don't explicitly flush a buffer, we
            # may left hanging forever. This step is usually done
            # during an unref().
            shadow_buffer.flush()

            Gimp.drawable_merge_shadow(drawable_id, True)
            Gimp.drawable_update(drawable_id, x, y, width, height)
            Gimp.displays_flush()
        else:
            retval = procedure.new_return_values(Gimp.PDBStatusType.CALLING_ERROR,
                                                 GLib.Error("No pixels to process in the selected area."))

        return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())
예제 #4
0
#!/usr/bin/env python

from gi.repository import Gegl
from gi.repository import Gtk

from application import Application

Gegl.init([])
Gtk.init([])

application = Application()
application.run()
예제 #5
0
 def test_100_init(self):
     Gegl.init(None);
예제 #6
0
Intended as bootstrap for building larger scripts.

License: Creative Commons - Atribution required. Author: João S. O. Bueno 
"""

import sys
from gi.repository import Gegl as gegl

try:
    origin, target = sys.argv[1:3]
except IndexError:
    sys.stderr.write("Usage: %s origin_png target_png" % __file__)
    sys.exit(1)

gegl.init([])

ops = gegl.list_operations()

x = gegl.Node()

y = gegl.Node()
y.set_property("operation", "gegl:png-load")
y.set_property("path", origin)
x.add_child(y)

z = gegl.Node()
z.set_property("operation", "gegl:invert")
x.add_child(z)

w = gegl.Node()
예제 #7
0
        self.assertFalse(crop_rect.equal(trans_node.get_bounding_box()))

        trans_rect = crop_rect.dup()
        trans_rect.x += 10

        self.assertTrue(trans_rect.equal(trans_node.get_bounding_box()))


class TestGeglXml(unittest.TestCase):
    def test_load_xml(self):
        graph = Gegl.Node.new_from_xml(invert_crop_xml, "")

        children = graph.get_children()

        self.assertEqual(len(children), 2)

        self.assertEqual(children[0].get_operation(), "gegl:crop")
        self.assertEqual(children[1].get_operation(), "gegl:invert-linear")

    def test_load_save_roundtrip(self):
        graph = Gegl.Node.new_from_xml(invert_crop_xml, "")
        output = graph.to_xml("")

        self.assertEqual(output, invert_crop_xml)


if __name__ == '__main__':
    Gegl.init(None)
    unittest.main()
    Gegl.exit()
예제 #8
0
    # Get/Set current base value for the given setting
    print "Base value is: %f" % brush.get_base_value(setting)
    brush.set_base_value(setting, 2.0)
    assert brush.get_base_value(setting) == 2.0

    # Get dynamics for given setting
    inputs = [getattr(MyPaint.BrushInput, a) for a in dir(MyPaint.BrushInput) if a.startswith("INPUT_")]
    if not brush.is_constant(setting):
        for input in inputs:
            mapping_points = brush.get_mapping_n(setting, input)
            if mapping_points > 1:  # If 0, no dynamics for this input
                points = [brush.get_mapping_point(setting, input, i) for i in range(mapping_points)]
                print "Has dynamics for input %s:\n%s" % (input, str(points))

    # Create a surface to paint on
    Gegl.init(0, "")
    surface = MyPaintGegl.TiledSurface()
    s = surface.interface()

    print surface.get_buffer()

    for x, y in [(0.0, 0.0), (100.0, 100.0), (100.0, 200.0)]:
        dtime = 0.1  # XXX: Important to set correctly for speed calculations
        s.begin_atomic()
        brush.stroke_to(s, x, y, pressure=1.0, xtilt=0.0, ytilt=0.0, dtime=dtime)
        rect = s.end_atomic()
        print rect.x, rect.y, rect.width, rect.height

    Gegl.exit()
예제 #9
0
 def test_init(self):
     Gegl.init(0, "")
예제 #10
0
# This is a very minimal example, that doesnt even construct the graph and
# instantiate the nodes, but cheats and uses XML to get at an intial graph.
# it expect a file /tmp/lena.png to exist


def locate_by_type(self, opname):
    for i in self.get_children():
        if i.get_operation() == opname:
            return i


Gegl.Node.locate_by_type = locate_by_type

if __name__ == '__main__':

    Gegl.init(0, "")  # < that is rather ugly

    node = Gegl.Node.new_from_xml(
        """
      <gegl>
        <gegl:save path='/tmp/output.png'/>
        <gegl:crop width='512' height='512'/>
        <gegl:over >
          <gegl:translate x='30' y='30'/>
          <gegl:dropshadow radius='1.5' x='3' y='3'/>
          <gegl:text size='80' color='white'
><params><param name='string'>GEGL
 I
 R</param></params></gegl:text>
        </gegl:over>
        <gegl:unsharp-mask std-dev='30'/>
예제 #11
0
#!/usr/bin/env python

from gi.repository import Gegl
import sys

if __name__ == '__main__':
  Gegl.init(sys.argv)
  
  ptn = Gegl.Node()
  
  # Disable caching on all child nodes
  ptn.set_property("dont-cache", True)
  
  # Create our background buffer. A gegl:color node would
  # make more sense, we just use a buffer here as an example.
  background_buffer = Gegl.Buffer.new("RGBA float", 246, -10, 276, 276)
  white = Gegl.Color.new("#FFF")
  background_buffer.set_color(background_buffer.get_extent(), white)
  
  src = ptn.create_child("gegl:load")
  src.set_property("path", "data/surfer.png")
  
  crop = ptn.create_child("gegl:crop")
  crop.set_property("x", 256)
  crop.set_property("y", 0)
  crop.set_property("width", 256)
  crop.set_property("height", 256)
  
  buffer_src = ptn.create_child("gegl:buffer-source")
  buffer_src.set_property("buffer",background_buffer)
  
예제 #12
0
    def run(self, procedure, run_mode, image, drawable, args, run_data):
        if run_mode == Gimp.RunMode.INTERACTIVE:
            gi.require_version('Gtk', '3.0')
            from gi.repository import Gtk
            gi.require_version('Gdk', '3.0')
            from gi.repository import Gdk

            GimpUi.ui_init("palette-offset.py")

            dialog = GimpUi.Dialog(use_header_bar=True,
                                   title=_("Exercise a goat (Python 3)"),
                                   role="goat-exercise-Python3")

            dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL)
            dialog.add_button("_Source", Gtk.ResponseType.APPLY)
            dialog.add_button("_OK", Gtk.ResponseType.OK)

            geometry = Gdk.Geometry()
            geometry.min_aspect = 0.5
            geometry.max_aspect = 1.0
            dialog.set_geometry_hints(None, geometry, Gdk.WindowHints.ASPECT)

            box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2)
            dialog.get_content_area().add(box)
            box.show()

            # XXX We use printf-style string for sharing the localized
            # string. You may just use recommended Python format() or
            # any style you like in your plug-ins.
            head_text = ("This plug-in is an exercise in '%s' to "
                         "demo plug-in creation.\nCheck out the last "
                         "version of the source code online by clicking "
                         "the \"Source\" button." % ("Python 3"))
            label = Gtk.Label(label=head_text)
            box.pack_start(label, False, False, 1)
            label.show()

            contents = None
            # Get the file contents Python-style instead of using
            # GLib.file_get_contents() which returns bytes result, and
            # when converting to string, get newlines as text contents.
            # Rather than wasting time to figure this out, use Python
            # core API!
            with open(os.path.realpath(__file__), 'r') as f:
                contents = f.read()

            if contents is not None:
                scrolled = Gtk.ScrolledWindow()
                scrolled.set_vexpand(True)
                box.pack_start(scrolled, True, True, 1)
                scrolled.show()

                view = Gtk.TextView()
                view.set_wrap_mode(Gtk.WrapMode.WORD)
                view.set_editable(False)
                buffer = view.get_buffer()
                buffer.set_text(contents, -1)
                scrolled.add(view)
                view.show()

            while (True):
                response = dialog.run()
                if response == Gtk.ResponseType.OK:
                    dialog.destroy()
                    break
                elif response == Gtk.ResponseType.APPLY:
                    url = "https://gitlab.gnome.org/GNOME/gimp/-/blob/master/plug-ins/goat-exercises/goat-exercise-py3.py"
                    Gio.app_info_launch_default_for_uri(url, None)
                    continue
                else:
                    dialog.destroy()
                    return procedure.new_return_values(
                        Gimp.PDBStatusType.CANCEL, GLib.Error())

        intersect, x, y, width, height = drawable.mask_intersect()
        if intersect:
            Gegl.init(None)

            buffer = drawable.get_buffer()
            shadow_buffer = drawable.get_shadow_buffer()

            graph = Gegl.Node()
            input = graph.create_child("gegl:buffer-source")
            input.set_property("buffer", buffer)
            invert = graph.create_child("gegl:invert")
            output = graph.create_child("gegl:write-buffer")
            output.set_property("buffer", shadow_buffer)
            input.link(invert)
            invert.link(output)
            output.process()

            # This is extremely important in bindings, since we don't
            # unref buffers. If we don't explicitly flush a buffer, we
            # may left hanging forever. This step is usually done
            # during an unref().
            shadow_buffer.flush()

            drawable.merge_shadow(True)
            drawable.update(x, y, width, height)
            Gimp.displays_flush()

        return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS,
                                           GLib.Error())
예제 #13
0
#!/usr/bin/env python

from gi.repository import Gegl
import sys

if __name__ == '__main__':
    Gegl.init(sys.argv)

    ptn = Gegl.Node()

    # Disable caching on all child nodes
    ptn.set_property("dont-cache", True)

    # Create our background buffer. A gegl:color node would
    # make more sense, we just use a buffer here as an example.
    background_buffer = Gegl.Buffer.new("RGBA float", 246, -10, 276, 276)
    white = Gegl.Color.new("#FFF")
    background_buffer.set_color(background_buffer.get_extent(), white)

    src = ptn.create_child("gegl:load")
    src.set_property("path", "data/surfer.png")

    crop = ptn.create_child("gegl:crop")
    crop.set_property("x", 256)
    crop.set_property("y", 0)
    crop.set_property("width", 256)
    crop.set_property("height", 256)

    buffer_src = ptn.create_child("gegl:buffer-source")
    buffer_src.set_property("buffer", background_buffer)
예제 #14
0
파일: gegl.py 프로젝트: jsbueno/python-gegl
# coding: utf-8
# Author: João S. O. Bueno

import sys
import gi
gi.require_version("Gegl", "0.4")
from gi.repository import Gegl as _gegl
from .path import Path

DEFAULT_OP_NAMESPACE = "gegl"

_gegl.init(sys.argv[1:])

def list_operations(filter=""):
    ops = _gegl.list_operations()
    return [op for op in ops if filter in op]

class OpNode(object):
    """ Wrapper for a GEGL node with an operation

    You can access OpNode._node attribute for raw access
    to the GEGL node as exposed by pygobject
    """
    def __init__(self, operation, **kw):
        object.__setattr__(self, "_node",  _gegl.Node())
        # cyclic - TODO: replace with weakref
        self._node._wrapper = self
        self.operation = operation
        for key, value in kw.items():
            setattr(self, key, value)
예제 #15
0
 def test_100_init(self):
     Gegl.init(None)
예제 #16
0
    def test_number_of_children(self):
        children = self.graph.get_children()

        self.assertEqual(len(children), 2)

    def test_child_operation(self):
        children = self.graph.get_children()

        self.assertEqual(children[0].get_operation(), "gegl:crop")
        self.assertEqual(children[1].get_operation(), "gegl:invert")


class TestGeglNodeSaveXml(unittest.TestCase):

    def setUp(self):
        self.graph = Gegl.Node.new()

    # Easiest way to test to_xml when we can't yet build graphs programatically
    def test_load_save_roundtrip(self):
        graph = Gegl.Node.new_from_xml(invert_crop_xml, "")
        output = graph.to_xml("")

        self.assertEqual(output, invert_crop_xml)

if __name__ == '__main__':
    Gegl.init(0, "");
    #print dir(Gegl.Node)

    unittest.main()

예제 #17
0
# this binding would itself just import things using GI

# This is a very minimal example, that doesnt even construct the graph and
# instantiate the nodes, but cheats and uses XML to get at an intial graph.
# it expect a file /tmp/lena.png to exist

def locate_by_type(self, opname):
  for i in self.get_children():
     if i.get_operation() == opname:
        return i
Gegl.Node.locate_by_type = locate_by_type


if __name__ == '__main__':

    Gegl.init(0,"")  # < that is rather ugly

    node = Gegl.Node.new_from_xml("""
      <gegl>
        <gegl:save path='/tmp/output.png'/>
        <gegl:crop width='512' height='512'/>
        <gegl:over >
          <gegl:translate x='30' y='30'/>
          <gegl:dropshadow radius='1.5' x='3' y='3'/>
          <gegl:text size='80' color='white'
><params><param name='string'>GEGL
 I
 R</param></params></gegl:text>
        </gegl:over>
        <gegl:unsharp-mask std-dev='30'/>
        <gegl:load path='/tmp/lena.png'/>
예제 #18
0
 def test_init(self):
     Gegl.init(0, "")
예제 #19
0
 def test_init_exit(self):
     Gegl.init(0, "")
     Gegl.exit()
예제 #20
0
 def test_init_exit(self):
     Gegl.init(0, "")
     Gegl.exit()
예제 #21
0
        self.assertFalse(crop_rect.equal(trans_node.get_bounding_box()))

        trans_rect = crop_rect.dup()
        trans_rect.x += 10

        self.assertTrue(trans_rect.equal(trans_node.get_bounding_box()))

class TestGeglXml(unittest.TestCase):

    def test_load_xml(self):
        graph = Gegl.Node.new_from_xml(invert_crop_xml, "")

        children = graph.get_children()

        self.assertEqual(len(children), 2)

        self.assertEqual(children[0].get_operation(), "gegl:crop")
        self.assertEqual(children[1].get_operation(), "gegl:invert-linear")

    def test_load_save_roundtrip(self):
        graph = Gegl.Node.new_from_xml(invert_crop_xml, "")
        output = graph.to_xml("")

        self.assertEqual(output, invert_crop_xml)

if __name__ == '__main__':
    Gegl.init(None);
    unittest.main()
    Gegl.exit()
예제 #22
0
    def test_number_of_children(self):
        children = self.graph.get_children()

        self.assertEqual(len(children), 2)

    def test_child_operation(self):
        children = self.graph.get_children()

        self.assertEqual(children[0].get_operation(), "gegl:crop")
        self.assertEqual(children[1].get_operation(), "gegl:invert")


class TestGeglNodeSaveXml(unittest.TestCase):
    def setUp(self):
        self.graph = Gegl.Node.new()

    # Easiest way to test to_xml when we can't yet build graphs programatically
    def test_load_save_roundtrip(self):
        graph = Gegl.Node.new_from_xml(invert_crop_xml, "")
        output = graph.to_xml("")

        self.assertEqual(output, invert_crop_xml)


if __name__ == '__main__':
    Gegl.init(0, "")
    #print dir(Gegl.Node)

    unittest.main()
예제 #23
0
    def init_ui(self):
        window = Gtk.Window()
        window.connect("destroy", self.destroy_cb)
        window.connect("size-allocate", self.size_allocate_cb)

        view_widget = GeglGtk.View()
        view_widget.set_node(self.add)
        view_widget.set_autoscale_policy(GeglGtk.ViewAutoscale.DISABLED)
        view_widget.set_size_request(800, 400)
        window.add(view_widget)

        window.show_all()

    def run(self):
        return Gtk.main()

    def destroy_cb(self, *ignored):
        Gtk.main_quit()

    def size_allocate_cb(self, widget, allocation):
        self.color.set_property("width", allocation.width)
        self.color.set_property("height", allocation.height)

if __name__ == '__main__':
    Gegl.init([])
    Gtk.init([])

    app = TintApp()
    app.run()
예제 #24
0
def something():

    #MyPaint.init()

    # Create a brush, load from disk
    brush = MyPaint.Brush()
    brush_def = open("brushes/classic/brush.myb").read()
    brush.from_string(brush_def)

    # List all settings
    # TODO: Is there a better way to list all enums with GI?
    settings = [
        getattr(MyPaint.BrushSetting, attr)
        for attr in dir(MyPaint.BrushSetting) if attr.startswith("SETTING_")
    ]
    print "Available settings: %s\n" % str(settings)

    # Get info about a given setting
    setting = MyPaint.BrushSetting.SETTING_RADIUS_LOGARITHMIC
    info = MyPaint.brush_setting_info(setting)

    # TODO: rename "def_" to "default"
    print "Setting: %s\n\t Max: %f \n\t Default: %f \n\t Min: %f" % (
        info.cname, info.max, info.def_, info.min)
    print "\t Name: %s\n\t Tooltip: '%s'\n" % (
        info.get_name(), info.get_tooltip()
    )  # Use the getters so that i18n works

    # TODO: should be MyPaint.BrushSetting.from_cname
    # Same with MyPaint.Brush.input_from_cname
    assert (MyPaint.Brush.setting_from_cname(info.cname) == setting)

    # Get/Set current base value for the given setting
    print "Base value is: %f" % brush.get_base_value(setting)
    brush.set_base_value(setting, 2.0)
    assert brush.get_base_value(setting) == 2.0

    # Get dynamics for given setting
    inputs = [
        getattr(MyPaint.BrushInput, a) for a in dir(MyPaint.BrushInput)
        if a.startswith('INPUT_')
    ]
    if not brush.is_constant(setting):
        for input in inputs:
            mapping_points = brush.get_mapping_n(setting, input)
            if mapping_points > 1:  # If 0, no dynamics for this input
                points = [
                    brush.get_mapping_point(setting, input, i)
                    for i in range(mapping_points)
                ]
                print "Has dynamics for input %s:\n%s" % (input, str(points))

    # Create a surface to paint on
    Gegl.init(0, "")
    surface = MyPaintGegl.TiledSurface()
    s = surface.interface()

    print surface.get_buffer()

    for x, y in [(0.0, 0.0), (100.0, 100.0), (100.0, 200.0)]:
        dtime = 0.1  # XXX: Important to set correctly for speed calculations
        s.begin_atomic()
        brush.stroke_to(s,
                        x,
                        y,
                        pressure=1.0,
                        xtilt=0.0,
                        ytilt=0.0,
                        dtime=dtime)
        rect = s.end_atomic()
        print rect.x, rect.y, rect.width, rect.height

    Gegl.exit()