2022/07/01(金) [n年前の日記]
#1 [python][cg_tools] ディザリング処理をするプログラムをPythonに移植中その5
任意のパレットを指定してディザリングをかけるサンプルプログラム群を ―― C++ で書かれてるソレを Python で書き直しているところ。
_Arbitrary-palette positional dithering algorithm
アルゴリズム3を移植中だけど、C++のソースの中に map というものが出現してきた。ググってみたら連想配列相当らしい。平衡二分木がどうとか書いてある…。それってPythonではどう書けばいいのか…。とりあえず、Pythonの辞書(dict)で代替して様子を見てみようか…。
_Arbitrary-palette positional dithering algorithm
アルゴリズム3を移植中だけど、C++のソースの中に map というものが出現してきた。ググってみたら連想配列相当らしい。平衡二分木がどうとか書いてある…。それってPythonではどう書けばいいのか…。とりあえず、Pythonの辞書(dict)で代替して様子を見てみようか…。
[ ツッコむ ]
2022/07/02(土) [n年前の日記]
#1 [python][cg_tools] ディザリング処理をするプログラムをPythonに移植中その6
任意のパレットを指定してディザリングをかけるサンプルプログラム群を ―― C++ で書かれてるソレを Python で書き直しているところ。
_Arbitrary-palette positional dithering algorithm
上記で紹介されている、Adobe Photoshop っぽいディザ処理を Python で書き直しているのだけど、かなりシンプルな処理なのに、ちゃんとそれっぽい画像に変換されるあたりがなんとも不思議。前回の計算処理で出てしまった誤差を、次の計算に持ち越すあたりがポイントなのだろうか…?
_Arbitrary-palette positional dithering algorithm
上記で紹介されている、Adobe Photoshop っぽいディザ処理を Python で書き直しているのだけど、かなりシンプルな処理なのに、ちゃんとそれっぽい画像に変換されるあたりがなんとも不思議。前回の計算処理で出てしまった誤差を、次の計算に持ち越すあたりがポイントなのだろうか…?
[ ツッコむ ]
2022/07/03(日) [n年前の日記]
#1 [nitijyou] 自宅サーバ止めてました
雷が鳴ったので、16:15-19:15の間、自宅サーバ止めてました。申し訳ないです。
[ ツッコむ ]
#2 [python] パレットデータを取り出すPythonスクリプトを書いてる
ここ最近、任意のパレットデータでディザ処理をかける実験をしているのだけど、そのパレットデータを別途指定できるようにしたいなと。今まではソース内に配列として書いてしまっていたので、パレットデータを変更して実験することが容易ではなかった。
Python の Pillow(PIL) を使って、インデックスカラーのPNGを読み込んで、パレット値を読み取る処理を書いてみたけど、使ってない色まで RGB=(0,0,0) で得られてしまう。インデックスカラー画像は256色あるものと決め打ちされているっぽい。16色や32色しか使ってないpngをパレット指定用画像として使いたいのだけどな…。
もしかして、GIMPのパレットデータファイル (.gpl) を読み込んで処理するのもアリかなと思えてきた。RGB値を正規表現で取り出せそうか少し試してみよう…。
Python の Pillow(PIL) を使って、インデックスカラーのPNGを読み込んで、パレット値を読み取る処理を書いてみたけど、使ってない色まで RGB=(0,0,0) で得られてしまう。インデックスカラー画像は256色あるものと決め打ちされているっぽい。16色や32色しか使ってないpngをパレット指定用画像として使いたいのだけどな…。
もしかして、GIMPのパレットデータファイル (.gpl) を読み込んで処理するのもアリかなと思えてきた。RGB値を正規表現で取り出せそうか少し試してみよう…。
[ ツッコむ ]
2022/07/04(月) [n年前の日記]
#1 [nitijyou] 腹痛で大変だった
おそらくだけど、また尿路結石の痛みが出て苦しんでた。
ロキソニンを飲んでもこんなに痛いのか…と絶望的な気分になるぐらいの痛みだった。ただ、あらかじめ薬を飲んでいたせいか、前回のように何度も吐くほどの痛みにはならかった。とは言っても、布団の上でゴロゴロとのたうち回るぐらい痛かったけど…。
19:00頃、あまりに痛いので、ロキソニンを追加で飲んだ。本来最低でも4時間ほど間隔を空けて飲むこと、となっていたのだけど、どうにも耐えられなくて…。4時間も3時間もたいして変わらんだろと勝手に決めつけて飲んだけれど、何かしらの効果があったのかどうかは不明。追加で飲んでも、その後もずっと痛かった。
トイレで小さいほうをしたら血が出ていたので、やはりコレは尿路結石なんだろうなと。
前回この症状が出たのは… _2022/04/16 だったらしい。2ヶ月半で再発ということになるのだろうか。メモを確認したら、前回は19:10頃から痛み出して、21:40頃に病院を出たと書いてあった。自分の場合、2時間以上は痛みが続くようだなと。
- 16:00頃に右脇腹に違和感を覚えて、これはもしや、また例の痛みではないのかと、痛み止めのロキソニンを飲んだ。
- 2時間後、18:00頃から、右脇腹や背中の痛みがどんどん増してきた。
- 2時間半後、20:30頃に、ようやく収まった。
ロキソニンを飲んでもこんなに痛いのか…と絶望的な気分になるぐらいの痛みだった。ただ、あらかじめ薬を飲んでいたせいか、前回のように何度も吐くほどの痛みにはならかった。とは言っても、布団の上でゴロゴロとのたうち回るぐらい痛かったけど…。
19:00頃、あまりに痛いので、ロキソニンを追加で飲んだ。本来最低でも4時間ほど間隔を空けて飲むこと、となっていたのだけど、どうにも耐えられなくて…。4時間も3時間もたいして変わらんだろと勝手に決めつけて飲んだけれど、何かしらの効果があったのかどうかは不明。追加で飲んでも、その後もずっと痛かった。
トイレで小さいほうをしたら血が出ていたので、やはりコレは尿路結石なんだろうなと。
前回この症状が出たのは… _2022/04/16 だったらしい。2ヶ月半で再発ということになるのだろうか。メモを確認したら、前回は19:10頃から痛み出して、21:40頃に病院を出たと書いてあった。自分の場合、2時間以上は痛みが続くようだなと。
[ ツッコむ ]
2022/07/05(火) [n年前の日記]
#1 [nitijyou] 自宅サーバ止めてました
雷が鳴ったので、18:00-19:40の間、自宅サーバ止めてました。申し訳ないです。
かなり近くに雷が落ちたようで、普段聞いたことが無いような音が…。不安になってエアコンのコンセントまで抜いたりもして。この時期にエアコンが雷で壊されたら命に係わる…。
かなり近くに雷が落ちたようで、普段聞いたことが無いような音が…。不安になってエアコンのコンセントまで抜いたりもして。この時期にエアコンが雷で壊されたら命に係わる…。
[ ツッコむ ]
#2 [nitijyou] 一日中寝てた
昨日のダメージが尾を引いてしまったのか、眠くて眠くて、一日中寝てた。起きたら起きたで手足に力が入らず。考えてみたら昨晩素麺を御椀一杯程度食べて、それ以降何も食べてないなと…。夕飯をどうにか食べたら少し動くようになってきた。
[ ツッコむ ]
2022/07/06(水) [n年前の日記]
#1 [gimp] GIMP を 2.10.32 に更新した
数日前に、Windows10 x64 21H2上にインストールしてあった GIMP 2.10.30 x64 Portable samj版を、GIMP 2.10.32 x64 Portable samj版に更新していたことをメモしてなかった気がするので一応メモ。
最初は上書きでインストールしてみたのだけど、GIMP を起動したら .dll が見つからない等のエラーが出てしまった。2.10.30 と 2.10.32 のフォルダ構成も結構違っていたようなので、別フォルダを作成してインストールすることにした。今後更新があった場合も、別フォルダを作成してインストールすることにしよう…。
ただ、別フォルダにインストールしてしまうと再設定が面倒で…。今回は、旧版インストールフォルダ\Preferences\ 内の、以下のファイルをコピーして再設定を避けてみた。
APNGエクスポート用プラグインも一応導入しておいた。
_APNG (animated PNG) plug-in for Gimp 2.10 Windows64x - GIMP Chat
ただ、GIMP 2.10 はWebP画像フォーマットに標準で対応しているので、フルカラーのアニメ画像が欲しい場合は WebP でエクスポートしたほうがいいような気もする。APNG は拡張子が .png だから、一般的な画像ビューアは、普通のpngなのかAPNG なのか判別できなくて正常表示されないので…。WebPなら拡張子からして違うので、そういった問題は起きないのではないかと…。
最初は上書きでインストールしてみたのだけど、GIMP を起動したら .dll が見つからない等のエラーが出てしまった。2.10.30 と 2.10.32 のフォルダ構成も結構違っていたようなので、別フォルダを作成してインストールすることにした。今後更新があった場合も、別フォルダを作成してインストールすることにしよう…。
ただ、別フォルダにインストールしてしまうと再設定が面倒で…。今回は、旧版インストールフォルダ\Preferences\ 内の、以下のファイルをコピーして再設定を避けてみた。
- controllerrc : マウスボタンの割り当てが設定されてる。
- gimprc : ブラシ、スクリプト、プラグインフォルダ等が設定されてる。GIMPインストールフォルダの記述部分を修正する必要有。
- menurc : ショートカットキー割り当てが設定されてる。
- sessionrc : 各ウインドウの位置その他が設定されてる。
- templaterc : テンプレート一覧が設定されてる。
APNGエクスポート用プラグインも一応導入しておいた。
_APNG (animated PNG) plug-in for Gimp 2.10 Windows64x - GIMP Chat
ただ、GIMP 2.10 はWebP画像フォーマットに標準で対応しているので、フルカラーのアニメ画像が欲しい場合は WebP でエクスポートしたほうがいいような気もする。APNG は拡張子が .png だから、一般的な画像ビューアは、普通のpngなのかAPNG なのか判別できなくて正常表示されないので…。WebPなら拡張子からして違うので、そういった問題は起きないのではないかと…。
[ ツッコむ ]
2022/07/07(木) [n年前の日記]
#1 [python] Pillowのgetpixel()は本当に遅いのか気になったので確認してみた
Python で画像を扱える Pillow (PIL)モジュールについて、1ドット単位で値を読んだり書いたりできる .getpixel()/.putpixel() というメソッドがあるのだけど。巷の各種記事では処理速度が遅いと書いてあって、本当にそうなのかなと気になってきた。
そんなわけで、ベンチマークを取ってみた。環境は、Windows10 x64 21H2 + Python 3.9.13 64bit + Pillow 9.1.1。CPU は AMD Ryzen 5 5600X (6コア12スレッド、ベースクロック3.7GHz)。
4288x2848ドットの画像に対してひたすらドットを読むだけの処理をしてみた。ちなみに利用した画像は以下。
_十代の少女 可愛い 肖像画 - Pixabayの無料写真
ソースは以下。
_05getpixel_bench.py
動作には、Pillow と benchmarker が必要。
結果は以下のような感じになった。
.getdata() を使えばたしかに速くなるけれど、一次元配列に対してアクセスするような書き方になるので、可読性はほんのちょっと、若干かすかに、ビミョーに悪くなるような気もする。
対して、.load() を使ったアクセスなら、.getpixel() と同様に x, y を指定してアクセスできるし、しかも .getdata() を使った場合とそれほど処理速度も変わらないわけで…。
個人的には、.getdata() より、可読性と処理速度の両方をそこそこ得られる .load() を使ったほうがいいのではないかと思えてきた。
余談。手元で実験に使ってるスクリプトが、とにかく遅くて…。.load() を使って画像の各ドットにアクセスしていたのだけど、.getdata() を使ったらもっと速く処理できないかと少し期待しながらベンチマークを取ったわけで。ある意味、残念な結果になってしまった。今回、そこらへんを変えてみても結果は変わらないようだなと…。
そんなわけで、ベンチマークを取ってみた。環境は、Windows10 x64 21H2 + Python 3.9.13 64bit + Pillow 9.1.1。CPU は AMD Ryzen 5 5600X (6コア12スレッド、ベースクロック3.7GHz)。
4288x2848ドットの画像に対してひたすらドットを読むだけの処理をしてみた。ちなみに利用した画像は以下。
_十代の少女 可愛い 肖像画 - Pixabayの無料写真
ソースは以下。
_05getpixel_bench.py
from PIL import Image from benchmarker import Benchmarker infile = "teen-girl-4467541_4288x2848.jpg" def main(): im = Image.open(infile) width, height = im.size print("%d x %d" % (width, height)) with Benchmarker(100) as bench: @bench(".getdata()") def _(bm): im = Image.open(infile) dt = im.getdata() for y in range(height): idx = width * y for x in range(width): _ = dt[idx + x] @bench(".load()") def _(bm): im = Image.open(infile) src = im.load() for y in range(height): for x in range(width): _ = src[x, y] @bench(".getpixel()") def _(bm): im = Image.open(infile) for y in range(height): for x in range(width): _ = im.getpixel((x, y)) if __name__ == '__main__': main()
動作には、Pillow と benchmarker が必要。
pip install Pillow -U pip install Benchmarker -U
結果は以下のような感じになった。
> py 05getpixel_bench.py 4288 x 2848 ## benchmarker: release 4.0.1 (for python) ## python version: 3.9.13 ## 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 25 Model 33 Stepping 2, AuthenticAMD ## parameters: loop=100, cycle=1, extra=0 ## real (total = user + sys) .getdata() 0.7155 0.7188 0.6875 0.0312 .load() 0.7961 0.7969 0.7969 0.0000 .getpixel() 6.2659 6.2656 6.2656 0.0000 ## Ranking real .getdata() 0.7155 (100.0) ******************** .load() 0.7961 ( 89.9) ****************** .getpixel() 6.2659 ( 11.4) ** ## Matrix real [01] [02] [03] [01] .getdata() 0.7155 100.0 111.3 875.8 [02] .load() 0.7961 89.9 100.0 787.1 [03] .getpixel() 6.2659 11.4 12.7 100.0
- .getpixel() は、たしかに遅かった。他のアクセス方法より数倍遅い。
- .getdata() は、たしかに一番速かった。
- ただ、Image.load() をしてからアクセスする方法も、.getdata() 並みの速さでアクセスできるように見える。
.getdata() を使えばたしかに速くなるけれど、一次元配列に対してアクセスするような書き方になるので、可読性はほんのちょっと、若干かすかに、ビミョーに悪くなるような気もする。
対して、.load() を使ったアクセスなら、.getpixel() と同様に x, y を指定してアクセスできるし、しかも .getdata() を使った場合とそれほど処理速度も変わらないわけで…。
個人的には、.getdata() より、可読性と処理速度の両方をそこそこ得られる .load() を使ったほうがいいのではないかと思えてきた。
余談。手元で実験に使ってるスクリプトが、とにかく遅くて…。.load() を使って画像の各ドットにアクセスしていたのだけど、.getdata() を使ったらもっと速く処理できないかと少し期待しながらベンチマークを取ったわけで。ある意味、残念な結果になってしまった。今回、そこらへんを変えてみても結果は変わらないようだなと…。
[ ツッコむ ]
#2 [python][cg_tools] ディザリング処理をするプログラムをPythonに移植中その7
任意のパレットを指定してディザリングをかけるサンプルプログラム群を ―― C++ で書かれてるソレを Python で書き直しているところ。
_Arbitrary-palette positional dithering algorithm
ある程度動くようになったので、一応アップロード。元記事内の、アルゴリズム1、2、3、及び Photoshopっぽいアルゴリズムを、全部1つのファイルにまとめてみた。
_Yliluoma's ordered dithering algorithm 1, 2, 3. Python version.
動作には、Pillow と tqdm が必要。
動作確認環境は、Windows10 x64 21H2 + Python 3.9.13 64bit + Pillow 9.1.1 + tqdm 4.64.0。
_Arbitrary-palette positional dithering algorithm
ある程度動くようになったので、一応アップロード。元記事内の、アルゴリズム1、2、3、及び Photoshopっぽいアルゴリズムを、全部1つのファイルにまとめてみた。
_Yliluoma's ordered dithering algorithm 1, 2, 3. Python version.
動作には、Pillow と tqdm が必要。
pip install Pillow -U pip install tqdm -U
動作確認環境は、Windows10 x64 21H2 + Python 3.9.13 64bit + Pillow 9.1.1 + tqdm 4.64.0。
◎ 使い方。 :
使い方は以下のような感じ。--mode N でアルゴリズムを選べる。
一応、ヘルプ表示も載せておく。
mode の違いは以下のような感じ。元記事を読まないと分からないとは思うけど…。
py yliluoma_ordered_dither.py -i scene.png -o scenedither_m0_8x8.png --mode 0 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m1_8x8.png --mode 1 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m2_8x8.png --mode 2 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m3_8x8.png --mode 3 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m4_8x8.png --mode 4 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m5_8x8.png --mode 5 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m6_8x8.png --mode 6 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m7_8x8.png --mode 7 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m8_8x8.png --mode 8
一応、ヘルプ表示も載せておく。
> py yliluoma_ordered_dither.py --help usage: yliluoma_ordered_dither.py [-h] -i INPUT -o OUTPUT [-p PALETTE] [-d DITHER] [-m MODE] [-c] Yliluoma ordered dithering 1, 2, 3, 4 optional arguments: -h, --help show this help message and exit -i INPUT, --input INPUT Input png filename -o OUTPUT, --output OUTPUT Output png filename -p PALETTE, --palette PALETTE Palette file (.png or .gpl) -d DITHER, --dither DITHER Dither type 2,4,8 (2x2,4x4,8x8). default: 8 -m MODE, --mode MODE job kind 0 - 8. default: 3 -c, --ciede2000 Enable CIEDE2000 (mode 6 only
mode の違いは以下のような感じ。元記事を読まないと分からないとは思うけど…。
- mode 0: アルゴリズム1。2色の組み合わせを意識して差し替えるべき色を求める。かなり遅い。
- mode 1: アルゴリズム1。mode 0 の改良版。突飛な色の組み合わせは除外する。かなり遅い。
- mode 2: アルゴリズム1。mode 1 の改良版。ガンマ値を正しく反映させる。かなり遅い。
- mode 3: アルゴリズム1。mode 2 の処理高速化版。ループを回さずに数式で近似値を求める。少し早い。
- mode 4: アルゴリズム1。3色の組み合わせを意識して処理する。かなり遅い。
- mode 5: アルゴリズム2。N色の組み合わせを意識しないで色を求める。かなり遅い。
- mode 6: アルゴリズム2。mode 5 の改良版。ガンマ値を正しく反映させる。かなり遅い。
- mode 7: アルゴリズム3。mode 6 の改良版。かなり遅い。
- mode 8: Adobe Photoshop っぽいアルゴリズム。結構早い。
◎ 問題点。 :
このスクリプト、とにかく処理が遅い…。CPU: AMD Ryzen 5 5600X を使って、289x176ドットの画像に対して、16色でディザリングをかけるのに、最悪8分ぐらいかかる…。もちろん、使うアルゴリズムにもよるのだけど…。
比較的変換処理が速いのは、--mode 3 と --mode 8。
それ以外のアルゴリズムは、まあ、遅い。とんでもなく遅い。
比較的変換処理が速いのは、--mode 3 と --mode 8。
- mode 3 は、ループを回して総当たりで相応しい色を探さずに、数式で大まかに合いそうな色を探すアルゴリズム。ただ、速くはなるけれど、生成画像の品質は落ちる。
- mode 8 は、Adobe Photoshop で使われていたらしいアルゴリズム。品質と処理速度のバランスが取れている。ただ、生成画像は全体的にボケ気味な印象を受けた。
それ以外のアルゴリズムは、まあ、遅い。とんでもなく遅い。
◎ 改善策。 :
改善策は、いくつか思いつく。
元記事のソースは 8x8 のディザで処理しているけれど、見た感じ、4x4 のディザでも十分かなと思えた。8x8のディザだと、一番深いところで64回ループが回るけど、4x4なら16回のループで済むので、単純計算で約4倍の速さになりそう。
並列処理を導入するのも手かもしれない。Python で並列処理をさせる方法が分からなかったので今回は試してないけど、今時のCPUなら4コアだの6コアだの持ってるだろうから、1/4、1/6 の処理時間で済むのではなかろうか。実際、元々のC++版は、OpenMP(?) を有効にしてビルドして、並列処理する実行バイナリにしたら爆速になった。
画像の全てのドットに対して、毎回ループを回して、適切なパレットカラーを求めているあたりがアレだろうなという気もする。どれかしらの要素を事前に計算してキャッシュしておいて、そのキャッシュを使い回すようにすれば、もうちょっと改善されるかもしれない。例えばベタ部分が多い画像の場合、画像内に出てくる色の数は限定されるはずで、以前計算したことがある色が出現したら、その時の計算結果を再度使う、という作りにするだけでも効果はありそう。
元記事にも書いてあるけど、kd-tree 等を導入すれば改善される可能性もあるのだろうなと…。画像内のとある色について、差し替えに相応しい色はどれか、と探すあたりで時間がかかっているので、探索時間が短くなれば効果はあるはず。
元記事のソースは 8x8 のディザで処理しているけれど、見た感じ、4x4 のディザでも十分かなと思えた。8x8のディザだと、一番深いところで64回ループが回るけど、4x4なら16回のループで済むので、単純計算で約4倍の速さになりそう。
並列処理を導入するのも手かもしれない。Python で並列処理をさせる方法が分からなかったので今回は試してないけど、今時のCPUなら4コアだの6コアだの持ってるだろうから、1/4、1/6 の処理時間で済むのではなかろうか。実際、元々のC++版は、OpenMP(?) を有効にしてビルドして、並列処理する実行バイナリにしたら爆速になった。
画像の全てのドットに対して、毎回ループを回して、適切なパレットカラーを求めているあたりがアレだろうなという気もする。どれかしらの要素を事前に計算してキャッシュしておいて、そのキャッシュを使い回すようにすれば、もうちょっと改善されるかもしれない。例えばベタ部分が多い画像の場合、画像内に出てくる色の数は限定されるはずで、以前計算したことがある色が出現したら、その時の計算結果を再度使う、という作りにするだけでも効果はありそう。
元記事にも書いてあるけど、kd-tree 等を導入すれば改善される可能性もあるのだろうなと…。画像内のとある色について、差し替えに相応しい色はどれか、と探すあたりで時間がかかっているので、探索時間が短くなれば効果はあるはず。
◎ 余談。 :
このスクリプトで実験した後、減色ツールの OPTPiX や Yukari を使って減色をしてみたら、どれも一瞬で結果が返ってきて…。もしかすると1秒もかかってないのでは…。
それらはおそらくC/C++で書かれているのかなと想像するのだけど、それにしても処理時間が違い過ぎる。おそらく、アルゴリズムからして、もっと上手いやり方があるのだろう…。
それらはおそらくC/C++で書かれているのかなと想像するのだけど、それにしても処理時間が違い過ぎる。おそらく、アルゴリズムからして、もっと上手いやり方があるのだろう…。
[ ツッコむ ]
2022/07/08(金) [n年前の日記]
#1 [python] Pythonの並行処理・並列処理について勉強中
Python の並行処理(マルチスレッド)、並列処理(マルチプロセス)について勉強中。
動作確認環境は、Windows10 x64 21H2 + Python 3.9.13。
巷の解説記事内で紹介されてる各サンプルを手元で動かしてみて、マルチスレッドについてはちゃんと動作することを確認できたのだけど。マルチプロセスのサンプルを動かそうとしたら、いきなりエラーが出て悩んでしまった。もしかして、Windows ではマルチプロセスは使えないのだろうか? 試しに Ubuntu Linux 20.04 LTS上で同じスクリプトを動かしてみたら、そちらではすんなり動いてしまった。
どうやら、マルチスレッドはともかく、Windows上ではPythonのマルチプロセスは動かないようだなと…。「Linux や Mac ならマルチプロセスが使えますよ」「Windows? 知らんがな」という状況なのだろう…。
と、一瞬思い込んでしまったのだけど、その後も他の解説記事を眺めて試していたら、Windows上でもマルチプロセスのサンプルが動いてくれた。「Linux でしか使えないよ」というわけではないらしい。
Windows上、かつ、マルチプロセスを使うスクリプトは、以下の記述が無いといかんようで。実処理をトップレベル(?)に書いてしまうとエラーが出てしまう。ただし、Linux上ではトップレベルに書いてしまっても動く、というオチだった模様。
ということで、巷の解説記事内でマルチプロセスのサンプルを見かけて、もし、処理がトップレベルに書かれてたら、上記の記述を追加して動作確認してみると良い、という話になるのだろうなと。
動作確認環境は、Windows10 x64 21H2 + Python 3.9.13。
巷の解説記事内で紹介されてる各サンプルを手元で動かしてみて、マルチスレッドについてはちゃんと動作することを確認できたのだけど。マルチプロセスのサンプルを動かそうとしたら、いきなりエラーが出て悩んでしまった。もしかして、Windows ではマルチプロセスは使えないのだろうか? 試しに Ubuntu Linux 20.04 LTS上で同じスクリプトを動かしてみたら、そちらではすんなり動いてしまった。
どうやら、マルチスレッドはともかく、Windows上ではPythonのマルチプロセスは動かないようだなと…。「Linux や Mac ならマルチプロセスが使えますよ」「Windows? 知らんがな」という状況なのだろう…。
と、一瞬思い込んでしまったのだけど、その後も他の解説記事を眺めて試していたら、Windows上でもマルチプロセスのサンプルが動いてくれた。「Linux でしか使えないよ」というわけではないらしい。
Windows上、かつ、マルチプロセスを使うスクリプトは、以下の記述が無いといかんようで。実処理をトップレベル(?)に書いてしまうとエラーが出てしまう。ただし、Linux上ではトップレベルに書いてしまっても動く、というオチだった模様。
def main(): ... if __name__ == "__main__": main()
ということで、巷の解説記事内でマルチプロセスのサンプルを見かけて、もし、処理がトップレベルに書かれてたら、上記の記述を追加して動作確認してみると良い、という話になるのだろうなと。
◎ 参考ページ。 :
_[Python] スレッドで実装する - Qiita
_PythonのThread(並列処理)は速度改善効果がないので「concurrent.futures」を使う - "BOKU"のITな日常
_Pythonでconcurrent.futuresを使った並列タスク実行 - Qiita
_concurrent.futures: 並行処理 in Python - Heavy Watal
_[Python] multiprocessingを試す (1)
_[Python] multiprocessingを試す (2)
_Pythonの並列処理・並行処理をしっかり調べてみた - Qiita
_【Python】並列処理でプログラムを高速化 | 無次元日記
_Pythonで並列処理のすすめ
_Pythonのthreadingとmultiprocessingを完全理解 - Qiita
_【Python】マルチプロセスについて - Qiita
_PythonのThread(並列処理)は速度改善効果がないので「concurrent.futures」を使う - "BOKU"のITな日常
_Pythonでconcurrent.futuresを使った並列タスク実行 - Qiita
_concurrent.futures: 並行処理 in Python - Heavy Watal
_[Python] multiprocessingを試す (1)
_[Python] multiprocessingを試す (2)
_Pythonの並列処理・並行処理をしっかり調べてみた - Qiita
_【Python】並列処理でプログラムを高速化 | 無次元日記
_Pythonで並列処理のすすめ
_Pythonのthreadingとmultiprocessingを完全理解 - Qiita
_【Python】マルチプロセスについて - Qiita
[ ツッコむ ]
2022/07/09(土) [n年前の日記]
#1 [python] Pythonの並行処理・並列処理についてまだ勉強中
昨日に引き続き、Python の並行処理・並列処理について勉強中。巷の解説記事のサンプルをコピペして動作確認。
[ ツッコむ ]
2022/07/10(日) [n年前の日記]
#1 [nitijyou] 投票してきた
朝08:00頃、近所の公会堂まで電動自転車で行ってきて、参議院選挙の投票をしてきた。帰りにザ・ビッグに寄って夜食等を購入。
朝の時点でも暑いなと思ってたら、やはり昼間には30度を超えてた…。朝のうちに行っておいて良かった…。
朝の時点でも暑いなと思ってたら、やはり昼間には30度を超えてた…。朝のうちに行っておいて良かった…。
[ ツッコむ ]
2022/07/11(月) [n年前の日記]
#1 [xyzzy] xyzzyのスニペットについて調べてた
自分は普段 xyzzy という、操作感覚が emacsに近いWindows専用エディタを使っているのだけど。スニペット(Snippet)相当の機能は無いのかなと気になってきたので少し調べてみたり。
スニペット機能と言うのは…要は「定型文入力機能」という説明でいいのだろうか。プログラムソースを打ち込んでいく際、お決まりの一文を入力する場面がちょくちょくあるけれど、それらの定型文を登録しておいて挿入できれば作業が楽になる。
xyzzy の場合、abbrev と dabbrev という、2つの入力補完機能を持っていて。
スニペットは、前者の abbrev に相当するのだろうなと。
ただ、自分の手元の xyzzy では、abbrev の実行(?)が割り当てられてるはずの C-x ' が機能しなくて。設定ファイル ~/.xyzzy を確認したら、C-x ' には just-one-space が割り当てられていて、代わりに M-SPC に snippet-expand が割り当てられてた。昔、自分で設定したんだろうけど…何だっけコレ…。
どうやら自分、snippet.l という拡張を導入して、expand-abbrev の代わりに snippet-expand を使うようにしていたようだなと…。
スニペット機能と言うのは…要は「定型文入力機能」という説明でいいのだろうか。プログラムソースを打ち込んでいく際、お決まりの一文を入力する場面がちょくちょくあるけれど、それらの定型文を登録しておいて挿入できれば作業が楽になる。
xyzzy の場合、abbrev と dabbrev という、2つの入力補完機能を持っていて。
- abbrev : 静的補完。事前に登録した定型文を選んで入力補完してくれる。
- dabbrev : 動的補完。現在開いているバッファ(ファイル)の中から単語を抽出して、入力補完してくれる。
スニペットは、前者の abbrev に相当するのだろうなと。
ただ、自分の手元の xyzzy では、abbrev の実行(?)が割り当てられてるはずの C-x ' が機能しなくて。設定ファイル ~/.xyzzy を確認したら、C-x ' には just-one-space が割り当てられていて、代わりに M-SPC に snippet-expand が割り当てられてた。昔、自分で設定したんだろうけど…何だっけコレ…。
どうやら自分、snippet.l という拡張を導入して、expand-abbrev の代わりに snippet-expand を使うようにしていたようだなと…。
◎ snippet.lについて。 :
ググってみたら、snippet.l はもう入手不可能っぽい。Web Archive で解説ページは見つけられたけど、.zipファイルはDLできなかった。
_silog - script/snippet (Web Archive)
幸い、xyzzyインストールフォルダ\.netinst\src\ 以下で、snippet-2007.07.15.zip というファイルが見つかった。一応、バックアップも兼ねて置いておきます。
_snippet-2007.07.15.zip
snippet.l と abbrev の違いは、定型文を挿入した直後の動作だろうか…。abbrev は定型文を挿入して終わるけど、snippet.l は、挿入後に入力が必要な個所にカーソルを合わせてくれて、C-n や C-p で入力箇所を移動できるっぽい。
まあ、一般的には、abbrev が使えるだけでも十分かなという気もする。 *1
_silog - script/snippet (Web Archive)
幸い、xyzzyインストールフォルダ\.netinst\src\ 以下で、snippet-2007.07.15.zip というファイルが見つかった。一応、バックアップも兼ねて置いておきます。
_snippet-2007.07.15.zip
snippet.l と abbrev の違いは、定型文を挿入した直後の動作だろうか…。abbrev は定型文を挿入して終わるけど、snippet.l は、挿入後に入力が必要な個所にカーソルを合わせてくれて、C-n や C-p で入力箇所を移動できるっぽい。
まあ、一般的には、abbrev が使えるだけでも十分かなという気もする。 *1
◎ abbrevについて。 :
以下のページが分かりやすいだろうか…。
_単語補完機能 - xyzzy - emacs like editor in windows
_xyzzyで単語の自動補完(Static編) - tohokuaikiのチラシの裏
_abbrevの使い方 - himadatanode’s blog
_xyzzy - 覚書wiki - atwiki(アットウィキ)
_abbrev modeのやりかた (Web Archive)
_QuickTour/abbrev - XyzzyWiki (Web Archive)
_動的補完と静的補完の設定と使い方 | for programer | しょぼしょぼすくりぷと xyzzy (Web Archive)
消滅してしまったページが多いのがなんとも。
emacsの解説も参考になるかもしれず。
_abbrev
以下で、デフォルトのキー割り当てが紹介されてる。
_xyzzy機能分類別キーバインド一覧
abbrev の定義ファイルは ~/.abbrev_defs だけど、M-x list-abbrevs か M-x edit-abbrevs を実行すれば編集できる。
C-x C-a か C-x + を使って仮登録してから、M-x list-abbrevs でちゃんと修正、てな感じの登録の仕方になるのかな。たぶん。
_単語補完機能 - xyzzy - emacs like editor in windows
_xyzzyで単語の自動補完(Static編) - tohokuaikiのチラシの裏
_abbrevの使い方 - himadatanode’s blog
_xyzzy - 覚書wiki - atwiki(アットウィキ)
_abbrev modeのやりかた (Web Archive)
_QuickTour/abbrev - XyzzyWiki (Web Archive)
_動的補完と静的補完の設定と使い方 | for programer | しょぼしょぼすくりぷと xyzzy (Web Archive)
消滅してしまったページが多いのがなんとも。
emacsの解説も参考になるかもしれず。
_abbrev
以下で、デフォルトのキー割り当てが紹介されてる。
_xyzzy機能分類別キーバインド一覧
- C-x C-a : add-mode-abbrev 現在のモードのアブレブテーブルに登録(展開する文字列→略称)
- C-x C-h : inverse-add-mode-abbrev 現在のモードのアブレブテーブルに登録(展開する文字列→略称)
- C-x ' : expand-abbrev アブレブ略語を展開
- C-x + : add-global-abbrev グローバルアブレブテーブルに登録(展開する文字列→略称)
- C-x - : inverse-add-global-abbrev グローバルアブレブテーブルに登録(略称→展開する文字列)
abbrev の定義ファイルは ~/.abbrev_defs だけど、M-x list-abbrevs か M-x edit-abbrevs を実行すれば編集できる。
C-x C-a か C-x + を使って仮登録してから、M-x list-abbrevs でちゃんと修正、てな感じの登録の仕方になるのかな。たぶん。
*1: いやまあ、今から新規に xyzzy を使う人は居ないだろうから、一般的もへったくれも無いだろうけど。開発停止状態と言っていいほど枯れ切ってしまって、慣れ過ぎちゃって離れられない人しか使ってないエディタのはずだし…。
[ ツッコむ ]
2022/07/12(火) [n年前の日記]
#1 [python] ディザをかけるPythonスクリプトを弄ってる
Pythonで並列処理(マルチプロセス)を使うやり方が大体分かってきたので、先日 Python で書いた、ディザをかけるスクリプトに並列処理を加えてみようと作業を始めたのだけど。特定のモードの処理に必要な関数だけを残して実行してみたら、以前のスクリプトで得られた生成画像と違う結果になってしまって悩んでいるところ。自分はどこでミスをしてしまったのか…。
[ ツッコむ ]
2022/07/13(水) [n年前の日記]
#1 [python] ディザリング処理をするPythonスクリプトに並列処理を追加してみた
任意のパレットを指定してディザリングをかけるサンプルプログラム群を ―― C++ で書かれてるソレを Python で書き直してみたわけだけど。
_Arbitrary-palette positional dithering algorithm
_Yliluoma's ordered dithering algorithm 1, 2, 3. Python version.
あまりに処理時間がかかり過ぎるので、並列処理(マルチプロセス)も使えるように修正してみた。
動作確認環境は、Windows10 x64 21H2 + Python 3.9.13 + Pillow 9.1.1 + tqdm 4.64.0。
ソースは以下。
_yodither1.py (Yliluoma's dithering algorithm 1, slow, not tri-tone)
_yodither1tritone.py (Yliluoma's dithering algorithm 1, tri-tone)
_yodither3.py (Yliluoma's dithering algorithm 3)
_yodither4.py (adobe like algorithm)
動作には、Pillow、tqdm が必要。
スクリプトの使い方は以下。
一応ヘルプも載せておきます。
コマンドラインオプションに --mp をつければ並列処理(マルチプロセス)が有効になる。
_Arbitrary-palette positional dithering algorithm
_Yliluoma's ordered dithering algorithm 1, 2, 3. Python version.
あまりに処理時間がかかり過ぎるので、並列処理(マルチプロセス)も使えるように修正してみた。
動作確認環境は、Windows10 x64 21H2 + Python 3.9.13 + Pillow 9.1.1 + tqdm 4.64.0。
ソースは以下。
_yodither1.py (Yliluoma's dithering algorithm 1, slow, not tri-tone)
_yodither1tritone.py (Yliluoma's dithering algorithm 1, tri-tone)
_yodither3.py (Yliluoma's dithering algorithm 3)
_yodither4.py (adobe like algorithm)
動作には、Pillow、tqdm が必要。
pip install Pillow -U pip install tqdm -U
スクリプトの使い方は以下。
python yodither1.py -i input.png -o out.png --mp python yodither1tritone.py -i input.png -o out.png --mp python yodither3.py -i input.png -o out.png --mp python yodither4.py -i input.png -o out.png --mp
一応ヘルプも載せておきます。
> py yodither1.py --help usage: yodither1.py [-h] -i INPUT -o OUTPUT [-p PALETTE] [-d DITHER] [--mp] Yliluoma ordered dithering 1 optional arguments: -h, --help show this help message and exit -i INPUT, --input INPUT Input png filename -o OUTPUT, --output OUTPUT Output png filename -p PALETTE, --palette PALETTE Palette file (.png or .gpl) -d DITHER, --dither DITHER Dither type 2,4,8 (2x2,4x4,8x8). default: 8 --mp Enable multi process
コマンドラインオプションに --mp をつければ並列処理(マルチプロセス)が有効になる。
◎ 処理時間を実測。 :
CPU : AMD Ryzen 5 5600X (6コア12スレッド、3.7 - 4.6GHz) 上で、289 x 176 ドットの画像を変換して動作確認してみた。
ということで、並列処理にすることで速くなる場合と、遅くなる場合があると分かった。でもまあ、8分近くかかってた処理が2分で終わるようになった点はありがたい。
1ドット単位の計算をする際に並列処理を使ってしまったので、すぐに結果が得られるアルゴリズムの場合は、並列処理をするための下準備のほうがネックになってしまったのだろうけど。これがもし、1ラインずつ処理する形で並列処理を使っていたら、どのスクリプトでも効果が得られたのではないか、という気もする。
ただ、どのみち Python では、この手の処理は遅すぎてアレだなと…。
Script name | --mp (multi process) | Time |
---|---|---|
yodither1.py | off | 07:41 |
yodither1.py | on | 02:11 |
yodither1tritone.py | off | 02:36 |
yodither1tritone.py | on | 01:11 |
yodither3.py | off | 00:39 |
yodither3.py | on | 00:53 |
yodither4.py | off | 00:30 |
yodither4.py | on | 00:49 |
- yodither1.py, yodither1tritone.py は並列処理にすることで速くなった。
- yodither3.py, yodither4.py は並列処理にしたらむしろ遅くなった。
ということで、並列処理にすることで速くなる場合と、遅くなる場合があると分かった。でもまあ、8分近くかかってた処理が2分で終わるようになった点はありがたい。
1ドット単位の計算をする際に並列処理を使ってしまったので、すぐに結果が得られるアルゴリズムの場合は、並列処理をするための下準備のほうがネックになってしまったのだろうけど。これがもし、1ラインずつ処理する形で並列処理を使っていたら、どのスクリプトでも効果が得られたのではないか、という気もする。
ただ、どのみち Python では、この手の処理は遅すぎてアレだなと…。
◎ 余談。 :
以前作成したスクリプトと生成画像が違ってしまって悩んでいたのだけど、以前作成したスクリプト内で、r2, g2, b2 と書くべきところを r2, b2, g2 と書いてしまっていたのが原因だった。以前のスクリプトの生成画像のほうが間違っていた…。
一応、修正して、Gist にアップロードし直しておいた。
_Yliluoma's ordered dithering algorithm 1, 2, 3. Python version.
一応、修正して、Gist にアップロードし直しておいた。
_Yliluoma's ordered dithering algorithm 1, 2, 3. Python version.
[ ツッコむ ]
2022/07/14(木) [n年前の日記]
#1 [prog] 減色ツール iZYINS をビルドしてみる
減色ツール xPadie のソースコードを参考にして、C# で書かれた iZYINS という減色ツールがあるそうで。ライセンスはGPL。
_iZYINS : Color Reducer on .NET Framework Project Top Page - OSDN
ただ、この iZYINS、ソースコードは公開されているけれど、実行バイナリは配布されてない。
ということで、ビルドできるか試してみた。
環境は、Windows10 x64 21H2 + Microsoft Visual Studio Community 2019。ちなみに今現在は Visual Studio 2022 が現行版らしい…。
_Visual Studio: ソフトウェア開発者とチーム向けの IDE およびコード エディター
_iZYINS : Color Reducer on .NET Framework Project Top Page - OSDN
ただ、この iZYINS、ソースコードは公開されているけれど、実行バイナリは配布されてない。
ということで、ビルドできるか試してみた。
環境は、Windows10 x64 21H2 + Microsoft Visual Studio Community 2019。ちなみに今現在は Visual Studio 2022 が現行版らしい…。
_Visual Studio: ソフトウェア開発者とチーム向けの IDE およびコード エディター
◎ ビルド手順。 :
iZYINS の公式サイトから、ソースコード、iZYINS100_src.zip をダウンロードした。解凍すると、中に iZYINS.sln というファイルがあった。これを Visual Studio で開けばいいのだろう…。「プロジェクト/ソリューションを開く」を選んで開けばいいのかな。たぶん。
開いたら、上のほうで「Debug」を「Release」にして、メニューの中から、ビルド → ソリューションのビルド、を選ぶ。
iZYINS\bin\Release\ 以下に、iZYINS.exe と iZYINS.pdb が出来上がった。これで実行バイナリが得られたのだと思う。たぶん。
.exeファイルは実行ファイルだけど、.pdbファイルは何だろう? ググってみたら、デバッグ時に必要なファイルらしい。プロジェクトのプロパティを設定すれば作らないようにできる模様。プロジェクト → xxxxのプロパティ → ビルド → 詳細 → デバッグ情報を「なし」にする。
以下、参考ページ。
_.pdb ファイルを生み出さない - rksoftware
_Visual StudioユーザーがReleaseビルドをするときに必ずやってほしい2つの設定 - Qiita
_PDB ファイルとは何か? - C# の開発環境 - C# 入門
開いたら、上のほうで「Debug」を「Release」にして、メニューの中から、ビルド → ソリューションのビルド、を選ぶ。
iZYINS\bin\Release\ 以下に、iZYINS.exe と iZYINS.pdb が出来上がった。これで実行バイナリが得られたのだと思う。たぶん。
.exeファイルは実行ファイルだけど、.pdbファイルは何だろう? ググってみたら、デバッグ時に必要なファイルらしい。プロジェクトのプロパティを設定すれば作らないようにできる模様。プロジェクト → xxxxのプロパティ → ビルド → 詳細 → デバッグ情報を「なし」にする。
以下、参考ページ。
_.pdb ファイルを生み出さない - rksoftware
_Visual StudioユーザーがReleaseビルドをするときに必ずやってほしい2つの設定 - Qiita
_PDB ファイルとは何か? - C# の開発環境 - C# 入門
◎ 使い方。 :
iZYINS の使い方は、大体以下のような感じ。
iZYINS.exe INPUT.png OUTPUT.png iZYINS.exe INPUT.png OUTPUT.png -P16 iZYINS.exe INPUT.png OUTPUT.png -P16 -D4 iZYINS.exe INPUT.png OUTPUT.png -P16 -D4 -R1
- iZYINS.exe 入力画像 出力画像、と指定する。
- -Pxx で色数を指定。例えば -P16 と指定すれば、16色に減色する。
- -Dx でディザパターンの種類を指定。-D4 と指定すれば、アニメ調とされるディザ(組織化ディザリング)になる。
- -R1 をつけると、出力画像が既に存在していても上書きする。
◎ 問題に遭遇。 :
動作確認していたら問題に遭遇した。-D4 をつければアニメ調のディザがかかるはずだけど、エラーを出してしまう。
以下の投稿(2009/09/12)で、元々そういう状態でソースが配布されていると知った。
_チケット #18654: ディザモードの1と4について - iZYINS : Color Reducer on .NET Framework - OSDN
もう一つ、問題に遭遇。-Fオプションを使って、パレットデータ相当の画像を渡そうとするとエラーが出てしまう。これでは固定パレットで減色できない…。
以下の投稿(2009/09/12)で、元々そういう状態でソースが配布されていると知った。
_チケット #18654: ディザモードの1と4について - iZYINS : Color Reducer on .NET Framework - OSDN
モード1は全体で単色で塗りつぶされてしまいモード4はエラーになるのですが、まだ実装されていないという事なのでしょうか?
モード4の方はエラーが出る部分だけ適当に弄ってみて(a2lの初期化と、Array.Sort(a2l,0,16)→Array.Sort(a2l,0,16,a2l0))一応は動作したのですが、少し試した感じではおかしな色が使われる事があるような気がします。チケット #18654: ディザモードの1と4について - iZYINS : Color Reducer on .NET Framework - OSDN より
もう一つ、問題に遭遇。-Fオプションを使って、パレットデータ相当の画像を渡そうとするとエラーが出てしまう。これでは固定パレットで減色できない…。
◎ ディザモード4でエラーが出る問題を修正。 :
自分はアニメ調のディザ、というか市松模様が大好きなので、ディザモード4を使えるようにしたい。前述の投稿記事を参考にしてソースを修正してみた。
問題を起こしてるソースは、iZYINS\Quant.cs だった。以下に、diff -u の結果を載せてみる。
_quant.cs.patch
要するに、関数 Mtscan() 内の記述がおかしいらしい。
ところで、a2l2 は使ってないように見えるのだけど、気のせいだろうか…?
問題を起こしてるソースは、iZYINS\Quant.cs だった。以下に、diff -u の結果を載せてみる。
- 行頭に「+」がついている行が追加した行。
- 行頭に「-」がついている行が削除した行。
_quant.cs.patch
--- iZYINS\Quant.cs.orig Mon Jul 21 20:04:24 2008 +++ iZYINS\Quant.cs Thu Jul 14 04:59:57 2022 @@ -62,20 +62,21 @@ } - public class Anime2line : IComparer + public class Anime2line { public int pal; public int d; + } + public class Anime2lineComparer : IComparer + { public int Compare(object a, object b) { - int n = (((Anime2line)a).d) - (((Anime2line)b).d); if (n > 0) return 1; if (n < 0) return -1; return (((Anime2line)a).pal) - (((Anime2line)b).pal); - - } + } } @@ -1185,8 +1186,20 @@ Anime2line[] a2l= new Anime2line[32]; Anime2line[] a2l2 = new Anime2line[16]; + Anime2lineComparer a2lcomp = new Anime2lineComparer(); + + for (i = 0; i < 32; i++) + a2l[i] = new Anime2line(); + + for (i = 0; i < 16; i++) + a2l2[i] = new Anime2line(); - Byte[] dit = { 0, 8, 2,10, 12, 4,14, 6, 3,11, 1, 9,15, 7,13, 5 }; + Byte[] dit = { + 0, 8, 2,10, + 12, 4,14, 6, + 3,11, 1, 9, + 15, 7,13, 5 + }; for (y=0;y<height;y++) { for (x=0;x<width;x++) { @@ -1208,8 +1221,9 @@ dz=(gz-gcstable[kk].Z)*ditherlevel/10; } + // Array.Sort(a2l, 0, 16); + Array.Sort(a2l, a2lcomp); - Array.Sort(a2l,0,16); k=a2l[dit[(y & 3)*4+(x & 3)]].pal; } palbuf[x+y*picx]=(byte)k;
要するに、関数 Mtscan() 内の記述がおかしいらしい。
- 元ソースでは、a2l, a2l2 のクラス配列サイズは確保されてるけど、クラスの実体(?)は確保されてないので、NULLポインタにアクセスしてエラーが出てしまう。改めて確保し直す。
- Array.Sort() を使ってクラス配列をソートしようとしてるけど、記述がおかしいっぽい。ソート用に、Anime2lineComparer というクラスを作っておいて、それを渡しつつソートするように指定してみた。
ところで、a2l2 は使ってないように見えるのだけど、気のせいだろうか…?
◎ パレットデータ画像を指定するとエラーが出る問題を修正。 :
もう一つの問題、-Fオプションでパレットデータ相当の画像ファイルを渡すとエラーになる件は、どうやらオプション解析がバグってた模様。Program.cs 内の以下を修正したら解決した。
_program.cs.patch
要するに、コマンドラインオプション文字列の「-Fxxxx」の「-F」だけ削除すれば済むはずが、「-Fx」を削除しちゃって、文字数が足りなくなってエラーが出ていた模様。また、-Hオプションにも同じバグがあった。
_program.cs.patch
--- iZYINS\Program.cs.orig Mon Jul 21 20:04:24 2008 +++ iZYINS\Program.cs Thu Jul 14 05:58:07 2022 @@ -60,7 +60,7 @@ string s = iZYINSVersion + " : Color Reducer on .NET Framework or MONO" + "\n\r" + "Copyright (C) 2005-2008 Y.Nomura all rights reserved." + "\n\r" + "This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA."; - + int n; if (args.Length < 1) @@ -209,7 +209,7 @@ } break; case 'F': - s = args[i].Substring(3, args[i].Length - 2); + s = args[i].Substring(2, args[i].Length - 2); if (File.Exists(s)) { Bitmap bmp = new Bitmap(s); @@ -224,7 +224,7 @@ } break; case 'H': - s = args[i].Substring(3, args[i].Length - 2); + s = args[i].Substring(2, args[i].Length - 2); if (File.Exists(s)) { Bitmap bmp = new Bitmap(s);
要するに、コマンドラインオプション文字列の「-Fxxxx」の「-F」だけ削除すれば済むはずが、「-Fx」を削除しちゃって、文字数が足りなくなってエラーが出ていた模様。また、-Hオプションにも同じバグがあった。
◎ 実行バイナリ。 :
せっかくビルドしたので、Visual Studio Community 2019 のプロジェクトフォルダごとzipにして置いときます。bin\Release\ 以下に実行バイナリも入ってます。ライセンスはGPLだから、修正ソースも一緒に同梱しておけば配布しても問題無いのではないかと…。たぶん。
_iZYINS100_src_fork01.zip
ただ、おそらく他にもバグがありそうな気配がする。前述の投稿記事によると、ディザのモードによっては正常な結果が得られない、と報告されてたし…。
まあ、学習用ソースコードという扱いらしいので、バグを見つけて自力で直してみましょう、というお題だったりするのかも。
_iZYINS100_src_fork01.zip
ただ、おそらく他にもバグがありそうな気配がする。前述の投稿記事によると、ディザのモードによっては正常な結果が得られない、と報告されてたし…。
まあ、学習用ソースコードという扱いらしいので、バグを見つけて自力で直してみましょう、というお題だったりするのかも。
◎ 余談。 :
ちなみに、iZYINS 関連の情報をググっているうちに知ったのだけど、減色ツール Yukari にかつて同梱されていたコンソール版 Flan.exe は、iZYINS で加えられた改良点が反映されていて、かつ、iZYINS のバグも修正してあるそうで。単に減色ツールを使いたいだけなら Flan.exe を入手して利用したほうが良さそうではあるなと。
_結社「障泥烏賊ライブラリ」用地
ただ、Flan.exe は、ウイルスとして誤検出される問題を抱えていて…。ウイルス対策ソフト側で Flan.exe はチェックしないように除外設定をするのが若干面倒ではあるなと…。
_結社「障泥烏賊ライブラリ」用地
ただ、Flan.exe は、ウイルスとして誤検出される問題を抱えていて…。ウイルス対策ソフト側で Flan.exe はチェックしないように除外設定をするのが若干面倒ではあるなと…。
[ ツッコむ ]
#2 [prog] Visual Studio Community 2022をインストールしてみた
Windows10 x64 21H2上で、Microsoft Visual Studio Community 2022 をインストールしてみた。
_Visual Studio Tools のダウンロード - Windows、Mac、Linux 用の無料インストール
VisualStudioSetup.exe をDLして実行。C++とC#のソースをビルドできるように、「C++によるデスクトップ開発」「.NETデスクトップ開発」にチェックを入れてインストールを進めた。インストール場所はデフォルトの Cドライブのまま。
ちなみに、Visual Studio Community 2019 もインストールされている環境なのだけど、2019 と 2022 の共存はできる模様。
ググった感じでは、2019 と比べて、IDE が64bitになって、Windows7/8 や 32bit環境はサポート外になったらしい。Winodws10/11、64bit環境しかサポートしない、ということなのだな…。
_Visual Studio Tools のダウンロード - Windows、Mac、Linux 用の無料インストール
VisualStudioSetup.exe をDLして実行。C++とC#のソースをビルドできるように、「C++によるデスクトップ開発」「.NETデスクトップ開発」にチェックを入れてインストールを進めた。インストール場所はデフォルトの Cドライブのまま。
ちなみに、Visual Studio Community 2019 もインストールされている環境なのだけど、2019 と 2022 の共存はできる模様。
ググった感じでは、2019 と比べて、IDE が64bitになって、Windows7/8 や 32bit環境はサポート外になったらしい。Winodws10/11、64bit環境しかサポートしない、ということなのだな…。
◎ 旧バージョンの入手。 :
ふと、今から 2019 Community は入手できるのかどうかが気になってあちこち辿ってみたのだけど。「古いバージョンのダウンロード」というリンクを辿っていったら入手できそうなページに辿り着いた。であれば、旧バージョン決め打ちで配布されてるプロジェクトに遭遇しても大丈夫、ということかな…。
[ ツッコむ ]
2022/07/15(金) [n年前の日記]
#1 [prog] FreeImageとDevILライブラリを試用
C/C++で、pngファイルを読み込んだり書き込んだりする処理をしてみたい。
画像処理用のライブラリとして、FreeImage、DevIL というライブラリがあるらしいと知ったので試用してみた。
_C/C++ にて 画像ファイルを読み込む - Qiita
動作確認環境は、Windows10 x64 21H2 + MSYS2 (MinGW64)。g++ 12.1.0。GNU Make 4.3。
画像処理用のライブラリとして、FreeImage、DevIL というライブラリがあるらしいと知ったので試用してみた。
_C/C++ にて 画像ファイルを読み込む - Qiita
動作確認環境は、Windows10 x64 21H2 + MSYS2 (MinGW64)。g++ 12.1.0。GNU Make 4.3。
◎ FreeImageライブラリ。 :
C/C++ から利用できる画像処理用ライブラリとして、FreeImage というライブラリがあるらしい。
_The FreeImage Project
ライセンスは、GPL、または FreeImage Public License (FIPL)。どちらかを選べる、ということなのだろう。たぶん。
_GNU General Public License | Open Source Initiative
_freeimage.sourceforge.net/freeimage-license.txt
MSYS2 なら、パッケージが既に用意されていた。pacman -Ss hoge でパッケージ検索。
インストールしてみる。pacman -S hoge でインストールできる。
以下を参考にしてサンプルを用意した。pngファイルを読み込んで、1ドットずつグレースケール変換して、out.png として保存する、という処理をしている。
_FreeImageで画像の読み込みと保存 - Qiita
_画像変換ツールを自作する - Qiita
_FreeImage 3.13.1 documentation - FreeImage3131.pdf
_01_load_png01.cpp
コンパイルは以下。
実行。
グレースケールになった out.png が得られた。
ただ、ldd 01_load_png01.exe と打って、使用している .dll を確認したところ、かなり多い。ここまで多いのでは、おそらく静的リンク(スタティックリンク)はできない予感がする。
_The FreeImage Project
ライセンスは、GPL、または FreeImage Public License (FIPL)。どちらかを選べる、ということなのだろう。たぶん。
_GNU General Public License | Open Source Initiative
_freeimage.sourceforge.net/freeimage-license.txt
MSYS2 なら、パッケージが既に用意されていた。pacman -Ss hoge でパッケージ検索。
$ pacman -Ss freeimage mingw32/mingw-w64-i686-freeimage 3.18.0-8 Library project for developers who would like to support popular graphics image formats (mingw-w64) mingw64/mingw-w64-x86_64-freeimage 3.18.0-8 Library project for developers who would like to support popular graphics image formats (mingw-w64) ucrt64/mingw-w64-ucrt-x86_64-freeimage 3.18.0-8 Library project for developers who would like to support popular graphics image formats (mingw-w64) clang32/mingw-w64-clang-i686-freeimage 3.18.0-8 Library project for developers who would like to support popular graphics image formats (mingw-w64) clang64/mingw-w64-clang-x86_64-freeimage 3.18.0-8 Library project for developers who would like to support popular graphics image formats (mingw-w64)
インストールしてみる。pacman -S hoge でインストールできる。
pacman -S mingw-w64-x86_64-freeimage pacman -S mingw-w64-i686-freeimage
以下を参考にしてサンプルを用意した。pngファイルを読み込んで、1ドットずつグレースケール変換して、out.png として保存する、という処理をしている。
_FreeImageで画像の読み込みと保存 - Qiita
_画像変換ツールを自作する - Qiita
_FreeImage 3.13.1 documentation - FreeImage3131.pdf
_01_load_png01.cpp
// load png image with freeimage. #include <stdio.h> #include <iostream> #include <FreeImage.h> const char *outfile = "out.png"; int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage:\n\t01_load_png01.exe IN.png\n"); return -1; } FreeImage_Initialise(FALSE); printf("FreeImage ver. %s\n", FreeImage_GetVersion()); printf("%s\n\n", FreeImage_GetCopyrightMessage()); try { auto filename = argv[1]; // get input image format FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; int flag = 0; fif = FreeImage_GetFileType(filename); if (fif == FIF_UNKNOWN) fif = FreeImage_GetFIFFromFilename(filename); if (fif == FIF_PNG) flag = PNG_DEFAULT; else if (fif == FIF_BMP) flag = BMP_DEFAULT; else if (fif == FIF_GIF) flag = GIF_DEFAULT; else if (fif == FIF_JPEG) flag = JPEG_DEFAULT; // load image FIBITMAP *image = FreeImage_Load(fif, filename, flag); if (image) printf("Load : %s\n", filename); else throw std::runtime_error("Load failed"); // convert to 24bit image FIBITMAP *image24 = FreeImage_ConvertTo24Bits(image); // convert greyscale int width = FreeImage_GetWidth(image24); int height = FreeImage_GetHeight(image24); FIBITMAP *newimg = FreeImage_Allocate(width, height, 24); RGBQUAD col; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { FreeImage_GetPixelColor(image24, x, y, &col); double ncol = 0.299 * col.rgbRed + 0.587 * col.rgbGreen + 0.114 * col.rgbBlue; if (ncol < 0) ncol = 0; if (ncol > 255) ncol = 255; col.rgbRed = int(ncol); col.rgbGreen = int(ncol); col.rgbBlue = int(ncol); FreeImage_SetPixelColor(newimg, x, y, &col); } } // save png image if (FreeImage_Save(FIF_PNG, newimg, outfile, PNG_DEFAULT)) printf("Save : %s\n", outfile); else throw std::runtime_error("Save failed"); FreeImage_Unload(image); FreeImage_Unload(newimg); } catch (std::exception &e) { std::cout << "exception!\n" << e.what() << std::endl; } FreeImage_DeInitialise(); return 0; }
コンパイルは以下。
g++ 01_load_png01.cpp -o 01_load_png01.exe -lfreeimage
実行。
./01_load_png01.exe in.png
グレースケールになった out.png が得られた。
ただ、ldd 01_load_png01.exe と打って、使用している .dll を確認したところ、かなり多い。ここまで多いのでは、おそらく静的リンク(スタティックリンク)はできない予感がする。
◎ DevILライブラリ。 :
C/C++から利用できる画像処理用ライブラリとして、DevILというライブラリがあるらしい。
_DevIL - A full featured cross-platform Image Library
_DevILを用いた画像ファイルの読み込み - 月とスカラベ
_How To Load and Display an Image with DevIL and OpenGL | Geeks3D
MSYS2では、FreeImage と同様にパッケージが用意されていた。
インストール。
あちこちからコピペしてサンプルを書いてみた。画像を読み込んで画像サイズを出力するだけのスクリプト。
_01_load_image_devil.cpp
以下でコンパイル。
一応動いたものの、ldd 01_load_image_devil.exe で使用DLLを確認したら、これまたかなりの .dllを利用すると分かった。
試しに -static をつけて静的リンクを試みたところ、-lIL -ILU が見つからないとエラーが出てしまった。ググった感じでは、静的リンクをするなら DevILライブラリ自体をビルドし直さないといけないらしい。
_DevIL - A full featured cross-platform Image Library
_DevILを用いた画像ファイルの読み込み - 月とスカラベ
_How To Load and Display an Image with DevIL and OpenGL | Geeks3D
MSYS2では、FreeImage と同様にパッケージが用意されていた。
$ pacman -Ss devil mingw32/mingw-w64-i686-devil 1.8.0-8 Library for reading several different image formats (mingw-w64) mingw64/mingw-w64-x86_64-devil 1.8.0-8 Library for reading several different image formats (mingw-w64) ucrt64/mingw-w64-ucrt-x86_64-devil 1.8.0-8 Library for reading several different image formats (mingw-w64) clang32/mingw-w64-clang-i686-devil 1.8.0-8 Library for reading several different image formats (mingw-w64) clang64/mingw-w64-clang-x86_64-devil 1.8.0-8 Library for reading several different image formats (mingw-w64)
インストール。
pacman -S mingw-w64-x86_64-devil pacman -S mingw-w64-i686-devil
あちこちからコピペしてサンプルを書いてみた。画像を読み込んで画像サイズを出力するだけのスクリプト。
_01_load_image_devil.cpp
// DevIL sample. #include <IL/ilu.h> #include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #undef USE_WCHAR_T int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage:\n\thoge.exe IN.png\n"); return 0; } char *filename = argv[1]; ILuint img; int width, height; // DevIL init ilInit(); iluInit(); // generate image ID ilGenImages(1, &img); ilBindImage(img); #ifdef USE_WCHAR_T // char to wchar_t size_t newsize = strlen(filename) + 1; wchar_t *wcfilename = new wchar_t[newsize]; size_t convertedChars = 0; mbstowcs_s(&convertedChars, wcfilename, newsize, filename, _TRUNCATE); #endif ILboolean fg; if (1) { // not use ilLoadImage() ILubyte *lump; ILuint size; FILE *fp; fp = fopen(filename, "rb"); fseek(fp, 0, SEEK_END); size = ftell(fp); lump = (ILubyte *)malloc(size); fseek(fp, 0, SEEK_SET); fread(lump, 1, size, fp); fclose(fp); fg = ilLoadL(IL_PNG, lump, size); free(lump); } else { // use ilLoadImage() fg = ilLoadImage(filename); } if (fg) { // load success printf("Load : %s\n", filename); width = ilGetInteger(IL_IMAGE_WIDTH); height = ilGetInteger(IL_IMAGE_HEIGHT); printf("image size : %d x %d\n", width, height); if (ilGetInteger(IL_IMAGE_ORIGIN) != IL_ORIGIN_LOWER_LEFT) { iluFlipImage(); } } else { // load failure ILenum err = ilGetError(); std::cerr << iluErrorString(err) << std::endl; } ilDeleteImages(1, &img); #ifdef USE_WCHAR_T delete wcfilename; #endif return 0; }
以下でコンパイル。
g++ 01_load_image_devil.cpp -o 01_load_image_devil.exe -lIL -lILU
一応動いたものの、ldd 01_load_image_devil.exe で使用DLLを確認したら、これまたかなりの .dllを利用すると分かった。
試しに -static をつけて静的リンクを試みたところ、-lIL -ILU が見つからないとエラーが出てしまった。ググった感じでは、静的リンクをするなら DevILライブラリ自体をビルドし直さないといけないらしい。
◎ wchar_t と char の変換。 :
Visual Studio Code 上で、DevIL のサンプルを書いていた際、ilLoadImage() に char* を渡す書き方をしたところ、「この関数は wchar_t* を要求している」と警告が表示されてしまった。
色々ググって、char* を wchar_t* に変換するやり方を記述したのだけど…。MSYS2 + MinGW64 でビルドしてみたら、今度は「これは char* を要求する関数だぞ」と言われてエラーが出てしまった。
どうやら、Visual Studio Code 上の警告は無視して、そのまま char* を渡せば良かったらしい。
ちなみに、char* から wchar_t* に変換する処理は以下。wcfilename に wchar_t の文字列が入る。はず。また、使い終わったら delete で消去(解放)しておかないといけない。
さておき。前述の問題の解決策が分かった。#define _UNICODE を無効にすれば、wchar_t* ではなく char* が使われる状態になるらしい。そのあたり、以下の韓国語ページで解説されていた。
_c++ devil library char または wchar_t の問題
vscode(Visual Studio Code)上で、この定義、_UNICODE を無効にするためには、以下の解説に従って作業する。
_Visual Studio Code C++ remove 'define' in c_cpp_properties.json - Stack Overflow
まず、vscode-preinclude.h というファイルをワークスペースフォルダ内に作って、以下の一文を書いておく。
vscode上で、Ctrl + Shift + P → C/C++:構成の編集(UI) C/C++: Edit Configurations (UI)。設定画面が出てくるので下のほうまでスクロールして「詳細設定」をクリック。「強制インクルード」の欄に以下を記述。
これで、vscode に vscode-preinclude.h が読み込まれて、そこに _UNICODE の定義を削除する一文が書いてあるから、DevIL の各関数が、wchar_t* ではなく char* を要求するものとして vscode に認識されて、おかしな警告が表示されなくなる。
あるいは、以下で紹介されているように、C++ の標準機能でファイルを開いてメモリに格納してから、そのメモリ領域を ilLoadL() に渡すのもアリかもしれない。
_The Developer's Image Library (DevIL) Tutorials
色々ググって、char* を wchar_t* に変換するやり方を記述したのだけど…。MSYS2 + MinGW64 でビルドしてみたら、今度は「これは char* を要求する関数だぞ」と言われてエラーが出てしまった。
どうやら、Visual Studio Code 上の警告は無視して、そのまま char* を渡せば良かったらしい。
ちなみに、char* から wchar_t* に変換する処理は以下。wcfilename に wchar_t の文字列が入る。はず。また、使い終わったら delete で消去(解放)しておかないといけない。
// char to wchar_t size_t newsize = strlen(filename) + 1; wchar_t *wcfilename = new wchar_t[newsize]; size_t convertedChars = 0; mbstowcs_s(&convertedChars, wcfilename, newsize, filename, _TRUNCATE); ... delete wcfilename;
さておき。前述の問題の解決策が分かった。#define _UNICODE を無効にすれば、wchar_t* ではなく char* が使われる状態になるらしい。そのあたり、以下の韓国語ページで解説されていた。
_c++ devil library char または wchar_t の問題
vscode(Visual Studio Code)上で、この定義、_UNICODE を無効にするためには、以下の解説に従って作業する。
_Visual Studio Code C++ remove 'define' in c_cpp_properties.json - Stack Overflow
まず、vscode-preinclude.h というファイルをワークスペースフォルダ内に作って、以下の一文を書いておく。
#undef _UNICODE
vscode上で、Ctrl + Shift + P → C/C++:構成の編集(UI) C/C++: Edit Configurations (UI)。設定画面が出てくるので下のほうまでスクロールして「詳細設定」をクリック。「強制インクルード」の欄に以下を記述。
${workspaceFolder}/vscode-preinclude.h
これで、vscode に vscode-preinclude.h が読み込まれて、そこに _UNICODE の定義を削除する一文が書いてあるから、DevIL の各関数が、wchar_t* ではなく char* を要求するものとして vscode に認識されて、おかしな警告が表示されなくなる。
あるいは、以下で紹介されているように、C++ の標準機能でファイルを開いてメモリに格納してから、そのメモリ領域を ilLoadL() に渡すのもアリかもしれない。
_The Developer's Image Library (DevIL) Tutorials
[ ツッコむ ]
#2 [nitijyou] 体調が悪い
朝、妙な息苦しさを感じた。喉にも痛みが。なんだろうコレは…。
実のところ、昨日一昨日から息苦しさを感じる瞬間はあって。寝ようとして横になったら急に息苦しくなったりとか。
症状からして、もしやコロナだろうか…。外出、というか密になる場面はできるだけ少なくしてるつもりなのだけど…。 *1
実のところ、昨日一昨日から息苦しさを感じる瞬間はあって。寝ようとして横になったら急に息苦しくなったりとか。
症状からして、もしやコロナだろうか…。外出、というか密になる場面はできるだけ少なくしてるつもりなのだけど…。 *1
*1: 夜食を買いに、数日に1回、近所のスーパー(ザ・ビッグ)、もしくはドラッグストア(カワチ)に入るぐらいで。できるだけ素早く買い物して早く店から出るように心掛けてはいるつもり。
[ ツッコむ ]
2022/07/16(土) [n年前の日記]
#1 [prog] 画像処理ライブラリを探してた
昨日、FreeImage と DeviIL という、C/C++で利用できる画像処理ライブラリを試用してみたものの、静的リンク(スタティックリンク)が難しそうなあたりがちょっと厳しかったので、他に良さそうな画像処理ライブラリは無いものかとググってた。
興味が湧いたのは、stbライブラリだろうか…。ヘッダファイルの形で提供しているので、#inlcude するだけで利用できてしまうそうで。
_nothings/stb: stb single-file public domain libraries for C/C++
_でらうま倶楽部 : stbライブラリが便利すぎる!!
_C++で超簡単に画像出力+サンプル - Qiita
_Reading an image file in C/C++ - Stack Overflow
_stbライブラリを使おうとするとLNK2001(外部シンボルは未解決です)エラーになる
_c++ - stb_image.h in Visual Studio - unresolved external symbol - Stack Overflow
_stbライブラリで画像読み込み | ぬの部屋(仮)
他にも、シングルファイルに近い形で提供されてるライブラリがいくつか存在しているらしい。
_nothings/single_file_libs: List of single-file C/C++ libraries.
CImgというライブラリも気になった。
_The CImg Library - C++ Template Image Processing Library
_dtschump/CImg: The CImg Library is a small and open-source C++ toolkit for image processing
_CImg を使う C++ プログラム例
_The CImg Library - C++ Template Image Processing Toolkit - Reference Documentation
興味が湧いたのは、stbライブラリだろうか…。ヘッダファイルの形で提供しているので、#inlcude するだけで利用できてしまうそうで。
_nothings/stb: stb single-file public domain libraries for C/C++
_でらうま倶楽部 : stbライブラリが便利すぎる!!
_C++で超簡単に画像出力+サンプル - Qiita
_Reading an image file in C/C++ - Stack Overflow
_stbライブラリを使おうとするとLNK2001(外部シンボルは未解決です)エラーになる
_c++ - stb_image.h in Visual Studio - unresolved external symbol - Stack Overflow
_stbライブラリで画像読み込み | ぬの部屋(仮)
他にも、シングルファイルに近い形で提供されてるライブラリがいくつか存在しているらしい。
_nothings/single_file_libs: List of single-file C/C++ libraries.
CImgというライブラリも気になった。
_The CImg Library - C++ Template Image Processing Library
_dtschump/CImg: The CImg Library is a small and open-source C++ toolkit for image processing
_CImg を使う C++ プログラム例
_The CImg Library - C++ Template Image Processing Toolkit - Reference Documentation
[ ツッコむ ]
2022/07/17(日) [n年前の日記]
#1 [prog] stbライブラリを試用
_昨日調べて
存在を知った、C/C++で画像処理をするためのstbライブラリを少しだけ試用。
_nothings/stb: stb single-file public domain libraries for C/C++
動作確認環境は Windows10 x64 21H2 + MSYS2 + MinGW64。g++ 12.1.0。GNU Make 4.3。
今回は画像のロードとセーブを試してみたかったので、stb_image.h と stb_image_write.h をDL。メインとなるソースコードと同じ場所に置いて利用した。
_nothings/stb: stb single-file public domain libraries for C/C++
動作確認環境は Windows10 x64 21H2 + MSYS2 + MinGW64。g++ 12.1.0。GNU Make 4.3。
今回は画像のロードとセーブを試してみたかったので、stb_image.h と stb_image_write.h をDL。メインとなるソースコードと同じ場所に置いて利用した。
◎ 画像ロード。 :
stb_image.h の使用例。画像(.png)を読み込んで、画像サイズと1ピクセルあたりのバイト数を出力する。
_01_loadimage.cpp
コンパイルは以下。ここでは静的リンク(スタティックリンク)をしている。
以下で実行。画像サイズと Byte per pixel が出力された。
stb_image.h の使い方としては、最初に以下を書いておく。
_01_loadimage.cpp
// load image with stb_image.h #include <stdio.h> #define STB_IMAGE_STATIC #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage\n\t01_loadimage.exe IN.png"); } auto filename = argv[1]; unsigned char *pixels; int width; int height; int bpp; pixels = stbi_load(filename, &width, &height, &bpp, 0); printf("Image size %d x %d\n", width, height); printf("Image bpp %d\n", bpp); stbi_image_free(pixels); }
コンパイルは以下。ここでは静的リンク(スタティックリンク)をしている。
g++ 01_loadimage.cpp -o 01_loadimage.exe -static -lstdc++ -lgcc -lwinpthread
以下で実行。画像サイズと Byte per pixel が出力された。
$ ./01_loadimage.exe in.png Image size 512 x 512 Image bpp 3
stb_image.h の使い方としては、最初に以下を書いておく。
#define STB_IMAGE_STATIC #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h"
- stb_image.h を使う場合、必ず、「#define STB_IMAGE_IMPLEMENTATION」と「#include "stb_image.h"」を記述する。
- STB_IMAGE_STATIC を定義しておくと、各関数の頭に static がつく、らしい。
- stbi_load() で画像のロード。
- 画像を使い終わったら stbi_image_free() で解放する。
◎ 画像セーブ。 :
stb_image_write.h の使用例。画像(.png)を読み込んで、グレースケールに変換して、out.png というファイル名で保存する。
_02_writeimage.cpp
コンパイル。
実行。
グレースケールの画像が得られた。
stb_image_write.h の使い方としては、最初に以下を書いておく。
ちなみに、stb_image_write.h 内のコメントによると、ソースコードの量を減らすためにpng画像の圧縮率は低い状態になっているそうで。zlib関係の関数を STBIW_ZLIB_COMPRESS に定義することで圧縮率は改善できると書いてあった。もちろん、zlib を使えるようにビルドしないといかんのだろうけど。
何にせよ、stb_image.h にしろ、stb_image_write.h にしろ、比較的簡単な記述で画像のロードやセーブができる上に、静的リンクもすんなりできてしまうとは…。これは便利だなと…。
_02_writeimage.cpp
// write png image with stb_image_write.h #include <stdio.h> #define STB_IMAGE_STATIC #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #define STB_IMAGE_WRITE_STATIC #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage\n\t02_writeimage.exe IN.png"); } auto filename = argv[1]; unsigned char *pixels; int width; int height; int bpp; // load image pixels = stbi_load(filename, &width, &height, &bpp, 0); printf("Image size %d x %d\n", width, height); printf("Image bpp %d\n", bpp); for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) { int idx = (y * width + x) * bpp; unsigned int r = (unsigned int)pixels[idx + 0]; unsigned int g = (unsigned int)pixels[idx + 1]; unsigned int b = (unsigned int)pixels[idx + 2]; // convert greyscale if (1) { double grey = 0.299 * (double)r + 0.587 * (double)g + 0.114 * (double)b; if (grey < 0) grey = 0; if (grey > 255) grey = 255; unsigned int ui_grey = (unsigned int)grey; pixels[idx + 0] = ui_grey; pixels[idx + 1] = ui_grey; pixels[idx + 2] = ui_grey; } } // write image if (stbi_write_png("out.png", width, height, 3, pixels, width * 3)) { printf("Save out.png\n"); } else { printf("Failure save.\n"); } stbi_image_free(pixels); }
コンパイル。
g++ 02_writeimage.cpp -o 02_writeimage.exe -static -lstdc++ -lgcc -lwinpthread
実行。
$ ./02_writeimage.exe in.png Image size 512 x 512 Image bpp 3 Save out.png
グレースケールの画像が得られた。
stb_image_write.h の使い方としては、最初に以下を書いておく。
#define STB_IMAGE_WRITE_STATIC #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h"
- stb_image_write.h を使う場合、必ず、「#define STB_IMAGE_WRITE_IMPLEMENTATION」と「#include "stb_image_write.h"」を記述する。
- STB_IMAGE_WRITE_STATIC を定義しておくと、各関数の頭に static がつく、らしい。
- stbi_write_png() で、png画像の保存。
stbi_write_png(保存ファイル名, 画像横幅, 画像縦幅, bpp, ピクセルデータ群へのポインタ, 1ライン分のバイト数)ただ、巷のサンプルを見ると、一番最後で「0」を指定してる場合が多くて…。
ちなみに、stb_image_write.h 内のコメントによると、ソースコードの量を減らすためにpng画像の圧縮率は低い状態になっているそうで。zlib関係の関数を STBIW_ZLIB_COMPRESS に定義することで圧縮率は改善できると書いてあった。もちろん、zlib を使えるようにビルドしないといかんのだろうけど。
何にせよ、stb_image.h にしろ、stb_image_write.h にしろ、比較的簡単な記述で画像のロードやセーブができる上に、静的リンクもすんなりできてしまうとは…。これは便利だなと…。
◎ stbi_write_png() の最後の引数について。 :
stbi_write_png() の最後の引数がよく分からなかったけど、ソースを眺めた感じでは 0 を指定しても良かったらしい。
stbi_write_png() は、内部で stbi_write_png_to_mem() を呼んでいるけれど、この stbi_write_png_to_mem() の中で、値が 0 なら width * bpp を代入、みたいなことをしている。
なので、自分で指定してもいいし、面倒臭ければ 0 を指定してもよい。どちらも同じ結果になるはず。たぶん。
stbi_write_png() は、内部で stbi_write_png_to_mem() を呼んでいるけれど、この stbi_write_png_to_mem() の中で、値が 0 なら width * bpp を代入、みたいなことをしている。
なので、自分で指定してもいいし、面倒臭ければ 0 を指定してもよい。どちらも同じ結果になるはず。たぶん。
[ ツッコむ ]
2022/07/18(月) [n年前の日記]
#1 [prog] getoptについて調べてる
C/C++で書かれているコマンドラインツール(?)の中で、コマンドラインオプションの解析をしたい。
ググってみた感じでは、getopt() や getopt_long() を使うと、多少は簡単に処理を書けるらしい。試してみた。
環境は Windows10 x64 21H2 + MSYS2 + MinGW64 + g++ 12.1.0。
_getopt_sample.cpp
コンパイル。
オプションを指定して実行してみる。
ヘルプメッセージは自分で列挙するしかないのだろうか…?
ググってみた感じでは、getopt() や getopt_long() を使うと、多少は簡単に処理を書けるらしい。試してみた。
環境は Windows10 x64 21H2 + MSYS2 + MinGW64 + g++ 12.1.0。
_getopt_sample.cpp
// getopt() sample. #include <stdio.h> #include <getopt.h> void usage(char *name) { printf("Usage:\n"); printf(" %s -i IN.png -o OUT.png [-d N]\n", name); printf("\n"); printf(" -i FILE, --input FILE input png image file.\n"); printf(" -o FILE, --output FILE output png image file.\n"); printf(" -d N, --dither N dither map. N = 2/4/8 (2x2, 4x4, 8x8)\n"); printf(" -h, --help display help message\n"); printf("\n"); } int main(int argc, char **argv) { // parse option char *infile = NULL; char *outfile = NULL; int dither = 4; struct option longopts[] = { {"help", no_argument, NULL, 'h'}, {"input", required_argument, NULL, 'i'}, {"output", required_argument, NULL, 'o'}, {"dither", required_argument, NULL, 'd'}, {0, 0, 0, 0}}; int opt; int longindex; while ((opt = getopt_long(argc, argv, "hi:o:d:", longopts, &longindex)) != -1) { switch (opt) { case 'i': // input image filename infile = optarg; break; case 'o': // output image filename outfile = optarg; break; case 'd': // dither map size, 2 or 4 or 8 switch (optarg[0]) { case '2': dither = 2; break; case '4': dither = 4; break; case '8': dither = 8; break; default: printf("Error : Unknown dither mode = %s\n\n", optarg); dither = -1; break; } break; case 'h': // help usage(argv[0]); return 0; default: break; } } if (optind < argc) { for (; optind < argc; optind++) printf("Unknown option : %s\n", argv[optind]); usage(argv[0]); return 1; } printf("infile : %s\n", infile); printf("outfile : %s\n", outfile); printf("dither : %d\n", dither); if (infile == NULL || outfile == NULL || dither == -1) { usage(argv[0]); return 1; } }
コンパイル。
g++ getopt_sample.cpp -o getopt_sample.exe
オプションを指定して実行してみる。
$ ./getopt_sample.exe --help Usage: D:\...\getopt_sample.exe -i IN.png -o OUT.png [-d N] -i FILE, --input FILE input png image file. -o FILE, --output FILE output png image file. -d N, --dither N dither map. N = 2/4/8 (2x2, 4x4, 8x8) -h, --help display help message $ ./getopt_sample.exe -i in.png -o out.png -d 2 infile : in.png outfile : out.png dither : 2
- getopt() を使う場合、#include <getopt.h> を記述。
- getopt() は、-a や -b 等の短いオプションを解析する際に使える。
- getopt_long() は、--input 等の長いオプションを解析する際に使える。
ヘルプメッセージは自分で列挙するしかないのだろうか…?
◎ 参考ページ。 :
[ ツッコむ ]
2022/07/19(火) [n年前の日記]
#1 [prog] cmdline.hを少し試用
C++で書いたコマンドラインツールに、コマンドラインオプションを渡して、処理が変わるようにしたい。昨日、getopt() や getopt_long() を使って試してみたけど、それらは記述が面倒だなと…。ヘルプメッセージは自分で用意しないといけないし。
もっと便利なライブラリは無いのかなとググったら、cmdline.h というライブラリがあることを知った。ヘッダーファイル1つを inlcude するだけで使えるらしい。
_C++向け簡易コマンドラインパーザ cmdline - 純粋関数型雑記帳
_tanakh/cmdline: A Command Line Parser
_C++版のgetopt - Qiita
興味が湧いたので、手元で動作確認。動作確認環境は、Windows10 x64 21H2 + MSYS2 + MinGW64 + g++ 12.1.0。
_getopt_sample2.cpp
コンパイルは以下。
実行。
記述量も少なくて済むし、ヘルプメッセージも自動生成してくれるし、ヘッダファイル1つだから使うのも楽だし、静的リンクもしやすい。これは便利だなと…。
もっと便利なライブラリは無いのかなとググったら、cmdline.h というライブラリがあることを知った。ヘッダーファイル1つを inlcude するだけで使えるらしい。
_C++向け簡易コマンドラインパーザ cmdline - 純粋関数型雑記帳
_tanakh/cmdline: A Command Line Parser
_C++版のgetopt - Qiita
興味が湧いたので、手元で動作確認。動作確認環境は、Windows10 x64 21H2 + MSYS2 + MinGW64 + g++ 12.1.0。
_getopt_sample2.cpp
#include "cmdline.h" #include <stdio.h> #include <iostream> int main(int argc, char *argv[]) { // parse options cmdline::parser a; a.add<std::string>("input", 'i', "Input png image", true, ""); a.add<std::string>("output", 'o', "Output png image", true, ""); a.add<std::string>("palette", 'p', "Palette (.png or .gpl)", false, ""); a.add<int>("dither", 'd', "Dither map 2/4/8 (2x2/4x4/8x8)", false, 4); a.parse_check(argc, argv); // get options auto infile = a.get<std::string>("input").c_str(); auto outfile = a.get<std::string>("output").c_str(); auto palette = a.get<std::string>("palette").c_str(); auto dither = a.get<int>("dither"); if (0) { std::cout << "input : " << infile << std::endl; std::cout << "output : " << outfile << std::endl; std::cout << "palette : " << palette << std::endl; std::cout << "dither : " << dither << std::endl; } else { printf("input : [%s]\n", infile); printf("output : [%s]\n", outfile); printf("palette : [%s]\n", palette); printf("dither : %d\n", dither); } if (strlen(infile) == 0 || strlen(outfile) == 0) { // Not set infile or outfile printf("%s\n", a.usage().c_str()); return 1; } if (strlen(palette) == 0) { // Not set palette printf("Use default palette\n"); } if (!(dither == 2 || dither == 4 || dither == 8)) { printf("Error : Unknown dither mode = %d\n\n", dither); printf("%s\n", a.usage().c_str()); return 1; } return 0; }
コンパイルは以下。
g++ getopt_sample2.cpp -o getopt_sample2.exe -static -lstdc++ -lgcc -lwinpthread -lm
実行。
$ ./getopt_sample2.exe --help usage: D:\...\getopt_sample2.exe --input=string --output=string [options] ... options: -i, --input Input png image (string) -o, --output Output png image (string) -p, --palette Palette (.png or .gpl) (string [=]) -d, --dither Dither map 2/4/8 (2x2/4x4/8x8) (int [=4]) -?, --help print this message $ ./getopt_sample2.exe -i in.png -o out.png -d 8 input : [in.png] output : [out.png] palette : [] dither : 8 Use default palette $ ./getopt_sample2.exe --input in.png --output out.png --dither 8 input : [in.png] output : [out.png] palette : [] dither : 8 Use default palette
記述量も少なくて済むし、ヘルプメッセージも自動生成してくれるし、ヘッダファイル1つだから使うのも楽だし、静的リンクもしやすい。これは便利だなと…。
[ ツッコむ ]
#2 [prog] パレットデータ相当を読み込みたい
C++で、パレットデータ相当を読み込みたい。以下のような処理をしたい。
ということで、一応そういう処理を書いてみた。
動作確認環境は、Windows10 x64 21H2 + MSYS2 + MinGW64 + g++ 12.1.0。
画像の読み込みには、stbライブラリ(stb_image.h) を使わせてもらった。ありがたや。
_nothings/stb: stb single-file public domain libraries for C/C++
- png画像を読み込んで、画像内で使われているRGB値を数え上げて、パレットデータ相当として扱う。
- あるいは、テキストデータである .gplファイル(GIMP Paletteファイル)を読み込んで、列挙されているRGB値をパレットデータとして扱う。
ということで、一応そういう処理を書いてみた。
動作確認環境は、Windows10 x64 21H2 + MSYS2 + MinGW64 + g++ 12.1.0。
画像の読み込みには、stbライブラリ(stb_image.h) を使わせてもらった。ありがたや。
_nothings/stb: stb single-file public domain libraries for C/C++
◎ ソース。 :
ソースは以下。
_loadpalette.cpp
コンパイルは以下。
実行は以下。
.gpl も .png も読み込めているように見える。
動作確認に使った .gpl、.png は以下。
_def16.gpl
_def16.png
_loadpalette.cpp
// load palette (.gpl or .png) #include <map> #include <string.h> /* use stb library nothings/stb: stb single-file public domain libraries for C/C++ https://github.com/nothings/stb */ #define STB_IMAGE_STATIC #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #define CBUF_N 1024 #define TMP_PAL_NUM 1024 unsigned int *load_palette_from_gpl(char *infile, int *len_pal) { unsigned int *pal = nullptr; unsigned int tmp_pal[TMP_PAL_NUM]; FILE *fp; char str[CBUF_N]; unsigned int r, g, b; int idx = 0; for (int i = 0; i < TMP_PAL_NUM; i++) tmp_pal[i] = 0; fp = fopen(infile, "r"); if (fp == NULL) { printf("Error : Can not open %s\n", infile); *len_pal = 0; return nullptr; } while (fgets(str, CBUF_N, fp) != NULL) { str[strlen(str) - 1] = '\0'; if (strncmp("GIMP Palette", str, 12) == 0) continue; if (strncmp("Name:", str, 5) == 0) continue; if (strncmp("Columns", str, 7) == 0) continue; if (strncmp("#", str, 1) == 0) continue; sscanf(str, "%d %d %d", &r, &g, &b); // printf("%s", str); // printf("\t\tRGB : (%d, %d, %d)\n", r, g, b); tmp_pal[idx] = (r << 16) | (g << 8) | b; idx++; } fclose(fp); *len_pal = idx; pal = new unsigned int[idx]; for (int i = 0; i < idx; i++) pal[i] = tmp_pal[i]; return pal; } unsigned int *load_palette_from_img(char *infile, int *len_pal) { unsigned int *pal = nullptr; std::map<unsigned int, unsigned int> pal_map; // load image unsigned char *pixels; int w; int h; int bpp; pixels = stbi_load(infile, &w, &h, &bpp, 0); if (pixels == NULL) { printf("Error : Can not load %s\n", infile); *len_pal = 0; return nullptr; } for (int y = 0; y < h; y++) { int yofs = y * w * bpp; for (int x = 0; x < w; x++) { int i = x * bpp + yofs; unsigned int col = (pixels[i + 0] << 16) | (pixels[i + 1] << 8) | pixels[i + 2]; pal_map[col] += 1; } } stbi_image_free(pixels); int n = pal_map.size(); // pal = (unsigned int *)malloc(sizeof(unsigned int) * n); pal = new unsigned int[n]; int j = 0; for (auto i = pal_map.begin(); i != pal_map.end(); i++) { pal[j] = i->first; j++; } // printf("Count palette = %d\n", j); *len_pal = j; return pal; } unsigned int *load_palette(char *infile, int *len_pal) { unsigned int *pal = nullptr; int n; char *ext = strrchr(infile, '.'); if (stricmp(".gpl", ext) == 0) { // load from .gpl (GIMP palette file) pal = load_palette_from_gpl(infile, &n); } else { // load from .png pal = load_palette_from_img(infile, &n); } *len_pal = n; return pal; } int main(int argc, char **argv) { if (argc != 2) { printf("Usage:\n %s PALETTE\n\n PALETTE (.png or .gpl)\n", argv[0]); return 0; } auto palfile = argv[1]; printf("Palette : %s\n", palfile); int len_pal = 0; unsigned int *my_pal = load_palette(palfile, &len_pal); if (my_pal == nullptr) { printf("Error : Load failure palette [%s]\n", palfile); return 1; } printf("Palette size = %d\n", len_pal); // dump palette data for (int i = 0; i < len_pal; i++) printf("%06X, ", my_pal[i]); printf("\n"); for (int i = 0; i < len_pal; i++) { unsigned int col = my_pal[i]; unsigned int r = (col >> 16) & 0x0ff; unsigned int g = (col >> 8) & 0x0ff; unsigned int b = col & 0x0ff; printf("{%d, %d, %d}, ", r, g, b); } printf("\n"); delete my_pal; }
コンパイルは以下。
g++ loadpalette.cpp -o loadpalette.exe -static -lstdc++ -lgcc -lwinpthread -lm
実行は以下。
$ ./loadpalette.exe def16.gpl Palette : def16.gpl Palette size = 16 080000, 201A0B, 432817, 492910, 234309, 5D4F1E, 9C6B20, A9220F, 2B347C, 2B7409, D0CA40, E8A077, 6A94AB, D5C4B3, FCE76E, FCFAE2, {8, 0, 0}, {32, 26, 11}, {67, 40, 23}, {73, 41, 16}, {35, 67, 9}, {93, 79, 30}, {156, 107, 32}, {169, 34, 15}, {43, 52, 124}, {43, 116, 9}, {208, 202, 64}, {232, 160, 119}, {106, 148, 171}, {213, 196, 179}, {252, 231, 110}, {252, 250, 226}, $ ./loadpalette.exe def16.png Palette : def16.png Palette size = 16 080000, 201A0B, 234309, 2B347C, 2B7409, 432817, 492910, 5D4F1E, 6A94AB, 9C6B20, A9220F, D0CA40, D5C4B3, E8A077, FCE76E, FCFAE2, {8, 0, 0}, {32, 26, 11}, {35, 67, 9}, {43, 52, 124}, {43, 116, 9}, {67, 40, 23}, {73, 41, 16}, {93, 79, 30}, {106, 148, 171}, {156, 107, 32}, {169, 34, 15}, {208, 202, 64}, {213, 196, 179}, {232, 160, 119}, {252, 231, 110}, {252, 250, 226},
.gpl も .png も読み込めているように見える。
動作確認に使った .gpl、.png は以下。
_def16.gpl
◎ 余談。 :
.gpl内のRGB値をどうやって取り込めばいいのか悩んだけれど、sscanf() であっさり取り込めてしまった。ただ、.gpl内の記述の仕方によっては、sscanf() で対応できなくてエラーになる場面もありそう。
そもそも .gplの記述ルールがアバウト過ぎる気もする。空白無し、区切り文字は「,」にでもしておけばよかったのに。あるいは xml にしておくとか。
そもそも .gplの記述ルールがアバウト過ぎる気もする。空白無し、区切り文字は「,」にでもしておけばよかったのに。あるいは xml にしておくとか。
[ ツッコむ ]
2022/07/20(水) [n年前の日記]
#1 [cg_tools][tic80] TIC-80のパレットデータを手元に残そうとして少しハマった
TIC-80 は、ある時期からパレットデータを SWEETIE 16 というデータに差し替えていたらしいのだけど。
*1
_Palette - nesbox/TIC-80 Wiki
_Sweetie 16 Palette - lospec.com
この SWEETIE 16 パレットデータを手元に残そうとして、少しハマってしまった。
TIC-80 の Wiki にアップロードされているパレットデータ画像は、ページに記述されてる数値とビミョーに違っているようで…。具体的には、水色がちょっとずれてる。作業していてなんだか変だなと思ったら、そういうオチだった…。
そんなわけで、画像はちょっと当てにならないので、記述されている数値を元にしてパレットデータ画像を新規に生成するPythonスクリプトを書いてみた。
いやまあ、losepc.com からダウンロードできる画像や .gpl を使えば問題無さそうだけど…。ざっと調べた感じでは、そちらはちゃんと数値が合ってるように見えた。TIC-80 の Wiki に載ってる画像のみがおかしい。
_Sweetie 16 Palette - lospec.com
でもまあ、「Python + Pillow を使えばこういうこともできるよね」的サンプルの一つ、みたいな感じで一応アップロードしておきます。
_Palette - nesbox/TIC-80 Wiki
_Sweetie 16 Palette - lospec.com
この SWEETIE 16 パレットデータを手元に残そうとして、少しハマってしまった。
TIC-80 の Wiki にアップロードされているパレットデータ画像は、ページに記述されてる数値とビミョーに違っているようで…。具体的には、水色がちょっとずれてる。作業していてなんだか変だなと思ったら、そういうオチだった…。
そんなわけで、画像はちょっと当てにならないので、記述されている数値を元にしてパレットデータ画像を新規に生成するPythonスクリプトを書いてみた。
いやまあ、losepc.com からダウンロードできる画像や .gpl を使えば問題無さそうだけど…。ざっと調べた感じでは、そちらはちゃんと数値が合ってるように見えた。TIC-80 の Wiki に載ってる画像のみがおかしい。
_Sweetie 16 Palette - lospec.com
でもまあ、「Python + Pillow を使えばこういうこともできるよね」的サンプルの一つ、みたいな感じで一応アップロードしておきます。
◎ 生成した .gpl や .png。 :
◎ 生成Pythonスクリプト。 :
動作確認環境は、Windows10 x64 21H2 + Python 3.9.13 64bit + Pillow 9.1.1。
sweetie-16_tic80new_.gpl と sweetie-16_tic80new.png を生成する。
動作には Pillow のインストールが必要。pip install Pillow -U でインストールできるはず。
_create_sweetie-16_image.py
py create_sweetie-16_image.py で実行すれば、.gpl と .png が得られる。
sweetie-16_tic80new_.gpl と sweetie-16_tic80new.png を生成する。
動作には Pillow のインストールが必要。pip install Pillow -U でインストールできるはず。
_create_sweetie-16_image.py
from PIL import Image from PIL import ImageDraw out_gpl_file = "sweetie-16_tic80new_.gpl" out_img_file = "sweetie-16_tic80new.png" title = "Sweetie-16 (TIC-80 new)" tbl = [ ["Black", 0, "1A1C2C"], ["Purple", 1, "5D275D"], ["Red", 2, "B13E53"], ["Orange", 3, "EF7D57"], ["Yellow", 4, "FFCD75"], ["Light Green", 5, "A7F070"], ["Green", 6, "38B764"], ["Dark Green", 7, "257179"], ["Dark Blue", 8, "29366F"], ["Blue", 9, "3B5DC9"], ["Light Blue", 10, "41A6F6"], ["Cyan", 11, "73EFF7"], ["White", 12, "F4F4F4"], ["Light Grey", 13, "94B0C2"], ["Grey", 14, "566C86"], ["Dark Grey", 15, "333C57"], ] def main(): pal = [] # create .gpl lst = [] lst.append("GIMP Palette") lst.append("Name: %s" % title) lst.append("Columns: 8") lst.append("#") lst.append("#") for t in tbl: name, index, hexstr = t col = int(hexstr, 16) r = (col >> 16) & 0x0ff g = (col >> 8) & 0x0ff b = col & 0x0ff s = "%-8d%-8d%-8d%06x %d %s" % (r, g, b, col, index, name) lst.append(s) pal.append((r, g, b)) for s in lst: print(s) # save .gpl file with open(out_gpl_file, mode="w") as f: f.write("\n".join(lst)) f.write("\n") print("# Save %s" % out_gpl_file) # create image and save xcnt, ycnt = 8, 2 # xcnt, ycnt = 16, 1 w, h = 32, 32 img_w, img_h = w * xcnt, h * ycnt im = Image.new("P", (img_w, img_h), (0, 0, 0)) paldata = [] for c in pal: r, g, b = c paldata.append(r) paldata.append(g) paldata.append(b) im.putpalette(paldata, rawmode="RGB") draw = ImageDraw.Draw(im) x, y = 0, 0 for c in range(len(pal)): draw.rectangle((x, y, x + w - 1, y + h - 1), fill=c) x += w if x >= img_w: x = 0 y += h im.save(out_img_file) print("# Save %s" % out_img_file) if __name__ == '__main__': main()
py create_sweetie-16_image.py で実行すれば、.gpl と .png が得られる。
*1: 最初の頃は、DB16 (DawnBringer 16) というパレットデータが割り当てられてた。
[ ツッコむ ]
#2 [pc] お袋さん用ノートPCをセットアップ
作業メモ。お袋さんが会社で使ってたノートPCが、社内のPC管理の都合で不要になったそうで、しばらく前に、お袋さんがそのノートPCを自宅に持って帰ってきた。型番は、DELL Vostro 15 3558、と書いてある。
しばらく放置してしまっていたけど、さすがにそろそろ使えるようにしなければと、夕食の後にセットアップ作業をしてみた。と言っても、MACアドレスを調べて、無線LANルータにMACアドレスを登録して、Wi-Fi接続しただけ。とりあえず、これでお袋さん用のノートPCもネット接続できるようになった。
その他の詳細はGRPでメモ。 そもそも、MACアドレスフィルタリングって今となっては無意味、という話も見かけたような…。
_高木浩光@自宅の日記 - 無線LANのMACアドレス制限の無意味さがあまり理解されていない
_MACアドレスフィルタリングって何?【“Wi-Fiの困った”を解決:基本編 第8回】 - INTERNET Watch
_「意味ない」どころか「悪影響」!?Wi-FiのセキュリティとMACアドレスフィルタリング再考|そだフラ!
_MACアドレス制限は“効果ゼロ”今さら聞けない「無線LAN認証」の基本【1/4】 | 大塚商会
まあ、そういうものと思っておくことにしよう…。
しばらく放置してしまっていたけど、さすがにそろそろ使えるようにしなければと、夕食の後にセットアップ作業をしてみた。と言っても、MACアドレスを調べて、無線LANルータにMACアドレスを登録して、Wi-Fi接続しただけ。とりあえず、これでお袋さん用のノートPCもネット接続できるようになった。
その他の詳細はGRPでメモ。 そもそも、MACアドレスフィルタリングって今となっては無意味、という話も見かけたような…。
_高木浩光@自宅の日記 - 無線LANのMACアドレス制限の無意味さがあまり理解されていない
_MACアドレスフィルタリングって何?【“Wi-Fiの困った”を解決:基本編 第8回】 - INTERNET Watch
_「意味ない」どころか「悪影響」!?Wi-FiのセキュリティとMACアドレスフィルタリング再考|そだフラ!
_MACアドレス制限は“効果ゼロ”今さら聞けない「無線LAN認証」の基本【1/4】 | 大塚商会
「進入禁止」と書かれた規制テープのようなものであり、一定の抑止効果はあるものの悪意を持った攻撃者はそれを気にもとめず乗り越えてくることを理解したうえで導入すべきでしょう。
まあ、そういうものと思っておくことにしよう…。
[ ツッコむ ]
2022/07/21(木) [n年前の日記]
#1 [prog] C++の勉強中
ディザパターン画像に変換するC++のソースを弄って、ディザのマップサイズを変更したり、パレットデータ相当を読み込んだりする処理を追加しているところ。
C++は使ったことがないので、関数に引数を渡すあたりですら躓く始末。二次元配列ってどうやって渡せばいいのだ…。勉強しないと…。
C++は使ったことがないので、関数に引数を渡すあたりですら躓く始末。二次元配列ってどうやって渡せばいいのだ…。勉強しないと…。
[ ツッコむ ]
2022/07/22(金) [n年前の日記]
#1 [prog][cg_tools] ディザパターンに変換するプログラムを修正
以下のページで紹介されている、ディザパターンアルゴリズムのサンプルソースに、色々と手を加えて機能追加をしてみた。
_Arbitrary-palette positional dithering algorithm
変更点は以下。
コンパイルに使った環境は、Windows10 x64 21H2 + MSYS2 + MinGW64。g++ 12.1.0 + GNU Make 4.3。
png画像の読み込みや書き込みは stbライブラリの stb_image.h と stb_image_write.h を使わせてもらった。*.cpp と同じ場所に置いておけばコンパイルできるようになる。
_nothings/stb: stb single-file public domain libraries for C/C++
_Arbitrary-palette positional dithering algorithm
変更点は以下。
- -d N で、ディザマップを 2x2, 4x4, 8x8 から選べるようにした。
- -p PALETTE.png で、パレットデータ相当を別途指定できるようにした。
- gdライブラリからstbライブラリに変更したので、単体 exe で実行できるようになった。(MSYS2関係の .dll を別途用意しなくてもいい。静的リンクしてある。)
コンパイルに使った環境は、Windows10 x64 21H2 + MSYS2 + MinGW64。g++ 12.1.0 + GNU Make 4.3。
png画像の読み込みや書き込みは stbライブラリの stb_image.h と stb_image_write.h を使わせてもらった。*.cpp と同じ場所に置いておけばコンパイルできるようになる。
_nothings/stb: stb single-file public domain libraries for C/C++
◎ ソース。 :
ソースは以下。
_yodither1.cpp
_yodither3.cpp
_yodither4.cpp
Makefile は以下。
_Makefile
基本的には、以下でコンパイルできるはず。
_yodither1.cpp
_yodither3.cpp
_yodither4.cpp
Makefile は以下。
_Makefile
基本的には、以下でコンパイルできるはず。
g++ -O3 yodither1.cpp -fopenmp -o yodither1.exe -static -lstdc++ -lgcc -lwinpthread -lm
◎ 実行バイナリ。 :
一応、実行バイナリも含めた一式を .zip にして置いときます。各 .exe を別PC (Windows 10 x64機) にコピーしても動いたので、他のPC上でも動いてくれるのではないかと…。たぶん。
_yodither_20220722.zip
使用例は以下。--help をつければ使い方の簡単な説明が表示されるはずなので…。
16〜32色程度のパレットデータでしか動作確認してません。256色あたりを指定すると、とんでもなく処理時間がかかりそうなので、怖くて試してないです。
_yodither_20220722.zip
使用例は以下。--help をつければ使い方の簡単な説明が表示されるはずなので…。
yodither1.exe --help yodither1.exe -i INPUT.png -o OUTPUT.png yodither1.exe -i INPUT.png -o OUTPUT.png -d 4 yodither1.exe -i INPUT.png -o OUTPUT.png -d 4 -p db32.gpl yodither1.exe -i INPUT.png -o OUTPUT.png -d 4 -p db32.png yodither4.exe --help yodither4.exe -i INPUT.png -o OUTPUT.png yodither4.exe -i INPUT.png -o OUTPUT.png -d 8 yodither4.exe -i INPUT.png -o OUTPUT.png -d 8 -p db32.gpl yodither4.exe -i INPUT.png -o OUTPUT.png -d 8 -p db32.png
> yodither1.exe --help Usage: yodither1.exe -i IN.png -o OUT.png [-d N] [-p PALETTE] [-t] [-v] [-h] -i FILE, --input FILE input png image file. -o FILE, --output FILE output png image file. -d N, --dither N dither map. N = 2/4/8(2x2,4x4,8x8) [default=8] -p FILE, --palette FILE Set palette (.gpl or .png) -t, --trimode Enable tri-mode. -v, --verbose Print verbose -h, --help print this message
> yodither4.exe --help Usage: yodither4.exe -i IN.png -o OUT.png [-d N] [-p PALETTE] [-v] [-h] -i FILE, --input FILE input png image file. -o FILE, --output FILE output png image file. -d N, --dither N dither map. N = 2/4/8 (2x2/4x4/8x8) [Default=4] -v, --verbose Print verbose -h, --help print this message
- yodither1.exe : 処理時間が結構かかる。生成結果の品質はそこそこ良い。
- yodither3.exe : パレットデータを変更すると妙な生成結果になりがち。あまり使えない感じがする。
- yodither4.exe : 処理時間はそれほどかからない。品質は yodither1.exe よりちょっと落ちる。
16〜32色程度のパレットデータでしか動作確認してません。256色あたりを指定すると、とんでもなく処理時間がかかりそうなので、怖くて試してないです。
[ ツッコむ ]
2022/07/23(土) [n年前の日記]
#1 [comic] 漫画を読んでた
弟が帰省した際、漫画の単行本をダンボール箱で数箱分ほど持ってきてくれるのだけど、そのあたり手つかずだったので目を通そうとしているところ。今日は二冊ほど読んでみた。
「ぴっかり職業訓練中」1巻。野村宗弘著。職業訓練校の様子を漫画で解説した作品。農業高校を舞台にした「銀の匙」、大学の獣医学部を舞台にした「動物のお医者さん」のようなジャンルになるのだろうか。かなり勉強になった…。
「カナリアたちの舟」。全1巻。高松美咲著。ミステリー、いや、SFミステリー作品だろうか。ある日空から何かがやってきて、気づけばヒロインとおじさんの二人だけで見知らぬ場所に、みたいな。なんとなくだけど、藤子F先生のSF短編、あるいは星新一作品を思い出す、そんな感じの基本設定。今の時代の漫画の絵柄・見せ方ならおそらくこうなるのだろうな、みたいな。
「ぴっかり職業訓練中」1巻。野村宗弘著。職業訓練校の様子を漫画で解説した作品。農業高校を舞台にした「銀の匙」、大学の獣医学部を舞台にした「動物のお医者さん」のようなジャンルになるのだろうか。かなり勉強になった…。
「カナリアたちの舟」。全1巻。高松美咲著。ミステリー、いや、SFミステリー作品だろうか。ある日空から何かがやってきて、気づけばヒロインとおじさんの二人だけで見知らぬ場所に、みたいな。なんとなくだけど、藤子F先生のSF短編、あるいは星新一作品を思い出す、そんな感じの基本設定。今の時代の漫画の絵柄・見せ方ならおそらくこうなるのだろうな、みたいな。
[ ツッコむ ]
2022/07/24(日) [n年前の日記]
#1 [comic] 漫画を読んでた
漫画単行本を消化中。
「あまんちゅ!」天野こずえ著、1〜7巻を読了。現代日本を舞台にして、スキューバダイビングにハマっていく高校生(主に女子高校生)達の日常を描いた作品、という説明でいいのだろうか。アニメ版は一応見ていたはずなのだけど内容をすっかり忘れていたので新鮮な(?)感覚で読めた。なんとも独特な雰囲気を持つ漫画だなと…。この雰囲気をアニメ化するのは、そりゃ難しいよな…。
「あまんちゅ!」天野こずえ著、1〜7巻を読了。現代日本を舞台にして、スキューバダイビングにハマっていく高校生(主に女子高校生)達の日常を描いた作品、という説明でいいのだろうか。アニメ版は一応見ていたはずなのだけど内容をすっかり忘れていたので新鮮な(?)感覚で読めた。なんとも独特な雰囲気を持つ漫画だなと…。この雰囲気をアニメ化するのは、そりゃ難しいよな…。
[ ツッコむ ]
2022/07/25(月) [n年前の日記]
#1 [comic] 漫画を読んでた
漫画単行本を消化中。
「あまんちゅ!」天野こずえ著、8巻から、最終巻の17巻まで読了。ヒロインが高校に入学してから卒業するまでを描いていて、構成としては奇麗にまとまった気がする。見ていて嫌な気分にさせられるキャラが一人も出てこないあたり、癒し系作品に分類されるのだろうか、とも。ググったところ、2008年から2021年まで連載していたとのことで…いやはやお疲れさまでした…。
「あまんちゅ!」天野こずえ著、8巻から、最終巻の17巻まで読了。ヒロインが高校に入学してから卒業するまでを描いていて、構成としては奇麗にまとまった気がする。見ていて嫌な気分にさせられるキャラが一人も出てこないあたり、癒し系作品に分類されるのだろうか、とも。ググったところ、2008年から2021年まで連載していたとのことで…いやはやお疲れさまでした…。
[ ツッコむ ]
2022/07/26(火) [n年前の日記]
#1 [comic] 漫画を読んでた
漫画単行本を消化中。
「雑草家族」「10歳かあさん」「ブーゲンビリア 小路啓之短編集」小路啓之著を読了。2016年に46歳の若さでお亡くなりになった漫画家、小路啓之氏の作品群。「雑草家族」「10歳かあさん」は未完の状態で単行本化されているらしい。絵柄はともかく、極めて淡白というか、独特な台詞回しを感じる作家性で、帯や巻末で異才と称して紹介されていることに納得した。なんとも惜しい…。
「プラネットガール」大石日々緒、1巻を読了。事故を起こした宇宙船の回収カプセルを開けたら、そこに居たのは…。宇宙開発が絡んだSFファンタジー or SFミステリー、という分類でいいのだろうか。と思ったけど再度表紙を眺めたみたら、帯に日常系SFアドベンチャーと書いてあった。キャラの線は多いけれど、各コマは整理されていて、とても読みやすい漫画のように感じた。
「アイゼンフリューゲル 弾丸の歌よ龍に届いているか」原作: 虚淵玄、原作イラスト: 中央東口、作画: 七竈アンノ、1巻を読了。ドラゴンが存在する世界で、ジェット機の開発ストーリーを描くという基本設定、なのだろうか。原作は小説らしい。まるでイラスト集を見ているような感覚になるぐらいに絵は上手いのだけど、えてしてそういった絵柄の作家さんが描いた漫画は、漫画としては読みづらいわけで…。とは言え、こういう絵柄じゃないと、この世界観には合わないのかもしれないなと…。
「戦国機甲伝クニトリ」あさりよしとお著、1巻を読了。日本の戦国時代に巨大ロボットが存在して、それらが合戦で活躍していたら、という一風変わった設定の作品。ロボットは米(→酒→アルコール)を燃料にして動くという設定が秀逸だなと…。それはつまり各地の米の生産高が軍事力と直結する上、米を食料に回すのか、それとも軍備に回すのかと言う選択が戦国武将に絶えず突き付けられるわけで…。何のためにわざわざロボットを動かすのか、一体誰がそんな状況を作り上げたのか、といった話になってきて…。さすがあさりよしとお先生…。面白い設定を考える…。
「クラッシャージョウ REBIRTH」原作: 高千穂遥、キャラ原案: 安彦良和、作画: 針井佑、1〜2巻を読了。スペースオペラ小説「クラッシャージョウ」の漫画化作品。絵柄、コマ割り、擬音の類まで、かなり安彦良和先生のソレに寄せているように見えて感心してしまった。安彦先生は漫画を筆で描いてるらしいけど、そのタッチをペンで再現したのだろうか。妙なタイミングで何故かコミカルな表現を入れてくる安彦先生のソレまで再現してるように思えて…。いやはや、よくまあここまで…。
「雑草家族」「10歳かあさん」「ブーゲンビリア 小路啓之短編集」小路啓之著を読了。2016年に46歳の若さでお亡くなりになった漫画家、小路啓之氏の作品群。「雑草家族」「10歳かあさん」は未完の状態で単行本化されているらしい。絵柄はともかく、極めて淡白というか、独特な台詞回しを感じる作家性で、帯や巻末で異才と称して紹介されていることに納得した。なんとも惜しい…。
「プラネットガール」大石日々緒、1巻を読了。事故を起こした宇宙船の回収カプセルを開けたら、そこに居たのは…。宇宙開発が絡んだSFファンタジー or SFミステリー、という分類でいいのだろうか。と思ったけど再度表紙を眺めたみたら、帯に日常系SFアドベンチャーと書いてあった。キャラの線は多いけれど、各コマは整理されていて、とても読みやすい漫画のように感じた。
「アイゼンフリューゲル 弾丸の歌よ龍に届いているか」原作: 虚淵玄、原作イラスト: 中央東口、作画: 七竈アンノ、1巻を読了。ドラゴンが存在する世界で、ジェット機の開発ストーリーを描くという基本設定、なのだろうか。原作は小説らしい。まるでイラスト集を見ているような感覚になるぐらいに絵は上手いのだけど、えてしてそういった絵柄の作家さんが描いた漫画は、漫画としては読みづらいわけで…。とは言え、こういう絵柄じゃないと、この世界観には合わないのかもしれないなと…。
「戦国機甲伝クニトリ」あさりよしとお著、1巻を読了。日本の戦国時代に巨大ロボットが存在して、それらが合戦で活躍していたら、という一風変わった設定の作品。ロボットは米(→酒→アルコール)を燃料にして動くという設定が秀逸だなと…。それはつまり各地の米の生産高が軍事力と直結する上、米を食料に回すのか、それとも軍備に回すのかと言う選択が戦国武将に絶えず突き付けられるわけで…。何のためにわざわざロボットを動かすのか、一体誰がそんな状況を作り上げたのか、といった話になってきて…。さすがあさりよしとお先生…。面白い設定を考える…。
「クラッシャージョウ REBIRTH」原作: 高千穂遥、キャラ原案: 安彦良和、作画: 針井佑、1〜2巻を読了。スペースオペラ小説「クラッシャージョウ」の漫画化作品。絵柄、コマ割り、擬音の類まで、かなり安彦良和先生のソレに寄せているように見えて感心してしまった。安彦先生は漫画を筆で描いてるらしいけど、そのタッチをペンで再現したのだろうか。妙なタイミングで何故かコミカルな表現を入れてくる安彦先生のソレまで再現してるように思えて…。いやはや、よくまあここまで…。
[ ツッコむ ]
2022/07/27(水) [n年前の日記]
#1 [nitijyou] 自宅サーバ止めてました
雷が鳴ったので、11:55-21:40の間、自宅サーバ止めてました。申し訳ないです。
昼頃から雷が鳴り始めて、夕方には鳴り止んだかなと思ったら、そこからまた夜までずっと鳴り続ける状態で…。幸い近くには落ちなかったようだけど…。なんともはや…。
昼頃から雷が鳴り始めて、夕方には鳴り止んだかなと思ったら、そこからまた夜までずっと鳴り続ける状態で…。幸い近くには落ちなかったようだけど…。なんともはや…。
[ ツッコむ ]
#2 [ubuntu][linux] xscreensaver経由で動画を再生
Linux上で動くメジャーなスクリーンセーバ、xscreensaver を経由して動画を再生してみたいなと思い立った。
もし動画を再生できるなら、わざわざスクリーンセーバのプログラムを作らなくても、何かしらのCGツールを使って動画を作ってソレを流しとけばいいじゃん、ってことになりそうだよなと…。
そんなわけで試してみた。動作確認環境は、Ubuntu Linxu 20.04 LTS。xscreensaver が利用できる状態になっていること。
もし動画を再生できるなら、わざわざスクリーンセーバのプログラムを作らなくても、何かしらのCGツールを使って動画を作ってソレを流しとけばいいじゃん、ってことになりそうだよなと…。
そんなわけで試してみた。動作確認環境は、Ubuntu Linxu 20.04 LTS。xscreensaver が利用できる状態になっていること。
◎ 参考ページ。 :
◎ mpvのインストール。 :
動画再生用ツールとして mpv をインストールする。Ubuntu の場合はパッケージが用意されていた。ありがたや。
sudo apt install mpv
◎ プレイリストファイルを作成。 :
mpv に渡すためのプレイリストファイルを作成する。前述の参考ページに倣って、~/.config/screensaver.m3u というファイル名にしておく。
以下は、参考ページで紹介されていた記述例。
vi ~/.config/screensaver.m3u
#EXTM3U /home/USER/Videos/hoge.mp4 /home/USER/Videos/
- 1行目には、「#EXTM3U」と記述する。これで、m3u形式のプレイリストと判別されるらしい。
- 3行目あたりから、動画ファイル(.mp4)のパスを記述。あるいは、動画が入っているディレクトリのパスを記述しても良い。
- 更に、youtube-dl なるツールが利用できる場合は、YouTube の動画のURLを記述して、それを再生することも可能らしい。ただ、今回は、youtube-dl を導入してないので、そのあたりの記述は削除した。
以下は、参考ページで紹介されていた記述例。
#EXTM3U /path/to/some_video.mp4 /path/to/dir_with_many_videos/ # any youtube video or other sites supported by `youtube-dl` https://www.youtube.com/watch?v=Xjs6fnpPWy4
◎ xscreensaver の設定ファイルを編集。 :
xscreensaver の設定ファイル、~/.xscreensaver を編集する。programs: 以下に mpv起動用の項目を追加する。
まあ、一旦は1行で記述してしまって、xscreensaver の設定ウインドウで何かしら値を変更すれば、~/.xscreensaver が整形された状態で上書き保存されるので、手作業でインデントを整えなくてもいいのかもしれない。
オプションの意味は以下。
xscreensaver は、スクリーンセーバを実行する際、環境変数 XSCREENSAVER_WINDOW に、スクリーンセーバ画面のウインドウIDを設定してくれるらしい。
つまり、件の環境変数を読み取って、そのウインドウIDを管理して描画ができる言語であれば、xscreensaver用のスクリーンセーバを作れるはず…。なのだけど、ソースコードに添付されていたドキュメントには、「まあ、そんなことができるのってC/C++ぐらいだから、実際にはC/C++で書くことになるだろうね」みたいな感じの一文が書いてあった気がする。
ただ、mpv は、自身が利用するウインドウを --wid オプションで指定できるので…。故に mpv を使えば好きな動画をスクリーンセーバとして再生できるのだろうなと。
vi ~/.xscreensaver
"MPV" mpv --really-quiet --no-stop-screensaver \ --fs --wid=$XSCREENSAVER_WINDOW \ --no-audio --loop=inf --shuffle \ --ytdl-format="bestvideo[height<=1080]" \ $HOME/.config/screensaver.m3u \n\上記はスペース文字で記述してしまっているけれど、実際に追加する際は、TAB文字有効、かつ、TABは8スペースでインデント等をしたほうが良さそう。
まあ、一旦は1行で記述してしまって、xscreensaver の設定ウインドウで何かしら値を変更すれば、~/.xscreensaver が整形された状態で上書き保存されるので、手作業でインデントを整えなくてもいいのかもしれない。
オプションの意味は以下。
- --really-quiet : stdout(標準出力)への出力を抑制。
- --no-stop-screensaver : mpv自体をスクリーンセーバにする、らしい。
- --fs : フルスクリーン表示
- --wid=$XSCREENSAVER_WINDOW : 環境変数 XSCREENSAVER_WINDOW で与えられたウインドウIDに描画する。
- --no-audio : 無音にする。
- --loop=inf : ループ再生
- --shuffle : シャッフル再生
- --ytdl-format="bestvideo[height<=1080]" : YouTubeの動画を再生する場合の指定
- $HOME/.config/screensaver.m3u : プレイリストファイルのパスを指定
xscreensaver は、スクリーンセーバを実行する際、環境変数 XSCREENSAVER_WINDOW に、スクリーンセーバ画面のウインドウIDを設定してくれるらしい。
つまり、件の環境変数を読み取って、そのウインドウIDを管理して描画ができる言語であれば、xscreensaver用のスクリーンセーバを作れるはず…。なのだけど、ソースコードに添付されていたドキュメントには、「まあ、そんなことができるのってC/C++ぐらいだから、実際にはC/C++で書くことになるだろうね」みたいな感じの一文が書いてあった気がする。
ただ、mpv は、自身が利用するウインドウを --wid オプションで指定できるので…。故に mpv を使えば好きな動画をスクリーンセーバとして再生できるのだろうなと。
◎ 動作確認。 :
xscreensaver の設定画面を出して、「MPV」を選ぶ。
これで、スクリーンセーバが起動する際、プレイリストファイル ~/.config/screensaver.m3u 内に記述した動画が再生された。
これで、スクリーンセーバが起動する際、プレイリストファイル ~/.config/screensaver.m3u 内に記述した動画が再生された。
◎ 余談。 :
手元の環境ではデスクトップとして Xfce を使っているけど、デフォルトでは xfce4-screensaver というスクリーンセーバがインストールされていて、~/.xscreensaver を修正しても修正内容が反映されなかった。xscreensaver をインストールしてそちらを使う状態にしないと、~/.xscreensaver は読まれないらしい。
xfce4-screensaver のアンインストールと、xscreensaver のインストールは以下。
今時の Ubuntu は、xscreensaver を使わずに、gnome-screensaver 等々、違うスクリーンセーバがデフォルトで入っているので、そのあたりはちょっと注意。各スクリーンセーバがどの設定ファイルを読み込むのかが分かれば、xscreensaver に切り替えずに済むのだろうけど…。
xfce4-screensaver のアンインストールと、xscreensaver のインストールは以下。
sudo apt remove xfce4-screensaver sudo apt install xscreensaver
今時の Ubuntu は、xscreensaver を使わずに、gnome-screensaver 等々、違うスクリーンセーバがデフォルトで入っているので、そのあたりはちょっと注意。各スクリーンセーバがどの設定ファイルを読み込むのかが分かれば、xscreensaver に切り替えずに済むのだろうけど…。
[ ツッコむ ]
#3 [comic] 漫画を読んでた
漫画単行本を消化中。
「川島芳子は男になりたい」田中ほさな著、全3巻を読了。大正末期の上海を舞台に、男になりたいと願うヒロインがスパイとして活躍する冒険活劇漫画、という説明であってるのだろうか。なんとなくだけど、リアル版らんま1/2、みたいなものかもしれないと思ったりもして。さておき、川島芳子という名前はどこかで見たなとググってみて、なるほどそういうことかと納得。それにしても史実のソレは状況が複雑過ぎて何が何だか…。ガンダムやSTAR WARSの設定並みに把握するのが難しい…。ただ、この作品は、自分でも分かる程度の設定量に抑えてあって助かった。
「ディエンビエンフー」復刊版(?)、全6巻、「ディエンビエンフー TRUE END」全3巻、西島大介著を読了。ベトナム戦争を舞台にして繰り広げられる、ハイスピードスプラッタ超人バトルアクションラブストーリー、という分類でいいのだろうか。なんだその分類意味わからんって言われそうだけど、おそらく読めば納得してもらえそうな気もする。とにかく全てが独特…。漫画と言う表現手法の幅の広さ、自由奔放さを痛感させられた。漫画ならこういうスタイルだって全然アリなのだと学生時代のうちに知っておきたかった、とすら思えた。もし知ってたら、「漫画はこういう絵じゃないといけない」「こういうスタイルで仕上げないといけない」等々、視野の狭い勝手な思い込みを振り回して周囲に迷惑(?)をかけずに済んでいた、かもしれない。こういう方向でまとめていく選択肢もあったのだよな…。このスタイルに自力で辿り着いたのであろう作者の非凡さに感服。また、巻末の参考文献の量にも驚かされた。ベトナム戦争を描くならここまで調べないといかんのだな…。
「川島芳子は男になりたい」田中ほさな著、全3巻を読了。大正末期の上海を舞台に、男になりたいと願うヒロインがスパイとして活躍する冒険活劇漫画、という説明であってるのだろうか。なんとなくだけど、リアル版らんま1/2、みたいなものかもしれないと思ったりもして。さておき、川島芳子という名前はどこかで見たなとググってみて、なるほどそういうことかと納得。それにしても史実のソレは状況が複雑過ぎて何が何だか…。ガンダムやSTAR WARSの設定並みに把握するのが難しい…。ただ、この作品は、自分でも分かる程度の設定量に抑えてあって助かった。
「ディエンビエンフー」復刊版(?)、全6巻、「ディエンビエンフー TRUE END」全3巻、西島大介著を読了。ベトナム戦争を舞台にして繰り広げられる、ハイスピードスプラッタ超人バトルアクションラブストーリー、という分類でいいのだろうか。なんだその分類意味わからんって言われそうだけど、おそらく読めば納得してもらえそうな気もする。とにかく全てが独特…。漫画と言う表現手法の幅の広さ、自由奔放さを痛感させられた。漫画ならこういうスタイルだって全然アリなのだと学生時代のうちに知っておきたかった、とすら思えた。もし知ってたら、「漫画はこういう絵じゃないといけない」「こういうスタイルで仕上げないといけない」等々、視野の狭い勝手な思い込みを振り回して周囲に迷惑(?)をかけずに済んでいた、かもしれない。こういう方向でまとめていく選択肢もあったのだよな…。このスタイルに自力で辿り着いたのであろう作者の非凡さに感服。また、巻末の参考文献の量にも驚かされた。ベトナム戦争を描くならここまで調べないといかんのだな…。
[ ツッコむ ]
2022/07/28(木) [n年前の日記]
#1 [xscreensaver][python] xscreensaverからPythonスクリプトを起動できないか模索
xscreensaver用のスクリーンセーバを作る際に、C/C++ で書くのはちょっとハードルが高いなと。せめてPythonスクリプトを起動できたら楽になりそうだなと。
一応、そういったこともできるらしいのだけど…。
_A Python screensaver for xscreensaver (Linux) | alvinalexander.com
紹介されているソースは昔のPython用のソースだったようで。Ubuntu Linux 20.04 LTS ではもう利用できなくなった PyGTK を使ってたりする…。PyGObject を使うように書き換えないと…。よく見たら print も print() になってない…。
色々ググってたら、PyGTKCompat を使えばソースの改変を最小限にして過去の資産を活かせる、と知ったのだけど。
_Projects/PyGObject/PyGTKCompat - GNOME Wiki!
試してみたものの、gtk.gdk.Window() でエラーが出てしまう。Gtk2 と Gtk3 で渡す引数が違うのだろうか。
ちなみに、if self.flags() & gtk.REALIZED: は、if self.get_realized(): に変更してみた。それで合ってるのかどうか分からんけど…。
一応、そういったこともできるらしいのだけど…。
_A Python screensaver for xscreensaver (Linux) | alvinalexander.com
紹介されているソースは昔のPython用のソースだったようで。Ubuntu Linux 20.04 LTS ではもう利用できなくなった PyGTK を使ってたりする…。PyGObject を使うように書き換えないと…。よく見たら print も print() になってない…。
色々ググってたら、PyGTKCompat を使えばソースの改変を最小限にして過去の資産を活かせる、と知ったのだけど。
_Projects/PyGObject/PyGTKCompat - GNOME Wiki!
試してみたものの、gtk.gdk.Window() でエラーが出てしまう。Gtk2 と Gtk3 で渡す引数が違うのだろうか。
ちなみに、if self.flags() & gtk.REALIZED: は、if self.get_realized(): に変更してみた。それで合ってるのかどうか分からんけど…。
[ ツッコむ ]
#2 [python] vscode + autopep8がimportの順番を変更してしまう。
Visual Studio Code を使ってPythonのスクリプトソースを書いていたのだけど、autopep8 を呼んでソース整形をしてみたらimport行の順番が変更されてしまって、PyGObject を使ったソースが動かなくなってしまった。import行は変更しないように設定したいのだけど…。
以下の設定で、import行には変更を加えない状態にできるらしい。
_【VS Code】モジュールの自動整形(並び替え)をオフする方法 | peachdotpy
_python - Allow statements before imports with Visual Studio Code and autopep8 - Stack Overflow
_autopep8がsys.path.append()行をImportの下に持ってきてしまう問題 - Qiita
変更されたくない行の最後に「#nopep8」と書いておくのが一番簡単だろうか。
あるいは、Visual Studio Code の設定画面で、autopep8Args に「--ignore E402」を追加しておけばいいようで。
以下の設定で、import行には変更を加えない状態にできるらしい。
_【VS Code】モジュールの自動整形(並び替え)をオフする方法 | peachdotpy
_python - Allow statements before imports with Visual Studio Code and autopep8 - Stack Overflow
_autopep8がsys.path.append()行をImportの下に持ってきてしまう問題 - Qiita
変更されたくない行の最後に「#nopep8」と書いておくのが一番簡単だろうか。
あるいは、Visual Studio Code の設定画面で、autopep8Args に「--ignore E402」を追加しておけばいいようで。
[ ツッコむ ]
#3 [comic] 漫画を読んでた
漫画単行本を消化中。
「フルメタル・パニック! 0 -ZERO-」原作:賀東招二、キャラクター原案:四季童子、作画:カサハラテツロー、1〜5巻を読了。近未来を舞台にしたSFロボットバトル漫画、だろうか。「RIDEBACK」で独特なロボットやメカ描写を見せてくれたカサハラテツロー先生が漫画化しただけあって、ロボットバトルシーンがイイ感じに思えたし、途中で挿入されるロボットの内部図解や、搭乗する際の各手順を何ページも使って見せていくあたりもリアリティを高めていたように感じた。自分、フルメタル・パニックシリーズはアニメ版の一部を少し目にした程度なのだけど、結構面白い内容のシリーズなのだなと…。いや、この漫画版は結構アレンジされてるのかもしれないけれど…。
「フルメタル・パニック! 0 -ZERO-」原作:賀東招二、キャラクター原案:四季童子、作画:カサハラテツロー、1〜5巻を読了。近未来を舞台にしたSFロボットバトル漫画、だろうか。「RIDEBACK」で独特なロボットやメカ描写を見せてくれたカサハラテツロー先生が漫画化しただけあって、ロボットバトルシーンがイイ感じに思えたし、途中で挿入されるロボットの内部図解や、搭乗する際の各手順を何ページも使って見せていくあたりもリアリティを高めていたように感じた。自分、フルメタル・パニックシリーズはアニメ版の一部を少し目にした程度なのだけど、結構面白い内容のシリーズなのだなと…。いや、この漫画版は結構アレンジされてるのかもしれないけれど…。
[ ツッコむ ]
2022/07/29(金) [n年前の日記]
#1 [nitijyou] 自宅サーバ止めてました
雷が鳴ったので、15:55-19:10の間、自宅サーバ止めてました。
かなり近くで何度も雷が落ちていた上に、普段は聞かない「バリバリ」という音も…。後から落雷情報を確認したら、一帯が真っ赤になってた。
かなり近くで何度も雷が落ちていた上に、普段は聞かない「バリバリ」という音も…。後から落雷情報を確認したら、一帯が真っ赤になってた。
[ ツッコむ ]
#2 [python] PyGTKのドキュメントが見つからない
PyGTK を使ってるスクリプトを PyGObject を使うように書き直したいのだけど、PyGTK のAPIドキュメントが見つからなくて作業が進まず。どのリンクを辿っても PyGObject のドキュメントしか出てこない。たしかに今現在は PyGObject を使うことが推奨されてるけど、だからといって昔のドキュメントを PyGObject のソレに差し替えなくてもええやろ…。PyGTK時代の仕様が分からないから、PyGObject の何で置き換えたらいいのか分からん…。
[ ツッコむ ]
#3 [comic] 漫画を読んでた
漫画単行本を消化中。
「海帝」星野之宣著を読んだ。全9巻、なのだけど、4,5巻だけ何故か箱に入ってなかったのでそこだけ未読。中国が明だった頃に南の諸外国まで大艦隊を率いて航海した主人公の生涯を描く、みたいな内容だろうか。帯に海洋冒険ロマンと書いてあったけど、たしかにそういうジャンルだなと…。ラストのあたり、浪漫溢れる展開としか言いようがない…。イカだの猿だの写楽くんだの、あちこちのエピソードでSFっぽい設定が入ってくるあたりもなかなか。いや、これはSFなんだろうか…? 奇想天外な設定ではあろうけど…。でも、それぞれの設定にそれらしい理屈をつけながら描いてあるからやはりSFのような気もする。
「海帝」星野之宣著を読んだ。全9巻、なのだけど、4,5巻だけ何故か箱に入ってなかったのでそこだけ未読。中国が明だった頃に南の諸外国まで大艦隊を率いて航海した主人公の生涯を描く、みたいな内容だろうか。帯に海洋冒険ロマンと書いてあったけど、たしかにそういうジャンルだなと…。ラストのあたり、浪漫溢れる展開としか言いようがない…。イカだの猿だの写楽くんだの、あちこちのエピソードでSFっぽい設定が入ってくるあたりもなかなか。いや、これはSFなんだろうか…? 奇想天外な設定ではあろうけど…。でも、それぞれの設定にそれらしい理屈をつけながら描いてあるからやはりSFのような気もする。
[ ツッコむ ]
2022/07/30(土) [n年前の日記]
#1 [python][pygtk] PyGObjectがよく分からない
Python + PyGObject を勉強中だけど、どうもよく分からない…。
◎ 背景色すら指定できない。 :
Widget の背景色を変更しようとして、win.modify_bg(Gtk.StateType.NORMAL, Gdk.Color(0, 0, 0)) と書いてみたら、Ubuntu Linux 20.04 LTS 上では特に何も言われなかったけど、Windows10 x64 21H2 + MSYS2 上では DeprecationWarning: Gtk.Widget.modify_bg is deprecated と言われてしまった。どうやら廃止予定らしい…。
代わりに何を使うのかを調べてみたら、Gtk.Widget.override_background_color() を使え、と書いてある。
_Gtk.Widget - Classes - Gtk 3.0
ならばと、win.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(0.3, 0.3, 0.3)) と書いてみたら、これまた DeprecationWarning: Gtk.Widget.override_background_color is deprecated と言われる。これも廃止予定なのか…。
_Gtk.Widget - Classes - Gtk 3.0
独自のCSSスタイルを使え、とか言い出した…。どんどん複雑になってきてないか…。
代わりに何を使うのかを調べてみたら、Gtk.Widget.override_background_color() を使え、と書いてある。
_Gtk.Widget - Classes - Gtk 3.0
ならばと、win.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(0.3, 0.3, 0.3)) と書いてみたら、これまた DeprecationWarning: Gtk.Widget.override_background_color is deprecated と言われる。これも廃止予定なのか…。
_Gtk.Widget - Classes - Gtk 3.0
独自のCSSスタイルを使え、とか言い出した…。どんどん複雑になってきてないか…。
◎ PyGTKのドキュメントは見つかった。 :
PyGObject ではなく、PyGTK時代のドキュメントを探していたけど、ようやく見つけた。WebArchive に残ってた。
_PyGTK (WebArchive)
_PyGTK Reference Manual (WebArchive)
_gtk.Widget (WebArchive)
でも、公式サイトで PyGObject のドキュメントしか置いてないのは困る…。昔のドキュメントが無かったら、昔のスクリプトを今風に書き直すのも難しくなるやん…。
_PyGTK (WebArchive)
_PyGTK Reference Manual (WebArchive)
_gtk.Widget (WebArchive)
でも、公式サイトで PyGObject のドキュメントしか置いてないのは困る…。昔のドキュメントが無かったら、昔のスクリプトを今風に書き直すのも難しくなるやん…。
◎ 変換ツールがあるらしい。 :
以下のページで、pygi-convert.sh というシェルスクリプトが紹介されていた。
_Porting from Static Bindings - PyGObject
_Projects/PyGObject/IntrospectionPorting - GNOME Wiki!
./pygi-convert.sh hoge.py と打てば、PyGTK時代のスクリプトを PyGObject向けに変換してくれるらしい。中では Perl を呼び出して、PyGTK時代の書き方を PyGObject向けの書き方に置換している模様。
Ubuntu Linux 20.04 LTS 上で、以下のページのスクリプトに対して試してみたけど…。
_A Python screensaver for xscreensaver (Linux) | alvinalexander.com
残念ながら、すんなり動く状態にはならなかった。self.window なんて無い、と言われてしまう。
一応あちこちの単語を書き換えてくれているようではあるけれど…。
_Porting from Static Bindings - PyGObject
_Projects/PyGObject/IntrospectionPorting - GNOME Wiki!
./pygi-convert.sh hoge.py と打てば、PyGTK時代のスクリプトを PyGObject向けに変換してくれるらしい。中では Perl を呼び出して、PyGTK時代の書き方を PyGObject向けの書き方に置換している模様。
Ubuntu Linux 20.04 LTS 上で、以下のページのスクリプトに対して試してみたけど…。
_A Python screensaver for xscreensaver (Linux) | alvinalexander.com
残念ながら、すんなり動く状態にはならなかった。self.window なんて無い、と言われてしまう。
$ ./01_xscrsav.py ... File "./01_xscrsav.py", line 50, in realize if self.window == None: AttributeError: 'ScreenSaverWindow' object has no attribute 'window'
一応あちこちの単語を書き換えてくれているようではあるけれど…。
◎ PyGTKを無理矢理インストールしてみた。 :
Ubuntu Linux 20.04 LTS 上で、Ubuntu Linux 18.04 用のパッケージ、python-gtk2 と python-gtk2-dev をDLして無理矢理インストールしてみた。
_bluetooth - "No package 'pygtk-2.0' found" on Ubuntu 20.04 even after installing python-gtk2 from archives - Ask Ubuntu
一応インストールはできた。
以下のスクリプトを動かしてみたけど…。
_A Python screensaver for xscreensaver (Linux) | alvinalexander.com
一応ウインドウは表示されたものの、内部に何も表示されない。本来は Hello World という文字列が表示されるはずなのだけど…。やはり無理矢理インストールしたのがよろしくないのだろうか。
そもそも、Ubuntu Linux 20.04 LTS 上では PyGTK は廃止されて PyGObject を使えということになっているわけで…。python-gtk2* はアンインストールしておいた。
_bluetooth - "No package 'pygtk-2.0' found" on Ubuntu 20.04 even after installing python-gtk2 from archives - Ask Ubuntu
cd ~/Downloads wget -c http://archive.ubuntu.com/ubuntu/pool/universe/p/pygtk/python-gtk2_2.24.0-5.1ubuntu2_amd64.deb wget -c http://archive.ubuntu.com/ubuntu/pool/universe/p/pygtk/python-gtk2-dev_2.24.0-5.1ubuntu2_all.deb sudo apt-get update sudo apt-get install ./python-gtk2-dev_2.24.0-5.1ubuntu2_all.deb ./python-gtk2_2.24.0-5.1ubuntu2_amd64.deb
一応インストールはできた。
以下のスクリプトを動かしてみたけど…。
_A Python screensaver for xscreensaver (Linux) | alvinalexander.com
一応ウインドウは表示されたものの、内部に何も表示されない。本来は Hello World という文字列が表示されるはずなのだけど…。やはり無理矢理インストールしたのがよろしくないのだろうか。
そもそも、Ubuntu Linux 20.04 LTS 上では PyGTK は廃止されて PyGObject を使えということになっているわけで…。python-gtk2* はアンインストールしておいた。
sudo apt remove python-gtk2 python-gtk2-dev
[ ツッコむ ]
2022/07/31(日) [n年前の日記]
#1 [ruby] ruby-gtk2がWindows10上で動かない
ruby-gtk2 (Ruby-GNOME2?) がWindows10 x64 21H2上で動かなくて悩んでいるところ。環境は、RubyInstaller版の Ruby 2.3.3 x86、Ruby 2.6.10 x86、Ruby 3.0.4 x86。
_RubyInstaller for Windows
_RubyGems.org
結論を先に書くと、上記の環境では ruby-gtk2 をインストールすることができなかった。ただ、Ruby 1.8.7 x86 + gtk2 なら、かろうじてインストールできた。
_RubyInstaller for Windows
_RubyGems.org
結論を先に書くと、上記の環境では ruby-gtk2 をインストールすることができなかった。ただ、Ruby 1.8.7 x86 + gtk2 なら、かろうじてインストールできた。
◎ ruby-gtk2を動かしたい理由。 :
どうして ruby-gtk2 を動かそうとしているのかというと、ruby-gtk2 を使えば xscreensaver用のスクリーンセーバを書けそうだなと思いついたから。
ここ数日、Python を使って xscreensaver用のスクリーンセーバを書けないものかと試行錯誤していたのだけど、Python + PyGTK で書かれた雛形ソースは存在するものの、Python + PyGObject で書かれたものは見当たらなくて手詰まりになっていて。
_A Python screensaver for xscreensaver (Linux) | alvinalexander.com
今時の Linux は、Python から GTK2 を制御するモジュール、PyGTK を本気で殺しにかかっていて、各ディストリの公式リポジトリにパッケージが用意されてない上に、「PyGTK を使っているPythonスクリプトは GTK3 を制御する PyGObject で書き直せ」という風潮にもなっている。しかし、自分の知識では、前述のスクリプトを PyGObject を使った形に書き直すことができず…。
何かヒントが無いかとググっていたら、ruby-gtk2 を使って xscreensaver用のスクリーンセーバを書いてる事例を見かけたわけで。
_zhum/rubysaver: Xscreensaver module, displaying weather, forecast, clock and now playing song title and author.
「そうか。Python がダメなら Ruby と GTK2 を使えばいいんじゃん」と気づいたわけで。できればメジャーな Python を使って書きたかったけれど、マイナーな Ruby を使ったとしても C/C++ で書くより随分と楽になるはずだよなと。
しかし…。まずは Windows10 上で ruby-gtk2 を勉強すべく環境を整えようとしたところ、そもそも ruby-gtk2 のインストールすらできない状態になっていることに気づいたという…。
ここ数日、Python を使って xscreensaver用のスクリーンセーバを書けないものかと試行錯誤していたのだけど、Python + PyGTK で書かれた雛形ソースは存在するものの、Python + PyGObject で書かれたものは見当たらなくて手詰まりになっていて。
_A Python screensaver for xscreensaver (Linux) | alvinalexander.com
今時の Linux は、Python から GTK2 を制御するモジュール、PyGTK を本気で殺しにかかっていて、各ディストリの公式リポジトリにパッケージが用意されてない上に、「PyGTK を使っているPythonスクリプトは GTK3 を制御する PyGObject で書き直せ」という風潮にもなっている。しかし、自分の知識では、前述のスクリプトを PyGObject を使った形に書き直すことができず…。
何かヒントが無いかとググっていたら、ruby-gtk2 を使って xscreensaver用のスクリーンセーバを書いてる事例を見かけたわけで。
_zhum/rubysaver: Xscreensaver module, displaying weather, forecast, clock and now playing song title and author.
「そうか。Python がダメなら Ruby と GTK2 を使えばいいんじゃん」と気づいたわけで。できればメジャーな Python を使って書きたかったけれど、マイナーな Ruby を使ったとしても C/C++ で書くより随分と楽になるはずだよなと。
しかし…。まずは Windows10 上で ruby-gtk2 を勉強すべく環境を整えようとしたところ、そもそも ruby-gtk2 のインストールすらできない状態になっていることに気づいたという…。
◎ ruby-gtk2のインストールができない。 :
再度書くけど、環境は Windows10 x64 21H2 + Ruby 2.3.3、2.6.10、3.0.4 x86。
_gtk2 | RubyGems.org
ただ、日記を検索したら、昔は Windowsでも ruby-gtk2 のインストールができて、かつ、動作していたようでもあり…。
_2018/02/27 Ruby-GNOME2を試用
_2019/04/20 green_shoes を動かせないか試したり
2018年、2019年頃なら、Ruby 2.3.3 p222 x86 上で、gtk2 3.2.1、glib2 3.2.1、cairo 1.15.11 x86-mingw32版をインストールできていた模様。x86-mingw32 の記述があるパッケージはバイナリ(.soファイル)も含まれているから、msys2 でビルドしなくて済むし、インストール時にエラーも出なかったのだろう。たぶん。
であれば、バージョンと platform を指定すればインストールできるのではないかと、Ruby 2.3.3 p222 x86上で試してみたのだけど。
何故か、最後の3つ、cairo-gobject、pango、gtk2 のインストール時に、cairo 1.17.6 をビルド + インストールしようとしてエラーが出てしまう。既に cairo 1.15.11 をインストールしてあるから、cairo 1.17.6 のビルドはしなくてもよさそうなものだけど…。
であればと、rubygems から、バージョン 3.2.1 の 各 .gem をWebブラウザ経由でダウンロードして、ローカルでインストールしてみたところ、そのやり方ならインストールはできた。
しかし、動作確認してみたら別の問題が発生。require "cairo" をすると、「LoadError: cannot load such file -- cairo.so」とエラーが出る…。
cairo-1.15.11-x86-mingw32/lib/ 以下に、2.3/cairo.so はあるのだけどな…。何にせよ、require "gtk2" をした時も「cairo.so が読み込めない」とエラーが出てしまうので、これでは ruby-gtk2 が使えない。
Ruby本体がおかしくなっているのかと疑って、Ruby 2.3.3 p222 x86 をアンインストール・再インストールして、その後、ローカルに保存した .gem を順々にインストールして再度動作確認してみたけれど、やはり cairo.so が読み込めないと言ってくる。うーん。
ちなみに、Ruby 2.3.3 のインストールは以前のメモを参考にして作業した。
_Windows10上で Ruby 2.3.3 をインストールしようとして少しハマった
余談。Ruby 2.6.10 x86 上で gem install cairo をしたところ、cairo 1.17.6 のビルドに成功してインストールできたように見えた。require "cairo" もできている。ただ、Ruby 2.6.10 は gtk2 のビルドでエラーを出してインストールできないのだけど…。
Debian Linux の ruby-gtk2 パッケージを確認したら 3.4.3 を配布しているように見えた。ひょっとすると 3.4.3 ならインストールできるのではないかと思えてきた。そこで、Ruby 2.6.10 x86 上で、glib2 や gtk2 に対して -v 3.4.3 を指定してインストールを試みてみた。
しかし、最後の最後、gtk2 3.4.3 のビルドでエラーが大量に出てしまう。やはり Windows10 上で ruby-gtk2 のインストールはできない模様。
_gtk2 | RubyGems.org
- Ruby 2.6.10 p210 i386-minge32 で gem install gtk2 をしたら msys2利用のビルド時にエラーが出る。
- Ruby 3.0.4 p208 i386-mingw32 でも同様。
- Ruby 2.3.3 p222 i386-mingw32 でも同様。最新版はビルド時にエラーが出る。
ただ、日記を検索したら、昔は Windowsでも ruby-gtk2 のインストールができて、かつ、動作していたようでもあり…。
_2018/02/27 Ruby-GNOME2を試用
_2019/04/20 green_shoes を動かせないか試したり
2018年、2019年頃なら、Ruby 2.3.3 p222 x86 上で、gtk2 3.2.1、glib2 3.2.1、cairo 1.15.11 x86-mingw32版をインストールできていた模様。x86-mingw32 の記述があるパッケージはバイナリ(.soファイル)も含まれているから、msys2 でビルドしなくて済むし、インストール時にエラーも出なかったのだろう。たぶん。
であれば、バージョンと platform を指定すればインストールできるのではないかと、Ruby 2.3.3 p222 x86上で試してみたのだけど。
gem install pkg-config -v 1.2.9 gem install native-package-installer -v 1.0.6 gem install cairo -v 1.15.11 --platform=x86-mingw32 gem install glib2 -v 3.2.1 --platform=x86-mingw32 gem install atk -v 3.2.1 --platform=x86-mingw32 gem install gobject-introspection -v 3.2.1 --platform=x86-mingw32 gem install gio2 -v 3.2.1 --platform=x86-mingw32 gem install gdk_pixbuf2 -v 3.2.1 --platform=x86-mingw32 gem install cairo-gobject -v 3.2.1 --platform=x86-mingw32 gem install pango -v 3.2.1 --platform=x86-mingw32 gem install gtk2 -v 3.2.1 --platform=x86-mingw32
何故か、最後の3つ、cairo-gobject、pango、gtk2 のインストール時に、cairo 1.17.6 をビルド + インストールしようとしてエラーが出てしまう。既に cairo 1.15.11 をインストールしてあるから、cairo 1.17.6 のビルドはしなくてもよさそうなものだけど…。
> gem list | grep cairo cairo (1.15.11 x86-mingw32) > gem install cairo-gobject -v 3.2.1 --platform=x86-mingw32 Temporarily enhancing PATH to include DevKit... Building native extensions. This could take a while... ERROR: Error installing cairo-gobject: ERROR: Failed to build gem native extension. current directory: C:/Ruby/Ruby23-x86/lib/ruby/gems/2.3.0/gems/cairo-1.17.6/ext/cairo C:/Ruby/Ruby23-x86/bin/ruby.exe -I C:/Ruby/Ruby23-x86/lib/ruby/site_ruby/2.3.0 -r ./siteconf20220731-10340-gvbbgt.rb extconf.rb checking for GCC... yes checking for Homebrew... no checking for cairo version (>= 1.2.0)... no *** extconf.rb failed *** Could not create Makefile due to some reason, probably lack of necessary libraries and/or headers. Check the mkmf.log file for more details. You may need configuration options. Provided configuration options: --with-opt-dir --without-opt-dir --with-opt-include --without-opt-include=${opt-dir}/include --with-opt-lib --without-opt-lib=${opt-dir}/lib --with-make-prog --without-make-prog --srcdir=. --curdir --ruby=C:/Ruby/Ruby23-x86/bin/$(RUBY_BASE_NAME) --with-pkg-config --without-pkg-config --with-override-variables --without-override-variables To see why this extension failed to compile, please check the mkmf.log which can be found here: C:/Ruby/Ruby23-x86/lib/ruby/gems/2.3.0/extensions/x86-mingw32/2.3.0/cairo-1.17.6/mkmf.log extconf failed, exit code 1 Gem files will remain installed in C:/Ruby/Ruby23-x86/lib/ruby/gems/2.3.0/gems/cairo-1.17.6 for inspection. Results logged to C:/Ruby/Ruby23-x86/lib/ruby/gems/2.3.0/extensions/x86-mingw32/2.3.0/cairo-1.17.6/gem_make.out
であればと、rubygems から、バージョン 3.2.1 の 各 .gem をWebブラウザ経由でダウンロードして、ローカルでインストールしてみたところ、そのやり方ならインストールはできた。
gem install cairo-gobject-3.2.1-x86-mingw32.gem gem install pango-3.2.1-x86-mingw32.gem gem install gtk2-3.2.1-x86-mingw32.gem
しかし、動作確認してみたら別の問題が発生。require "cairo" をすると、「LoadError: cannot load such file -- cairo.so」とエラーが出る…。
> irb irb(main):001:0> require "cairo" LoadError: cannot load such file -- cairo.so from C:/Ruby/Ruby23-x86/lib/ruby/site_ruby/2.3.0/rubygems/core_ext/kernel_require.rb:85:in `require' from C:/Ruby/Ruby23-x86/lib/ruby/site_ruby/2.3.0/rubygems/core_ext/kernel_require.rb:85:in `require' from C:/Ruby/Ruby23-x86/lib/ruby/gems/2.3.0/gems/cairo-1.15.11-x86-mingw32/lib/cairo.rb:54:in `rescue in <top (required)>' from C:/Ruby/Ruby23-x86/lib/ruby/gems/2.3.0/gems/cairo-1.15.11-x86-mingw32/lib/cairo.rb:50:in `<top (required)>' from C:/Ruby/Ruby23-x86/lib/ruby/site_ruby/2.3.0/rubygems/core_ext/kernel_require.rb:160:in `require' from C:/Ruby/Ruby23-x86/lib/ruby/site_ruby/2.3.0/rubygems/core_ext/kernel_require.rb:160:in `rescue in require' from C:/Ruby/Ruby23-x86/lib/ruby/site_ruby/2.3.0/rubygems/core_ext/kernel_require.rb:170:in `require' from (irb):1 from C:/Ruby/Ruby23-x86/bin/irb.cmd:19:in `<main>'
cairo-1.15.11-x86-mingw32/lib/ 以下に、2.3/cairo.so はあるのだけどな…。何にせよ、require "gtk2" をした時も「cairo.so が読み込めない」とエラーが出てしまうので、これでは ruby-gtk2 が使えない。
Ruby本体がおかしくなっているのかと疑って、Ruby 2.3.3 p222 x86 をアンインストール・再インストールして、その後、ローカルに保存した .gem を順々にインストールして再度動作確認してみたけれど、やはり cairo.so が読み込めないと言ってくる。うーん。
ちなみに、Ruby 2.3.3 のインストールは以前のメモを参考にして作業した。
_Windows10上で Ruby 2.3.3 をインストールしようとして少しハマった
余談。Ruby 2.6.10 x86 上で gem install cairo をしたところ、cairo 1.17.6 のビルドに成功してインストールできたように見えた。require "cairo" もできている。ただ、Ruby 2.6.10 は gtk2 のビルドでエラーを出してインストールできないのだけど…。
Debian Linux の ruby-gtk2 パッケージを確認したら 3.4.3 を配布しているように見えた。ひょっとすると 3.4.3 ならインストールできるのではないかと思えてきた。そこで、Ruby 2.6.10 x86 上で、glib2 や gtk2 に対して -v 3.4.3 を指定してインストールを試みてみた。
gem install cairo gem install glib2 -v 3.4.3 gem install atk -v 3.4.3 gem install gobject-introspection -v 3.4.3 gem install gio2 -v 3.4.3 gem install gdk_pixbuf2 -v 3.4.3 gem install cairo-gobject -v 3.4.3 gem install pango -v 3.4.3 gem install gtk2 -v 3.4.3
しかし、最後の最後、gtk2 3.4.3 のビルドでエラーが大量に出てしまう。やはり Windows10 上で ruby-gtk2 のインストールはできない模様。
◎ 何が何でもruby-gtk2を動かす。 :
glib2 や gtk2 のバージョンを色々変えて何度試してもエラーが出てインストールできないので、もはや意地になってきた。何が何でも Windows10上で ruby-gtk2 を動かしてみたい。
もしかすると、Ruby 1.8 + ruby-gtk2 なら動かせるかもしれない…。Ruby 1.8 の時代なら、GTK2のランタイムバイナリも含めた形のセットアップファイルが配布されていたらしいので…。
そんなわけで、Windows10 x64 21H2 + Ruby 1.8.7 mswin32 版上で利用できるか試してみた。Ruby 1.8.7 mswin32 がインストールされている環境で、以下から、ruby-gnome2-0.16.0-1-i386-mswin32.exe を入手する。
_Ruby-GNOME 2 - Browse /ruby-gnome2/ruby-gnome2-0.16.0 at SourceForge.net
ちなみに、この ruby-gnome2-0.16.0-1-i386-mswin32.exe は Ruby 1.8 のみに対応。Ruby 1.9 や 2.x では動かない。Ruby 1.8 用のバイナリしか同梱されてない状態なので…。
一応、ruby-gnome2-0.16.0-1-i386-mswin32.exe を実行した際の、セットアップ画面のスクリーンショットも載せておく。
インストール後、以下を実行できれば gtk2 のインストールは成功している。
Rubyのコマンドラインオプションについては以下が参考になる。
_Rubyの起動 - Rubyリファレンスマニュアル
もしかすると、Ruby 1.8 + ruby-gtk2 なら動かせるかもしれない…。Ruby 1.8 の時代なら、GTK2のランタイムバイナリも含めた形のセットアップファイルが配布されていたらしいので…。
そんなわけで、Windows10 x64 21H2 + Ruby 1.8.7 mswin32 版上で利用できるか試してみた。Ruby 1.8.7 mswin32 がインストールされている環境で、以下から、ruby-gnome2-0.16.0-1-i386-mswin32.exe を入手する。
_Ruby-GNOME 2 - Browse /ruby-gnome2/ruby-gnome2-0.16.0 at SourceForge.net
ちなみに、この ruby-gnome2-0.16.0-1-i386-mswin32.exe は Ruby 1.8 のみに対応。Ruby 1.9 や 2.x では動かない。Ruby 1.8 用のバイナリしか同梱されてない状態なので…。
- 実行すると、GUIでインストールウイザード画面が開く。
- Choose Components 画面では、Ruby-GNOME2 と GTK2 Runtime にチェックを入れて、Register Environment Variables はチェックを外した状態に。
- インストールフォルダは、Ruby 1.8.7 インストールフォルダを指定。(例 : C:\Ruby187 , C:\Ruby\Ruby187p330mswin32 等々)
- 先に進んで、Installボタンをクリックすればインストールされる。
一応、ruby-gnome2-0.16.0-1-i386-mswin32.exe を実行した際の、セットアップ画面のスクリーンショットも載せておく。
インストール後、以下を実行できれば gtk2 のインストールは成功している。
> ruby -r gtk2 -e "p Gtk::VERSION" [2, 10, 6]
Rubyのコマンドラインオプションについては以下が参考になる。
_Rubyの起動 - Rubyリファレンスマニュアル
[ ツッコむ ]
以上、31 日分です。