mieki256's diary



2022/04/01(金) [n年前の日記]

#1 [python] tkinterを勉強中

tkinter を使ってスクロールバーを備えたキャンバスを表示できないか実験中。.Scrollbar() と .Canvas() を使って、.grid() でレイアウトしていけばいいらしいけど…。scrollregion= とやらでどんな値を指定すればいいのかがよく分からない…。

ウインドウサイズをマウスドラッグで変更した際に、キャンバスサイズをウインドウサイズに追従させるあたりもよく分からない。.pack(expand=1, fill=tkinter.BOTH) を使えば親のウィジェットのサイズ変更に追従するらしいけど、.grid() でレイアウトする場合は何を指定すればいいのやら。

2022/04/02追記。 :

.grid() でレイアウトしつつ、親のウィジェットのサイズ変更に追従させる場合は、weight= の指定をすれば目的が果たせるらしい。

_Tkinter grid ジオメトリマネージャ - Tkinter による GUI プログラミング - Python 入門

.columnconfigure(0, weight=1) と .rowconfigure(0, weight=1) を指定すれば、指定した行と列が ―― この場合は (0,0) のセル(?)のサイズが親に追従してくれる模様。

#2 [movie] 「ファンタスティック・ビーストと魔法使いの旅」を視聴

金曜ロードショーで流れてたので視聴してみた。初見。「ハリー・ポッター」シリーズのスピンオフ映画らしい。「ハリー・ポッター」より70年前を舞台にした設定だそうで。魔獣オタクな主人公がNYにやってきて騒動を起こす、という話っぽい。新作がもうすぐ劇場公開されるようで、その宣伝目的の放送なのかなと。

自分はハリポタシリーズをほとんど見てないので設定が分かるかどうか不安だったのだけど、見ていてフツーに面白かった。本編を見てなくても楽しめる作りというか、誰でも楽しめる映画になっていたような気がする。もちろん、シリーズを見てる人なら更に楽しめるようになっているのだろうけど。

それにしても、CGというか、VFXがスゴイなと…。霧だか雲だか分からんけどモヤモヤしたソレはフラクタル関係のアルゴリズムで生成してるのかなと想像したけどどうなんだろう…。もはや魔法にしか見えない…。もはや魔法にしか見えない映像制作技術を駆使して魔法のシーンを次々に描くという…。ややこしい…。

2022/04/02() [n年前の日記]

#1 [python] tkinterのScrollbarについて勉強

Python + tkinter で、以下のようなことをしたい。
動作確認環境は以下。
以下のページを参考にして実験してみた。

_Tkinterの使い方: スクロールバー(Scrollbar)の使い方 | だえうホームページ
_python - Tkinter button expand using grid - Stack Overflow
_python tkinter キャンバスのスクロールバーについて

たぶん、できた、ような気がする。こんな感じになった。

_02_scrollbar_canvas.py
try:
    # Python 2.7
    import Tkinter as tk
    # import ttk
except Exception:
    # Python 3.x
    import tkinter as tk
    # from tkinter import ttk

from PIL import Image
from PIL import ImageTk

imgfile = "tex_1024.png"

app = tk.Tk()

frame = tk.Frame(app, bg="green")
frame.pack(expand=1, fill=tk.BOTH)

frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1)

# create Canvas
canvas = tk.Canvas(frame, bg="#888888")
canvas.grid(row=0, column=0, sticky=tk.N + tk.S + tk.W + tk.E)

# create Scrollbar
xbar = tk.Scrollbar(frame, orient=tk.HORIZONTAL, command=canvas.xview)
ybar = tk.Scrollbar(frame, orient=tk.VERTICAL, command=canvas.yview)
xbar.grid(row=1, column=0, sticky=tk.W + tk.E)
ybar.grid(row=0, column=1, sticky=tk.N + tk.S)
canvas.config(xscrollcommand=xbar.set)
canvas.config(yscrollcommand=ybar.set)

# load png image, set to canvas
im = Image.open(imgfile)
photo_image = ImageTk.PhotoImage(im)
canvas.create_image(16, 16, anchor=tk.NW, image=photo_image)

# set scroll region
iw = photo_image.width()
ih = photo_image.height()
region = (0, 0, iw + 32, ih + 32)
canvas.config(scrollregion=region)

# set drag scroll
canvas.bind("<ButtonPress-1>", lambda e: canvas.scan_mark(e.x, e.y))
canvas.bind("<B1-Motion>", lambda e: canvas.scan_dragto(e.x, e.y, gain=1))

app.mainloop()

動作に必要なpng画像は以下。

_tex_1024.png

py 02_scrollbar_canvas.py と打って実行。こうなった。



スクロールバーを動かすとキャンバス内の画像の表示位置も変わっているし、ウインドウサイズを変更するとキャンバスのサイズも追従して変化している。更に、キャンバス内をマウスの左ボタンでドラッグしてスクロールができるようにもなった。これで目的は果たせそう。

少し解説。 :

ウインドウサイズを変更した際に、.grid() でレイアウトしたウィジェットのサイズを追従させて変化させるには、weight= を使う。

frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1)

上記の指定の場合、.grid() で配置した (0,0) のウィジェットのサイズが、親に追従するようになる。

ちなみに、.pack() でレイアウトしたウィジェットのサイズを親に追従させたい場合は、expand=1, fill=tk.BOTH を指定することになる。

frame.pack(expand=1, fill=tk.BOTH)

マウスボタン押しのドラッグでキャンバス内をPANさせたい場合は、以下のような記述でいいらしい。

canvas.bind("<ButtonPress-1>", lambda e: canvas.scan_mark(e.x, e.y))
canvas.bind("<B1-Motion>", lambda e: canvas.scan_dragto(e.x, e.y, gain=1))


余談。tkinter のキャンバスに画像を表示したい場合、Pillow (PIL) を使って画像を読み込んで、ImageTk.PhotoImage() で tkinter が利用できる状態に変換するのがヨサゲ。と言うのも、Python 2.7.18 32bit + tkinter (Tkinter) の機能で png画像を読み込もうとしたらエラーになってしまったので…。Pillow を経由すれば、どんな画像フォーマットも読み込んで表示できるようになるはず。
im = Image.open(imgfile)
photo_image = ImageTk.PhotoImage(im)
canvas.create_image(16, 16, anchor=tk.NW, image=photo_image)

2022/04/03() [n年前の日記]

#1 [python] tkinterのCanvasについて勉強中

Python + tkinter について勉強中。

キャンバス(Canvas())のサイズ内に画像がピッタリ収まるような処理をしたいなと。以下のページが参考になった。

_【Python/tkinter】Canvasに画像を表示する | イメージングソリューション
_Pythonの文法メモ: 【Pillow】ImageOpsモジュールによる画像拡大縮小・トリミング・パディング

PIL(Pillow)に入っている ImageOps.pad() を使えば、パディングを考慮しつつ画像をリサイズすることができるらしい。手元でも試したところ、期待通りの動作をしてくれた。

super().__init__()で悩んだ。 :

Python 3.x の場合、class の def __init__() 内で、super()__init__() を呼んでも動いてくれたのだけど…。Python 2.7 で同じ記述をしてもエラーが出てしまうことに気づいた。

