Windows 11を26H2にアップデートしたらスリープやシャットダウンから復帰できなくなったのを直した?

Windows UpdateでWindows 11を25H2から26H2にアップデートしたらスリープから復帰しなくなったのを直した話。シャットダウンからも復帰できないケースがあったが、これも多分直った。

と思うが微妙に再発するので完全には直ってなさそう。

起きていたことと、一時的な解決方法

先に一時的な解決だけ書いておくと主電源を切り、入れ直せば復帰可能だった。

PCの電源ボタンを押下しスリープすると、高確率で復帰できなくなっていた

高確率でとあるが、6回中4回復帰できなかった。復帰できた2回はスリープ後、即座に電源ボタンを押したときであり、それ以外は復帰できなかった。

電源ボタン以外にもキーボードやマウス、NIC(WoL)を通じたスリープ復帰が出来るようにデバイスマネージャーで設定しているが、いずれの手段でも復帰できなかった。

この時の特徴として、普段スリープ時であれば電源ボタンのLEDが点滅しているが、点滅していなかった。また、電源ボタン押下時には一切なにも起こらず、一瞬だけファンが回るような挙動もなかった。

主電源を一度切って、入れ直すと起動自体は出来たが、OS起動中にコンセントを抜いたのと同じ扱いになるため、再起動後はクラッシュから復帰した状態になった。

スタートメニューからスリープに入る操作方法では試していない。

スタートメニューからシャットダウンすると、ブートできなくなっていた

これは一回しか試していないので、一回しか起きていないが、スタートメニューからシャットダウンを選びPCをシャットダウンすると、電源ボタンを押しても起動させることが出来なかった。

この時は一瞬だけファンが回り、その後停止した。何度電源ボタンを押してもブートしなかったが、スリープ時同様に一度主電源を落として入れ直すことでブートさせることができた。

発生時の条件

Windowsのバージョン

Windows 11 Pro 26H2 (OSビルド 26300.9711)

hypervisorlaunchtype

AUTO

電源オプションの電源ボタンの動作設定

電源とスリープ ボタンの設定

設定項目 設定値
電源ボタンを押したときの動作 スリープ
スリープボタンを押したときの動作 何もしない

シャットダウン設定

設定項目 設定値
高速スタートアップを有効にする OFF
スリープ ON
休止状態 OFF
ロック ON

恒久的に解決した方法

コマンドプロンプトを管理者権限で起動し、以下のコマンドを流す。

bcdedit /set hypervisorlaunchtype off

戻したいときは同様に以下を流せば戻る。

bcdedit /set hypervisorlaunchtype auto

特に効果がなかったこと

使用しているマザーボード(ASRock Z890 Pro RS)のBIOSバージョンを1.39から3.40まで上げてみたが、特に効果はなかった。

あとがき

10/23にWindows Updateし10/24に対策したが、たまに再発している。

hypervisorlaunchtypeをautoにするだけで容易に再現するため、これが原因の一つであることは間違いなさそうだが、他にも要因がありそうだ。

hypervisorlaunchtypeをoffにしたことによる影響は不明だが、BCDEditのヘルプによると設定値自体はHyper-Vのデバッグ用にあるらしい。

25H2に戻してもhypervisorlaunchtype: autoであれば起きていたため、もしかすると26H2になったときに、この設定が切り替わったのかもしれない。ただ25H2に戻して、hypervisorlaunchtypeをoffにしても偶に再現したため、26H2で何かの設定か何かが変わったままになっているのかも知れない。

或いは偶々このタイミングでハードウェアが故障したのか…。

さくらのレンタルサーバーでAVIFを作れるようにする

さくらのレンタルサーバーでもAVIFが作れたらいいよねというのでやってみた。

前提

  • シェルにzshを使っている。さくらのレンタルサーバーのデフォルトシェルはcshなので注意されたし。
  • ~/binにパスが通っている

やり方

  1. アセンブラのビルド

    cd ~
    wget https://www.nasm.us/pub/nasm/releasebuilds/2.16.03/nasm-2.16.03.tar.xz
    tar xf nasm-2.16.03.tar.xz
    cd nasm-2.16.03
    ./configure --prefix=$HOME
    gmake -j4 && gmake install
    
    export PATH=$HOME/bin:$PATH
    nasm -v
    
  2. libavifのビルドとゴミ掃除

    cd ~
    git clone -b v1.2.1 https://github.com/AOMediaCodec/libavif.git
    sed -i '' 's|^static_assert(sizeof(off_t) == sizeof(int64_t), "");|/* & */|' libavif/src/io.c
    cmake -S libavif -B libavif/build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF \
    -DAVIF_CODEC_AOM=LOCAL -DAVIF_LIBYUV=LOCAL -DAVIF_LIBSHARPYUV=LOCAL \
    -DAVIF_JPEG=LOCAL -DAVIF_ZLIBPNG=LOCAL -DAVIF_BUILD_APPS=ON
    cmake --build libavif/build --parallel 1
    cp ~/libavif/build/avifenc bin/
    rm -Rf libavif nasm-2.16.03 nasm-2.16.03.tar.xz
    
  3. avifを作る
    avifenc -q 65 -y 420 -s 6 --ignore-xmp src.jpeg out.avif
    

