Integração GTK e Cairo Para Criação de Aplicação de Pintura Digital

Há algumas semanas iniciei estudos sobre como usar Python, GTK e Cairo para desenvolver aplicativos de pintura digital. Li sobre a arquitetura e o fluxo de programas como Krita, GIMP, MyPaint e Clip Studio Paint, especialmente sua interface, o modelo dos pincéis e o pipeline de renderização. Embora GTK + Cairo seja minha escolha principal, também é possível criar soluções similares com Qt (usando PySide em Python ou C++ nativo).

Para montar essa base, utilizei dois recursos fundamentais:

  1. Gtk.DrawingArea – fornece a “tela” onde tudo é desenhado e captura eventos de mouse/mesa digitalizadora.

  2. Cairo – cria e gerencia os buffers de desenho, permitindo implementar o pincel e as operações gráficas.

No Windows, instalei o MSYS2 para obter o GCC, Python, GTK, Cairo e PyGObject; depois empacotei o executável com PyInstaller. No Linux, basta usar o gerenciador de pacotes (por exemplo, apt install python3-gi python3-gi-cairo gir1.2-gtk-3.0) para ter tudo pronto.


Introdução ao GTK + Cairo

  • GTK (GIMP Toolkit) é a biblioteca de GUI: janelas, botões, menus e áreas de desenho (Gtk.DrawingArea).

  • Cairo é a biblioteca de gráficos 2D vetoriais: linhas, formas, texto e imagens, com antialiasing e transparência, via cairo.Context.

  • Integração: sempre que a DrawingArea precisa ser redesenhada, o GTK emite o sinal "draw" e passa um contexto Cairo (cr) para sua função de callback. Você desenha no cr, e o GTK exibe o resultado.

Fluxo resumido

  1. Crie um widget Gtk.DrawingArea.

  2. Conecte o sinal "draw" ao seu método de desenho.

  3. No callback, use o cairo.Context para pintar formas, cores e texturas.

  4. Chame queue_draw() sempre que precisar atualizar a tela (por clique ou movimento).


Exemplo minimalista em Python

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
import cairo

class AreaDesenho(Gtk.DrawingArea):
    def __init__(self):
        super().__init__()
        self.set_size_request(400, 300)
        self.pontos = []
        self.set_events(Gdk.EventMask.BUTTON_PRESS_MASK |
                        Gdk.EventMask.POINTER_MOTION_MASK)
        self.connect("draw", self.on_draw)
        self.connect("button-press-event", self.on_press)
        self.connect("motion-notify-event", self.on_move)

    def on_draw(self, widget, cr):
        # Limpa o fundo
        cr.set_source_rgb(1, 1, 1)
        cr.paint()
        # Desenha traços
        cr.set_source_rgb(0, 0, 0)
        cr.set_line_width(2)
        for p1, p2 in zip(self.pontos, self.pontos[1:]):
            cr.move_to(*p1)
            cr.line_to(*p2)
        cr.stroke()
        return False

    def on_press(self, widget, event):
        self.pontos.append((event.x, event.y))
        self.queue_draw()

    def on_move(self, widget, event):
        if event.state & Gdk.ModifierType.BUTTON1_MASK:
            self.pontos.append((event.x, event.y))
            self.queue_draw()

class JanelaDesenho(Gtk.Window):
    def __init__(self):
        super().__init__(title="Desenho Digital")
        self.set_default_size(400, 300)
        self.connect("destroy", Gtk.main_quit)
        self.add(AreaDesenho())

JanelaDesenho().show_all()
Gtk.main()

Como funciona

  1. AreaDesenho herda de Gtk.DrawingArea e armazena pontos do mouse.

  2. No evento "draw", pinta o fundo e traça linhas entre os pontos coletados.

  3. Eventos de clique e arrasto (button-press-event e motion-notify-event) registram os pontos e solicitam redesenho com queue_draw().


Referências

Gostou deste material e do conteúdo do blog considere apoiar o desenvolvimento do mesmo visitando nossa página "Como Contribuir". Também é possível contribuir divulgando e comentando ajudando a desenvolver e melhorar o conteúdo aqui disponível. Post comumente compartilhado no mural Apoiase da minha página Dimensão Alfa
 
 
Agradece, 
 
Wandeson Ricardo  

Nenhum comentário:

Postar um comentário