class App(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        ...

ググったところ、Python 2.7 と 3.x では、このあたり仕様が変わったそうで、以下の記述に変えたら動いてくれた。

class App(tk.Frame, object):
    def __init__(self, master=None):
        try:
            # Python 3.x
            super().__init__(master)
        except Exception:
            # Python 2.7
            # tk.Frame.__init__(self, master)
            super(App, self).__init__(master)
        ...

class App(tk.Frame): ではなく、class App(tk.Frame, object): のように、object も指定していることに注意。

ちなみに、super(App, self).__init__(master) ではなく、継承してるクラス名(tk.Frame)を直接記述して、tk.Frame.__init__(self, master) と書いても動作した。

_python - How to use super() when subclassing Tkinter widgets? - Stack Overflow
_Python の super() 関数の使い方 - Life with Python

#2 [anime] 「マギアレコード 魔法少女まどか☆マギカ外伝 Final SEASON 浅き夢の暁」を視聴

BS11で放送されていたので視聴。ゲーム原作のTVアニメ化作品。TV放映時は制作が間に合わなかったようで、最後の4話分を2時間の枠で一気に放送、という形なのかな。たぶん。

実は今まで設定等がよく分からないままTVアニメ版を眺めていたのだけど、今回の放送の冒頭で、これまでの展開や設定についてナレーションでガンガン説明してくれたのでとても助かった。いやまあ、細かいところは思い出せないし、やっぱりよく分からないところもたくさんあるのだけど、それでも、まあ、大体わかった。やはり「前回のラブライブ!」を入れておくのって大事だよなと…。

最初の30分で、「実はこういうことでした」と設定を開示していたあたりは結構楽しめた。なるほど、そういうことだったのか…。考えたなあ…。この3人凄いじゃないか…。君達めっちゃ賢いねえ…。だからこうなってしまったのね…。みたいな。オリジナル版でほむほむの設定が開示された回をちょっと思い出したりもしたけれど、そのぐらい楽しめた気がする。

自分はもうくたびれちゃったおじさんだから、作品内で提示された謎に対して、能動的に推察していく作業は面倒臭くてアレだったりするのだけど。まだ若さに溢れてる学生さんなら ―― と言っても小学生にはちょっと難し過ぎるだろうから中学生より上の年齢なら ―― それぞれの謎に対してアレコレ想像を巡らせて、答え合わせをして楽しめそうな作品っぽい印象も受けた。盛り込んである設定の量、シナリオの分量的に、若い人なら全然楽しめる作品、というか、受け手側の若さやバイタリティが試される作品とも言えそう…。

劇団イヌカレー総監督作品だけあって、映像面も見応えがあった。こういう映像を作ってたら、そりゃ放送落としますわ、とも。アニメ作品のはずなのに、ところどころのカットで、まるで絵本を眺めているような感覚にもなった。「まどか☆マギカ」もそうだったけど、この独特な映像美は一見の価値有り、かもしれない。おそらく、しばらくの間はコレが代表作になるんだろうか。そのくらいのボリュームはあるよなと…。

何にせよ、最後まで見ることができて気分的にスッキリ。なるほど、そういう話だったのね…。視聴できて良かった…。

2022/04/04(月) [n年前の日記]

#1 [python] tkinterを勉強中

Python + tkinter + Pillow を使ってウインドウ内に画像を表示する実験中。tkinter のキャンバス(Canvas)にスクロールバー(Scrollbar)を追加して画像をスクロールできるようにしつつ、ボタンを押したら画像がキャンバス内にフィットする表示になるように処理できないかと試しているところ。

2022/04/05(火) [n年前の日記]

#1 [python] tkinterとPillowでウインドウサイズに画像サイズを合わせる

Python + tkinter + Pillow で、ウインドウサイズ(キャンバスサイズ)に画像サイズを合わせて表示する処理を試しているところ。ついでにスクロールバーもつけてみたりして。

動作確認環境は以下。
参考ページは以下。ありがたや。

_【Python/tkinter】Canvasに画像を表示する | イメージングソリューション
_Pythonの文法メモ: 【Pillow】ImageOpsモジュールによる画像拡大縮小・トリミング・パディング
_Tkinterの使い方 : スクロールバー(Scrollbar)の使い方 | だえうホームページ

自分の手元でも、たぶんできた。一応動いてるように見える。

_03_canvas_zoom2.py
try:
    # Python 3.x
    import tkinter as tk
except Exception:
    # Python 2.7
    import Tkinter as tk

from PIL import Image, ImageTk, ImageOps


class App(tk.Frame, object):
    def __init__(self, master=None):
        try:
            # Python 3.x
            super().__init__(master)
        except Exception:
            # Python 2.7
            # tk.Frame.__init__(self, master)
            super(App, self).__init__(master)

        self.master.title("Canvas sample")
        # self.master.geometry("512x512")

        self.rootfrm = tk.Frame(self.master)
        self.rootfrm.pack(expand=1, fill=tk.BOTH)

        self.rootfrm.rowconfigure(1, weight=1)
        self.rootfrm.columnconfigure(0, weight=1)

        # create Button
        self.btnfrm = tk.Frame(self.rootfrm)
        self.btnfrm.grid(row=0, column=0, sticky=tk.W)

        self.btn0 = tk.Button(self.btnfrm, text="Fit", command=lambda: self.set_zoom_fit())
        self.btn0.pack(side=tk.LEFT, padx=4, ipadx=8)

        self.btn1 = tk.Button(self.btnfrm, text="1:1", command=lambda: self.set_zoom_full())
        self.btn1.pack(side=tk.LEFT, padx=4, ipadx=8)

        # create Canvas
        self.cvsfrm = tk.Frame(self.rootfrm)
        self.cvsfrm.grid(row=1, column=0, sticky=tk.N + tk.S + tk.W + tk.E)

        self.cvsfrm.rowconfigure(0, weight=1)
        self.cvsfrm.columnconfigure(0, weight=1)

        self.canvas = tk.Canvas(self.cvsfrm, bg="#666666", width=512, height=256)
        self.canvas.grid(row=0, column=0, sticky=tk.N + tk.S + tk.W + tk.E)

        # create Scrollbar
        xbar = tk.Scrollbar(self.cvsfrm, orient=tk.HORIZONTAL, command=self.canvas.xview)
        ybar = tk.Scrollbar(self.cvsfrm, orient=tk.VERTICAL, command=self.canvas.yview)
        xbar.grid(row=1, column=0, sticky=tk.W + tk.E)
        ybar.grid(row=0, column=1, sticky=tk.N + tk.S)
        self.canvas.config(xscrollcommand=xbar.set)
        self.canvas.config(yscrollcommand=ybar.set)

        # set drag scroll
        self.canvas.bind("<ButtonPress-1>", lambda e: self.canvas.scan_mark(e.x, e.y))
        self.canvas.bind("<B1-Motion>", lambda e: self.canvas.scan_dragto(e.x, e.y, gain=1))

        self.zoomfit = True
        self.im = Image.open("tex_1024.png")
        self.set_image()

    def set_zoom_fit(self):
        self.zoomfit = True
        self.set_image()

    def set_zoom_full(self):
        self.zoomfit = False
        self.set_image()

    def set_image(self):
        self.update()
        cw = self.canvas.winfo_width()
        ch = self.canvas.winfo_height()

        if self.zoomfit:
            # view fit
            self.im_pad = ImageOps.pad(self.im, (cw - 4, ch - 4), method=Image.LANCZOS)
            self.photo_image = ImageTk.PhotoImage(image=self.im_pad)
        else:
            # view 1:1
            self.photo_image = ImageTk.PhotoImage(image=self.im)

        self.canvas.create_image(0, 0, image=self.photo_image, anchor=tk.NW)

        # set scroll region
        iw = self.photo_image.width()
        ih = self.photo_image.height()
        region = (0, 0, iw, ih)
        self.canvas.config(scrollregion=region)


def main():
    root = tk.Tk()
    app = App(master=root)
    app.mainloop()


if __name__ == '__main__':
    main()

使用画像は以下。

_tex_1024.png

py 03_canvas_zoom2.py で実行すると、以下のような感じで動いてくれた。



ImageOps.pad() で、パディングを考慮したサイズに変換してくれるので簡単。method=Image.LANCZOS を渡せば、Lanczos で変換してくれるようでもあるし…。Pillow は便利だなあ。ありがたや。

でも、画像表示に特化した処理を ―― キャンバスに画像を表示できて、スクロールバーがついてて、拡大縮小表示ができて、マウスドラッグでスクロールができる、みたいなクラスだかモジュールだかを誰かが既に書いてたりしないのかなという疑問も湧いた。何かの処理結果画像を画像ビューアっぽい感じで表示したい場面って結構あるのではないだろうか。毎回こんな感じのスクリプトを書かなきゃいけないのだろうか…。

#2 [pc] Bluetoothカセットアダプタが気になってる

MZ-700関係のアレコレをググっていたら、Bluetoothカセットアダプタなるものの存在を知って、なんだか気になり始めてしまった。

大昔の8bitPCは、カセットテープからプログラムをロードして動かすわけだけど、Bluetoothカセットアダプタを使えば、今時のPCだのスマホだのからBluetooth(無線)で音声データを送って、昔の8bitPCにプログラムを読み込ませることができるようになるはずで。カセットテープという物理的なメディアを管理しなくても済む点は、なんだか便利そうだなと…。

ただ、ググった感じでは、もう商品ジャンルとして存在していないようでもあり…。2014年〜2016年頃は、まだ販売されていたみたいだけど…。いやまあ、今でも Amazon で検索すれば一応出てくるけれど、どれもカセットアダプタから謎の線が飛び出してる製品ばかりで、8bitPCのデータレコーダ(カセットテープを入れる部分)に、物理的に入るかどうかビミョーだよなと…。線が引っ掛かりそう…。

となると、自作するしか手は無さそうだけど、有線カセットアダプタとBluetoothヘッドセットを分解して作業することになるようで…。それはちょっと面倒臭いな…。カセットアダプタに入らないヘッドセットを買ってしまったらダメージもデカいだろうし…。

ちょっと待て。落ち着け自分。そもそもお前、今後レトロPC(MZ-700)の実機を起動する機会がどれだけあるのかと。そういえば今現在、表示デバイスは持っているのだろうか…? 実は画面すら出せない状況だったりしないか。

ということで、冷静になって考えたら今時そんなものを入手してどうするの、滅多に使わないだろう、てな話なのだけど…。でも、なんだか気になる…。

他にも、今時のPCからUSB経由でバイナリを送信してレトロPCのパラレルポートで受け取る方法とか、レトロPCからSDカードを読めるようにする方法もあったりするっぽい。カセットテープ(データレコーダ)から読み込むと数分かかってしまうけど、USB経由だの、SDカードだのから読み込むならロード時間も短縮できそう…。ちょっと待て。落ち着け自分。

参考ページをメモ。 :

#3 [nitijyou] OPPテープ購入

ホーマックでOPPテープなるものを購入してきた。以前何かをググっていた際にそういうテープがあると知って気になっていたのだけど、ようやくゲットできた。
セロハンテープのセロハンは木材パルプで出来ているから時間が経つとボロボロになってしまうけど、OPPテープはポリプロピレンでできているからボロボロになりにくいらしい。ただ、環境に優しいのはセロハンテープと言われている模様。

とりあえず、玄関周辺の電気コードを隠すモールが落ちそうになっていたので、梱包用OPPテープを貼って止めてみた。今までは養生テープで対処してたけど、半透明だから見た目は悪いし、すぐに剥がれるしで…。今回購入した品は透明を謳うだけあって、パッと見はテープが貼ってあることも分からない状態になった。ただ、次回テープを剥がそうとした際は、テープの粘着力が強いから壁までバリバリと剥がれるだろうけど…。その時は貼れる壁紙の類を入手してどうにか誤魔化そう…。

乾電池も購入。 :

ケーズデンキで単3乾電池を購入。
  • maxell ボルテージ(VOLTAGE) LR6(T) 12P (12個入り), 液漏れ保障付き, 780円 (1本65円)

わざわざ液漏れ保障を謳うぐらいだから、そうそう液漏れはしないだろう、しないといいなと期待しつつ購入。100円ショップ等で売っている乾電池と比べるとお値段はちょっと高いけど、以前ダイソーで購入した乾電池が軒並み液漏れしてしまって、いくつかの電子機器をダメにしてしまったので、もう安さだけで乾電池は選ばないぞ、と…。1本数十円をケチったせいで、数千円、数万円の機器を台無しにしてたら馬鹿馬鹿しい話だし…。

2022/04/06(水) [n年前の日記]

#1 [python] tkinterで画像の拡大縮小表示を試しているところ

Python + tkinter + Pillow を使って、画像の拡大縮小表示を試しているところ。マウスホイールの上下で画像が拡大縮小したり、「-」「+」ボタンのクリックで拡大縮小できたらいいなと。

以下、参考ページ。

_【Python/tkinter】Canvasに画像を表示する | イメージングソリューション
_Pythonの文法メモ: 【Pillow】ImageOpsモジュールによる画像拡大縮小・トリミング・パディング
_Tkinterの使い方 : スクロールバー(Scrollbar)の使い方 | だえうホームページ
_Python, Pillowで画像を一括リサイズ(拡大・縮小) | note.nkmk.me
_【Python/tkinter】マウスホイールで画像のリサイズを行う | だえうホームページ

動作確認環境は以下。


一応、動作してるっぽい感じのスクリプトは書けたのだけど…。ちょっと問題があるというか…。

_04_canvas_zoom4.py
import sys
import platform

if sys.version_info.major == 2:
    # Python 2.7
    import Tkinter as tk
else:
    # Python 3.x
    import tkinter as tk

from PIL import Image, ImageTk, ImageOps


class App(tk.Frame, object):

    def __init__(self, master=None):
        try:
            # Python 3.x
            super().__init__(master)
        except Exception:
            # Python 2.7
            # tk.Frame.__init__(self, master)
            super(App, self).__init__(master)

        self.master.title("Canvas zoom sample")
        # self.master.geometry("512x512")

        self.rootfrm = tk.Frame(self.master)
        self.rootfrm.pack(expand=1, fill=tk.BOTH)

        self.rootfrm.rowconfigure(1, weight=1)
        self.rootfrm.columnconfigure(0, weight=1)

        # create Button
        self.btnfrm = tk.Frame(self.rootfrm)
        self.btnfrm.grid(row=0, column=0, sticky=tk.W)

        b0 = tk.Button(self.btnfrm, text="Fit", command=lambda: self.set_zoom_fit())
        b1 = tk.Button(self.btnfrm, text="-", command=lambda: self.dec_ratio())
        b2 = tk.Button(self.btnfrm, text="1:1", command=lambda: self.set_zoom_full())
        b3 = tk.Button(self.btnfrm, text="+", command=lambda: self.inc_ratio())
        b0.pack(side=tk.LEFT, padx=4, ipadx=8)
        b1.pack(side=tk.LEFT, padx=4, ipadx=8)
        b2.pack(side=tk.LEFT, padx=4, ipadx=8)
        b3.pack(side=tk.LEFT, padx=4, ipadx=8)

        self.ratiostr = tk.StringVar()
        self.ratiostr.set("100%")
        self.ratiolbl = tk.Label(self.btnfrm, textvariable=self.ratiostr, relief=tk.GROOVE)
        self.ratiolbl.pack(side=tk.LEFT, padx=4, ipadx=8)

        # create Canvas
        self.cvsfrm = tk.Frame(self.rootfrm)
        self.cvsfrm.grid(row=1, column=0, sticky=tk.N + tk.S + tk.W + tk.E)

        self.cvsfrm.rowconfigure(0, weight=1)
        self.cvsfrm.columnconfigure(0, weight=1)

        self.canvas = tk.Canvas(self.cvsfrm, bg="#666666", width=512, height=256)
        self.canvas.grid(row=0, column=0, sticky=tk.N + tk.S + tk.W + tk.E)

        # create Scrollbar
        xbar = tk.Scrollbar(self.cvsfrm, orient=tk.HORIZONTAL, command=self.canvas.xview)
        ybar = tk.Scrollbar(self.cvsfrm, orient=tk.VERTICAL, command=self.canvas.yview)
        xbar.grid(row=1, column=0, sticky=tk.W + tk.E)
        ybar.grid(row=0, column=1, sticky=tk.N + tk.S)
        self.canvas.config(xscrollcommand=xbar.set)
        self.canvas.config(yscrollcommand=ybar.set)

        # set left button drag scroll
        self.canvas.bind("<ButtonPress-1>", lambda e: self.canvas.scan_mark(e.x, e.y))
        self.canvas.bind("<B1-Motion>", lambda e: self.canvas.scan_dragto(e.x, e.y, gain=1))

        # set middle button drag scroll
        self.canvas.bind("<ButtonPress-2>", lambda e: self.canvas.scan_mark(e.x, e.y))
        self.canvas.bind("<B2-Motion>", lambda e: self.canvas.scan_dragto(e.x, e.y, gain=1))

        # set mouse wheel event
        # .bind_all() ... Worked with Python 2.7 and Python 3.9
        # .bind() ... It worked in Python 3.9, but not in Python 2.7.
        self.canvas.bind_all("<MouseWheel>", lambda e: self.event_wheel(e))
        if platform.system() == "Linux":
            self.canvas.bind_all("<Button-4>", lambda e: self.dec_ratio())
            self.canvas.bind_all("<Button-5>", lambda e: self.inc_ratio())

        self.reset_ratio()

        self.zoomfit = False
        self.im = Image.open("tex_1024.png")
        self.set_image()

    def set_zoom_fit(self):
        self.zoomfit = True
        self.set_image()

    def set_zoom_full(self):
        self.zoomfit = False
        self.set_image()

    def reset_ratio(self):
        self.ratio = 100

    def inc_ratio(self):
        # check 32bit, 64bit, Py27, Py3x
        is64bits = (sys.maxsize > 2**32)
        ispy3x = (sys.version_info.major >= 3)
        maxsize = 1024 * (8 if (is64bits and ispy3x) else 5)

        w, h = self.im.size
        maxratio = min([(maxsize * 100 / w), (maxsize * 100 / h)])

        if self.ratio == maxratio:
            return

        self.ratio = self.ratio + (10 if self.ratio < 100 else 100)
        self.ratio = min([self.ratio, maxratio])

        self.change_ratio()

    def dec_ratio(self):
        minratio = 10
        if self.ratio == minratio:
            return

        self.ratio = self.ratio - (10 if self.ratio <= 100 else 100)
        self.ratio = max([self.ratio, minratio])

        self.change_ratio()

    def event_wheel(self, e):
        if e.delta > 0:
            self.dec_ratio()
        elif e.delta < 0:
            self.inc_ratio()

    def change_ratio(self):
        w, h = self.im.size
        w = int(w * self.ratio / 100)
        h = int(h * self.ratio / 100)
        if w < 0 or h < 0:
            return

        self.canvas.delete("all")
        if self.ratio < 100:
            self.im_pad = self.im.resize((w, h), Image.LANCZOS)
            self.photo_image = ImageTk.PhotoImage(image=self.im_pad)
        elif self.ratio > 100:
            self.im_pad = self.im.resize((w, h), Image.NEAREST)
            self.photo_image = ImageTk.PhotoImage(image=self.im_pad)
        else:
            self.photo_image = ImageTk.PhotoImage(image=self.im)

        self.create_canvas_image()

    def set_image(self):
        self.update()
        cw = self.canvas.winfo_width()
        ch = self.canvas.winfo_height()

        self.canvas.delete("all")
        if self.zoomfit:
            # view fit
            self.im_pad = ImageOps.pad(self.im, (cw - 4, ch - 4), method=Image.LANCZOS)
            self.photo_image = ImageTk.PhotoImage(image=self.im_pad)
            ow, oh = self.im.size
            nw = self.photo_image.width()
            nh = self.photo_image.height()
            rw = float(nw) / float(ow)
            rh = float(nh) / float(oh)
            self.ratio = int(min([rw, rh]) * 100)
        else:
            # view 1:1
            self.reset_ratio()
            self.photo_image = ImageTk.PhotoImage(image=self.im)

        self.create_canvas_image()

    def create_canvas_image(self):
        self.canvas.create_image(0, 0, image=self.photo_image, anchor=tk.NW)

        # set scroll region
        iw = self.photo_image.width()
        ih = self.photo_image.height()
        region = (0, 0, iw, ih)
        self.canvas.config(scrollregion=region)

        # update ratio label
        self.ratiostr.set("%d%%" % int(self.ratio))


def main():
    root = tk.Tk()
    app = App(master=root)
    app.mainloop()


if __name__ == '__main__':
    main()

使用画像は以下。

_tex_1024.png

py 04_canvas_zoom4.py で実行。以下のような感じになった。




ただ、いくつかの問題があって…。

問題点。 :

問題点その1。Python 2.7.18 32bit + Pillow 6.2.2 で実行すると、1024 x 1024 の画像を8倍(800%)に拡大しようとした際に ―― つまりは 8192 x 8192 の画像サイズに拡大して変換しようとした際に、MemoryError が発生してしまう。RAMは16GB積んでるのだけどな…。

> py -2 04_canvas_zoom4.py
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python\Python27\lib\lib-tk\Tkinter.py", line 1547, in __call__
    return self.func(*args)
  File "04_canvas_zoom4.py", line 69, in <lambda>
    b3 = tk.Button(self.btnfrm, text="+", command=lambda: self.inc_ratio())
  File "04_canvas_zoom4.py", line 147, in inc_ratio
    self.change_ratio()
  File "04_canvas_zoom4.py", line 178, in change_ratio
    self.photo_image = ImageTk.PhotoImage(image=self.im_pad)
  File "C:\Python\Python27\lib\site-packages\PIL\ImageTk.py", line 121, in __init__
    self.paste(image)
  File "C:\Python\Python27\lib\site-packages\PIL\ImageTk.py", line 176, in paste
    block = image.new_block(self.__mode, im.size)
MemoryError

以下の行でエラーが出ている模様。Pillow の Image を、tkinter で利用できるように、ImageTk.PhotoImage() を使って変換しようとしたタイミングでメモリエラーが発生している。

            self.photo_image = ImageTk.PhotoImage(image=self.im_pad)

ちなみに、Python 3.9.12 64bit + Pillow 9.0.1 で実行すると、8倍(800%)に拡大してもメモリエラーは発生しない。

原因は何だろう…。Python 32bit版では発生するけど、64bit版では発生しないから、32bit版の制限なのだろうか。それとも、Python 2.7.18 32bit で動かしている Pillow は 6.2.2 とバージョンが古いのでバグを持っているのだろうか。

仕方ないので、Python 2.* 32bit で動かしている時だけ、最大拡大率を5倍までに制限してみた。ダサいけど、仕方ない。

    def inc_ratio(self):
        # check 32bit, 64bit, Py27, Py3x
        is64bits = (sys.maxsize > 2**32)
        ispy3x = (sys.version_info.major >= 3)
        maxsize = 1024 * (8 if (is64bits and ispy3x) else 5)

問題点その2。画像を縮小するのはともかく、拡大時が重い…。処理時間が数秒かかってしまう…。

参考ページでは、キャンバスに描画されるはずの範囲だけ事前にクロップしてから拡大処理(Image.resize())すれば改善される、という対策が紹介されていたけれど。今回は、拡大状態でスクロールバー等を操作したら、キャンバス外の部分もスクロールして見れるようにしたいので、クロップしてしまうとよろしくない。

このあたりは諦めるしかないかな…。本来、こういった画像ビューアっぽいことをやりたいなら、例えば OpenGL等を使ったライブラリを利用するべきだろうか。単に画像を表示させるだけなら、CPUじゃなくてGPUを働かせるべき、かもしれない…。

余談。マウスホイールの取得でちょっとハマった。

Python 3.9.12 64bit の場合は、.bind() で動いたけれど、Python 2.7.18 32bit の場合は反応してくれなかった。.bind() ではなく、.bind_all() に変えてみたら、Python 2.7.18 32bit でも動くようになった。ただ、何が原因なのかは分かってない…。

self.canvas.bind("<MouseWheel>", lambda e: self.event_wheel(e))
↓
self.canvas.bind_all("<MouseWheel>", lambda e: self.event_wheel(e))

2022/04/07追記。 :

Ubuntu Linux 20.04 LTS (64bit)上でも動作確認してみた。スクリプトを少し修正する必要があった。 詳細は、 _2022/04/07 の日記 にメモ。

#2 [python][linux][ubuntu] termdownはPython 2.7では動かない

一応メモ。termdown という、カウントダウンをしてくれる Python製のツールがあるのだけど。

_mieki256's diary - termdownを試用
_GitHub - trehn/termdown: Countdown timer and stopwatch in your terminal

現行版の termdown 1.18.0 は Python 2.7.x 上で動作しない実装になった模様。

_ImportError: No module named queque - Issue #62 - trehn/termdown - GitHub

「Python 2.7なんてOSから削除しろ」と言われてしまっている…。

とりあえず、Ubuntu Linux 20.04 LTS 上で termdown をアンインストールしておいた、とメモ。

sudo pip uninstall termdown

ちなみに、Python 3.x 側でインストールしたら動いてくれた。

sudo pip3 install termdown

あるいは、Ubuntu Linux 上で使いたい場合は、snap版 termdown を使えばいいのだろうか。

_termdown - 端末にアスキーアートのタイマーを表示するコマンド | Ubuntuアプリのいいところ

もっとも、最近使う場面があるかというと…。自分の場合、スマホでタイマーアプリを起動して用を済ませる場面が多くなってる気もする…。

#3 [ubuntu][python][wxpython] Ubuntu Linux上でwxPythonをpipでインストールしてはいけない

久々に Ubuntu Linux 20.04 LTS を起動してパッケージを更新していたのだけど、Python 関係のモジュールを pip や pip3 を使って更新しようとして少しハマった。wxPython がアップデートできない…。

手元のメモを眺めてみたら、「Ubuntu Linux 上で wxPython をインストールするなら sudo apt でインストールすべし」と書いてあった。完全に忘れてた。pip で作業しちゃダメだったのだな…。また忘れそうなので再度メモ。

sudo apt install python-wxgtk3.0 python3-wxgtk4.0

six も sudo apt でインストールしろとメモしてあった…。

sudo apt install python-six python3-six

さておき。久々に起動したものだから、更新パッケージが200以上あって、なかなか落ちてこない…。今日中にダウンロードが終わらないのでは…。

2022/04/07(木) [n年前の日記]

#1 [python] tkinterのキャンバスで画像を拡大縮小させるスクリプトの動作確認中

_昨日作成した Python + tkinter + Pillow を使って画像表示するスクリプトを、Ubuntu Linux 20.04 LTS (64bit)上でも動かしてみた。

メモリエラーの問題。 :

Windows10 x64 21H2 + Python 2.7.18 32bit 上では、1024 x 1024の画像を8倍(8192 x 8192)まで拡大表示した際にメモリエラーが発生していたのだけど。

Ubuntu Linux 20.04 LTS上なら、Python 2.7.18 64bit、Python 3.8.10 64bit、どちらも8倍まで拡大表示できた。

つまり、この問題は、Python や Pillow のバージョンが原因では無く、32bit版か否かに起因する、ということになるのだろう…。

Pillowのアルゴリズム指定が変更された。 :

Ubuntu Linux 20.04 LTS + Python 3.8.10 + Pillow 9.1.0 で動かした際、拡大縮小アルゴリズムの種類を示す Image.LANCZOS や Image.NEAREST という指定に対して警告が表示された。

$ python3 04_canvas_zoom4.py
04_canvas_zoom4.py:173: DeprecationWarning: LANCZOS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  self.im_pad = self.im.resize((w, h), Image.LANCZOS)

04_canvas_zoom4.py:194: DeprecationWarning: LANCZOS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  self.im_pad = ImageOps.pad(self.im, (cw - 4, ch - 4), method=Image.LANCZOS)

04_canvas_zoom4.py:179: DeprecationWarning: NEAREST is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.NEAREST or Dither.NONE instead.
  self.im_pad = self.im.resize((w, h), Image.NEAREST)

Image.LANCZOS や Image.NEAREST は Pillow 10.x で削除される予定らしい…。Image.Resampleing.LANCZOS や Image.Resampling.NEAREST と記述せよとのこと。

しかし、新しい記述の仕方をしたら、例えば Python 2.7.x + Pillow 6.x.x で動かないスクリプトになりそうな気がする…。まあ、以下のような書き方をすれば動きそう。たぶん。

            try:
                mkind = Image.Resampling.LANCZOS
            except Exception:
                mkind = Image.LANCZOS
            self.im_pad = self.im.resize((w, h), mkind)

修正版のスクリプト。 :

そんなわけで、スクリプトを少し修正。Windows10 x64 21H2 上でも、Ubuntu Linux 20.04 LTS 上でも、どちらでも動いてくれた。

_04_canvas_zoom4.py


使用画像は以下。

_tex_1024.png

zoom や subsample というメソッドもあった。 :

tkinter の PhotoImage についてググってたら、zoom や subsample という、拡大や縮小に使えるメソッドがあると知った。
  • PhotoImage.zoom(n) : 整数倍(n倍)で拡大する。
  • PhotoImage.subsample(n) : 整数分の一(1/n)で縮小する。

整数を指定することしかできないので、細かいリサイズはできないけれど、これらのメソッドを使えば、Pillow を使って画像をリサイズするのと比べて、メモリエラーが出にくいのではと思えてきた。Pillow の ImageTk.PhotoImage() に、リサイズ後の巨大な Image を渡してしまうとメモリエラーが発生するわけだけど、PhotoImage.zoom() を使って拡大処理をすれば、Pillow の ImageTk.PhotoImage() は元々の画像サイズで変換することになるので、メモリエラーを回避できるのでは、と…。

ということで、試してみた。

_01_photoimage_zoom.py
try:
    import Tkinter as tk
except Exception:
    import tkinter as tk

from PIL import Image, ImageTk


class App(tk.Frame):

    def __init__(self, master=None):
        tk.Frame.__init__(self, master)

        self.frm = tk.Frame(self.master)
        self.frm.pack(expand=1, fill=tk.BOTH)
        self.frm.rowconfigure(1, weight=1)
        self.frm.columnconfigure(2, weight=1)

        self.btn0 = tk.Button(self.frm, text="-", command=lambda: self.dec_ratio())
        self.btn1 = tk.Button(self.frm, text="+", command=lambda: self.inc_ratio())
        self.zoomstr = tk.StringVar()
        self.zoomlbl = tk.Label(self.frm, textvariable=self.zoomstr)
        self.btn0.grid(row=0, column=0, ipadx=4)
        self.btn1.grid(row=0, column=1, ipadx=4)
        self.zoomlbl.grid(row=0, column=2)

        self.canvas = tk.Canvas(self.frm, bg="#666666")
        self.canvas.grid(row=1, column=0, columnspan=3, sticky=tk.N + tk.S + tk.W + tk.E)

        self.im = Image.open("tex_1024.png")
        self.photo_image = ImageTk.PhotoImage(image=self.im)

        self.ratio = 1
        self.set_image()

    def set_image(self):
        self.canvas.delete("all")
        if self.ratio == 1:
            # 1:1
            self.zoomstr.set("%d%%" % (self.ratio * 100))
            self.zoom_image = self.photo_image
        elif self.ratio > 1:
            # zoom (x 2, 3, 4, ...)
            zm = int(self.ratio)
            self.zoomstr.set("%d%%" % (self.ratio * 100))
            self.zoom_image = self.photo_image._PhotoImage__photo.zoom(zm)
        else:
            # subsample (/ 2, 3, 4, ...)
            zm = -self.ratio
            r = int(100 / zm)
            self.zoomstr.set("%d%%" % r)
            self.zoom_image = self.photo_image._PhotoImage__photo.subsample(zm)

        self.canvas.create_image(0, 0, image=self.zoom_image, anchor=tk.NW)

    def inc_ratio(self):
        maxratio = 16
        if self.ratio < maxratio:
            self.ratio = self.ratio + 1
            self.ratio = min([maxratio, self.ratio])
            if -1 <= self.ratio <= 1:
                self.ratio = 1
            self.set_image()

    def dec_ratio(self):
        minratio = -10
        if self.ratio > minratio:
            self.ratio = self.ratio - 1
            self.ratio = max([minratio, self.ratio])
            if -1 <= self.ratio <= 0:
                self.ratio = -2
            self.set_image()


def main():
    root = tk.Tk()
    app = App(master=root)
    app.mainloop()


if __name__ == '__main__':
    main()

使用画像は以下。

_tex_1024.png

動作確認環境は以下。
  • Windows10 x64 21H2 + Python 3.9.12 64bit + Pillow 9.1.0
  • Windows10 x64 21H2 + Python 2.7.18 32bit + Pillow 6.2.2

py 01_photoimage_zoom.py で実行。以下のような感じで動作した。




Python 2.7.18 32bit + Pillow 6.2.2 で処理をした場合、1024 x 1024 の画像を8倍(8192 x 8192)まで拡大させるとメモリエラーが発生してしまうけれど。.zoom() を使うと、Python 2.7.18 32bit上で9倍(9216 x 9216)まで拡大してもメモリエラーは出なかった。

しかし、どこまでも拡大できるわけでもないようで…。11倍(11264 x 11264)まで拡大しようとしたらメモリエラーが発生した。

> py -2 01_photoimage_zoom.py
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python\Python27\lib\lib-tk\Tkinter.py", line 1547, in __call__
    return self.func(*args)
  File "01_photoimage_zoom.py", line 32, in <lambda>
    self.btn1 = tk.Button(self.frm, text="+", command=lambda: self.inc_ratio())
  File "01_photoimage_zoom.py", line 75, in inc_ratio
    self.set_image()
  File "01_photoimage_zoom.py", line 58, in set_image
    self.zoom_image = self.photo_image._PhotoImage__photo.zoom(zm)
  File "C:\Python\Python27\lib\lib-tk\Tkinter.py", line 3400, in zoom
    self.tk.call(destImage, 'copy', self.name, '-zoom',x,y)
TclError: not enough free memory for image buffer

また、10倍(10240 x 10240)まで拡大してから、9倍に戻そうとしたら、そのタイミングでもメモリエラーが発生した。

ということで、.zoom() を使えば、Python 32bit版上でも、Pillow でリサイズ処理をする場合と比べて、もうちょっと大きく拡大表示ができることが分かった。ただ、拡大率を上げていくと、そのうちどこかでメモリエラーが発生するし、拡大すると処理時間が目に見えて遅くなるあたりはどちらも同じなので、五十歩百歩な感も否めない…。

余談。Pillow の ImageTk.PhotoImage() を使って得られた PhotoImage に対して、.zoom() や .subsample() を使いたい場合は、hoge._PhotoImage__photo.zoom(n) といった具合に記述するらしい。「._PhotoImage__photo.」を挿入することで、.zoom() 等が呼べるようになる模様。

_python - PhotoImage zoom - Stack Overflow
_Tkinter Photoimage | Delft Stack

#2 [python][wxpython] wxPython 3.0と4.0の違いを少し調べた

昔、wxPython 3.0.2.0 用に書いていたスクリプトが、wxPython 4.1.0 で動かないことに気が付いたので、どこらへんの仕様が変わったのか、ほんの少しだけ調べてみた。

ある程度は、以下のページで記述されてる気配はあるけれど…。

_wxPython Changelog | wxPython

確認した環境は以下。
気づいたところをいくつかメモ。


wx.EVT_PAINT(self, self.OnPaint) や wx.EVT_SIZE(self, self.OnSize) という書き方は非推奨。.Bind() を使って指定する。
wx.EVT_PAINT(self, self.OnPaint)
wx.EVT_SIZE(self, self.OnSize)
↓
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_SIZE, self.OnSize)