あとがき

これを活用すればさくらのレンタルサーバーでもavifを作れるようになるので、任意のCMSから蹴ればサムネイルの軽量化とかができるかもしれない。注意点としてコマンドライン呼び出しになるため任意コマンドが実行されないように注意する必要はある。

ビルドはnice不要で、avifの生成についても4000x3000のJPEGをAVIFにするのはniceなしで行けた。

レンタルサーバーにないバイナリをソースコードからビルドして使うという意味で、本記事はさくらのレンタルサーバーにNode.jsをインストールするの親戚記事である。

Lyndbaum v4.26アップデート

adiary置き換え計画始動から連なる、Lyndbaum v4.22アップデートの続き。これまで毎日のように更新していた気がするが二日も開いてしまった。それだけやることがなくなってきたということかもしれない。

今回は前回から0.4バージョン増え、52ファイルの変更と3,004行の追加、1,219行の削除があり、機能追加中心のアップデートだった。

バグ修正

基本設定→詳細設定のコメント設定で画面幅を狭めたときに中身がはみ出る不具合の修正

恒例のレスポンシブ画面崩れ。こういうのは見つけ次第直している。

GIFのサムネイル処理が1コマ目からサムネイルを作るのに全コマ読んでいた不具合を修正

1コマ目だけ読めばいいのに全コマ読み込むため、巨大なGIFを読み込んだ時にImageMagickのメモリ制限に引っかかってサムネイルが作られない問題があった。

なんであろうと1コマ目だけ読むことで回避するようにした。たぶん本家にもある不具合。

機能追加・変更

パスワード仕様の変更

パスワードに設定できる文字列の最低長を標準で8文字以上にし、ハッシュ化方式をbcryptに変更した。元々は4文字以上とSHA512だった。

マイグレーション処理の厄介さを減らす関係で、この変更だけでv4.23を構成しており、バージョン稼ぎになっている。

セキュリティ向上が目的だが、桁数を増やした以外はハッシュが漏洩しない限り影響ないし、漏洩した時点で割と終わってるので、ハッシュアルゴリズムを変えたことに深い意味はない。

この方式はLyndbaum0にあった実装であるため、Lyndbaum0機能バックポートの一環である。

サイト内の添付画像のテキストリンクをビューワーで開けるようにした

LightboxからFancyboxに変更して以来、長らくテキストリンクをポップアップするモーダル的なビューワで見ることができていなかったが、これをできるようにした。

理由としてサイト内のテキストリンクをLythumbで開けるようにしたで必要な機能だったため追加した。

テキスト画像リンク記法の追加

[image:T:...]記法を追加し、[image:T:posts/2026/11/:src.jpeg:JPEG元画像]のように書くことでテキストから添付画像へのリンクが作れるようにした。

この対応は前述の添付画像のテキストリンクをビューワーで開けるようにした対応に紐づく内容で、この構文で書くとJSのハンドラに登録されるようにしている。

またこの構文があることで添付ファイルに関連する変更があったときに出力するHTMLを一元的に変更できるのもある。

かつては[JPEG元画像](pub/attachments/posts/2026/11/src.jpeg)のように書いていたのだが、こういう書き方にしてしまうと添付ファイルかどうかを区別する処理が必要になったりして面倒で、今回のビューワー対応も載せづらいため、過去の記法はすべてテキスト画像リンク記法に置き換えた[1]。

RSSにサイト画像を載せるようにした

SSPにRSSを食わせていてMastodonのRSSを突っ込むとアイコンが出ることに気が付いたので、RSSにサイトの画像を載せた。

SSP上でLycologのRSS画像を表示しているところ

なんと、これによってSSPにうちのブログのRSSを食わせると画像が出るようになった。素晴らしい!

これは元々ヘッドラインセンサにLyndbaumを読ませようと試行錯誤していた時に気づいたのでやった対応だ。SSPはRSSを標準で読めるためヘッドラインセンサを作る必要はなかった。

またこの対応をしている中で、SSPが特定の<channel><link>を持つRSSのインストールに失敗する問題を発見したため報告したところ僅か半日で対応していただけた。この問題はインストールに失敗するだけで手組で設定ファイルを書けば読ませることはできた。

