PeperspeceでSuperMergerのSequential XY Merge and Generation がグリッド画像を表示しない

[2023/06/25追記]スクリプトを書き換えないスマートな方法

だにえるさんに感謝🙏

pip install fonts
pip install roboto
pip install font_roboto

はじめまして

どうも、朝霧ちしゃです。note初投稿です。
Web-UIの拡張機能が増えすぎて、何をやったかわけわからなくなりがちなので備忘録的にやったことを残していこうと思います。
当方、プログラマではありませんゆえ、間違った情報を書いてしまうこともあると思いますが、その時は温かくコメントで指摘していただければ幸いです。

不具合の内容

今回遭遇した不具合は、タイトルにもある通り
Automatic1111版Stable-Diffusion web UIにてマージを行う便利な拡張、hako-mikan/sd-webui-supermerger 
Sequential XY Merge and Generation 機能が、
"NameError: name 'roboto_ttf_file' is not defined"
エラーを起こし、グリッド画像を表示できないという症状です。

新計算方法のTensorを試していて、複数の混ぜパターンを試そうとしたところグリッドの生成結果が表示されない現象にブチ当たってしまいました!
しかし、個別に画像は生成されているのでどうやらグリッド画像の作成に失敗しているようです。
とりあえずエラーを見てみましょう。

エラー全文

Traceback (most recent call last):
  File "/storage/stable-diffusion/stable-diffusion-webui/extensions/sd-webui-supermerger/scripts/mergers/mergers.py", line 561, in get_font
    from fonts.ttf import Roboto
