mieki256's diary



2022/05/20(金) [n年前の日記]

#1 [gimp][linux][ubuntu] Linux版GIMPはPython-Fuが使えなくなってた

最近の Linux版GIMP は Python-Fu (Gimp-Python) が使えない状態になっていたらしい。恥ずかしながら今頃になってようやく知った。

正確には、Debian Linux 11 bullseye や Ubuntu Linux 20.04 LTS の公式リポジトリからインストールできる GIMP 2.10 は、Python-Fu (Gimp-Python)が利用できない状態で何年も放置されている模様。

理由としては、Pythonが絡んでいるっぽい。Debian も Ubuntu も、Python 2.x から 3.x への移行を進めているので、Python 2.x を利用するパッケージを切り捨てる方向で動いているそうで。そして、GIMP の Python-Fu (Gimp-Python) は Python 2.x に依存しているので、関連パッケージも公式リポジトリからあっさり削除されてしまったのだとか。

昔は gimp-python というパッケージが存在していて、sudo apt install gimp-python をするだけで使えるようになったらしいけど…。今は、そんなパッケージは存在しない。Debian 11、Ubuntu 20.04、どちらも見つからなかった。

回避策は無いのかとググってみたら、flatpak (flathub) 版GIMPなら Python-Fu もサポートしているので、「Python-Fu が使いたければ公式リポジトリ版ではなく flatpak版を使いましょう」ということになっているっぽい。

そんなわけで試してみた。環境は、Ubuntu Linux 20.04 LTS 64bit。Xubuntu関連パッケージをインストールして、デスクトップ環境は Xfce4 で利用している。ちなみに CPU は AMD A8-3850。

flatpakをインストール。 :

Ubuntu Linux 20.04 LTS 上で flatpak をインストールする手順は以前の日記でメモしてあった。

_mieki256's diary - wxPython関係をUbuntu 20.04上で試用

sudo apt install flatpak
sudo apt install gnome-software-plugin-flatpak
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
sudo reboot

GIMPをインストール。 :

基本的には以下のページに従えば良い。

_GNU Image Manipulation Program - Linux Apps on Flathub
flatpak install flathub org.gimp.GIMP