JPEG画像アップロード時に拡張XMP領域の一部を落とすようにした

画像フォーマット別のベンチマークをしてみたで言及している話だが、Androidスマホのカメラが吐いたJPEGの過半数は再編集用のデータでブログに表示するだけなら一切不要なのでアップロード時に落とすようにした。

この対応によってストレージの増加速度を抑えられ、閲覧者にも無駄な通信を発生させずに済むようになった。既にアップロード済みのJPEGからゴミを除去するツールも作ったのでストレージを開けることもできる。試したら700MBくらい空いた。

AVIFでサムネイルを作成する機能を追加

サムネイルのAVIF対応はv4.20で断念していたが、再検討し乗せることにした。

このために画像フォーマット別のベンチマークを行っている。またAVIFをより低負荷・低用量かつ画質維持させるための追加のベンチマークを行い、そのうえで設定値を決めて実装した。

過去のサムネイルをすべて再生成するツールも同時に作っている。AVIFとJPEGのサムネイルが混在している場合、AVIF>JPEGの順で採用するようにしてあるため、画像のサムネイルがAVIFのみ、AVIFとJPEG、JPEGのみでもサムネイルを出せるようにしている。これによりサムネイルの状態が中途半端になっていても表示できるように対応できている。

この対応でサムネイルの容量が従来比で35%ほど減っており、画面ロード時の通信容量削減に貢献するようになったと考えている。また、PNGファイルのサムネイルについては従前より画質が大幅に向上している。これはJPEGノイズがなくなったためである。その代わり若干のっぺりしている。私はJPEGノイズがサムネイルに出るのがちょっとした不満だったので、これは改善だといえる。

今回の対応でサムネイルファイルの総容量がどれだけ減ったか見たかったのだが、サムネイルサイズが混在しており、今回のバッチ変換によって全部同一サイズに揃ったため、増減については比較できなかった。それでも一応結果だけ書いておくと74.5MBが71.8MBに減っている。240pxが6割ほどあり、これが320pxに増えている。しかしそれでも総容量が減っているというのはすごいと思う。AVIFさまさまである。

アイキャッチ画像を未設定にできるようにした

現在の実装では記事の中に画像があれば、その中で最初の画像が自動的にアイキャッチにされるのだが、コードフェンスやコードスパンの中に紛れていても設定される状態だった。

これは不具合に近い挙動だが、そうでなくとも不本意にアイキャッチが設定されることもあると思うので、編集画面にアイキャッチを未設定にする機能を足した。

取り敢えずアイキャッチ自動設定の振る舞いについてはバグとして起票しておいたが、今のところ手抜き実装が起因で、実装時から分かっていたので既知の不具合ではある。

機能削除

Windowsサポートの廃止

パスワード仕様を変更した関係で、Windowsのサポートが出来なくなったため切り捨てた。

WindowsとLinuxには差がありすぎてサポートしたくないのもあった。Node.jsやPHPみたいに言語側に便利なラッパーがあればまだいいが、Perlにそんなものはないので…。

それに今はWindowsでもWSLを使えばLinuxが動かせるため、LyndbaumがネイティブでWindows対応をする必要はないと考えている。

Markdownの参照形式のリンク記法を削除

[文字][id]形式の記法を削除した。理由は私が使っていないこと、使っている文章をほとんど見たことがないこと、脚注や同じリンクを何度も書けばいいこと、ブログの記事に同じリンクが何度も出てくることが考えづらいことなど、要するに必要性が不明なため。

Markdownの文法をすべてサポートしてたら大変なので余計なものは気づいたら消していく方針。

2つ目のRSS配信を削除

adiaryには「2つ目のRSS配信」という機能があり、メインのRSSと別に任意のタグのRSSを出す機能があったが、これを削除した。

特定カテゴリのRSSを出したいケースが分からないし、使っているサイトを見たことがないし、私も使っていないため。

あとがき

v4.25になり、優先度高めのやりたいことリストはすべて消化しきれたのでしばらくは落ち着いていられそうだ(ホンマか?)

少なくともadiaryに持っていた不満の多くを解消することができ、非常に使い勝手のいいCMSにできたと思う。これからも何かあればちょいちょい直していきたいし、今後のやりたいことリストはGitHubリポジトリのIssueに挙げておいたので、またそのうち、いつかやりたい。いつやるかは不明だが…w

そういえばマイナーバージョンが2桁しかないため、99まで行くと次はメジャーを上げないといけないことに気が付いたが、まぁその時までには何とかなるだろう。v5.00までに配布できるレベルまで引き上げるのが目標だ。まぁ4.8001みたいにすることはできるはずなので、最悪桁を増やせば問題ないだろう。

