Noisy cairo — создал пользовательский курсор в GTK3

#cursor #gtk #cairo #pygobject #gdk

#курсор #gtk #cairo #pygobject #gdk

Вопрос:

Я работаю над инструментом аннотации изображений. Он включает в себя рисование кругов разного размера поверх изображения. Для удобства я хотел бы изменить курсор, чтобы он был окружностью некоторого радиуса. Приведенный ниже фрагмент (в частности, функция custom_cursor ()) позволяет мне использовать пользовательский курсор (нарисованный с помощью cairo) и изменять его радиус с помощью клавиш скобок («[» и «]»). Проблема, с которой я столкнулся, очевидна в этом видео:https://imgur.com/a/swEmbzL . В принципе, при некоторых значениях радиусов возникает множество артефактов, покрывающих все изображение курсора. В чем причина этого и возможно ли устранить этот шум?

 import gi
import numpy as np
import cairo
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GdkPixbuf

class MainWindow(Gtk.Window):

  def __init__(self):
    Gtk.Window.__init__(self, title = "Test")
    self.maximize()
    self.radius = 137
    viewport = Gtk.Viewport()
    self.darea = Gtk.DrawingArea()
    self.darea.connect("draw", self.draw)
    self.pixbuf = GdkPixbuf.Pixbuf.new_from_file("any_image.jpg")
    self.darea.set_size_request(self.pixbuf.get_width(), self.pixbuf.get_height());
    grid = Gtk.Grid()
    self.add(grid)
    scrolled = Gtk.ScrolledWindow()
    scrolled.set_hexpand(True)
    scrolled.set_vexpand(True)
    scrolled.connect("key-press-event",self.press)
    viewport.add(self.darea)
    scrolled.add(viewport)
    grid.add(scrolled)
    self.custom_cursor(self.radius)

  def draw(self, widget, cr):
    Gdk.cairo_set_source_pixbuf(cr, self.pixbuf, 0, 0)
    cr.paint()
    self.darea.queue_draw()

  def custom_cursor(self, radius):
    display = self.get_screen().get_display()
    pb = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, 2 * radius, 2 * radius)
    surface = Gdk.cairo_surface_create_from_pixbuf(pb, 0, None)
    context = cairo.Context(surface)
    context.arc(radius, radius, radius, 0, 2 * np.pi)
    context.set_source_rgba(0, 0, 0, 1)
    context.stroke()
    pbdrawn = Gdk.pixbuf_get_from_surface(surface, 0, 0, surface.get_width(), surface.get_height())
    cursor = Gdk.Cursor.new_from_pixbuf(display, pbdrawn, radius, radius)
    self.darea.get_screen().get_root_window().set_cursor(cursor)

  def press(self, widget, event):
    if (event.keyval == 93):
      self.radius = self.radius   2
      self.custom_cursor(self.radius)
    elif (event.keyval == 91):
      self.radius = self.radius - 2
      self.custom_cursor(self.radius)

win = MainWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
  

Редактировать: Это может быть проблема с графикой. Я был бы признателен, если бы кто-нибудь мог подтвердить, что есть (нет) шума.

Комментарии:

1. Что именно делает ваша custom_cursor функция? Он создает pixbuf, преобразует его в cairo surface, а затем снова преобразует его в pixbuf? Почему вы вообще начинаете с pixbuf?

2. Это справедливый вопрос. Вы правы, нет необходимости начинать с pixbuf. Проблема решена. Спасибо!

Ответ №1:

Из документации для gdk_pixbuf_new :

Обратите внимание, что буфер не очищен; вам придется заполнить его полностью самостоятельно.

https://developer.gnome.org/gdk-pixbuf/2.36/gdk-pixbuf-Image-Data-in-Memory.html#gdk-pixbuf-new

По сути, вы видите здесь неинициализированную память.

Я бы предложил просто создать поверхность изображения cairo напрямую, вместо создания pixbuf просто для преобразования его в cairo surface. Cairo инициализирует для вас новую поверхность изображения.