GNOME Gsf

こんなの見つけた。

Zip files: GSF Reference Manual

何だよ、GNOME には ZIP ファイルを扱うライブラリがあったのか。
GLib や Gio ばかり見ていて気が付かなかった。

gsf_gir

Fedora 24 には普通に最初から libgsf が入っていますね。
GObject Introspection からも使える、これは使わない手はない。
以下は Vala だけどサンプルコードも見つかった。

Projects/Vala/GSFSample – GNOME Wiki!

早速コードを書いてみたけど色々困った。
gsf_infile_num_children はアーカイブの一階層分しか得ることができない。
階層がある場合は gsf_infile_num_children の戻り値を再帰するしかない。

しかも二階層以下はソートが名前の逆順に。
Python の ZIP ファイルもそうだったけど何故だ?
しかたがないので一階層以降は逆順の再帰で。

ついでに、サイズ取得が何故かプロパティ。
gst_input_size は size_t で size property は int64 だし。
意味ワカンネェけど動いたからいいや。

#!/usr/bin/env python3

import sys, gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gsf', '1')
from gi.repository import Gtk, Gio, GdkPixbuf, Gsf

PATH = "ziptest.cbz";
#PATH = "なえコレ.zip"

class GsfTest(Gtk.ApplicationWindow):
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app)
        self.datas = []
        # unzip
        f = Gsf.InputStdio.new(PATH)
        infile = Gsf.InfileZip.new(f)
        self.read_zipfile(infile)
        # add
        fbox = Gtk.FlowBox(valign=Gtk.Align.START, min_children_per_line=5)
        for data in self.datas:
            fbox.add(data)
        self.add(fbox)
        self.show_all()

    def read_zipfile(self, infile):
        num = infile.num_children()
        for i in range(num):
            item = infile.child_by_index(i)
            if item.size == 0:
                self.read_childfile(item)
            else:
                self.append_data(infile, item)

    def read_childfile(self, infile):
        num = infile.num_children()
        for i in range(num-1, -1, -1):
            item = infile.child_by_index(i)
            if item.size == 0:
                # recursive function
                self.read_childfile(item)
            else:
                self.append_data(infile, item)

    def append_data(self, infile, item):
        data = item.read(item.size)
        try:
            stream = Gio.MemoryInputStream.new_from_data(data)
            p = GdkPixbuf.Pixbuf.new_from_stream(stream)
            minp = p.scale_simple(80, 100, GdkPixbuf.InterpType.BILINEAR)
            image = Gtk.Image(pixbuf=minp)
            self.datas.append(image)
        except Exception as e:
            print(e)


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

    def do_activate(self):
        GsfTest(self)

app = GsfApp()
app.run(sys.argv)

コレでイケたけど。
階層の名前を取り出してソートしたほうが無難だろうか?

それより問題は速度がどうなるかだ。
Comipoli beta3 | PaePoi
の時からどう変わったか Comipoli に組み込んで同じ巨大ファイルを。

gsf_cpu

あんまり変わんねえヤン…
期待したのに。
せっかく安定して動いているのを変えるべきか悩む。