Claudeの使用量も火曜の終わり時点でMax x5が12%なので、Pro換算60%ということで落ち着いてきたように思う。次回の更新ではProに戻しても大丈夫だろう、きっと。


  1. マイグレーションとかは作ってないのでgrepで引いて手動で書き換えている ↩

画像フォーマット別のベンチマークをしてみた

PageSpeed Insightsからwebpかavifにして画像を軽くしろと言われるので、渋々ベンチをとってみた結果。JPEG, WebP, JPEG XL, AVIFで比較している。

比較では、画質を保ったままファイルサイズをどれだけ減らせるかに加えて、サーバーサイドでの変換にかかるCPU時間を重視した。本システムはリソースの限られた環境での運用を前提としており、変換が重いと画像のアップロードが終わるまでに時間がかかり、ストレスになるからだ。

以下に計測内容を残す。計測は3回行い、その中央値を出している。

変換に使った画像

形式 フォーマット 色数 画像サイズ ファイルサイズ(byte)
JPEG元画像 画質93・サブサンプリング4:2:0・ベースライン・EXIF・XMP有 24bit 4,000 x 3,000px 11,175,399
PNG元画像 埋め込みコメントあり 32bit 2,048 x 3,072px 7,636,570

計測に使った環境

Env Ver
CPU AMD Ryzen 5 8500G
メモリ DDR5-6000 16GB * 2
ストレージ Crucial P1 CT500P1SSD8JP
OS Ubuntu 26.04.1 LTS
ImageMagick 7.1.2-18 Q16 x86_64 23822
cjxl v0.11.1 [AVX3_DL,AVX2,SSE4,SSE2]
avifenc 1.3.0 (dav1d [dec]:1.5.3, libgav1 [dec]:0.20.0, aom [enc/dec]:v3.13.1)

サイズそのままで形式のみ変更

JPEGがサイズ削減率とCPU使用時間、画質の比率で最も優れており、他へ移る意義を見出すことができなかった。

というか可逆圧縮でなければ元画像壊れるので変換したらダメだろう…。以下の結果とは関係がなくなるが、JPEGはメタ情報を削ることで元画像を保ったまま小さくできることが分かったため、JPEG→JPEGのみメタ情報の削除によって画質を保ったまま容量を減らせることがわかった。

JPEGの軽量化

スマホのカメラで撮影して作ったJPEGがどれだけ縮むか見たもの。JPEGからJPEGに再圧縮するだけでも劇的に減っている。EXIFは残してある。

画像全体を比較してもわかりづらいため、元画像の一部をクロップした比較用に切り抜いたJPEG元画像と、それに対応する変換結果の画像をすべてPNGで置いている。開いてスライドショーをめくっていくと差分が分かりやすいようにしている。

変換 設定 サイズ削減率 サイズ比率(JPEG基準) CPU時間(ms) CPU時間比率(JPEG基準) 画質
JPEG->JPEG 画質80・サブサンプリング4:2:0・プログレッシブ 88.8% 100% 217 100% ほぼ同一(AVIFに劣る)
JPEG->WebP 画質80・サブサンプリング4:2:0 92.4% 68.0% 707 325.8% のっぺりしている
JPEG->JPEG XL 画質80・サブサンプリングなし 92.5% 66.5% 6,041 2783.9% 若干色が薄い
JPEG->AVIF 画質80・サブサンプリング4:2:0・速度6/10 90.9% 81.4% 2,939 1354.4% 限りなく同一(JPEGに勝る)
JPEG→JPEGが劇的に減っている理由

JPEGからJPEGにしても普通に考えれば容量はさほど変わらないはずだが、これには理由がある。これはimagemagickの出力時にXMP-GDepthとXMP-GImageが欠落している関係だ。

試しに元のJPEGから純粋に画像を引き抜いたところ2,516,842バイトしかなかった。元が11,175,399バイトなのを差し引くと8,658,557バイトがXMP-GDepthとXMP-GImageに使われていることが分かる。

この二つのフィールドはAndroidのカメラによって作成されるもので、JPEGで保存した写真を劣化させずに再編集するためにボケ情報が保存されているらしく、それらのデータが容量を食っているらしい。これは後からぼかしの強さやピント位置を調整し直すためのもので、要は写真の中にもう1枚写真が丸ごと入っているから大きいわけだ。

つまりこのデータは単純に画像を表示する分には不要で、マスタデータとして保持するために必要な情報であるから、ブログなどの表示用途では外してしまって構わない。

ちなみにこのデータがある状態では、ぼかしがない状態の素の画像と、ぼかしをかけるためのマスクデータ、ぼかし加工のされた画像が内部にあり、以下のコマンドで切り出すことができる。