ただ、今回は、GUIアプリ上から ―― gnome-software (ソフトウェア)経由でインストールしてみた。
  1. スタートメニュー(?)の検索欄に「software」と打ち込んだら「ソフトウェア」がリストアップされたので起動。
  2. 左上の虫メガネアイコンをクリックして、「gimp」で検索。
  3. リストアップされた「GIMP (GNU Image...」をクリックして詳細説明(?)を表示。
  4. 右上の「ソース」の項目が「Flathub」になっていることを確認して、「インストール」をクリック。

flatpak_gimp_install_ss01.png

flatpak_gimp_install_ss02.png

flatpak_gimp_install_ss03.png


インストールが終了したら、インストールしたアプリの一覧を表示して確認してみる。端末を開いて以下を打つ。
flatpak list

中に、以下の行がある…はず。
GIMP (GNU Image Manipulation Program)  org.gimp.GIMP  2.10.30  stable  flathub  system

これで、GIMP 2.10.30 がインストールされた。

GIMPを起動。 :

実行は、端末上で以下を打つ。
flatpak run org.gimp.GIMP

しかし、一々こうして打ち込んで起動するのは面倒臭い。

本来、flatpak 経由でインストールすると、スタートメニューの類にも登録されるらしいのだけど、何故か自分の環境では、メニューに登録されなかった。

ただ、メニューに登録されるべき、.desktop ファイル (Windowsのショートカットファイルみたいなもの?)は、以下の場所に存在している。

ls /var/lib/flatpak/exports/share/applications/

中に、org.gimp.GIMP.desktop というファイルが存在する。これを、自分のアカウントの、所定の場所にコピーする。

cp /var/lib/flatpak/exports/share/applications/org.gimp.GIMP.desktop /home/(USERNAME)/.local/share/applications/

これで、Ubuntu (Xubuntu) のスタートメニュー(?)の、「グラフィックス」の項に、GIMPの項目が追加された。

GIMPのプラグインの場所。 :

GIMP を起動してみたところ、フィルターメニューの中に、Python-Fu が存在していた。

flatpak_gimp_install_ss04.png

ということで、たしかに flatpak版GIMPなら Python-Fu が使えるらしい。

また、編集 → 設定 → フォルダー → プラグイン or スクリプト、で、Python-Fuスクリプトや Script-Fuスクリプトを置く場所が指定されているはずだけど、自分の環境では、記述が無いのに、何故か以下のフォルダの内容も読み取っていた。

~/.config/GIMP/2.10/plug-ins/*.py
~/.config/GIMP/2.10/scripts/*.scm

この2つのフォルダは、Ubuntu公式リポジトリ版の GIMP をインストールした際に参照される場所なのだけど…。でもまあ、動いてるから良しとする。

ちなみに、 *.py や *.scm に実行権限がついてないとGIMPがプラグインとして認識しない、という話もどこかで見かけたので、一応、念のため、各スクリプトファイルに対して実行権限をつけておいた。

cd ~/.config/GIMP/2.10/plug-ins/
chmod +x *.py


flatpak版GIMPを導入することで Python-Fu も使えると分かったので、以下のスクリプトが動作することも確認できた。

_mieki256/sci-fi-texture-generator: Sci-Fi bump mapping texture generator with GIMP Script-fu.

以下、証拠画像。

flatpak_gimp_install_ss05.png


このスクリプトが動いたということは…。flatpak版GIMP は、pycairo も使える状態になっているようだなと。Python-Fuコンソールを開いて、import cairo と打ってみても、エラーが出ないし。

>>> cairo.version
'1.10.0'

>>> cairo.cairo_version_string()
'1.16.0'

pycairo の現行バージョンは 1.21.0 だけど、それと比べると、GIMP同梱の pycairo は 1.10.0 と結構古い。

また、Ubuntu公式リポジトリ版の python-cairo は、バージョンが 1.16.2-2ubuntu2 と表示されたので *1 、flatpak版GIMP には、公式リポジトリ版とは違う pycairo が含まれているのだろう。たぶん。

2022/05/21追記。 :

Ubuntu Linux 18.04 LTS 上でも動作確認してみた。Ubuntu 18.04 LTS なら、公式リポジトリ版 GIMP 2.8.22 でも Python-Fu (Gimp-Python) が利用できた。また、Python-Fuコンソール上で import cairo もできた。cairo.version は '1.16.2'。cairo.cairo_version_string() は '1.15.10'。

*1: sudo apt show python-cairo と打てばバージョンが確認できる。

#2 [python][gimp] Python 3 でARGBからRGBAに変換

Windows10 x64 21H2 + Python 3.9.12 64bit の環境で、ARGB(BRGA)からRGBAに変換する処理を試してみた。

ちなみに、Python 2.7.18 を使って処理する版は、 _昨日 試した。

とりあえず、Python 3.9.12 で動く処理だけ抜き出してベンチマークを取ってみた。

_05_argb_rgba_conv_py3.py
from benchmarker import Benchmarker
import struct
import sys

# check_data_enable = True
check_data_enable = False

LOOP = 5

if sys.version_info.major != 3:
    print("This script is compatible only with Python3.")
    sys.exit()


def create_src_data():
    print("start.")
    r, g, b, a = 0, 1, 2, 3
    w, h = 2048, 2048
    rgba = bytearray(w * h * 4)
    for i in range(0, len(rgba), 4):
        rgba[i], rgba[i + 1], rgba[i + 2], rgba[i + 3] = b, g, r, a
    src = rgba
    print("create source data. %d byte" % len(src))
    # for i in range(8):
    #     print(src[i])
    return src


def get_rgba_str_g(src):
    lmax = len(src) // 4
    argb = list(struct.unpack("=%dL" % lmax, src))
    rgba = [(((d & 0x0ffffff) << 8) + ((d >> 24) & 0x0ff)) for d in argb]
    return struct.pack(">%dL" % lmax, *rgba)


def get_rgba_str_j(src):
    cnt = len(src)
    dst = bytearray(cnt)
    if sys.byteorder == "little":
        for i in range(0, cnt, 4):
            dst[i], dst[i + 1], dst[i + 2], dst[i + 3] = src[i + 2], src[i + 1], src[i], src[i + 3]
    else:
        for i in range(0, cnt, 4):
            dst[i], dst[i + 1], dst[i + 2], dst[i + 3] = src[i + 1], src[i + 2], src[i + 3], src[i]
    return dst


def check_result(src):
    print("compare")
    dst = []
    dst.append(get_rgba_str_g(src))
    dst.append(get_rgba_str_j(src))
    for i in range(1, len(dst)):
        if dst[0] == dst[i]:
            print("Success [%d]" % i)
        else:
            print("Failure [%d]" % i)


src = create_src_data()

if check_data_enable:
    # compare result data
    check_result(src)
    sys.exit()

with Benchmarker(LOOP, width=20) as bench:

    @bench("rgb shift G")
    def check_use_rgb_shift_g(bm):
        get_rgba_str_g(src)

    @bench("rgb shift J")
    def check_use_rgb_shift_j(bm):
        get_rgba_str_j(src)

ベンチマーク結果は以下。

> py -3 05_argb_rgba_conv_py3.py
start.
create source data. 16777216 byte
## benchmarker:         release 4.0.1 (for python)
## python version:      3.9.12
## python compiler:     MSC v.1929 64 bit (AMD64)
## python platform:     Windows-10-10.0.19044-SP0
## python executable:   C:\Python\Python39-64\python.exe
## cpu model:           AMD64 Family 23 Model 113 Stepping 0, AuthenticAMD
## parameters:          loop=5, cycle=1, extra=0

##                        real    (total    = user    + sys)
rgb shift G             0.8407    0.8438    0.7344    0.1094
rgb shift J             1.4964    1.5000    1.4844    0.0156

## Ranking                real
rgb shift G             0.8407  (100.0) ********************
rgb shift J             1.4964  ( 56.2) ***********

## Matrix                 real    [01]    [02]
[01] rgb shift G        0.8407   100.0   178.0
[02] rgb shift J        1.4964    56.2   100.0

やはり、bytearray を使って入れ替えていく書き方は、struct.pack や unpack、リスト内包表記を使う書き方と比べると、ちょっと遅い模様。

また、Python 2.7 より 3.9 で処理するほうが、処理時間が短くなる場合もあるらしい。Python 2.7 では 1秒台だった処理が、Python 3.9 では 0.84秒になった。

2022/05/19(木) [n年前の日記]

#1 [python][gimp] Python-FuでARGB(BRGA)をRGBAにしたい

GIMP の Python-Fu + pycairo を使って、何かしらを描画して、GIMPのレイヤーに転送したい。

pycairo の surface は、1ドットにつきARGB(リトルエンディアンならBRGA)の並びで格納されている。対して、GIMPのレイヤーは1ドットにつきRGBAの並びになっているので、ARGB(BRGA)からRGBAに並びを変更する処理を書かないといけない。

以前、そういった処理に関してベンチマークを取りながら、16秒かかってた処理を1.7秒まで短くできたけれど。

_mieki256's diary - Pythonのリスト内包表記を試してみた
_mieki256's diary - Pythonのstructを使った時の処理時間を調べてた

リトルエンディアン、ビッグエンディアンを事前に判定してその後の処理を変えれば、もっとシンプルに書けるのではないか、処理時間も短くならないかと思えてきたので、そういう処理を試してみた。

環境は、Windows10 x64 21H2 + Python 2.7.18 32bit。ちなみに、前回実験した時は CPU が Ryzen 7 1700 だったけど、Ryzen 5 3600 に変わっているので、処理時間が少し短くなってる。

以下が、実験用スクリプト。

_04_argb_rgba_conv_2.py

関係ありそうなところだけを引用。get_rgba_str_g() が、今のところ最短時間で処理できる書き方。get_rgba_str_(h|i|j)() が、今回試した書き方。

def get_rgba_str_g(src):
    lmax = len(src) / 4
    argb = list(struct.unpack("=%dL" % lmax, src))
    rgba = [(((d & 0x0ffffff) << 8) + ((d >> 24) & 0x0ff)) for d in argb]
    return struct.pack(">%dL" % lmax, *rgba)


def get_rgba_str_h(src):
    dst = list(src)
    if sys.byteorder == "little":
        for i in range(0, len(src), 4):
            dst[i], dst[i + 1], dst[i + 2], dst[i + 3] = src[i + 2], src[i + 1], src[i], src[i + 3]
    else:
        for i in range(0, len(src), 4):
            dst[i], dst[i + 1], dst[i + 2], dst[i + 3] = src[i + 1], src[i + 2], src[i + 3], src[i]
    return ''.join(dst)


def get_rgba_str_i(src):
    dst = list(src)
    if sys.byteorder == "little":
        for i in range(0, len(src), 4):
            dst[i], dst[i + 1], dst[i + 2], dst[i + 3] = src[i + 2], src[i + 1], src[i], src[i + 3]
    else:
        for i in range(0, len(src), 4):
            dst[i], dst[i + 1], dst[i + 2], dst[i + 3] = src[i + 1], src[i + 2], src[i + 3], src[i]
    return struct.pack("%dc" % len(src), *dst)


def get_rgba_str_j(src):
    cnt = len(src)
    dst = bytearray(cnt)
    if sys.byteorder == "little":
        for i in range(0, cnt, 4):
            dst[i], dst[i + 1], dst[i + 2], dst[i + 3] = src[i + 2], src[i + 1], src[i], src[i + 3]
    else:
        for i in range(0, cnt, 4):
            dst[i], dst[i + 1], dst[i + 2], dst[i + 3] = src[i + 1], src[i + 2], src[i + 3], src[i]
    return dst


ベンチマークを取ってみた。

> py -2 04_argb_rgba_conv_2.py
start.
create source data.
## benchmarker:         release 4.0.1 (for python)
## python version:      2.7.18
## python compiler:     MSC v.1500 32 bit (Intel)
## python platform:     Windows-10-10.0.19041
## python executable:   C:\Python\Python27\python.exe
## cpu model:           AMD64 Family 23 Model 113 Stepping 0, AuthenticAMD
## parameters:          loop=5, cycle=1, extra=0

##                        real    (total    = user    + sys)
argb split              9.7370    9.7344    7.6094    2.1250
rgb shift A             3.0880    3.0781    3.0625    0.0156
rgb shift G             1.2940    1.2969    1.2188    0.0781
rgb shift H             1.6870    1.6875    1.6875    0.0000
rgb shift I             1.8540    1.8594    1.7812    0.0781
rgb shift J             1.4470    1.4531    1.4531    0.0000

## Ranking                real
rgb shift G             1.2940  (100.0) ********************
rgb shift J             1.4470  ( 89.4) ******************
rgb shift H             1.6870  ( 76.7) ***************
rgb shift I             1.8540  ( 69.8) **************
rgb shift A             3.0880  ( 41.9) ********
argb split              9.7370  ( 13.3) ***

## Matrix                 real    [01]    [02]    [03]    [04]    [05]    [06]
[01] rgb shift G        1.2940   100.0   111.8   130.4   143.3   238.6   752.5
[02] rgb shift J        1.4470    89.4   100.0   116.6   128.1   213.4   672.9
[03] rgb shift H        1.6870    76.7    85.8   100.0   109.9   183.0   577.2
[04] rgb shift I        1.8540    69.8    78.0    91.0   100.0   166.6   525.2
[05] rgb shift A        3.0880    41.9    46.9    54.6    60.0   100.0   315.3
[06] argb split         9.7370    13.3    14.9    17.3    19.0    31.7   100.0

今回の書き方で、元々は10秒ほどかかってた処理を1.45秒にすることはできたけど、それでも、前回辿り着いた(?)書き方なら1.29秒で終わるので、struct.pack()、struct.unpack()、リスト内包表記を使った書き方が今のところベストっぽい。

もっとも、また違う書き方をすれば、更に高速化できるかもしれない。自分は Python について詳しくないのでアレだけど。

ちなみに、以下の Python-Fuスクリプトにも、このあたりの書き方を反映させておいた。

_mieki256/sci-fi-texture-generator: Sci-Fi bump mapping texture generator with GIMP Script-fu.

bytearrayを知った。 :

当初、バイト文字列をインデックス値を使って変更しようとしたらエラーになって、一旦リスト化しないと変更できないのかなと思ったのだけど。Python2.7 にも bytearray というものがあって、それを使えばバイト文字列相当をインデックス値で指定して変更できると知った。

Python では、通常のバイト文字列は変更不可だけど、bytearray なら変更可能、ということらしい。

前述の関数で言えば、get_rgba_str_h() が一旦リスト化している例で、get_rgba_str_j() がbytearray を使った例。

def get_rgba_str_h(src):
    dst = list(src)
    if sys.byteorder == "little":
        for i in range(0, len(src), 4):
            dst[i], dst[i + 1], dst[i + 2], dst[i + 3] = src[i + 2], src[i + 1], src[i], src[i + 3]
    else:
        for i in range(0, len(src), 4):
            dst[i], dst[i + 1], dst[i + 2], dst[i + 3] = src[i + 1], src[i + 2], src[i + 3], src[i]
    return ''.join(dst)

def get_rgba_str_j(src):
    cnt = len(src)
    dst = bytearray(cnt)
    if sys.byteorder == "little":
        for i in range(0, cnt, 4):
            dst[i], dst[i + 1], dst[i + 2], dst[i + 3] = src[i + 2], src[i + 1], src[i], src[i + 3]
    else:
        for i in range(0, cnt, 4):
            dst[i], dst[i + 1], dst[i + 2], dst[i + 3] = src[i + 1], src[i + 2], src[i + 3], src[i]
    return dst

Python 3.x では動かない。 :

上記のスクリプトは、Python 2.7 では動いたけれど、Python 3.x ではエラーが出て動かなかった。

どうも join() の処理が違っているようだなと…。おそらく以下で紹介されている事例に引っ掛かっている予感。str は結合できるけど int は結合できないのだとか。

_TypeError: sequence item 0: expected string, int found - せつないぶろぐ

また、Python 3.x は「/」を使って除算をした時に float になってしまう点もよろしくなかった。「//」を使って結果を整数に限定するべきだった。

2022/05/18(水) [n年前の日記]

#1 [pc] GeForce Driverを更新してみた

メインPCは、NVIDIA GeForce GTX 1060 6GB のビデオカードを積んでいるのだけど、ドライバーに脆弱性が見つかった云々の話を目にしたので、Game Ready Driver を 457.51 から 512.77 にアップデートしておいた。

_NVIDIA製GPUディスプレイドライバーに複数の脆弱性 〜GeForceユーザーはv512.77への更新を【16:00追記】 - 窓の杜

変更点を確認してみたところ、3D設定の管理 → グローバル設定の項目の中に、「シェーダーキャッシュサイズ」という項目が増えていた。結構前のバージョンから追加されていた項目らしい。

ちなみに、512.77 も、色々不具合があるようで…。

_GeForce 512.77 ドライバ 不具合情報 | ニッチなPCゲーマーの環境構築Z

以上、3 日分です。

過去ログ表示

Prev - 2022/05 -
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project