wx.Menu の .Append() 内で text="..." という書き方はできなくなった。
item = file_menu.Append(wx.ID_EXIT, text="&Exit")
↓
item = file_menu.Append(wx.ID_EXIT, "&Exit")

他にもまだまだ変更点があるはずだけど…。

2022/04/08追記。 :

以前も少し調べてメモしていたことをすっかり忘れてた…。

_mieki256's diary - wxPython 4.1.1 を少し触ってる

修正したスクリプト。 :

上記の変更を反映させて、以前書いたスクリプトを修正してみた。画像をウインドウ内にドラッグアンドドロップ(DnD)すると画像を表示して、その画像をドラッグすると位置を移動できるスクリプト。

_drag_image.py
import wx

USE_BUFFERED_DC = True


class MyObj():

    """マウスドラッグで移動できるオブジェクト用クラス"""

    def __init__(self, bmp, x=0, y=0):
        """初期化"""
        self.bmp = bmp  # bitmapを記録
        self.pos = wx.Point(x, y)  # 表示位置を記録
        self.diff_pos = wx.Point(0, 0)

    def HitTest(self, pnt):
        """座標とアタリ判定"""
        rect = self.GetRect()  # 矩形領域を取得
        
        # 座標が矩形内に入ってるか調べる
        try:
            r = rect.InsideXY(pnt.x, pnt.y)
        except:
            r = rect.Contains(pnt.x, pnt.y)
        return r
        

    def GetRect(self):
        """矩形領域を返す"""
        return wx.Rect(self.pos.x, self.pos.y,
                       self.bmp.GetWidth(), self.bmp.GetHeight())

    def SavePosDiff(self, pnt):
        """
        マウス座標と自分の座標の相対値を記録。
        この情報がないと、画像をドラッグした時の表示位置がしっくりこない
        """
        self.diff_pos.x = self.pos.x - pnt.x
        self.diff_pos.y = self.pos.y - pnt.y

    def Draw(self, dc, select_enable):
        """与えられたDCを使って画像を描画"""
        try:
            have_bitmap = self.bmp.Ok()
        except:
            have_bitmap = self.bmp.IsOk()

        if not have_bitmap:
            return False
        
        r = self.GetRect()  # 矩形領域を取得

        # ペンを設定しないと何故か描画できない
        dc.SetPen(wx.Pen(wx.BLACK, 4))
        dc.DrawBitmap(self.bmp, r.x, r.y, True)  # 画像を描画

        if select_enable:
            # 画像枠を描画
            dc.SetBrush(wx.TRANSPARENT_BRUSH)  # 透明塗り潰し
            dc.SetPen(wx.Pen(wx.RED, 1))  # 赤い線を指定
            dc.DrawRectangle(r.x, r.y, r.width, r.height)  # 矩形を描画

        return True


class MyFileDropTarget(wx.FileDropTarget):
    """ドラッグアンドドロップ担当クラス"""

    def __init__(self, obj):
        """初期化"""
        wx.FileDropTarget.__init__(self)
        self.obj = obj  # ファイルのドロップ対象を覚えておく

    def OnDropFiles(self, x, y, filenames):
        """ファイルドロップ時"""
        self.obj.LoadImage(filenames)  # 親?の画像読み込みメソッドを呼ぶ
        return True


class MyFrame(wx.Frame):
    """ダブルバッファで表示するFrame"""

    def __init__(self, parent=None, title=""):
        """初期化"""
        wx.Frame.__init__(self, parent=parent, title=title, size=(800, 600))

        # PAINTイベント、SIZEイベントで呼ばれるメソッドを割り当てる
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_SIZE, self.OnSize)

        # マウスボタンを押した時に呼ばれるメソッドを割り当てる
        self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown)
        self.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp)

        # マウスカーソルを動かした時に呼ばれるメソッドを割り当てる
        self.Bind(wx.EVT_MOTION, self.OnMouseMotion)

        # 画像格納用リストを初期化
        self.objs = []

        # マウスドラッグ処理用の変数を確保
        self.drag_obj = None
        self.drag_start_pos = wx.Point(0, 0)

        # 描画用バッファ初期化のために一度 OnSize() を呼ぶ
        self.OnSize()

        # ファイルドロップの対象をフレーム全体に
        self.droptarget = MyFileDropTarget(self)

        # ファイルドロップ受け入れを設定
        self.SetDropTarget(self.droptarget)

    def LoadImage(self, files):
        """D&Dされた画像をロードして描画"""
        x, y = 0, 0
        for filepath in files:
            b = wx.Bitmap(filepath)
            obj = MyObj(b, x, y)
            self.objs.append(obj)
            x += 32
            y += 32

        self.UpdateDrawing()  # 描画更新

    def OnSize(self, event=None):
        """ウインドウサイズが変更された時に呼ばれる処理"""
        size = self.ClientSize  # クライアントのウインドウサイズを取得

        # ウインドウサイズで、空の描画用バッファ(bitmap)を作成
        self._buffer = wx.Bitmap(*size)

        self.UpdateDrawing()  # 描画更新

    def UpdateDrawing(self):
        """描画更新"""
        dc = wx.MemoryDC()
        dc.SelectObject(self._buffer)

        self.Draw(dc)  # 実際の描画処理
        del dc  # Update()が呼ばれる前に MemoryDC を削除しておく必要がある

        # Falseを指定して背景を消さなくしたら画面のちらつきが出なくなった
        self.Refresh(eraseBackground=False)

        self.Update()

    def Draw(self, dc):
        """実際の描画処理"""
        dc.Clear()  # デバイスコンテキストでクリア
        for obj in self.objs:
            obj.Draw(dc, True)  # オブジェクトを描画

    def OnPaint(self, event=None):
        """画面書き換え要求があった時に呼ばれる処理"""
        if USE_BUFFERED_DC:
            # ダブルバッファを使う場合
            dc = wx.BufferedPaintDC(self, self._buffer)
        else:
            # ダブルバッファを使わない場合
            dc = wx.PaintDC(self)
            dc.DrawBitmap(self._buffer, 0, 0, True)

    def FindObj(self, pnt):
        """マウス座標と重なってるオブジェクトを返す"""
        result = None
        for obj in self.objs:
            if obj.HitTest(pnt):
                result = obj
        return result

    def OnMouseLeftDown(self, event):
        """マウスの左ボタンが押された時の処理"""
        pos = event.GetPosition()  # マウス座標を取得
        obj = self.FindObj(pos)  # マウス座標と重なってるオブジェクトを取得
        if obj is not None:
            self.drag_obj = obj  # ドラッグ移動するオブジェクトを記憶
            self.drag_start_pos = pos  # ドラッグ開始時のマウス座標を記録
            self.drag_obj.SavePosDiff(pos)

    def OnMouseLeftUp(self, event):
        """マウスの左ボタンが離された時の処理"""
        if self.drag_obj is not None:
            pos = event.GetPosition()
            self.drag_obj.pos.x = pos.x + self.drag_obj.diff_pos.x
            self.drag_obj.pos.y = pos.y + self.drag_obj.diff_pos.y

        self.drag_obj = None
        self.UpdateDrawing()

    def OnMouseMotion(self, event):
        """マウスカーソルが動いた時の処理"""
        if self.drag_obj is None:
            # ドラッグしてるオブジェクトが無いなら処理しない
            return

        # ドラッグしてるオブジェクトの座標値をマウス座標で更新
        pos = event.GetPosition()
        self.drag_obj.pos.x = pos.x + self.drag_obj.diff_pos.x
        self.drag_obj.pos.y = pos.y + self.drag_obj.diff_pos.y
        self.UpdateDrawing()  # 描画更新

def main():
    app = wx.App(False)
    frame = MyFrame(None, "DnD Image display use Double Buffer")
    frame.Show()
    app.MainLoop()

if __name__ == '__main__':
    main()


py drag_image.py で実行。以下のような感じになった。


2022/04/08(金) [n年前の日記]