# XMP-GDepth(ぼかしデータ
exiftool -b -DepthImage src.jpeg > depth.jpeg
# XMP-GImage(真の写真
exiftool -b -ImageData src.jpeg > gimage.jpg
# ぼかしデータと真の写真を掛け合わせた写真データ(編集済の写真)
exiftool -xmp:all= -o no-xmp.jpg src.jpeg

しかし切り出した画像を見てもそこまで大きくないので不思議だなと思ったら、XMPフィールドには文字列しか入らないので、真の写真はBase64エンコードされた文字列として格納されているらしい。そらでかくなるわ!

恐らく元々JPEGの仕様として存在したものではなく、拡張フィールドにバイナリを無理やり押し込んだ結果こうなっているのだろう。

PNGの軽量化

メタデータは落ちている。

画像全体を比較してもわかりづらいため、元画像の一部をクロップした比較用に切り抜いたPNG元画像と、それに対応する変換結果の画像をすべてPNGで置いている。開いてスライドショーをめくっていくと差分が分かりやすいようにしている。

変換先 設定 サイズ削減率 サイズ比率(JPEG基準) CPU時間(ms) CPU時間比率(JPEG基準) 画質
PNG->JPEG 画質80・サブサンプリング4:2:0・プログレッシブ 91.4% 100% 207 100% ほぼ同一(AVIFに劣る)
PNG->WebP 画質80・サブサンプリング4:2:0 95.6% 51.7% 569 274.9% のっぺりしている
PNG->JPEG XL 画質80・サブサンプリングなし 93.8% 71.6% 3,897 1882.6% 若干色が暗い
PNG->AVIF 画質80・サブサンプリング4:2:0・速度6/10 95.8% 49.4% 4,317 2085.5% 限りなく同一(JPEGに勝る)

サムネイル生成

全て幅を320pxに落としている。

サムネイル生成ではCPU使用時間がすべて誤差であるため、処理の負荷の割に、JPEGと同じファイルサイズで、JPEGより高い画質の得られるAVIFを採用する意義があることが分かった。

JPEG

変換先のリンクを開いてスライドショーをめくっていくと差分が分かりやすいようにしている。EXIFは落としてある。

変換先 設定 サイズ削減率 サイズ比率(JPEG基準) CPU時間(ms) CPU時間比率(JPEG基準) 画質
JPEG->JPEG 画質80・サブサンプリング4:2:0・プログレッシブ 99.9% 100% 281 100% 悪い
JPEG->WEBP 画質80・サブサンプリング4:2:0 99.9% 72.4% 286 101.8% のっぺりしている
JPEG->JPEG XL 画質80・サブサンプリングなし 99.9% 78.0% 327 116.4% 若干悪い
JPEG->AVIF 画質80・サブサンプリング4:2:0・速度6/10 99.9% 100.0% 311 110.7% 非常に良い

PNG

変換先のリンクを開いてスライドショーをめくっていくと差分が分かりやすいようにしている。

変換先 設定 サイズ削減率 サイズ比率(JPEG基準) CPU時間(ms) CPU時間比率(JPEG基準) 画質
PNG->JPEG 画質80・サブサンプリング4:2:0・プログレッシブ 99.6% 100% 493 100% ノイズが目立つ
PNG->WEBP 画質80・サブサンプリング4:2:0 99.7% 78.2% 503 102.0% JPEGよりノイズが少ない
PNG->JXL 画質80・サブサンプリングなし 99.7% 81.4% 600 121.7% ややノイズがある
PNG->AVIF 画質80・サブサンプリング4:2:0・速度6/10 99.6% 92.0% 569 115.4% 非常に鮮明

実行時のコマンド

原寸用

変換方法 出力サイズ(KB) 合計CPU時間(ms)
magick src.jpeg -quality 80 -sampling-factor 2x2,1x1,1x1 -interlace Plane out_jpg_jpg_A.jpg 1,223.4 217
magick src.jpeg -quality 80 out_jpg_webp_A.webp 832.2 707
cjxl src.jpeg out_jpg_jxl_A.jxl -q 80 --lossless_jpeg=0 813.9 6,041
avifenc -q 80 -y 420 -s 6 --ignore-xmp src.jpeg out_jpg_avif_A.avif 995.4 2,939
magick src.png -quality 80 -sampling-factor 2x2,1x1,1x1 -interlace Plane out_png_jpg_A.jpg 640.7 207
magick src.png -quality 80 out_png_webp_A.webp 331.3 569
cjxl src.png out_png_jxl_A.jxl -q 80 458.9 3,897
avifenc -q 80 -y 420 -s 6 src.png out_png_avif_A.avif 316.6 4,317