ModuleNotFoundError: No module named 'fonts'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/storage/stable-diffusion/stable-diffusion-webui/extensions/sd-webui-supermerger/scripts/mergers/mergers.py", line 568, in get_font
    return ImageFont.truetype(shared.opts.font or 'javascript/roboto.ttf', fontsize)
  File "/usr/local/lib/python3.10/dist-packages/PIL/ImageFont.py", line 996, in truetype
    return freetype(font)
  File "/usr/local/lib/python3.10/dist-packages/PIL/ImageFont.py", line 993, in freetype
    return FreeTypeFont(font, size, index, encoding, layout_engine)
  File "/usr/local/lib/python3.10/dist-packages/PIL/ImageFont.py", line 248, in __init__
    self.font = core.getfont(
OSError: cannot open resource

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/gradio/routes.py", line 414, in run_predict
    output = await app.get_blocks().process_api(
  File "/usr/local/lib/python3.10/dist-packages/gradio/blocks.py", line 1323, in process_api
    result = await self.call_function(
  File "/usr/local/lib/python3.10/dist-packages/gradio/blocks.py", line 1051, in call_function
    prediction = await anyio.to_thread.run_sync(
  File "/usr/local/lib/python3.10/dist-packages/anyio/to_thread.py", line 31, in run_sync
    return await get_asynclib().run_sync_in_worker_thread(
  File "/usr/local/lib/python3.10/dist-packages/anyio/_backends/_asyncio.py", line 937, in run_sync_in_worker_thread
    return await future
  File "/usr/local/lib/python3.10/dist-packages/anyio/_backends/_asyncio.py", line 867, in run
    result = context.run(func, *args)
  File "/storage/stable-diffusion/stable-diffusion-webui/extensions/sd-webui-supermerger/scripts/mergers/xyplot.py", line 52, in numanager
    result,currentmodel,xyimage,a,b,c= sgenxyplot(xtype,xmen,ytype,ymen,esettings,
  File "/storage/stable-diffusion/stable-diffusion-webui/extensions/sd-webui-supermerger/scripts/mergers/xyplot.py", line 350, in sgenxyplot
    grid = smakegrid(xyimage,xs,ys,gridmodel,image_temp[4])
  File "/storage/stable-diffusion/stable-diffusion-webui/extensions/sd-webui-supermerger/scripts/mergers/xyplot.py", line 367, in smakegrid
    grid = draw_origin(grid, currentmodel,w*len(xs),h*len(ys),w)
  File "/storage/stable-diffusion/stable-diffusion-webui/extensions/sd-webui-supermerger/scripts/mergers/mergers.py", line 575, in draw_origin
    fnt = get_font(fontsize)
  File "/storage/stable-diffusion/stable-diffusion-webui/extensions/sd-webui-supermerger/scripts/mergers/mergers.py", line 570, in get_font
    return ImageFont.truetype('javascript/roboto.ttf', fontsize)
  File "/usr/local/lib/python3.10/dist-packages/PIL/ImageFont.py", line 996, in truetype
    return freetype(font)
  File "/usr/local/lib/python3.10/dist-packages/PIL/ImageFont.py", line 993, in freetype
    return FreeTypeFont(font, size, index, encoding, layout_engine)
  File "/usr/local/lib/python3.10/dist-packages/PIL/ImageFont.py", line 248, in __init__
    self.font = core.getfont(
OSError: cannot open resource

生成環境

Peperspece gradient
コンテナ:cyberes/gradient-base-py3.10:latest


やったこと

結論!コードを書き換えた!

scripts/mergers/mergers.py 556行目 draw_origin

・変更前

def draw_origin(grid, text,width,height,width_one):
    grid_d= Image.new("RGB", (grid.width,grid.height), "white")
    grid_d.paste(grid,(0,0))
    def get_font(fontsize):
        try:
            from fonts.ttf import Roboto
            try:
                return ImageFont.truetype(opts.font or Roboto, fontsize)
            except Exception:
                return ImageFont.truetype(Roboto, fontsize)
        except Exception:
            try:
                return ImageFont.truetype(shared.opts.font or 'javascript/roboto.ttf', fontsize)
            except Exception:
                return ImageFont.truetype('javascript/roboto.ttf', fontsize)

    d= ImageDraw.Draw(grid_d)
    color_active = (0, 0, 0)
    fontsize = (width+height)//25
    fnt = get_font(fontsize)

    if grid.width != width_one:
        while d.multiline_textsize(text, font=fnt)[0] > width_one*0.75 and fontsize > 0:
            fontsize -=1
            fnt = get_font(fontsize)
    d.multiline_text((0,0), text, font=fnt, fill=color_active,align="center")
    return grid_d

・変更後

def draw_origin(grid, text,width,height,width_one):
    grid_d= Image.new("RGB", (grid.width,grid.height), "white")
    grid_d.paste(grid,(0,0))
    roboto_ttf_file = '/storage/stable-diffusion/stable-diffusion-webui/modules/Roboto-Regular.ttf'
    def get_font(fontsize):
        try:
            return ImageFont.truetype(opts.font or roboto_ttf_file, fontsize)
        except Exception:
            return ImageFont.truetype(roboto_ttf_file, fontsize)
#        try:
#            from fonts.ttf import Roboto
#            try:
#                return ImageFont.truetype(opts.font or Roboto, fontsize)
#            except Exception:
#                return ImageFont.truetype(Roboto, fontsize)
#        except Exception:
#            try:
#                return ImageFont.truetype(shared.opts.font or 'javascript/roboto.ttf', fontsize)
#            except Exception:
#                return ImageFont.truetype('javascript/roboto.ttf', fontsize)

    d= ImageDraw.Draw(grid_d)
    color_active = (0, 0, 0)
    fontsize = (width+height)//25
    fnt = get_font(fontsize)

    if grid.width != width_one:
        while d.multiline_textsize(text, font=fnt)[0] > width_one*0.75 and fontsize > 0:
            fontsize -=1
            fnt = get_font(fontsize)
    d.multiline_text((0,0), text, font=fnt, fill=color_active,align="center")
    return grid_d

どうしてそうなった?

まずエラーを下から見ていくと、
`OSError: cannot open resource`
リソースを開けないよ、というエラーのようです。
何を読み込めなかったんじゃ!ということで、もっと上を見ていくと
`ModuleNotFoundError: No module named 'fonts'`
というエラーがでてました。
これは'fonts'モジュールが見つからないよというエラーです。
じゃあとりあえず pip install fonts すればいいね!
となったところで、アレ? X/Y/Z Prot 機能は動いてるんだよな・・・ということに気づきます。
web-uiの X/Y/Z Prot 機能の実装は scripts/xyz_grid.py です。
ここからテキストの作成機能を探していくと、
141行目に draw_grid_annotations というグリッドの注釈を書き込む機能がありました。
draw_grid_annotations が定義されているのは、modules/images.py です。
その中で get_font を呼んでいて、定義は27行目にありました。

def get_font(fontsize: int):
    try:
        return ImageFont.truetype(opts.font or roboto_ttf_file, fontsize)
    except Exception:
        return ImageFont.truetype(roboto_ttf_file, fontsize)

roboto_ttf_file は modules/paths_internal.py で定義されています。

roboto_ttf_file = os.path.join(modules_path, 'Roboto-Regular.ttf')

modulesディレクトリを見てみると Roboto-Regular.ttf というフォントファイルがおかれてました。
じゃあ同じように書き換えれば動くじゃろ。ってことで書き換えたコードが上記の変更後になります。
一応、fontsモジュールも入れてみたんですが、結局Robotoファイルがないよってなりました・・・
今回はコード書き換えで動いたのでヨシ!としました。

まとめ

以上、PeperspeceでSequential XY Mergeがグリッド画像を生成しない件を解決した時の備忘録でした。
拡張が更新される度、書き直さないといけないので、なんかもっとスマートな解決方法があればなあとは思います。
paperspaceでやるといろいろローカルにはない不具合が出たりして大変ですね・・・(学習とか・・・
最後までお読みいただきありがとうございました!
TwitterやPixivではツインテールの女の子をメインに上げてますのでよかったら一度覗いてみてください!

Pixiv:https://www.pixiv.net/users/85793425

Twitter:https://twitter.com/Ai_llustrator 

この記事が気に入ったらサポートをしてみませんか?