#1 [python] tkinterのCanvas.scaleについて調べてた

Python + tkinter のキャンバス(Canvas)についてググってたら .scale() というメソッドがあると知って、もしやそのメソッドを使えばキャンバスの拡大縮小が簡単にできるのだろうかと気になってきた。巷の解説ページには「図形や画像を拡大縮小できる」と書いてあったりもするようだし…。画像も拡大縮小してくれるならありがたいのだけど、さてはて…。

そんなわけで、試してみた。動作確認環境は以下。
_05_canvas_scale.py
try:
    # Python 3.x
    import tkinter as tk
except Exception:
    # Python 2.7
    import Tkinter as tk

from PIL import Image, ImageTk


class App(tk.Frame, object):
    """My App."""

    def __init__(self, master=None):
        tk.Frame.__init__(self, master)

        self.master.title("Canvas sample")
        self.master.geometry("600x600")

        self.frm = tk.Frame(self.master)
        self.frm.pack(expand=1, fill=tk.BOTH)
        self.frm.rowconfigure(1, weight=1)
        self.frm.columnconfigure(0, weight=1)

        # create Button, Label
        self.bfrm = tk.Frame(self.frm)
        self.bfrm.grid(row=0, column=0, sticky=tk.W + tk.E)

        self.btn0 = tk.Button(self.bfrm, text="-", command=lambda: self.dec_ratio())
        self.btn1 = tk.Button(self.bfrm, text="+", command=lambda: self.inc_ratio())
        self.lblstr = tk.StringVar()
        self.lblstr.set("100%")
        self.lbl = tk.Label(self.bfrm, textvariable=self.lblstr)
        self.btn0.pack(side=tk.LEFT, ipadx=8, padx=4)
        self.btn1.pack(side=tk.LEFT, ipadx=8, padx=4)
        self.lbl.pack(side=tk.LEFT, ipadx=8, padx=8)

        # create Canvas
        self.canvas = tk.Canvas(self.frm, bg="#666666")
        self.canvas.grid(row=1, column=0, sticky=tk.N + tk.S + tk.W + tk.E)

        # load image
        self.im = Image.open("lena_std.png")
        self.photo_image = ImageTk.PhotoImage(image=self.im)

        self.now_ratio = 1.0
        self.tgt_ratio = 1.0

        self.update()
        cw = self.canvas.winfo_width()
        ch = self.canvas.winfo_height()

        # draw image
        self.canvas.create_image(cw / 2, ch / 2, image=self.photo_image)

        # darw Rectangle, Oval, Polygon
        x = cw / 2
        y = ch / 2
        self.canvas.create_rectangle(x, y, x + 24, y + 96, width=4, outline="#ff0000")
        self.canvas.create_oval(x + 32, y + 32, x - 32, y - 32, width=6, outline="#00ff00")
        self.canvas.create_polygon(x, y, x - 40, y - 60, x - 80, y + 30,
                                   width=2, outline="#0000ff", fill="")

    def inc_ratio(self):
        self.tgt_ratio = self.tgt_ratio + 0.5
        self.tgt_ratio = min([12.0, self.tgt_ratio])
        self.lblstr.set("%d%%" % int(self.tgt_ratio * 100))
        self.scale_canvas()

    def dec_ratio(self):
        self.tgt_ratio = self.tgt_ratio - 0.5
        self.tgt_ratio = max([0.5, self.tgt_ratio])
        self.lblstr.set("%d%%" % int(self.tgt_ratio * 100))
        self.scale_canvas()

    def scale_canvas(self):
        v = self.tgt_ratio / self.now_ratio
        cw = self.canvas.winfo_width()
        ch = self.canvas.winfo_height()
        self.canvas.scale(tk.ALL, cw / 2, ch / 2, v, v)
        self.now_ratio = self.now_ratio * v


def main():
    root = tk.Tk()
    app = App(master=root)
    app.mainloop()


if __name__ == '__main__':
    main()

使用画像は以下。

_lena_std.png

py 05_canvas_scale.py で実行。




うすうす予想はしていたけれど、画像は拡大縮小しないやん…。図形だけやん…。まあ、.scale() が画像も拡大縮小してくれるメソッドなら、皆 Pillow を使わずにコレで処理しているはずだけど、しかしそうではないわけで…。巷の解説ページは、自分でスクリプトを書いて動作確認をせずに、画像も変化するものと思い込んで紹介しているのだろうな…。

さておき。キャンバスに対して描画された、矩形、ポリゴン、楕円等は、たしかに拡大縮小しているように見える。線の太さは変わってないけれど、そこは変化しないほうが都合がいいのだろう…。あくまで、各図形の座標情報だけが拡大縮小される、と捉えればいいのだろうか。

2022/04/09() [n年前の日記]

#1 [python][gimp] GIMPのPython-Fuスクリプトを修正中

昔作成した、メカっぽいテクスチャを生成する GIMP Python-Fuスクリプトを修正中。GIMPの機能を使って描画せずに、pycairo を使って描画するようにできないかと。pycairo を使って描画すれば生成にかかる処理時間を短くできるはずなので…。

2022/04/10() [n年前の日記]

#1 [gimp][python] メカっぽいテクスチャを生成するPython-Fuスクリプトを修正した

メカっぽいテクスチャを生成する、自作のGIMP Python-Fuスクリプト (GIMP Python?)、sci-fi-texture-generator を修正して github にアップロードしておいた。

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

sci-fi-texture3_pycairo.py をダウンロードして、GIMPのユーザフォルダ\plug-ins\ の下にコピーすれば、フィルター → 下塗り → Sci-Fi texture pycairo で呼び出せるようになる。事前に、1024x1024ぐらいで新規画像を作って、件のフィルタを呼べば結果が得られるはず。

今回、GIMPの描画機能を使わずに、pycairoで描画するようにしたので、生成結果が得られるまでの時間が圧倒的に短くなった。

ただ、pycairo による描画処理は1秒もかかってないのだけど、pycairoのサーフェイスをGIMPのレイヤーに変換する処理で時間がかかってしまって、そこはどうしても待たされる…。Python のようなスクリプト言語で、1024x1024ドットに対してループ処理で1ドットずつ変換していくのは荷が重いなと…。

スタンドアローン版も用意した。 :

ついでに、GIMPが無くても使えるスタンドアローン版もアップロードしておいた。Python + tkinter + Pillow + pycairo がインストールされている環境なら動くのではないかと。

_sci-fi-texture-generator/standalone at master - mieki256/sci-fi-texture-generator - GitHub

scifi_texture_generator_sa.py をダウンロードして、python scifi_texture_generator_sa.py で実行できる。

こちらは、Generateボタンをクリックすると1秒もかからずに次々に生成していけるので、ヨサゲなテクスチャに辿り着きやすいはず。

使用例。 :

生成したテクスチャを使って、他のCGソフトで利用してみた。

Aerialod という、画像を高さ情報として立体化するツールで読み込んでみた。

_Aerialod

ss_aerialod.png


blender 2.93.8 x64 LTS 上で利用してみた。

バンプマッピングをしてみた例。




ディスプレイスモディファイアで使ってみた例。

output_displacement_test01.png


MicroDisplacements で使ってみた例。

output_microdisplacements_test01.png


一応、.blendファイルもzipにして置いておくので参考になれば…。

_bump_test01.zip
_displacement_test01.zip
_microdisplacements_test01.zip


バンプマッピングその他のやり方については以下を参考にした。ありがたや。

_Blender Bump(バンプ)とNomarl mapの質感の違いを比較 - TomoGのごちゃまぜ倉庫
_【Blender】Bumpを使用した質感表現の方法 | けものこばち
_【バンプマップ】テクスチャで凹凸を描く方法 / 画像のピクセル感を軽減する【Blender】 - 忘却まとめ

_Blender Displacement Mapの使い方!テクスチャ模様をメッシュに適用する - TomoGのごちゃまぜ倉庫
_【Blender2.9】表面を複雑に変化させる:ディスプレイスモディファイアー | Vtuberの解剖学
_Blender : テクスチャマップを理解する : ディスプレイスメントマップ-YATO NOTE

#2 [anime] 「さよなら銀河鉄道999 アンドロメダ終着駅」を視聴

BS12で放送されていたので視聴。今回で3回目か4回目の視聴だろうか。「銀河鉄道999」の劇場版アニメ第2作。

見れて良かった。やはり雰囲気がとにかく良い…。まあ、雰囲気だけ、とも言えちゃう映画だったりもして、設定や話はツッコミどころ満載なのだけど。「いやー、音楽で誤魔化されてるなー」と自覚できてしまう瞬間が何度もあって、やはり映画は総合芸術だなと…。音楽の力は偉大。コレを有効活用しない手はない。皆でどんどん頼るべき。

自分は大好きなんだけど、けして手放しで褒められないアニメ映画ではあるよなと…。いや、好きなんだけど。色々とアレなところがある映画なわけで…。

2022/04/11(月) [n年前の日記]

#1 [nitijyou] HDDの中を少し整理

メインPCのHDD内に保存してあるファイルを整理してた。某ゲームのシーンデータが只の連番で保存されてて作者別に分類されてなかったので、各ファイルの末尾に作者名を付加して検索しやすくしたり等。

手作業でリネームしてたけど、量を考えたらスクリプトを書いて作業すべきだったかもしれない…。Pythonの勉強にもなりそうだし…。

2022/04/12(火) [n年前の日記]

#1 [nitijyou] 暑い

気づいたら部屋の温度が30度を超えてた。こないだまで寒かった記憶があるのだけど…。急に上がり過ぎ…。

2022/04/13(水) [n年前の日記]

#1 [nitijyou] 今日も暑い

気づいたら午前中なのに部屋の温度が30度。今日も暑い…。

2022/04/14(木) [n年前の日記]

#1 [nitijyou] 今日は寒い

昨日一昨日は部屋の温度が30度超えでエアコンを入れて冷房してたのに、今日は寒い…。暖房を入れた…。何なの…この変化…。

#2 [zatta][neta] ローマ字入力はRISCでかな入力はCISCかもしれない

思考メモ。

たまたまTVで、キーボードを凄い速さで打ってる人の映像を目にして、ふとなんとなく思った。ローマ字入力はRISC的で、かな入力はCISC的かもしれないな。みたいな。

CPUは大別して2種類ある。 まあ、CISCと言っても、現代のCISCは内部的にRISCになってるという話もどこかで見かけた気がするけど…。

それを踏まえて。 数は少ないけど何度も行うのか、数は多いけど1発で済ませるのか。なんとなく、RISC と CISC に似てる気がする。

フリック入力はどうだろう。アレもRISC的かな…。覚えるキーの数は少ないけれど、多段で目的の文字を選択していくし…。

余談。日本語の文書を打ち込む速さを競う何かしらでは、上位入賞者はかな入力ばかりらしい。キーを打つ回数がローマ字入力に比べて約半分になるから有利なのだろうな…。

ライン生産方式とセル生産方式もRISCとCISC。 :

もしかすると、ライン生産方式とセル生産方式も、RISCとCISCみたいなものと捉えることもできるのだろうか…。
  • 各人が覚えなきゃいけない作業内容を少なくする代わりに、何人もずらりと並べて多段で組み立てるのがライン生産方式。
  • 各人が覚えなきゃいけない作業内容は広くなってしまうけど、一人もしくは数人で組み立てることができてしまうのがセル生産方式。

おそらく、あらゆる場所に、RISC と CISC のような発想はありそうな気がする。

ゲームに使えないかな。 :

こういうソレを、ゲームの仕様にも持ち込めないだろうか…。アクション仕様がたくさん盛り込まれていて、各アクションに対応するボタンの数もたくさんあるのがCISC的だとしたら…。ボタンの数が少なくて、アクション仕様も限られてるけど、それらを順々に繰り出していくことで複雑なことができたとしたら、それはRISC的なのかもしれない…。

考えてみたら、格闘ゲームのコマンド入力はRISC的だな…。たった1本のレバーの動きとボタンを押すという行為で、たくさん用意されたアクションの中から一つを選んでるわけだし…。レバーを一本しか使わないという点ではRISC的なのだろうか。ただ、レバーの動かし方を全部覚えなきゃいけないあたりは、なんだかCISC的でもある…。

いや、この場合、ローマ字入力とかな入力に当てはめてみたほうがしっくりくるのだろうか。格ゲーのコマンド入力はローマ字入力だよな…。頭の中にローマ字変換表が無いとローマ字入力できないけど、格ゲーは頭の中にコマンド入力表があるようなものだし。

すると、かな入力に近いコマンド入力方式で戦う格ゲーも作れたりするんだろうか。PCのキーボードの各キーにコマンドが ―― a-zの26キーにアクションが割り当てられている、とか。

いっそ、大昔の8bit PC時代のADVみたいに、コマンド入力で戦う格ゲーはどうだろう。「右に一歩」「ジャンプ」と打ち込むと移動したりジャンプしたり。「はどうけん」と打ち込むと波動拳。…なんだかそういうゲームが存在していたような気もしてきた。

オチは無いです。思考メモです。

2022/04/15(金) [n年前の日記]

#1 [nitijyou] 某ゲームを触ってる

某ゲームを触って操作仕様その他を勉強中。複数のシーンデータを1つのシーンデータにまとめられないものかと…。詳細はGRPでメモ。

2022/04/16() [n年前の日記]

#1 [nitijyou] 救急車を呼んだ

激しい腹痛になって、救急車を呼んでしまった。お医者さんの見立てでは尿路結石だろうとの話。

状況をメモ。 :

夕食後、右の脇腹が痛くなってきて、転げ回って呼吸もできないほどの痛みが30分ほど続いた。お袋さんや親父さんに背中をさすってもらって痛みを誤魔化そうとしたけれど、そのうち4回ほど吐いてしまって、これはさすがにマズいのではと救急車を呼ぶことに。ちなみに、お袋さんが同行してくれた。

救急車が到着した頃はかろうじて自力で歩ける程度の痛みになって、搬送先のS病院に着く頃には、それほど強い痛みは感じない状態になった。

S病院で、血液検査、尿検査、レントゲン? CT?の撮影をした。お医者さんの見立てでは、おそらく尿路結石だろうとの話。
  • 撮影結果の尿路のあたりに小さくて薄い点が見えるので、おそらく結石だろうとのこと。
  • 尿検査で潜血反応があるが、結石が尿路を傷つけている可能性がある。
  • 症状が尿路結石のソレと似ている。
結石で吐くことはあるのかと質問したら「ありますあります。全然あります」との答え。結石に限らず、強い痛みで吐いてしまうのはよくあることだそうで…。

ちなみに、CTの結果では両方の腎臓に巨大な白いモノが存在していて…。お医者さん曰く、「コレも結石ですが腎臓とくっついてるだろうから無害でしょう」との話…。心配なら泌尿器科に行って診てもらってほしいとのこと…。

自分は子供の頃に急性膵炎になったことがあるので、膵臓が原因ではないかとお袋さんは疑っていたけれど、医者の話によると今回その可能性は低いそうで。
  • 膵臓がおかしい場合、撮影結果上では膵臓の周りにもやもやしたものが見えたりするが、ソレが無い。外見ではどの臓器も異常無し。
  • 膵臓その他がおかしいなら血液検査の数値に現れるはずだけど、その兆候も全く無い。

痛みもほぼ治まって、入院するほどの状態でも無いので、妹に電話連絡して車で迎えに来てもらった。

費用がどうなるのか不安だったけど、夜、時間外の診察なので、その場では保険証+5,000円を仮預かりとして渡して、後日、昼間の診察時間内に診察料を払って、保険証を返すことになる、との話だった。

時間や病院名等、詳細はGRPでメモ。

2022/04/17() [n年前の日記]

#1 [moho] Moho 13.5.3が公開されたらしい

2Dアニメ制作ソフト Moho Pro 13.5.3 が公開されたらしいので、13.5.2 からアップデートした。環境は Windows10 x64 21H2。Moho1353_Win.exe をダウンロードして実行して上書きインストールした。

関連情報についてググってみたら、一部の環境でレイヤー名等が変更できない症状が発生していたらしい。が、自分の環境では今まで通り名前変更等の作業ができた。

新機能については、まだ調べていない…。

#2 [anime] 「ハイ☆スピード! Free! Starting Days」を視聴

BS12で放送されていたので視聴してみた。初見。京都アニメーション制作のTVアニメ「Free!」シリーズの劇場版、という扱いでいいのだろうか。ちなみに、「Free!」の原作小説は「ハイ☆スピード!」というタイトルらしい。監督は、例の事件でお亡くなりになっている武本康弘監督。

TVアニメ版は主人公達が高校生だったけど、その主人公達の中学時代を描いた内容だった。ジャンルとしては、爽やか青春スポーツドラマ、みたいな感じなのだろうか…。それぞれの少年達の悩みが終盤で一気に解放されていく感じの構成で、ちゃんと最後まで見ていれば不快な気分にはならない映画のように思えた。