サムネ用

サムネ用の画像は、事前に元画像を幅320pxへリサイズしてPNGに保存しているため、リサイズの処理時間は含んでいない。

変換方法 出力サイズ(KB) 合計CPU時間(ms)
magick mid_jpg_C.png -quality 80 -sampling-factor 2x2,1x1,1x1 -interlace Plane out_jpg_jpg_C.jpg 12.3 281
magick mid_jpg_C.png -quality 80 out_jpg_webp_C.webp 8.9 286
cjxl mid_jpg_C.png out_jpg_jxl_C.jxl -q 80 9.6 327
avifenc -q 80 -y 420 -s 6 mid_jpg_C.png out_jpg_avif_C.avif 12.3 311
magick mid_png_C.png -quality 80 -sampling-factor 2x2,1x1,1x1 -interlace Plane out_png_jpg_C.jpg 31.2 493
magick mid_png_C.png -quality 80 out_png_webp_C.webp 24.4 503
cjxl mid_png_C.png out_png_jxl_C.jxl -q 80 25.4 600
avifenc -q 80 -y 420 -s 6 mid_png_C.png out_png_avif_C.avif 28.7 569

確認用スクリプトと集計結果の全データ

詳細な全集計データには、本記事書いたデータの元ネタを格納している。

また以下に集計で使ったスクリプトも置いている。

確認用スクリプトのソースコード
#!/usr/bin/env bash
# 画像ダイエット ベンチマーク
# 使い方: src.jpeg / src.png と同じフォルダで  bash bench.sh
# 結果:   result.tsv(ファイル名・サイズKB・実時間ms・CPU時間ms・CPU使用率%)→ Excel の「測定結果」シート A1 に貼り付け
#         各コマンドのエラー出力は bench.log に残る
# Copyright Lycolia Rizzim All rights reserved.
# https://lycolia.info/

set -u

SRC_JPG=src.jpeg
SRC_PNG=src.png
RUNS=${RUNS:-3}        # 各コマンドを何回測るか(中央値を記録)。例: RUNS=5 bash bench.sh
OUT=result.tsv
LOG=bench.log

printf 'ファイル\tサイズ(KB)\t実時間(ms)\tCPU時間(ms)\tCPU使用率(%%)\n' > "$OUT"
: > "$LOG"

kb() { awk -v s="$(stat -c %s "$1")" 'BEGIN{printf "%.1f", s/1024}'; }

# measure 出力ファイル コマンド...
# bash の time で 実時間・user・sys を取り、CPU時間 = user + sys、CPU使用率 = CPU時間 / 実時間
measure() {
  local out=$1; shift
  local tf rows=() i line real user sys rc
  tf=$(mktemp)
  for ((i = 0; i < RUNS; i++)); do
    rm -f "$out"
    local TIMEFORMAT=$'%3R %3U %3S'
    { time "$@" >>"$LOG" 2>&1; rc=$?; } 2>"$tf"
    if (( rc != 0 )); then
      printf '%s\tERROR\t\t\t\n' "$out" >> "$OUT"
      echo "失敗: $out(bench.log を確認)" >&2
      rm -f "$tf"; return
    fi
    read -r real user sys < "$tf"
    rows+=( "$(awk -v r="$real" -v u="$user" -v s="$sys" 'BEGIN{printf "%d %d", r*1000, (u+s)*1000}')" )
  done
  rm -f "$tf"
  # 実時間の中央値の回を採用(CPU時間も同じ回の値)
  line=$(printf '%s\n' "${rows[@]}" | sort -n -k1,1 | sed -n "$(( (RUNS + 1) / 2 ))p")
  read -r real cpu <<< "$line"
  local pct
  pct=$(awk -v r="$real" -v c="$cpu" 'BEGIN{ if (r > 0) printf "%.0f", c / r * 100; else print "" }')
  printf '%s\t%s\t%s\t%s\t%s\n' "$out" "$(kb "$out")" "$real" "$cpu" "$pct" >> "$OUT"
  echo "完了: $out  実${real}ms  CPU${cpu}ms (${pct}%)" >&2
}

# 入力ファイルのサイズ(時間は空欄)
printf '%s\t%s\t\t\t\n' "$SRC_JPG" "$(kb "$SRC_JPG")" >> "$OUT"
printf '%s\t%s\t\t\t\n' "$SRC_PNG" "$(kb "$SRC_PNG")" >> "$OUT"

JPG_OPT=(-quality 80 -sampling-factor 2x2,1x1,1x1 -interlace Plane)
AVIF_OPT=(-q 80 -y 420 -s 6)

