Figured it out.
The ability to render an image with a configurable interpolation seems pretty straightforward, but instead I had to subclass the generic widget and implement my own scaling, which is not intuitive to me.
I suppose this is because a paintable is not necessarily pixel data, in which case interpolation does not apply, so the generic interface doesn’t provide for this circumstance and when pixel data is scaled, it just makes an assumption on the interpolation method. It’s weird to me, but is what it is.
My solution:
#!/usr/bin/python3
import sys
import gi
gi.require_version("Gtk", "4.0")
gi.require_version("Adw", "1")
gi.require_version("GdkPixbuf", "2.0")
from gi.repository import Gtk, Adw, GdkPixbuf # noqa: E402
from gi.repository import Gdk, Graphene # noqa: E402
class BlockyImage(Gtk.Widget):
def __init__(self, pixbuf, *args, **kwargs):
super().__init__(*args, **kwargs)
self.pixbuf = pixbuf
def do_snapshot(self, snapshot):
w = self.get_width()
h = self.get_height()
pixbuf = self.pixbuf.scale_simple(w, h, GdkPixbuf.InterpType.NEAREST)
texture = Gdk.Texture.new_for_pixbuf(pixbuf)
snapshot.append_texture(texture, Graphene.Rect().init(0, 0, w, h))
class MainWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
img = sum([[x * 8, y * 8, 0] for x in range(32) for y in range(16)], [])
pixbuf = GdkPixbuf.Pixbuf.new_from_data(
img,
colorspace=GdkPixbuf.Colorspace.RGB,
has_alpha=False,
bits_per_sample=8,
width=32,
height=16,
rowstride=32 * 3,
)
self.screen = BlockyImage(pixbuf)
self.screen.set_hexpand(True)
self.screen.set_vexpand(True)
self.screen.set_valign(Gtk.Align.FILL)
self.screen.set_halign(Gtk.Align.FILL)
self.hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
self.hbox.append(self.screen)
self.set_child(self.hbox)
class MyApp(Adw.Application):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.connect("activate", self.on_activate)
def on_activate(self, app):
self.win = MainWindow(application=app)
self.win.present()
app = MyApp(application_id="test.local.test1")
app.run(sys.argv)