ただ、映画をABCDパートに分けるとすると、Dパートまでは登場人物の悩む姿が延々描かれるので、途中で文句を言い出す層は居るだろうなと…。

このあたり、映画とTVの違いがあるわけで…。映画は、2時間前後、お客さんを拘束することを想定できるメディアなので、最後まで見てくれることを前提にした構成ができるのだけど、TVアニメは途中でチャンネルを変えられてしまったり、数話見たところで視聴を打ち切られてしまう可能性が高いので、映画とは構成が違ってきたりするわけで。逆に言えば、TVアニメの感覚で映画を眺めて文句を言うのはお門違いだろうと…。それぞれ違う特性を持ったメディアなのだから、映画に関してはひとまず最後まで見てから文句を言いましょう。みたいな。いやまあ、「この映画、途中で寝ちゃうよ」ぐらいの文句は全然アリだと思うけど。

さておき。作画や撮影に関しては、さすが京アニ作品だなと…。水面の表現についてはデジタル撮影万歳というか。セル+フィルムで作っていた時代なら、水面のハイライトをチラチラと作画で動かして表現するしかなかっただろうけど、今は光が揺らめく感じの表現ができて…。良い時代になった…。また、男子中学生の未発達な肉体を上手に作画していたような気もするわけで。しかも水泳だから半裸だし。そっち方面(?)が好きな人には終始グッとくる作画だったのではないか、と…。

何にせよ、どういう映画なのか少し気になっていたので、見れて良かった。

ただ、TVアニメ版を見ている人じゃないとキャラ設定が分からないであろうシーンも多々あって、その点は残念だなと…。もちろん、ファン向けの映画としては、それで全然OKなんだけど、これだけの映像を繰り出しておきながら、しかし誰でも見れる映画ではない ―― 事前知識が無くても楽しめる作りではないあたりは、なんだかもったいない…。 *1
*1: でもまあ、どういう反応をするのかさっぱり分からない一般層を狙うより、特定の層を狙うほうが商売としては堅実だよなあ、とも思うのだけど。

2022/04/18(月) [n年前の日記]

#1 [tic80] TIC-80 Android版をインストールしてみた

ふと気が付いたら、Google Play上で TIC-80 Android版が見当たらない状態になっていた。以前は存在していたような気がしたのだけど…。記憶違いだろうか…。

一応説明しておくと、TIC-80 は、fantasy computer (fantasy console)と称するジャンルのソフト。テキストエディタ、ドットエディタ、マップエディタ、サウンドエディタ等々が全部入ってるから、そのソフトさえあればゲーム制作ができる。この手のジャンルで一番有名なのはPICO-8という有償ソフトだけど、TIC-80 は無償で使える。 *1

さておき。公式サイトを眺めたら、TIC-80 の .apk (tic80-v0.90-android.apk, 0.90.1723) が用意されていた。

_Create / TIC-80

であれば、Android に .apk をインストールする方法が分かれば、TIC-80 を動かせるのではないかと思えてきた。

以下のページを参考にして、.apk をインストールしてみた。

_apkファイルをAndroid端末(実機)にインストールする方法|Android|モバイル/スマートフォン|PHP & JavaScript Room

  1. Android機の、設定 → アプリケーション → 開発元不明のアプリ、にチェックを入れて有効化。(Android 7.0 の場合、設定 → 詳細設定 → セキュリティ → 提供元不明のアプリ、にチェックを入れて有効化、だった。)
  2. Windows PC + Webブラウザで作業。TIC-80 Android版のダウンロードURLをクリップボードにコピー。
  3. URLをQRコードに変換。
  4. Android機のカメラで、QRコードをスキャン。得られたURLをブラウザで開いて、tic80-v0.90-android.apk を、ダウンロードフォルダにダウンロード。
  5. ダウンロードした .apk を開くとインストールが始まる。

これで、手持ちのAndroidスマホ、HUAWEI P9 lite (Android 7.0) にインストールができた。ホーム画面にTIC-80のアイコンが表示されて、アイコンをタップしたらフツーに起動してくれた。

何はともあれ、これでスマホさえあればゲームが作れる状態になった…と言えるのかもしれないなと。

インストールが終わったら、Android側の「開発元不明のアプリ」はチェックを外して無効化しておく。無効化しても、インストール済みのアプリが消えたりはしない模様。

その他をメモ。 :

作業に使ったPCは Windows10 x64 21H2。PC上のWebブラウザは Firefox 99.0.1 64bit。

QRコードへの変換は以下のサービスを使わせてもらった。ありがたや。

_QRコード作成【無料】/QRのススメ

HUAWEI P9 lite でQRコードをスキャンしたい場合は、以下の操作をすればいい。
  1. 待ち受け画面の最下部を上にスワイプ(?)。
  2. 下部にいくつかのアイコンが並んだ状態になる。
  3. その一番右側にQRコード用スキャナのアイコンが用意されているのでタップ。
Andorid 7.0 では共通の操作なのか、それとも P9 lite だけの仕様なのかは分からないけれど…。

*1: 有償版の TIC-80 もあったはず。有償版はいくつかの制限が解除されるらしい。

#2 [moho] Moho Pro 13.5.3について少し調べてた

Moho Pro 13.5.3 の変更点が分からなかったので、以下の動画を眺めて少しだけ把握した。

_Webinar - What is new in Moho 13.5.3 with Victor Paredes - YouTube


自動翻訳で字幕を表示して眺めていただけなので、間違ってるところがあるかもしれんけど…。とりあえず、作業時の使い勝手を考慮した変更が多いようではあるなと…。

2022/04/19追記。 :

公式フォーラムで変更点が記述されていることに気づいた。

_Moho 13.5.3 is available! Update now! - Moho Forum

わざわざ時間をかけて動画を眺めなくても、この投稿ページを眺めれば済んだのだな…。トホホ。次回のアップデート時は公式フォーラムを真っ先に眺めることにしよう…。

2022/04/19(火) [n年前の日記]

#1 [nitijyou] 午前中に地震

午前中に大き目の地震。Kiwi Monitor上では、福島県近辺で大きな予想震度が表示されて、かなり焦った…。

ニュース等では、また同レベルの地震が来るかもしれないとの話なので、気をつけないと…。

#2 [moho] Mohoを触ってる

せっかく Moho Pro 13.5.3 にアップデートしたことだし、操作を思い出すべく、ちょっとだけ触っているところ。

ポイント追加ツールやポイント変形ツールの使い方を完全に忘れている…。制御ハンドルの片方だけを変更するのってどうやるんだっけ…。Alt + ドラッグだったかな…。

0フレームに戻らないとレイヤー構成を変更できないことすら忘れてしまって、おかしいなおかしいなと悩んでしまった。使い方をほとんど忘れてるなあ…。

#3 [anime] どうして14話からなのだろう

思考メモ。

BSフジで放送開始されたTVアニメ「レイトン ミステリー探偵社 カトリーのナゾトキファイル」を録画していたので再生してみたら、いきなり14話から始まったので驚いてしまった。新番組と称していたから、てっきり1話から放送するものとばかり…。

ググった感じでは、既に50話前後制作されて、数年前に完結している古い(?)アニメらしいけど。今回のBSフジでの放送が、『初の全国放送』のはずなのに、何故いきなり14話から始めるのか…。一体どういう事情があったのか…。

まあ、1話完結タイプのアニメっぽいので、その気になれば視聴できそうではあったけど。でも、どうしていきなり14話なの…。

「初放送」を「再放送」と思い込む人達。 :

そういえば、「シュタインズゲート」がBSで『初放送』された時も、プロデューサーが「ただ『再放送』してもつまらないだろ」と言い出してラストを改変しちゃって、見ていたこっちは「なんじゃこりゃ…」になったけど。東京に住んでる人達は認識がおかしい…。東京の地上波で放送されたアニメは、日本全国でも既に放送されたのだと間違って思い込む悪癖(?)があるのではなかろうか…。

そのアニメ、田舎じゃ放送されてませんよ? 日本全国的には未放送のアニメですよ? BSでの『初放送』は『再放送』じゃないですよ? 『初の全国放送』ですよ? 大丈夫ですか? 分かってますか? いやまあ、東京都民的には再放送っぽい感覚になるのは分かるけどさあ…。

TV放送ってそれなりにお金がかかるんじゃないかと想像するのだけど、わざわざお金をかけて一体何をやってるんだろう…。

「あー、BSで『再放送』ですか」じゃなくて「やったぜ! 初の全国放送だぜ!」って思わないと…。北は北海道、南は沖縄まで、日本全国津々浦々の老若男女に、初めてその番組を届けられるせっかくの機会なのに、「あー、再放送かー」なんて思ってたら色々と策を間違えるわなと。そんな認識ではチャンス(?)を活かせるわけがない…。

もっとも…。東京は人の数が多いから、東京=日本と勘違いするのも仕方ないのかな…。自分も東京暮らしをしていた時期があるから、そのへんなんとなく分かる…。どこまで並ぶビル群と、あのたくさん人の群れを毎日目にしていると感覚が狂いますわな…。東京だけが日本の全て、などとうっかり無意識に思えてくるのだろう…。そんな状態だから、「日本全国に向けて放送」できる道具の扱い方だって間違えるのかもしれない…。

もしかすると、関係者のイメージ能力の限界なんだろうか。東京の中をイメージするだけでオーバーフローして、東京の外まではイメージできないのかも…。各人、イメージできるスケールの限界ってありそうだもんな…。所詮人間だし。神様じゃないし。

テレ東アニメは死産。 :

ついでに一応書いておくけど。「テレ東アニメは(日本全国的には)死産」と認識してもらいたいよなと…。

テレ東系列のネットワークって、テレ東含めて6局しかないので。他局みたいに28局ネットワークとかじゃないので。しかもテレ東アニメはBSテレ東では放送されないことが多いので。 *1

だから、テレ東アニメは、地方ではまず見れないわけで。

東京に住んでいる人達は、テレ東にチャンネルさえ合わせば、その場でそのアニメが流れてるものだから、どこでも放送されてるものと思い込むのだろうけど、それはとんでもない勘違いで…。「夏目友人帳」も「弱虫ペダル」も「けものフレンズ1」も、日本全国的には未放送アニメ相当なわけで。 *2 *3 「あの人気アニメが」とか言い出されても知らんがな。見たことないし。地方じゃ放送してねえし。何が「けものはいてものけものはいない」だよ地方民はずっと「のけもの」だよ! みたいな。

そういえばこの間も、いきなり2期からBSテレ東で放送開始したアニメがあったっけ…。他局のアニメと放送時間がぶつかってる上に、途中から見てもなあ、と視聴中止しちゃいましたけど…。 *4

苦労して作ったアニメだろうに、放送時の扱いが酷いよなあ…。それもこれも、東京の人達の、「あー、BSで『再放送』ですか」的勘違いから全てが生じてるのではあるまいか…。

TV自体が終わりなんだろうか。 :

もっとも、昨今のTVアニメは、えてしてどこかしらでネット配信されてたりするものだろうし…。「BS初放送=初の全国放送と捉えなくてもいいんじゃね?」「興味のある人は当の昔にネットで見てるでしょ」てな認識があったりして、だからBSでの初放送を悉く軽視するのかな、とも思えてきたりもして…。

もはや、「アニメはTVで見るもの」と思い込んでるのは、おじさんおばさんお爺さんお婆さんばかり、なのかもしれないのだよな…。

おじさん世代が消えたら、もうTVなんてオワコン扱いになるのかなあ…。邦画が斜陽になったように、TVも後を追うのだろうか。そのうち、「4K8K放送とは何だったのか」「アレは愚行の極みだった」みたいなことも言われちゃうのだろうか…。

思考メモです。オチは無いです。

*1: テレ東アニメはテレ東系の有料チャンネルに回されてそれっきり、なのでしょうな…。
*2: いやまあ、「夏目友人帳」はBSテレ東で「セレクション放送」してたけど、あくまで「セレクション」なので…。
*3: え? TVer? 「テレ東アニメはほとんど流れない」ってどこかで聞きましたけど…。不安になって調べてみたら、噂通り「ううーん…」なラインナップ…。
*4: 1期は黒歴史なのかなと邪推してググってみたら、むしろ評判が良かったそうで、何故評判が良かった1期から流さないのかと…。

2022/04/20(水) [n年前の日記]

#1 [moho] Mohoのパースペクティブワープを試した

せっかく Moho 13.5.3 にアップデートしたので、Moho の機能について調べているところ。環境は Windows10 x64 21H2。

チュートリアルpdf(英文)を眺めていたら、パースペクティブワープ(Perspective warp)なる機能が目に入って、気になったので使い方を調べてみた。Moho 13.5.2 で追加された機能、なのかな。たぶん。

パースペクティブワープについて。 :

パースペクティブワープは、ベクター/イメージレイヤーを、パースをつけて変形させる機能。変形させたいベクター/イメージレイヤーとは別に、ベクターレイヤーを新規作成しておいて、そこに塗り潰した四角形を描いて、「このベクターレイヤーを変形指定に使うよ」と、変形したいレイヤーのプロパティで設定してやれば、パース変形をすることができる。

もっとも、Moho は以前からレイヤーに対して、3Dで移動したり回転させたりできたので、「パース変形? 前からできてましたよね?」てな印象ではあるのだけど…。

ただ、回転角度を指定するのではなく、四角形の4つの頂点位置を調整して変形具合を指定できるあたりが、絵描きさんには分かりやすいのかもしれないなと…。例えば、手描きの動画に対して、一部分にテクスチャをパース変形させながら貼り込んでいく場合は、四角形の頂点で位置決めできたほうが楽なはず。宮崎アニメの「風立ちぬ」の計算尺のカットとか、ああいう感じで。

さておき。実際に使ってみる。

チュートリアルpdf上ではベクターレイヤーを変形させていたけれど、今回はイメージレイヤーを変形させてみることにした。変形させたいイメージレイヤーの上に、ベクターレイヤーを新規作成。レイヤー名は「mesh map」にしておいたけれど、分かりやすい名前なら何でもいいはず。

moho_pwarp_ss01.png


例えば、イメージレイヤーが下のような見た目だったら…。

moho_pwarp_ss02.png


先ほど新規作成したベクターレイヤー(mesh map レイヤー)上で、変形させたい部分を覆い隠すように、「塗り潰した」四角形を描いてやる。「シェイプを描画」ツールを選んで、四角形のアイコンをクリックして、「自動塗りつぶし」にチェックを入れて、キャンバス上で左ボタンを押しながらドラッグ。

moho_pwarp_ss03.png


mesh mapレイヤーのプロパティ設定を変更。「編集時に非表示」「このレイヤーをレンダリングしない」にチェックを入れる。

moho_pwarp_ss04.png


「このレイヤーを変形指定に使うよ」的な設定をする。変形させたいベクター/イメージレイヤーのプロパティ設定を開く。レイヤーウインドウ上で、目的のレイヤーをダブルクリックするか、レイヤーを選択してから、上のほうにある「…」アイコンをクリックすれば、そのレイヤーのプロパティが表示される。

moho_pwarp_ss05.png


ベクターレイヤーなら「ベクター」タブを、イメージレイヤーなら「イメージ」タブを選択。下のほうに「スマートワープレイヤー」という項目があって「なし」になっているはずなので、クリックして「mesh map」を選択してやる。ここで選択したレイヤーが、変形具合を指定するレイヤーになる。

moho_pwarp_ss06.png


mesh map レイヤーを選択して、タイムライン上の現在フレームを0フレーム以外(1〜最終フレーム)にしてから、四角形の頂点の位置を変更してやると、ベクター/イメージレイヤーがパースのついた状態で変形してくれる。0フレーム以外にしないと頂点位置を変更できないので注意。

moho_pwarp_ss07.png


そんなわけで、以下のようなアニメが作れました。




でもまあ、最初に書いた通り、レイヤーを3Dで移動したり回転させてもパース変形ができるので…。場面に合わせて、やり易いほうで作業すればいいのだろうなと…。

もっとも、3Dっぽく見せたいなら、blender等の3DCGソフトを使ったほうが良くね? という気もする…。簡単なモデルを作って、テクスチャ貼って、モデルを動かすだけでも、イイ感じの映像になるよな…。

#2 [moho] Mohoのクアッドワープを試した

Moho 13.5.2 から追加されたらしい、クアッドワープ(Quad warp)機能も試してみた。環境は Windows10 x64 21H2 + Moho Pro 13.5.3。

クアッドワープについて。 :

今までの Moho のメッシュ変形は、三角形ポリゴンで領域を分割して変形させていたらしいけど、四角形ポリゴンで分割して変形させることもできるようになった模様。それがクアッドワープ、なのだろう…。

使い方はパースペクティブワープと同じで、変形させたいベクター/イメージレイヤーとは別にベクターレイヤーを作って、そこに四角形を意識したメッシュを描画しておいて、そのメッシュで変形具合を指定していくらしい。

とりあえず、実際に試してみる。

変形したいベクター/イメージレイヤーの上に、ベクターレイヤーを新規作成。名前は「Quad Mesh」にしてみたけど、分かりやすい名前なら何でもいい。