for tag in jpg png; do
  if [[ $tag == jpg ]]; then src=$SRC_JPG; else src=$SRC_PNG; fi

  # 前処理(B: メタデータ除去 / C: さらに幅320px)
  measure "mid_${tag}_B.png" magick "$src" -strip "mid_${tag}_B.png"
  measure "mid_${tag}_C.png" magick "$src" -strip -resize '320x>' "mid_${tag}_C.png"

  # JPEG
  measure "out_${tag}_jpg_A.jpg" magick "$src" "${JPG_OPT[@]}" "out_${tag}_jpg_A.jpg"
  measure "out_${tag}_jpg_B.jpg" magick "mid_${tag}_B.png" "${JPG_OPT[@]}" "out_${tag}_jpg_B.jpg"
  measure "out_${tag}_jpg_C.jpg" magick "mid_${tag}_C.png" "${JPG_OPT[@]}" "out_${tag}_jpg_C.jpg"

  # WebP
  measure "out_${tag}_webp_A.webp" magick "$src" -quality 80 "out_${tag}_webp_A.webp"
  measure "out_${tag}_webp_B.webp" magick "mid_${tag}_B.png" -quality 80 "out_${tag}_webp_B.webp"
  measure "out_${tag}_webp_C.webp" magick "mid_${tag}_C.png" -quality 80 "out_${tag}_webp_C.webp"

  # JXL
  if [[ $tag == jpg ]]; then
    measure "out_jpg_jxl_A.jxl" cjxl "$src" out_jpg_jxl_A.jxl -q 80 --lossless_jpeg=0
    measure "out_jpg_jxl_L.jxl" cjxl "$src" out_jpg_jxl_L.jxl          # ロスレス再圧縮
  else
    measure "out_png_jxl_A.jxl" cjxl "$src" out_png_jxl_A.jxl -q 80
  fi
  measure "out_${tag}_jxl_B.jxl" cjxl "mid_${tag}_B.png" "out_${tag}_jxl_B.jxl" -q 80
  measure "out_${tag}_jxl_C.jxl" cjxl "mid_${tag}_C.png" "out_${tag}_jxl_C.jxl" -q 80

  # AVIF
  measure "out_${tag}_avif_A.avif" avifenc "${AVIF_OPT[@]}" --ignore-xmp "$src" "out_${tag}_avif_A.avif"
  measure "out_${tag}_avif_B.avif" avifenc "${AVIF_OPT[@]}" "mid_${tag}_B.png" "out_${tag}_avif_B.avif"
  measure "out_${tag}_avif_C.avif" avifenc "${AVIF_OPT[@]}" "mid_${tag}_C.png" "out_${tag}_avif_C.avif"
done

echo "結果を $OUT に書き出しました(Excel の「測定結果」シート A1 に貼り付け)" >&2

2026年11月3日追記:AVIFの品質と速度を調整した追加ベンチ

AVIFの速度と品質を調整してサムネイル画像に対してベンチマークした結果を作ったので雑に追記。

ベースのコマンドは以下のような感じで、-quality, -qと-sだけ書き換えて実行している。値はファイル名の内容でやっている。

