Paepoi

Paepoi » PyGObject Tips » GdkPixbuf(PyGObject) Tips

GdkPixbuf(PyGObject) Tips

# 最終更新日 2019.09.14

新規追加。

画像の変換とリサイズ
筆者が Gedit Plugin a_href_picture でやっている縮小画像作成です。
単純に変換だけを行なうなら下記 pixbuf を savev してください。
#!/usr/bin/env python3

import gi, os
gi.require_version('GdkPixbuf', '2.0')
from gi.repository import GdkPixbuf

# 同一ディレクトリにある画像ファイル名と縮小後の最大サイズを指定
FILENAME = '刀.jpg'
MAX_SIZE = 300

pixbuf = GdkPixbuf.Pixbuf.new_from_file(FILENAME)
aw = ah = MAX_SIZE
w = pixbuf.get_width()
h = pixbuf.get_height()
if w > aw or h > ah:
    cleate = True
    if (aw * h) > (ah * w):
        width = w * ah // h
        height = ah
    else:
        width = aw
        height = h * aw // w
    smallpix = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.BILINEAR)
    # jpeg と png を変換して保存
    # 圧縮率は GIMP エクスポートのデフォルト値に合わせています
    name, ext = os.path.splitext(FILENAME)
    lext = ext.lower()
    if lext == '.jpg' or lext == '.jpeg':
        smallpath = f'{name}-{width}x{height}.png'
        smallpix.savev(smallpath, 'png', ['compression'], ['9'])
    elif lext == '.png':
        smallpath = f'{name}-{width}x{height}.jpeg'
        smallpix.savev(smallpath, 'jpeg', ['quality'], ['85'])

ZIP ファイル内画像の読み込み
筆者が Comipoli というアプリでやっている ZIP 内の画像読み込みです。
init 内で読み込んでもいいのですが非同期にしないと全部完了するまで表示されません。
#!/usr/bin/env python3

import sys, re, gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib, Gio, GdkPixbuf

ZIPFILENAME = '愛知JK.zip'

class Win(Gtk.ApplicationWindow):
    '''
        zipfile, subprocess モジュールを使ってもいいです
        そちらは Comipoli macOS 版でやっています
        GSubprocess は直接 input_stream を得られるのでコチラを利用
    '''
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app, title='Py')
        self.fbox = Gtk.FlowBox(
            valign=Gtk.Align.START,
            max_children_per_line=10,
            homogeneous=True,
            selection_mode=Gtk.SelectionMode.BROWSE)
        # ファイル名リストの作成
        self.namelist = []
        sp = Gio.Subprocess.new(['zipinfo', '-1', ZIPFILENAME], Gio.SubprocessFlags.STDOUT_PIPE)
        istream = sp.get_stdout_pipe()
        dstream = Gio.DataInputStream(base_stream=istream)
        while True:
            line = dstream.read_line_utf8()[0]
            if line == None:
                break
            if re.search('\.(jpe?g|png|gif)$', line, re.I):
                self.namelist.append(line)
        self.namelist.sort()
        #
        scroll = Gtk.ScrolledWindow(child=self.fbox)
        self.add(scroll)
        self.resize(300, 200)
        self.show_all()
        # 非同期読み込み開始
        self.generator = self.add_thumbnail()
        GLib.idle_add(self.idle_function)

    def idle_function(self):
        try:
            next(self.generator)
            return True
        except StopIteration:
            return False

    def add_thumbnail(self):
        for name in self.namelist:
            ename = self._zip_escape(name)
            cmd_array = ['unzip', '-pj', ZIPFILENAME, ename]
            sp = Gio.Subprocess.new(cmd_array, Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_MERGE)
            sp.wait_check_async(None, self._on_wait)
            stream = sp.get_stdout_pipe()
            p = GdkPixbuf.Pixbuf.new_from_stream_at_scale(stream, 100, 100, True)
            image = Gtk.Image(pixbuf=p, visible=True)
            self.fbox.add(image)
            yield 1

    def _zip_escape(self, filename):
        '''
            unzip は以下をエスケープする必要あり
        '''
        ESCAPE = '[]*?!^-\\'
        res = ''
        for s in filename:
            if s in ESCAPE:
                res += '\\'
            res += s
        return res

    def _on_wait(self, proc, res):
        '''
            wait については fork wait で検索
        '''
        proc.wait_check_finish(res)

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self)

    def do_startup(self):
        Gtk.Application.do_startup(self)
        Win(self)

    def do_activate(self):
        self.props.active_window.present()

app = App()
app.run(sys.argv)
etc/pixbuf01.png
XPM 画像をソースに埋め込む
筆者が以前 Clipoli というアプリを作っていた時にやっていた手法です。
XPM 画像は GIMP 等で作成できるメタデータの画像形式です。
つまり文字列、配列内を Python の list としてコピペすればソースコードに埋め込み可能。
#!/usr/bin/env python3

import gi, sys
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib, GdkPixbuf
 
ICON = [
"32 32 3 1",
"   c None",
".  c #000000",
"+  c #FFFFFF",
"                                ",
"   ............                 ",
"   .++++++++++.                 ",
"   .++++++++++. ......          ",
"   .++++++++++. .++++.          ",
"   .++++++++++. .++++.          ",
"   .++++...+++. .++++.          ",
"   .++++....... .++++.          ",
"   .++++.       .++++.          ",
"   .++++.       .++++.          ",
"   .++++.       .++++. ......   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. ......   ",
"   .++++.       .++++.          ",
"   .++++.       .++++. ......   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++.       .++++. .++++.   ",
"   .++++....... .++++. .++++.   ",
"   .++++...+++. .++++. .++++.   ",
"   .++++++++++. .++++. .++++.   ",
"   .++++++++++. .++++. .++++.   ",
"   .++++++++++. .++++. .++++.   ",
"   .++++++++++. .++++. .++++.   ",
"   ............ ...... ......   ",
"                                "]
 
 
class Win(Gtk.ApplicationWindow):
    '''
        Alt+A でボタンが押されるのが解る
    '''
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app, title='Py')
        # Icon as XPM data
        pixbuf = GdkPixbuf.Pixbuf.new_from_xpm_data(ICON)
        image = Gtk.Image(pixbuf=pixbuf)
        self.add(image)
        self.show_all()
 
class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self)

    def do_startup(self):
        Gtk.Application.do_startup(self)
        Win(self)

    def do_activate(self):
        self.props.active_window.present()

app = App()
app.run(sys.argv)
etc/pixbuf02.png
Copyright(C) sasakima-nao All rights reserved 2002 --- 2020.