moho_qwarp_ss01.png


Quad Meshレイヤー上で、「ポイントを追加」ツールを使って、四角形を意識しつつ、変形したい部分を覆い隠すように線を引いて形を描いていく。
  • 「自動ウェルド」にチェックを入れて、既にあるポイントに自動で吸着するようにする。
  • 「コーナーをシャープ」にチェックを入れて、直線で線が描かれるように指定。
  • 後からスクリプトを使って自動で塗り潰しをするので、「自動塗りつぶし」「自動ストローク」のチェックは外しておく。

moho_qwarp_ss02.png


形が出来上がったら、スクリプトを使って塗り潰しをする。スクリプト → 描画 → Fill Quad Mesh、を選択。

moho_qwarp_ss03.png


自動で塗り潰しをしてくれた。もし、三角形や四角形以外の形があったらエラーを表示してくれるらしいので、その時は形を修正してスクリプトを実行し直す、のかな。たぶん。

moho_qwarp_ss04.png


Quad Meshレイヤーのプロパティを変更。「編集時に非表示」「このレイヤーをレンダリングしない」にチェックを入れる。

moho_qwarp_ss05.png


変形したいベクター/イメージレイヤーを選択して、プロパティを変更。「ベクター」または「イメージ」タブを選択。「スマートワープレイヤー」が「なし」になっているはずなので、クリックして「Quad Mesh」を選択。これで、Quad Meshレイヤー上の形に基づいて変形されるようになる。

moho_qwarp_ss06.png


Quad Mesh レイヤーを選択。タイムライン上で0フレーム以外にして、各頂点の位置を変更すると、変形ができる。

moho_qwarp_ss07.png


そんな感じで、こんなアニメが作れた。




四角形ポリゴンで変形すると、三角形ポリゴンで変形するより歪みが少なくなる場合があるらしいので、場面によって適切なポリゴン形状を選んで作業する、ということになるのかな…。たぶん。

#3 [moho] MohoからH.264エクスポートが無くなっていて微妙に困る

Moho Pro 13.5.2 から、H.264 動画のエクスポート機能が無くなっているようで。微妙に困るなと…。

_Moho Pro 13.5.2から出力映像形式にMP4(H.264-AAC)が無くなった… : 第三次ねこら対策要塞基地日誌
_Moho 13.5.2 update is available! - Page 4 - Moho Forum

H.264 が無くなって、代わり(?)に HEVC/H.265(MP4(H.265-AAC)) が追加されているのだけど、H.265は各ブラウザが対応してないわけで…。

動画エクスポート時に「MP4(MPEG4-AAC)」を選べばいいのかなと思ったけれど、出力してみたら Firefox 99.0.1 x64 でも Google Chrome 100.0.4896.127 x64 でも開けない mp4 だった。H.264、かつ、yuv420p じゃないとダメなのだろう…。

仕方ないので、連番pngでエクスポートして、ffmpeg を使って連番pngから動画を作成した。

まあ、公式フォーラムを眺めても、誰も彼もが「連番pngでエクスポートして別ソフトで動画にするもんだろJK」と言ってるようでもあるし…。

そもそも、「Moho から mp4 でエクスポートすると何故か動画が1秒短くなる」「avi なら大丈夫だった」みたいな話も見かけた…。なんだか怖い。バグだろうか。そういえば、Mohoでループアニメを作って、mp4でエクスポートして再生したら、ループ時にギクシャクしちゃって首を捻った記憶があるような…。もしやそのせいだったのでは…。

ffmpeg -y -framerate 24 -i render\output_%05d.png -vcodec utvideo out.avi
ffmpeg -y -i out.avi -vcodec libx264 -pix_fmt yuv420p -r 24 -crf 6 -preset veryslow out_1280x720.mp4
ffmpeg -y -i out.avi -vf scale=512:-2:flags=lanczos -vcodec libx264 -pix_fmt yuv420p -r 24 out_512x288.mp4

以下、参考ページ。ありがたや。

_H.264でエンコード:tech.ckme.co.jp

余談。上記のような指定を、Windows上でbatファイルにする時は、「%」を「%%」にしておくこと。

2022/04/21(木) [n年前の日記]

#1 [moho] Mohoのウィトルウィウスボーンについて調べてた

Windows10 x64 21H2 + Moho Pro 13.5.3上で、Moho の機能、ウィトルウィウスボーンについて、使い方を調べてみたのでメモ。

ウィトルウィウスボーンについて。 :

Vitruvian Bones と書くらしい。どう読むのか分からなかったけど、ツールチップ上では「ウィトルウィウスボーン」と表示されてるので、日本語版ではそう読むのだろう…。

どういう機能かというと、例えば腕だの足だのを数種類ほどその場所に描いておいて、各フレームではどれかしらを1種類だけ表示する、といった感じの機能らしい。

どうしてこういう機能が必要になるかというと…。

ボーンを使って動かすと、大体は平面的な動きしかつけることができなくて、見た目がショボい感じになってしまうものだけど。横から見た○○以外に、手前を向いている○○とか、奥を向いている○○とか、そういう見た目の○○が数フレーム挿入されるだけでも印象が変わってくる。ただ、それぞれ見るからに形が大きく違う場合がほとんどなので、1つの○○の絵からアレコレして捻り出すのは難しい。事前に数種類を別々に描いておくしかない…。

それら全然形が違う数種類のパーツの絵を、同じ場所に重なるように描いておいて、必要に応じて切り替える、というのがウィトルウィウスボーン、ということらしい。たぶん。

なんでも、レオナルド・ダ・ヴィンチが描いた、ウィトルウィウス的人体図からインスパイアされた機能だそうで…。

_ウィトルウィウス的人体図 - Wikipedia

ウィトルウィウス的人体図は、本来、一本の腕/足しか無いはずの場所に、二本の腕/足が平然と(?)描かれているわけだけど。「コレと見た目が似てるよね」ということで、この機能にこういう名前をつけた、とチュートリアルpdfには書いてあったように見えた。

操作方法。 :

実際に使ってみた。

まず、腕を3種類分、別々のレイヤーに描いてみた。

vbones_ss01.png


ボーンレイヤーを新規作成。

vbones_ss02.png


3種類の腕(3つのレイヤー)を、ボーンレイヤーにドラッグアンドドロップして登録する。

vbones_ss03.png


ボーンを追加していく。ボーンレイヤーを選択して、「ボーンを追加」ツールを選ぶ。

vbones_ss04.png


体に相当するボーンを追加しておく。

vbones_ss05.png


1本目の腕を担当するボーンを追加する。
  • 体担当ボーンを選択した状態からボーンの追加作業をしているので。体ボーンが親、上腕ボーンが子…となっている。
vbones_ss06.png


2本目の腕を担当するボーンを追加する。「ボーンを選択」ツールを選んで、体担当のボーンを選択した状態にしてから…。

vbones_ss07.png


2本目の腕を担当するボーンを追加。

vbones_ss08.png


同様に、3本目の腕を担当するボーンを追加。

vbones_ss09.png


これで腕3本分のボーンを追加できたので、どのボーンがどのレイヤーを担当するのかを設定する。

ボーンレイヤーを選択した状態で、「ボーンを選択」ツールを選んで、1本目の腕を担当するボーンを選択。
  • Shift + 左クリックで、複数のボーンを選択できる。
vbones_ss10.png


1本目の腕が描かれている、「arm1」レイヤーを選択。

vbones_ss11.png


ボーン → フレキシ結合に選択されたボーンを使用、を選ぶ。
  • Windows の場合は、Ctrl + Shift + F を叩いても良い。
vbones_ss12.png


arm1レイヤーと3つのボーンが紐づけ(?)られたので、ボーンが太い線で表示されている。これで、この3つのボーンは、arm1レイヤーに描かれたものしか動かせない状態になった。

vbones_ss13.png


同じように、arm2レイヤーとボーンを紐づけ。

vbones_ss14.png


また同じように、arm3レイヤーとボーンを紐づけ。

vbones_ss15.png


いよいよ、ウィトルウィウスボーンを設定していく。
  1. ボーンレイヤーを選択。
  2. 「ウィトルウィウスボーン」ツールを選ぶ。
  3. 3本の腕の、親に相当するボーン(上腕ボーン)を3つ選択。Shift + 左クリックで複数選択できる。
  4. 上のほうにある、「グループ」というボタンをクリック。

vbones_ss16.png


「グループ1」というグループができて、「アクティブなボーン」が、1本目の腕を担当する「B2」ボーンになった。キャンバス上でも、1本目の腕だけが表示される状態になった。「アクティブなボーン」の右の小さい三角をクリックすると、3種類のボーンがグループに登録されていることが分かる。

vbones_ss17.png


アクティブなボーンを、B5ボーンに切り替えてみた。2本目の腕に表示が切り替わった。

vbones_ss18.png


アクティブなボーンを、B8ボーンに切り替えてみた。3本目の腕に表示が切り替わった。

vbones_ss19.png


余談。各ボーンが、B2だの、B5だの、B8だのでは分かりづらいので、名前を変更したい。「ボーンを選択」ツールを選んで、目的のボーンを選択すれば、上のほうにボーン名が表示される。そこを書き換えてしまえば任意のボーン名をつけることができる。

vbones_ss20.png


ボーン名を「arm1_B2」「arm2_B5」「arm3_B8」に変更すると、ウィトルウィウスボーン利用時のボーン名表示にも反映された。

vbones_ss21.png


後は、「ボーンを操作」ツールを使って、ボーンの角度等を変更していけばいい。

vbones_ss22.png


タイムライン上で、カレントフレームを0フレーム以外にして、ウィトルウィウスボーンツールを選んで、アクティブなボーンを変更すれば、その変更もキーフレームとして記録される。

結果サンプル。 :

こんな感じで作業をして、以下のようなアニメが作れた。



元のパーツの絵がガタガタなので、動きもガタガタになってしまったけれど…。それでも、1種類の腕の絵をボーンで動かすよりは、ちょっとはマシな見た目になったような気もする。

上の動画は24FPSだけど、8FPSの動画も作ってみた。途中で、形が違う腕に差し変わっていることが分かるはず。




できた動画を眺めているうちに思ったけれど…。3コマベースなら「全部描いたほうが早い」と言われそうでもあるな…。

であればと、試しに60FPS版も作ってみた。さすがに60コマ/秒は手描きでやりたくないだろう…。




更にガタガタ感が増してしまった気がする…。元の絵が上手くなかったら、いくらフレームレートを増やしてもダメ、ってことですわな…。

2022/04/22(金) [n年前の日記]

#1 [moho] Mohoのスマートボーンダイヤルを試してた

Windows10 x64 21H2 + Moho Pro 13.5.3 で、スマートボーンダイヤルなる機能について使い方を調べてたのでメモ。

スマートボーンダイヤルについて。 :

Moho関係のチュートリアル動画を眺めていると、時々、次のような画面を目にすることがあって…。
  • キャンバスの端っこに、独立したボーンが数本置いてある。
  • ボーンを動かすと、キャンバスの真ん中に置いてあるキャラが、目パチ口パクしたり、向きを変えたりする。
目にするたびに、「コレって何だろう」「どうやったらこんなことができるんだろう」と気になってたわけで。

改めてググってみたら、スマートボーンダイヤル(Smart Bone Dial)という機能らしい。Moho上では「スマートボーンダイヤル」「スマートボーンダイアル」と表記が揺れているけど…。

なんでも、例えば目パチ口パク等、何度も出てくる同じアニメを、メインのタイムライン上でその都度逐一指定していたら面倒臭いので、メインのタイムラインとは別に管理される「アクション」と呼ばれるタイムライン上で、お決まりのアニメを作っておいて、そのアクションの何フレーム目を表示するか、という制御のためにスマートボーンダイヤルを使う、ということらしい。

するとつまり「アクション」というのは…プログラミングで言えばサブルーチンみたいなものだろうか…? それともクラスとか? 一度作っておいて後から何度も使い回す、という面は似ているような気もする…。

使ってみる。 :

とりあえず使ってみる。

アクションが関係してくるので、アクションウインドウを表示しておく。
  • ウインドウ → アクション、にチェックを入れると、アクションウインドウが表示される。
  • もし、アプリウインドウの周辺のどこかに組み込んで表示したいなら、ウインドウ → ドッキング → アクション、にチェックを入れる。

sbd_ss11.png


アニメをさせるために必要なベクターレイヤーを数枚用意して、ボーンレイヤーに登録。今回は、目玉全体と瞳の2つのレイヤーを作ってみた。

sbd_ss01.png


スマートボーンダイヤルにするためのボーンを追加する。ボーンレイヤーを選択して、「ボーンを追加」ツールを選んで、キャンバスの端っこのあたりにボーンを追加。
  • 各ボーンは、親を持たないようにしておく。ボーンが何も選択されていない状態からボーンを追加すれば、親を持たないボーンになる。
  • Shift + 左ボタンドラッグで、ボーンの方向を45度単位で制限できる。

sbd_ss02.png


先ほど作成したボーンを、スマートボーンダイヤルにする。「ボーンを選択」ツールを選んで、ボーンを選択して、「ボーン」 → 「スマートボーンダイヤルを作成」を選ぶ。

sbd_ss03.png


「スマートダイアルの作成」ダイアログが開く。
  • 名前には、選択したボーンの名前が自動で入っている。
  • 最小角度、最大角度、時間(フレーム)、を設定する。
  • 最小角度 〜 最大角度が、0 〜 +N なら、アクションが1つ作られる。
  • 最小角度 〜 最大角度が、-N 〜 +N なら、アクションが2つ作られる。

sbd_ss04.png


スマートボーンダイヤルが作られて、対応するアクション、「B1」「B1 2」の2つが作成された。アクションを選んでいるときは、タイムラインの背景色が変化する。

sbd_ss05.png


今回、アクションには48フレームを指定したので、タイムライン上でカレントフレームを48フレーム目にする。スマートボーンダイヤルの見た目(角度)が変化する。ベクターレイヤーの位置を変化させてアニメをつける。

sbd_ss06.png


アクションウインドウ上で「B1 2」をダブルクリックして切り替える。こちらも48フレーム目にして、ベクターレイヤーの位置を変えてアニメをつけた。

sbd_ss07.png


同じ流れで、「B2」ボーンもスマートボーンダイヤルにした。「B2」「B2 2」の2つのアクションが生成された。アクションウインドウ上で「B2」をダブルクリックして切り替えて、48フレーム目にしてアニメをつけた。

sbd_ss08.png


「B2 2」アクションにもアニメをつけた。

sbd_ss09.png


アクションウインドウ上で「メインライン」をダブルクリックして切り替える。「ボーンを操作」ツールを選んで、スマートボーンダイヤルのB1、B2の角度を変えてみると、ボーンの角度に応じてアニメが変化する。

sbd_ss10.png


こんな感じの作業で、以下のようなアニメが作れた。

参考ページ。 :


2022/04/23() [n年前の日記]

#1 [windows] 英文PDFの自動翻訳をAutoIt3を使って少し快適にした

Moho 13.5.3 の英文マニュアルpdfを眺めているのだけど、英文なのでなかなかツライ。できれば DeepL等の自動翻訳サービスを利用して、日本語に変換しつつ読みたい。

ただ、ちょっと問題があるというか、操作が面倒臭いというか…。


DeepLデスクトップアプリは、Ctrl+C を2回叩くと、クリップボード内のテキストを DeepL の入力欄に貼り付けて翻訳してくれるので…。フツーなら、PDF上のテキストを選択しておいて、Ctrl+C を2回叩けば自動翻訳できそうなものなのだけど。

しかし、PDFからテキストをコピーしようとすると、改行コードも入ってしまうので…。英文の途中で改行されている状態になってしまって翻訳結果がおかしくなってしまう。

今までは、DeepL に貼り付けてから、手作業で改行を削除して、再度翻訳させていたけれど、これがとても面倒臭い。こんなこと何度もやってられない。

そこで、AutoIt3 3.3.16.0 x86 を使って、作業を自動化してみた。処理内容は以下。
  1. PDFビューアをアクティブにして、選択範囲を Ctrl + C でコピー。
  2. クリップボード内のテキストに対して、改行をスペースに置換。
  3. DeepLデスクトップアプリをアクティブにして、自動で貼り付けをする。(Ctrl+A、Delete、Ctrl+V を送る。)

利用するには AutoIt3 のインストールが必要。

_Home - AutoIt
_AutoIt Downloads - AutoIt

スクリプトソース。 :

以下のような感じになった。

_copypaste_gui.au3
; Copy text from PDF viewer,
; replace CRLF in clipboard with space,
; paste it into deepl.

#include <GUIConstantsEx.au3>

; Dim $pdfviewer = "[CLASS:Chrome_WidgetWin_1]"
Dim $pdfviewer = "[CLASS:AcrobatSDIWindow]"
Dim $deeplclass = "DeepL"
Dim $state

Local $btn1, $btn2
Local $msg