magick "mid_${tag}_C.png" -quality 80 -sampling-factor 2x2,1x1,1x1 -interlace Plane "out_${tag}_jpg_C.jpg"
avifenc -q 80 -y 420 -s 6 mid_${tag}_C.png out_${tag}_avif_C.avif
ファイル サイズ(KB) 実時間(ms) CPU時間(ms) CPU使用率(%) メモ
mid_jpg_C.png 109.6
mid_png_C.png 260
out_jpg_jpg_q80.jpg 12.3 7 7 100
out_jpg_jpg_q75.jpg 10.7 7 6 86
out_jpg_jpg_q70.jpg 9.7 7 6 86
out_jpg_jpg_q65.jpg 8.9 7 7 100
out_jpg_avif_q80s4.avif 12.5 119 197 166
out_jpg_avif_q75s4.avif 10.7 105 183 174
out_jpg_avif_q70s4.avif 9.3 97 162 167
out_jpg_avif_q65s4.avif 8.1 103 170 165  
out_jpg_avif_q60s4.avif 6.8 95 156 164
out_jpg_avif_q80s5.avif 12.5 91 150 165
out_jpg_avif_q75s5.avif 10.7 82 138 168
out_jpg_avif_q70s5.avif 9.3 82 146 178
out_jpg_avif_q65s5.avif 8.1 84 132 157  
out_jpg_avif_q60s5.avif 6.8 74 116 157
out_jpg_avif_q80s6.avif 12.3 26 38 146
out_jpg_avif_q75s6.avif 10.5 24 34 142
out_jpg_avif_q70s6.avif 9.1 24 37 154
out_jpg_avif_q65s6.avif 7.9 24 34 142 採用
out_jpg_avif_q60s6.avif 6.7 25 39 156 あからさまに画質が悪い
out_jpg_avif_q80s8.avif 12.2 14 18 129
out_jpg_avif_q75s8.avif 10.4 14 17 121
out_jpg_avif_q70s8.avif 9 13 17 131
out_jpg_avif_q65s8.avif 7.9 13 16 123 画質が悪い
out_jpg_avif_q60s8.avif 6.6 12 16 133
out_png_jpg_q80.jpg 31.2 9 9 100
out_png_jpg_q75.jpg 27.6 12 12 100
out_png_jpg_q70.jpg 25.2 10 10 100
out_png_jpg_q65.jpg 23.1 9 9 100
out_png_avif_q80s4.avif 27.6 216 405 188
out_png_avif_q75s4.avif 24.4 204 378 185
out_png_avif_q70s4.avif 22.1 201 371 185
out_png_avif_q65s4.avif 20 201 373 186
out_png_avif_q60s4.avif 17.8 204 369 181
out_png_avif_q80s5.avif 27.7 178 329 185
out_png_avif_q75s5.avif 24.4 171 315 184
out_png_avif_q70s5.avif 22.1 169 306 181
out_png_avif_q65s5.avif 20.1 154 282 183
out_png_avif_q60s5.avif 18.1 152 278 183
out_png_avif_q80s6.avif 28.7 54 89 165
out_png_avif_q75s6.avif 25.4 51 81 159
out_png_avif_q70s6.avif 23 51 82 161
out_png_avif_q65s6.avif 20.6 60 97 162 採用
out_png_avif_q60s6.avif 18.3 61 99 162
out_png_avif_q80s8.avif 28.6 32 51 159 のっぺりしすぎ
out_png_avif_q75s8.avif 25.2 30 47 157
out_png_avif_q70s8.avif 22.7 28 41 146
out_png_avif_q65s8.avif 20.5 29 41 141
out_png_avif_q60s8.avif 18.2 29 45 155

あとがき

実はJPEG XLとWebPについてはデータ集めが目的で、元からPageSpeed Insightsの指摘とは関係がなかった。

JPEG XLはEdgeが対応していないので、どのみち採用するつもりはなかった。これまでの画像フォーマットのすべてを過去にするみたいな大層な謳い文句を見かけたので計測することにした。

WebPは昔計測したことがあり、画質のわりに容量が小さくならないことは知っていたが、計測したデータを残していなかったので、今回は計測データを残すために計測した。

本命はJPEGのメタデータを削ってどこまで減らせるかと、AVIFを活用できるかが焦点だった。結果としてよいデータが取れたので良かったと思う。

またJPEGのファイル構造が知れたことはいい勉強になったし、今回の記事でテキストリンクに紐づいた画像をポップアップ表示させる必要が出たので、その改修ができたのも収穫だった。詳しくはまたリリースノートの記事を作って書くが、実はテキストリンクをポップアップさせるのは前からやりたかったのだが、脳裏から消えていた。

あとどうでもいい話として、過去にStableDiffusionのベンチマークで作ってたうちの子が劇的に麗しくなったのが見れたのもいい収穫だった。何せベンチマークする時くらいしか見てなかったので…。

ひとまずは次期バージョンでJPEGの不要なXMP落としとavifサムネイルに対応していきたい。レンタルサーバー向け対応はどうするかなぁ…。恐らくさくらのレンサバでもやろうと思えば対応自体はできそうな気はするが…。例えば利用者がavifencを自前ビルドするなど…w(そもそも今このLyndbaumのユーザーは私しかいないはずなのでどうでもいい話ではあるが…w)

映画館での映画鑑賞録にミスがあったので直した

Claude Opus 5.5を使って鑑賞作品の整理をしていたところ、鑑賞履歴に漏れがある作品があることが分かった。エクセルのVLOOKUPで機械的に確認したところ『北極百貨店のコンシェルジュさん』と『大雪海のカイナ ほしのけんじゃ』が鑑賞履歴から欠落していることが判明した。

過去の予約メールと、保存している紙チケットから突き合せた結果、この画像のような差分があることが判明した。

恐らくどこかで操作を誤ったか何かで『アリスとテレスのまぼろし工場』がフィルされた結果、『北極百貨店のコンシェルジュさん』と『大雪海のカイナ ほしのけんじゃ』が消えてしまったのだと思う。

またそれとは別に『アリスとテレスのまぼろし工場』の鑑賞が一回分欠落していることが分かったので、そこも埋めた。

これによって『アリスとテレスのまぼろし工場』の鑑賞回数が前回集計時の8回から6回に減少した。