; create GUI window
Local $hGUI = GUICreate("Copy Paste", 280, 70)
$btn1 = GUICtrlCreateButton("Translation", 8, 8, 180, 50)
GUICtrlSetFont($btn1, 18, 700, 0, "Arial")
$btn2 = GUICtrlCreateButton("Exit", 200, 8, 70, 28)
GUISetState()

; HotKeySet("{ESC}", "Terminate")

While 1
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then
        ; Click window close button
        ExitLoop
    EndIf
    If $msg = $btn1 Then
        ; Click button 1
        trans()
    EndIf
    If $msg = $btn2 Then
        ; Click button 2
        ExitLoop
    EndIf
WEnd

GUIDelete($hGUI)
Exit 0

Func Terminate()
    GUIDelete($hGUI)
    Exit 0
EndFunc

Func trans()
    ; Activate PDF viewer
    $state = WinActivate($pdfviewer)
    If $state = 0 Then
        MsgBox(0, "Error", "Error: Not found PDF viewer")
        Exit 0
    EndIf

    Send("^c")  ; send Ctrl+C
    Sleep(500)

    ; Replace CRLF in clipboard with space
    ClipPut(StringReplace(ClipGet(), @CRLF, " "))

    ; Activate DeepL
    $state = WinActivate($deeplclass)
    If $state = 0 Then
        MsgBox(0, "Error", "Error: Not found DeepL")
        Exit 0
    EndIf

    Send("^a")  ; send Ctrl+A
    Sleep(250)
    Send("{DELETE}")  ; Delete key
    Sleep(250)
    Send("^v")  ; send Ctrl+V
EndFunc

スクリプトの最初のあたりの、Dim $pdfviewer = 〜 を書き換えれば、Google Chrome に対しても使えると思う。たぶん。手元の環境では一応動いた。もし動かない時は、AutoIt に付属している Au3Info.exe か Au3Info_x64.exe を起動して、Google Chrome のクラス名を調べて反映させれば動くかもしれず。

使い方。 :

  1. copypaste_gui.au3 を実行。
  2. ボタンが2つ並んだウインドウが表示されるので、適当な位置に置く。
  3. Adobe Acrobat Reader DC と、DeepLデスクトップアプリを起動しておく。
  4. Acrobat Reader DC で目的のPDFを開く。
  5. (重要) DeepLデスクトップアプリ上で、入力欄をクリックしてフォーカスを与えておく。これをしておかないと変な動作になる。
  6. PDF上の、翻訳したいテキストを選択して、copypaste_gui.au3 のウインドウの「Translation」をクリック。

以下のような感じで自動翻訳できる。




これで少しは英文pdfを眺めるのが楽になった…かな…。たぶん。

ところで。このくらいの処理なら、Python + PyAutoGUI を使ってもできるのではなかろうか…?

#2 [windows] AutoIt3用のSciTEの設定を少し変更

AutoIt (AutoIt3) は、Windows上で、特定のアプリにショートカットキーを送信したりして操作を自動化できるツール。

今回、Windows10 x64 21H2 上に AutoIt3 3.3.16.0 x86 をインストールして少し触ってみたのだけど、付属エディタ SciTE (SciTE4AutoIt3) の設定がちょっとアレだったのでカスタマイズしてみた。

_AutoIt Script Editor Downloads - AutoIt

上記ページから、SciTE4AutoIt3_Portable.zip をダウンロードして解凍。AutoIt3 インストールフォルダ\SciTE\ に上書きコピーした。

設定ファイルの内容。 :

設定ファイルは、SciTE を起動して、Options → Open User Options file、を選択すれば開ける。

内容は、以下にした。

_SciTEUser.properties
import au3.keywords.user.abbreviations
import au3.UserUdfs

autocompleteword.automatic = 1

# set UTF8
code.page=65001
character.set=128

# set SJIS (Japanese)
# code.page=932
# character.set=128

# code.page=0
# character.set=204

# font setting
if PLAT_WIN
    technology=1
    font.monospace=font:HackGen,size:16
    font.base=$(font.monospace)
    font.small=$(font.monospace)
    font.comment=$(font.monospace)
    font.text=$(font.monospace)
    font.text.comment=$(font.monospace)
    font.embedded.base=$(font.monospace)
    font.embedded.comment=$(font.monospace)
    font.vbs=$(font.monospace)

# .au3 style
# Comment line
style.au3.1=fore:#008000
# Comment block
style.au3.2=fore:#008000

tabbar.visible=1
tabbar.multiline=1
statusbar.visible=1
title.full.path=1

# line number
line.margin.visible=1
line.margin.width=6+
margin.width=4

# tab size
tabsize=4
indent.size=4
use.tabs=0

# recent file
save.recent=1
save.session=1

load.on.activate=1
#save.on.deactivate=1
are.you.sure.on.reload=1

virtual.space=1

visible.policy.strict=1
visible.policy.lines=4

# fold.symbols=3

# shortcut keys
user.shortcuts=\
$(user.shortcuts)\
Ctrl+Space|IDM_COMPLETEWORD|\
Alt+Up|2620|\
Alt+Down|2621|

少し説明。 :

記述内容を少し説明。

import au3.keywords.user.abbreviations
import au3.UserUdfs
AutoIt3用(.au3)の設定ファイルをインポート。

autocompleteword.automatic = 1
文字を打つと自動補完ウインドウが開くように指定。

# set UTF8
code.page=65001
character.set=128

# set SJIS (Japanese)
# code.page=932
# character.set=128

# code.page=0
# character.set=204
日本語文字列は UTF-8 として扱う。

# font setting
if PLAT_WIN
    technology=1
    font.monospace=font:HackGen,size:16
    font.base=$(font.monospace)
    font.small=$(font.monospace)
    font.comment=$(font.monospace)
    font.text=$(font.monospace)
    font.text.comment=$(font.monospace)
    font.embedded.base=$(font.monospace)
    font.embedded.comment=$(font.monospace)
    font.vbs=$(font.monospace)
フォント設定。全部モノスペースフォントにして、フォント種類は HackGen を指定した。「if PLAT_WIN」は、Windows上で動かした時に有効。「technology=1」を指定すると DirectWrite による描画になるらしい。

# .au3 style
# Comment line
style.au3.1=fore:#008000
# Comment block
style.au3.2=fore:#008000
.au3 ファイル内のコメント部分が斜体で表示されるのが嫌なので、斜体の指定を外した。

tabbar.visible=1
tabbar.multiline=1
statusbar.visible=1
title.full.path=1
タブバーを表示。

# line number
line.margin.visible=1
line.margin.width=6+
margin.width=4
行番号を表示。

# tab size
tabsize=4
indent.size=4
use.tabs=0
タブ文字のサイズを4文字に。かつ、タブ文字ではなくスペースにする。

# recent file
save.recent=1
save.session=1
最近開いたファイルを有効化。

load.on.activate=1
#save.on.deactivate=1
are.you.sure.on.reload=1
virtual.space=1
visible.policy.strict=1
visible.policy.lines=4
# fold.symbols=3
巷の解説ページからよく分からずにコピペ…。

# shortcut keys
user.shortcuts=\
$(user.shortcuts)\
Ctrl+Space|IDM_COMPLETEWORD|\
Alt+Up|2620|\
Alt+Down|2621|
ショートカットキーを設定。
  • Ctrl+ Spaceを補完キーにした。
  • Alt+Up、Alt+Down に、選択範囲の上下移動を割り当て。

余談。 :

SciTE4AutoIt3 には、KODA FormDesigner という、AutoIt3用のGUIデザインツールも同梱されていた。SciTE上で Alt+M を叩いたら起動した。

_KODA FormDesigner [Koda]

#3 [windows] タイトルバーに貼り付くランチャーが欲しい

Windows10上で動作する、アプリウインドウのタイトルバーに貼り付くランチャーが欲しいなと…。そういうランチャーがあれば、例えば AutoItのスクリプト等を登録して、まるでアプリがその機能を持っているかのように見せかけて使うことができるのではないだろうかと…。

ちなみに、昔はそういうランチャーが存在していたのだけど。

_「Asroc=Launcher 2nd」ウィンドウのタイトルバーに貼り付くランチャー - 窓の杜
_Asroc=Launcher 2nd - k本的に無料ソフト・フリーソフト

どうやら今現在は公開中止になってしまったようで。公式ページが404。

一応 WebArchive から asroc2nd_116.zip を入手して、Windows10 x64 21H2上で動作確認してみたけれど、基本機能は動いているっぽいものの、Windows10のデスクトップの見た目では、ランチャー部分と最小化ボタンが重なってしまってビミョーにアレだなと…。

代替ソフトが無いものかとググってみたけど、これが全然見つからない。需要として特殊過ぎるのだろうか。

2022/04/24追記。 :

Asroc=Launcher 2nd 1.16 について。Shift + ドラッグでランチャーの位置を変更できるとヘルプに書いてあった。これで最小化ボタンと重なってしまう問題は解決できそう。

ただ、Adobe Acrobat Reader DC 64bit 2022.001.20117 のタイトルバー上では、Asroc=Launcher 2nd が一瞬表示された直後、どこかに消えてしまう。どうやら、このランチャーを表示できるアプリと、表示できないアプリがあるようだなと…。

2022/04/24() [n年前の日記]

#1 [python] PyAutoGUIを少しだけ試用

Python + PyAutoGUI でも操作の自動化ができるという話をどこかで見かけたので手元の環境で少し試用。

環境は Windows10 x64 21H2 + Python 3.9.12 64bit。

インストール。 :

インストールは以下。
pip install pyautogui
PyAutoGUI 0.9.53 がインストールされた。

また、以下のモジュールも依存関係でインストールされた。
  • MouseInfo 0.1.3
  • PyGetWindow 0.0.9
  • PyMsgBox 1.0.9
  • pyperclip 1.8.2
  • PyRect 0.2.0
  • PyScreeze 0.1.28
  • pytweening 1.0.4

PDFの自動翻訳をしやすくする処理が書けた。 :

色々試していたところ、昨日、AutoIt を使って作成したスクリプトと似たような処理を、PyAutoGUI でも書けた気がする。

_英文PDFの自動翻訳をAutoIt3を使って少し快適にした

_04_copypaste.py
import pyautogui as ag
import pygetwindow as gw
import pyperclip
import sys
import time

pdfviewer = "Reader DC"
deepl = "DeepL "


def activate_window(w):
    """Activate appli window."""
    try:
        w.activate()
    except Exception:
        w.minimize()
        w.restore()
    time.sleep(0.35)


def get_window(name):
    hwnds = gw.getWindowsWithTitle(name)
    w = None
    if hwnds != []:
        w = hwnds[0]
    else:
        print("Error: Not found %s" % name)
    return w


def main():
    w = get_window(pdfviewer)
    if w is None:
        sys.exit()

    activate_window(w)
    ag.hotkey("ctrl", "c")
    time.sleep(0.25)

    # replace CRLF to space
    txt = pyperclip.paste()
    newtxt = " ".join(txt.splitlines())
    # newtxt = txt.replace("\n", " ")
    pyperclip.copy(newtxt)

    # print(newtxt)

    w = get_window(deepl)
    if w is None:
        sys.exit()

    activate_window(w)
    ag.hotkey("ctrl", "a")
    time.sleep(0.25)
    ag.hotkey("delete")
    time.sleep(0.25)
    ag.hotkey("ctrl", "v")
    time.sleep(0.25)


if __name__ == '__main__':
    main()

後は、このPythonスクリプトを、何かしらのランチャーに登録して起動できるようにすれば、1クリックでPDF上の選択テキストを自動翻訳できるのではないかな…。

一応、tkinter も使って、GUI版も書いてみた。

_05_copypaste_gui.pyw

実行するとGUIウインドウとボタンが表示されるので、ランチャーに登録等をしなくても使えるかもしれない。

ウインドウのアクティブ化でハマった。 :

これは PyAutoGUI というより PyGetWindow の問題っぽいけど…。Windows10 x64 21H2上では、既に起動しているアプリのウインドウをアクティブにできないことに気づいた。.activate() を呼ぶと、タスクバー上のアプリアイコンは点滅するものの、アプリウインドウが最前面になってくれない。エラーを吐く。

Python 3.9.12 (tags/v3.9.12:b28265d, Mar 23 2022, 23:52:46) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.

>>> import pyautogui as ag
>>> import pygetwindow as gw
>>> w = gw.getWindowsWithTitle("Chrome")[0]
>>> w.activate()
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    w.activate()
  File "C:\Python\Python39-64\lib\site-packages\pygetwindow\_pygetwindow_win.py", line 246, in activate
    _raiseWithLastError()
  File "C:\Python\Python39-64\lib\site-packages\pygetwindow\_pygetwindow_win.py", line 99, in _raiseWithLastError
    raise PyGetWindowException('Error code from Windows: %s - %s' % (errorCode, _formatMessage(errorCode)))
pygetwindow.PyGetWindowException: Error code from Windows: 0 - この操作を正しく終了しました。
>>> 

以下の、最大化、最小化は動いたから、ウインドウのID?を取得し損ねているわけではないのだろう…。
>>> w.minimize()
>>> w.maximize()

ググったところ、「Windows上ではアプリウインドウのアクティブ化はできないから、最小化+最大化で目的を果たせ」という話も見かけた。AutoIt と比べると厳しいな…。

一応、以下の投稿によると、最小化+復元すれば目的が果たせるらしい。

_.activate() sometimes throw error - Issue #31 - asweigart/PyGetWindow - GitHub
_Activate does not work - Issue #36 - asweigart/PyGetWindow - GitHub
_When using IPython, window.activate() raises error. - Issue #29 - asweigart/PyGetWindow - GitHub

>>> w.minimize()
>>> w.restore()

目標のアプリウインドウを間違えてしまう問題。 :

スクリプト作成中に、間違ったアプリウインドウを取得されてしまってハマった。ウインドウタイトルに「DeepL」という文字列を含んだ他のアプリがあると、そのアプリに文字列を貼り付けようとしてしまう。今回は、「copypaste_deepl.py」という名前のファイルを Visual Studio Code (vscode) で編集しながら動作確認していたら、vscode上のソースを全部消されてしまって焦った…。

アプリウインドウを、ウインドウタイトルだけで探すのはちょっと問題があるようだなと…。

でもまあ、とりあえず今回は、"DeepL" じゃなくて "DeepL " でウインドウタイトルを検索させれば誤魔化せるかな…。

改行コードの置換で悩んだ。 :

クリップボード内の、改行コードを複数含んだ文字列に対して、改行コードをスペースに置換するあたりでハマった。replace() を使ったら、何故か上手く置換できなくて…。

とりあえず、splitlines() と join() でどうにかしてみたけれど…。replace() では処理できないのだろうか…?

    # replace CRLF to space
    txt = pyperclip.paste()
    newtxt = " ".join(txt.splitlines())
    pyperclip.copy(newtxt)

もしかして、"\n" と "\r\n" が混ざってしまっているのかな。

以下のページによると、改行コードの種類が不明な場合は .splitlines() と .join() を使うのもアリ、らしい。であれば、これでもいいのかな…。

_Pythonで改行を含む文字列の出力、連結、分割、削除、置換 | note.nkmk.me

2022/04/25(月) [n年前の日記]

#1 [nitijyou] 暑い

部屋の温度が28度。暑い…。

#2 [nitijyou] 日記をチェックしているところ

手元ではこの日記を書き溜めているけれど、2021/10/19を最後に日記をアップロードしてないので、そろそろアップロードしないとアレだなと…。とりあえず、誤字脱字が無いか、うっかり炎上しそうなネタを書いてないか、チェックしているのだけど、分量が多くて…。溜め込みすぎ…。

2022/04/26(火) [n年前の日記]

#1 [digital] HDDレコーダのBDドライブが壊れたっぽい

手元で利用しているHDDレコーダ、TOSHIBA RD-BZ710 のBDドライブが、どうも壊れた気配がする。

状況は以下。 つまり、BDメディアが入ってることを認識してくれない状態。

使っているBD-Rメディアは、Panasonic LM-BR25LP5。録画用BD-R、25GB、片面1層、1〜4倍速。5枚入り。「東芝製HDDレコーダはBDメディアをかなり選り好みする」「Panasonic製のメディアなら相性問題も出にくい」と言われてるけど、そのPanasonic製ですらダメなのだから、メディアのせいではないだろう…。そもそも、今まで利用できていたメディアなわけだし…。

これは故障なのではないかと思えてくるまでの経緯は以下。
  1. HDD内の録画データをBD-Rに焼こうとして、新しいBD-Rメディアを入れて、BDの初期化を ―― BDAVフォーマットでフォーマットした。この時点までは、正常に動作していた気配がする。
  2. 録画データをBD-Rにダビング(移動)しようとしたら「予約が入ってるからダビングできない」と言われた。
  3. 5〜6時間ほど、BDドライブにメディアを入れっぱなしのまま、HDDレコーダが各番組の録画を終えるまで待っていた。どうもココがマズかった気がする…。いつもそんなことしてなかったから…。
  4. BD-Rへのダビングをしようとしたら、1/100% と表示された状態で、ドライブが何度も、キュイーン、キュイーンと音を立てて先に進まない。どうも延々リトライしてるような音だった。
  5. 数分待ったけど、ダビングが始まる気配がない。リモコンの操作も一切受け付けない。トレイ排出ボタンも反応しない。いつまでも、キュイーン、キュイーンを繰り返してる。
  6. 諦めて、電源ボタン長押しで強制的に電源OFF。30秒ほど待ってから、電源再投入。
  7. HDDの中身は見れたけど、BDドライブは前述のように動かなくなった。

ということで、これはBDドライブが壊れたのだろうなと…。

さて、困った。HDDレコーダ内には772ファイルほど残ってる。これをどうやって外部に逃がしたらいいのか…。

TOSHIBA RD-BZ710 は、最大でも792タイトルしかHDD内に記録できない。もうちょっとで、HDDの空き容量があっても、一切録画ができなくなる。困った。

ドライブの型番を調べた。 :

BDドライブが壊れたなら、そこだけ交換すれば治らないかと、RD-BZ710 に使われいてるドライブの型番をググってみた。どうやら FUNAI AM3 というドライブらしい。

_東芝HDDレコーダー/パーツ互換 - RD-Wiki (東芝REGZAブルーレイ&VARDIAまとめサイト)
_HDD・BD・DVDレコーダー/光学ドライブ換装 - usyWiki

ただ、一般向けに販売されているドライブではないし、今となっては入手が難しい模様。前述のページによると、代替ドライブとして FUNAI AM4 が使える可能性があるらしいけど、しかし、その製品も入手が難しい気配。

一応、Amazon で、FUNAI AM3 は出品されているけど、Amazon だし…。

録画データを外に逃がす方法。 :

今時のHDDレコーダは録画データに対して各メーカー独自の暗号化をかけているので、例えばHDDレコーダにUSB接続で外付けHDDを追加して、そちらに録画データをムーブ(移動)したとしても、HDDレコーダの製品個体が変わってしまうと再生できなくなる。 *1

だから、容量が少ない上に、アクセス速度も遅い、不便極まりないBD-Rにわざわざムーブで焼いて外に逃がしてたわけだけど、BDドライブが壊れてしまったのでは…逃がしようがない…。

録画データを外に逃がす手は他に無いかとググってみたら、DTCP-IP対応のNASであれば、HDDレコーダからLAN経由で録画データをダビングできる可能性があると知った。また、DTCP-IP対応NASから他のHDDレコーダにムーブすることができる可能性もあるらしい。

DTCP-IP対応NASとしてメジャーなのは、IODATA RECBOXシリーズだろうか…。あるいは、Buffalo LinkStationシリーズの中にも、DTCP-IP対応製品があるようだけど…。

値段を調べてみたら、最低限の機能を持った2TBの製品が、Amazon の FUNAI AM3 の価格+6千円ぐらいの感じだった。値段だけを見ると、BDドライブ交換を試みるほうが安い。ただ…。
  • 完動品の FUNAI AM3 を確実に入手できるのかどうか。
  • 仮に入手できたとしても、交換しただけで本当に治るのかどうか。
そのあたりを考えると、NASを選択するほうがはるかに安全な気もする。NAS があればHDDレコーダが壊れた時も録画データは残るのだし…。

しかし、それらのNASに対して本当に録画データをムーブできるのか、そのあたりもビミョーに怪しいようで。できているという事例もあれば、頻繁に失敗するという事例も見かけた。

日本のデジタル家電ってクソだ…。ホビロン!

PCのBDドライブを使う方法。 :

ググっていたら、PCのBDドライブを使って、HDDレコーダ内の録画データをBD-Rに焼く方法もあるらしい。PC上でDTCP-IP対応のソフトを起動しておいて、HDDレコーダからLAN経由でPCに録画データを送信して、転送が終わったらPC上でBD-Rを焼くらしい。

ただ…。昔は、「DTCP-IP Disc Recorder」「DiXiM BD Burner 2013」といったソフトが存在していたらしいけど。Windows10では動作しないらしい。Windows8までは対応を謳っていたようだけど…。

_Windows10 DTCP-IP Disc Recorder Toolが32bit OSでは使えるのに、64bit - Microsoft コミュニティ
_Windows 10 Threshold2 アップデートを適用した環境に、DiXiM BD Burner シリーズがインストールされるとブルースクリーンが発生する。 | DiXiM BD Burner 2013
_テレビの録画データを移したい。 : 本音を言えば、不満だらけ。

代替ソフトとしては、「SONY PC TV Plus」というソフトが存在する模様。

_パソコンでテレビ視聴、かんたんダビング「PC TV Plus」 | 関連ソフトウェア | ソニー

ただ、このソフトも、例えばBD-Rに書き込むタイミングで書き込みエラーが出ると、その瞬間にPC上にあったはずの録画データが消滅したりするらしい。

_PC TV Plusを使用して、REGZAの録画データをブルーレイにダビングできた - 東京生まれHOUSE MUSIC育ち

正常に書き込みができたか確認が取れたタイミングで削除しないとマズイだろうに…。酷過ぎる…。

BDドライブの交換が容易ならいいのに。 :

どうして、メーカーや製品毎に、てんでバラバラなドライブを使うのだろう…。PC用の内蔵型BDドライブを突っ込めるようにしておけば、交換用ドライブが手に入らない、なんて状況にもならなかっただろうに…。

もっとも、ファームウェアとかドライバとかそのあたりの関係もあるから、サイズや端子が統一されていてもダメなのか…。PCでBDドライブを使う場合も、ドライバのインストールは必要になるし。

でも、小学生ですらPCを組み立てちゃう時代なのに、コレ以外は使えません的な設計はどうなんだろう。せめて代替ドライブが入手できる状況ぐらいは欲しい…。

余談。タイトル結合を覚えた。 :

HDDレコーダ内のタイトル数が多過ぎて、そのうち録画できなくなりそうな、この状況だけでもなんとかしたいと色々調べていたら、RF-BZ710 の編集モードに「タイトル結合」という機能があることに今頃気が付いた。

もしかして、この機能を使えば、ちょっとはタイトル数を減らせるのでは…? 例えば、2クールアニメのOPEDは1クールを過ぎたあたりで変わるので、OPEDコレクターをやってると録画タイトル数が2つになるけれど、それを1つに結合してしまえばタイトル数が半分になるよなと…。

試してみたところ、見た目の総タイトル数はたしかに減ってくれそうな気配。ただ、結合したタイトルへのアクセス速度が、何故か遅くなっていくあたりが不安だけど…。

一度に2タイトルしか結合できないのがちょっと厳しい感じもするし、2つ目のタイトルの録画日時等の情報が消滅するあたりもビミョーに気になるけれど、背に腹は代えられぬ。これで少しでも総タイトル数を減らそう…。でも、録画データを外部に逃がせない限り、いつかは限界が来るわけで。どうしたもんか。

*1: 一応、今時は、SeeQVault なる規格に対応している外付けHDDにムーブすれば他の個体でも再生できなくもないですよ、ということになっているけれど。昔のHDDレコーダがその SeeQVault に対応してるはずもなく…。「これからHDDレコーダを購入する人はそういう恩恵を受けられなくもないです」「昔から使ってる人は録画データを諦めてください」という話になるのだと思う。

2022/04/27(水) [n年前の日記]

#1 [digital] HDDレコーダ内のタイトルを整理

HDDレコーダ RD-BZ710 のタイトル結合機能の使い方を知ったので、総タイトル数を少しでも減らすべく、結合できそうな録画データをコツコツと結合してみた。結果、772タイトルを590タイトルまで減らせた。

しかし、HDDレコーダ内に溜める一方では、いつかは最大録画タイトル数の792タイトルを超えて、録画できなくなるわけで…。外に逃がす方法を検討しないと…。

2022/04/28(木) [n年前の日記]

#1 [windows] SSDの電源管理設定を変更した

メインPCの処理がどうもたまにガクガクするような感じがして、これは使っているCPU、Ryzen 7 1700 のせいなのかなと気になってきた。関連情報をググってみたところ、SSDの電源管理関係でプチフリが起きる場合もある、という話を見かけた。

_PCの動作が突然止まってしまう!SSDの謎の不具合「プチフリ」の原因と対策は?

自分のメインPCに積んでいるSSD(Cドライブ)は、crucial MX500 CT500MX500SSD1/JP。SSD最適化設定 4.5 というツールを使わせてもらって調べてみたところ、LPM(HIPM)は未対応、LPM(DIPM)は対応、と表示された。ということは、Windows10の電源オプション設定で、ハードディスクの電源管理設定を、別の設定にしておかないといかんのではないだろうか…?

とりあえず、巷の解説記事に従って、「ハードディスク」 → 「AHCI Link Power Management - HIPM/DIPM」を、Active に設定しておいた。とメモ。これで何か違ってくるだろうか…。関係ないかな…。

環境は、Windows10 x64 21H2。

以下、参考ページ。

_PCの動作が突然止まってしまう!SSDの謎の不具合「プチフリ」の原因と対策は?
_AMD Ryzenでのプチフリーズ頻発対策 | UMilCL
_価格.com - 『交換後にフリーズ頻発』 crucial MX500 CT1000MX500SSD1 のクチコミ掲示板

手順をメモ。 :

まずは、SSD最適化設定というツールを入手。

_「SSD最適化設定」HDD向けになっているOSの初期設定を見直してSSDに適した設定へ変更するツール - 窓の杜
_SSDの寿命を3倍へ「SSD最適化設定」 |

SSD_Opt_v4.5.zip をDLして解凍。SSD_Opt201028 というフォルダが出てくる。中に、SSD最適化設定.exe というファイルがあるので実行。ウインドウが開く。

「SSDの最適化設定」 → 「手動設定...」 → LPM(省電力)設定の「LPMチェック...」をクリック。

ssd_lpm_ss01.png

ssd_lpm_ss02.png

ssd_lpm_ss03.png


搭載しているSSDの、LPM対応状態が表示される。Windows10側の電源管理設定を変更したい場合は、「LPM設定の呼び出し」をクリック。

ssd_lpm_ss04.png


LPMダイアログが開く。通常は表示設定が「OFF(初期値)」になっているので、「ON」をクリック。これで、レジストリに書き込みが行われて、ハードディスクの電源管理の設定項目が増える。その後、「電源オプションの呼び出し...」をクリックすれば、電源の詳細設定ができるダイアログが表示される。

ssd_lpm_ss05.png


Windows10の電源オプションを変更していく。「お気に入りのプラン」の右横のほうの「プラン設定の変更」をクリック。

ssd_lpm_ss06.png


「詳細な電源設定の変更」をクリック。

ssd_lpm_ss07.png


「ハードディスク」 → 「AHCI Link Power Management - HIPM/DIPM」を、Active に設定。これで、HIPM を使わない状態になるらしい。

ssd_lpm_ss08.png

#2 [neta] タツノコヒーローの美少女化ってどうだろう

妄想メモ。

寝ていたら夢の中で、「破裏拳ポリマー」が美少女になって出てきた。

目が覚めてから考えた。タツノコヒーローの美少女化企画はアリなのかどうか。みたいな。

まあ、今までもそういう企画はあった気もするけど…。 だから、美少女キャシャーンや、美少女ポリマーが居てもおかしくはないだろうなと…。もしかすると自分が知らないだけで、既にそういう企画はあったのかもしれない。いや、絶対あるだろう。マジンガーZやウルトラシリーズの怪獣が美少女化されたぐらいだし。タツノコだってやってるはず。

ムテキングやスターザンスやウラシマンが美少女でもいいのだよな…。

もしかしてムテキングリメイク版は、美少女が主人公だったりしたほうが話題になったのでは…。美少女だったら、話にしろ、見た目にしろ、印象が随分変わっただろうなあ…。

もっとも、「ムテキング」はダジャレ感があるけど、「ムテクィーン」ではダジャレ感が皆無なので、タイトルを変えないといかん気もする。タツノコヒーローモノにおいてダジャレ感の有無は重要だろう。さて、「○○クィーン」で収まりがいい単語は何かあるだろうか…。いやまあ、「ムテクィーング」でもいいのかもしれんけど。

親が議員。 :

自分が見た夢の中では、美少女ポリマーの母親が女性議員、それも東京都知事で、そこからの指令によりポリマーが裏で暗躍、という設定だった。目が覚めてから元ネタは何だろうと考えたけど、おそらくは先日まで放送していた「東京24区」からの連想だろう。アレも、メインキャラの親が区長だったし。

ヒーローと言えば自由人だの風来坊だのそういう印象があるけれど。都知事だの、都議会だの、要は自治体から指令を受けてヒーロー活動をするというのは、ヒーローのイメージ的にアリなのか、それともナシなのか。

まあ、BATMANだって、何かのライトで夜空を照らすと現れる、みたいな設定があったはずだし。アレだって、稀に自治体からの要請で活動してると言えなくも無いのかな。であれば、自治体だの、国だの、警察だの、そういうところからの指令で活動するヒーローもフツーにアリな設定かもしれない。

何かしらの組織からの指令となると、「それはちょっと荷が重すぎる」だの、「それは本当に妥当な方針なのか」だの、見ていてもやもやしちゃう指令もちょくちょくあったりするのだろうか…。

美少年化企画はどうだろう。 :

「なんでもかんでも美少女化するのはさすがに辟易」と思う方々も結構居そうな気もしてきた。であれば、美少年化企画はどうだろう…。

例えば「美少年戦士セーラームーン」はどうか。などと書いた直後にまさかそんな企画は無いだろうなと不安になってググってみたら、二次創作でイラストを描いてる方々が結構いらっしゃるようで。同案多数ネタだったのね…。そりゃそうか…。

でもまあ、「○○を美少年化したらどうなるだろう」という妄想も全然アリな気もする。というか昨今、アイドルモノの企画なら男性版も考えておくのが常のようでもあるから、特におかしな発想でもないだろうし。「コレが美少年になったらクラクラするぜ…」みたいなネタは何かあるかな…。

妄想メモです。オチは無いです。

2022/04/29(金) [n年前の日記]

#1 [comic] 「ゴールデンカムイ」を読み耽ってしまった

漫画「ゴールデンカムイ」の完結記念云々とやらで、期間限定で全話無料公開になっているという話を目にして、なんだか気になってしまった。昔、最初のあたりの数巻を妹から借りて読んだ記憶はあるのだけど…。

復習気分で読み始めてみたら、あまりに面白くて延々読み耽ってしまった。これはいかん…。他の作業ができなくなる…。やはりこの漫画は名作…。

あまりに濃密な内容なので、アニメ版はかなりの数のエピソードを割愛していることを、今更ながら再認識。漫画という、文字情報も列挙できる表現手法をフルに活用している作品なので、どんどん流れて行ってしまう映像メディアで提示するのが難しい場面が多々出現するのだよな…。アニメ版スタッフの努力も感じつつ、映像表現の限界も感じるというか…。

2022/04/30() [n年前の日記]

#1 [prog] Go言語を1.15.6から1.18.1にアップデートしてみた

Windows10 x64 21H2上にインストールしてあった Go言語(golang)を、1.15.6 x64 から 1.18.1 x64 にアップデートしてみた。

GUIライブラリの Fyne を利用しようとして、go get fyne.io/fyne と打ってみたところ、警告なのかエラーなのか分からんけど、とにかく「go get は使うな」「go install に変わったぞ」等のメッセージが表示されてしまった。

ググったところ、golang 1.16 から、モジュール管理? パッケージ管理? そのあたりの仕様が変わっていたようで。環境変数 GOPATH を利用する動作にするためには、環境変数 GO111MODULE を off にしないといかんらしい…。

_Go1.16からは go get は使わず go install を使おう - Qiita
_Go のモジュール管理【バージョン 1.17 改訂版】
_Go 1.16 からのモジュール管理 | text.Baldanders.info

巷の解説ページは、えてして golang 1.16 より古い環境で各種パッケージをインストールしていたりするので…。何かしらを試用してみようとして、解説ページ通りに打ち込んでも動作しないとなると、ちょっと厳しいなと。問題はあるのかもしれないけど、以前の動作になるように設定しておいた。

go env -w GO111MODULE=off

本来のデフォルト設定にするには、=off を =on にして打ち込めばいいのだろう…。たぶん。

Fyneを試用。 :

GUIライブラリ Fyne を試用。今現在は v2 というバージョンになっているらしい…?

_fyne-io/fyne: Cross platform GUI in Go inspired by Material Design

go get fyne.io/fyne/v2
go get fyne.io/fyne/v2/cmd/fyne_demo/
fyne_demo

fyne_demo と打ったら、デモプログラムが起動した。

一応、公式ページの hello world を書いて、実行できることを確認した。
go run main.go

exeファイルの生成は以下。
go build main.go
main.exe

以上、30 日分です。

過去ログ表示

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

カテゴリで表示

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


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

Powered by hns-2.19.6, HyperNikkiSystem Project