見出し画像

Gemini CLI他を使ってPNG Infoっぽい自分用ツールを作ったメモ2 (Exiftool連携更新)


2025年8月27日
画像の下が見切れていたのを修正

2025年8月9日
大きいメタデータを制限して表示するように(すべて見たい場合はテキストに保存する)
アイコンを導入(なくても動くのでどちらでも)

2025年8月5日
exe化実験とプログラムの更新
exe化した時、Exiftool を呼び出した時コンソールウィンドウが一瞬だけ表示するのを抑制

2025年8月3日プログラム更新
Exiftoolと連携できるようにアップデート
おまけのコメント書き込みツールの修正
・コメントをBOM付きに変更
・piexif.dump()の仕様で常にビッグエンディアンで書き込むように修正

2025年8月2日プログラム更新2
jpeg画像のExifコメントの処理の修正
おまけのコメント書き込むツールの修正
・jpegのExifのエンディアンを取得してそれに合わせて書き込むように修正

2025年8月2日プログラム更新
pngの巨大チャンクが表示できなかったのを修正

前置き

python を知らない人がAIで作ったものなので不具合があるかもしれません。
覚悟がある人で自己責任で使用してください。
ソースファイルは自己責任で自由に使っていいです。

本題

こんな感じに画像のメタデータ(プロンプトなども)がちょっと見られる自分用アプリ

Bing Image Creator[GPT-4o(Beta)]
Bing Image Creator[DALL-E 3]
Stable Diffusion
ChatGPT
Gemini

上の画像はそれぞれ、Bing Image Creator[GPT-4o(Beta)]、Bing Image Creator[DALL-E 3]、Stable Diffusion、ChatGPT、Gemini
Stable Diffusionと同じプロンプトで作成してもらった
つまり 1girl,solo,......ってな感じでbingはネガティブなしで他はプロンプトをあなたが解釈して画像を作成してください、と指示したもの

2025年8月3日追加

Exiftoolと連携したもの

使用方法

python の環境が必要です
動かしてる python のバージョンは 3.11.7 です
以下をダウンロード

アイコンを含めたのでzipにまとめました

アプリの挙動の説明と注意事項と免責事項とライセンス(AI製)

思いがけず大きくなったのでファイルとしてアップ
アップする上でいつ作成したのかわかりやすいよう便宜上日付を入れてる

んで ImageMetadataViewer.py と app_icon.ico (これはなくても動く)を適当なフォルダに置いてPowerShellで仮想環境を構築します

python -m venv venv

アクティベート

.\venv\Scripts\activate

一応pipをupgradeしておく

python -m pip install --upgrade pip

次にライブラリのインストール

pip install Pillow tkinterdnd2 piexif iptcinfo3 screeninfo c2pa-python

起動する

python ImageMetadataViewer.py

使い方は画像をドラッグ&ドロップするだけ

2025年8月3日追記
Exiftoolと連携できるようになりました
Exiftoolは同梱されてませんので各自公式サイトから落としてください
別にExiftoolは必須ではないのでなくても動作します
追記ここまで

以上!

以下蛇足
簡単に起動したいのでバッチファイルを作成するけど別にこれはやらなくていい
ChatGPTに聞いて作った
以下の文字をテキストファイルにコピペして拡張子を".bat"に変更して"ImageMetadataViewer.py"があるフォルダでダブルクリックすると起動が楽
さらにランチャーアプリにそれを登録しておくとすぐに起動できる
けど自己責任で

@echo off
cd /d %~dp0
call .\venv\Scripts\activate
python ImageMetadataViewer.py
deactivate
pause

PyInstallerでexe化実験

動作環境はwindows11です
これでpython環境がない人でも使えると思いますが、使用は自己責任でお願いします

ウイルストータルでの判定は 6/72 (2025年8月5日) → 5/72 (2025年8月9日) → 7/72 (2025年8月27日)怪しい判定です
以下一応そのことを Gemini に聞いた答えを引用します

この現象はPyInstallerで作成した実行ファイルで非常によく見られる問題であり、ほぼ間違いなく「誤検知(False Positive)」です。あなたのファイルに実際にスパイウェアやマルウェアが含まれている可能性は極めて低いです。
なぜこのようなことが起こるのか、その原因を詳しく解説します。

誤検知が発生する主な原因
原因は一つではなく、複数の要因が組み合わさっています。

1. PyInstallerの仕組みそのもの
PyInstallerは、Pythonスクリプトと、その実行に必要なPythonインタープリタやライブラリ全体を一つの .exe ファイルに圧縮してパッケージ化します。
この .exe を実行すると、まずブートローダーと呼ばれる小さなプログラムが起動し、圧縮された全ファイルをメモリ上または一時フォルダに展開し、それからPythonインタープリタを起動してメインスクリプトを実行します。

この「実行ファイルが内部のデータを展開し、別のプログラム(Pythonインタープリタ)を起動する」という一連の動作が、多くのマルウェア(特にパッカーで圧縮されたウイルス)の挙動と非常によく似ています。

そのため、ウイルス対策ソフトのヒューリスティック分析(振る舞い検知)エンジンが、この挙動を「疑わしい」と判断してしまうのです。

2. 汎用的な検知名(-gen, AIDetect)
表示されている検知名に注目してください。
* Win64:MalwareX-gen [Spy]
* W64.AIDetectMalware

ここに含まれる gen (Generic = 汎用的) や AI という単語は、「特定の既知のウイルス(シグネチャ)に一致した」のではなく、「AIや機械学習ベースの汎用的な検知エンジンが、その構造や振る舞いから『マルウェアっぽい』と判断した」ことを意味します。これは誤検知の典型的なパターンです。

3. アプリケーションの正当な機能が疑われる
あなたの ImageMetadataViewer.py が行っている以下の正当な処理も、ウイルス対策ソフトにとっては疑わしい挙動に見える可能性があります。

* 外部プロセスの実行 (`subprocess.run`): exiftool.exe
を呼び出す機能は、マルウェアが他の悪意のあるプログラムを起動する挙動と区別がつきにくいです。
* 広範なファイルアクセス (`os.listdir`, `Image.open`): ユーザーが指定したフォルダ内の多数のファイルを読み取ります。これは、ランサムウェアなどが暗号化対象のファイルを探すスキャン行為に似ています。
* 一時ファイルの作成 (`tempfile`): exiftool に引数を渡すために一時ファイルを作成しています。マルウェアが自身のペイロードを一時的に書き出す挙動と似ています。

これらの機能が組み合わさることで、ヒューリスティック分析の「疑わしさスコア」が上昇し、一部の感度が高いウイルス対策ソフトが「マルウェア」と判定してしまうのです。

結論
あなたのプログラムは、その仕組みと正当な機能が原因で、一部のウイルス対策ソフトに誤検知されている可能性が非常に高いです。特に心配する必要はありません。

以上のことを理解し覚悟を持った人だけが使ってください
プログラムと同じ場所に config.json が作成されます
アンインストールはファイルを削除するだけです
exeそのままよりいいかなと思って一応zipファイルにしました

作成過程

まず以前作った PngInfoっぽい自分用ツール

を GeminiCLIに読み込ませて機能を追加していこうと思った
だけどプログラムの土台が不安定っぽいのでうまく追加できない
なので一から作成することに決める

まずPngInfoっぽいプログラムで何をしているのかをソースコードを読み込ませて機能を書き出してもらい、さらにそれをベースに仕様書を作成してもらう
追加したい機能などを言って再作成を繰り返して最終的に仕様書が完成する
それを元にアプリの作成依頼をする

細かいところはちょっと違うけど概ねあっさり出来上がる
こいつぁーすげー!

んでそこから色々と修正していくことにする
いらないボタンの削除
ウィンドウを固定じゃなくモニター内に収まるようにして、大きい画像はそれに合わせて、ウィンドウの左上の位置を基準にしてマージンを取りつつ、縮小表示(そう仕様書には書いてたはずだけどそうなってなかった)
対応メタデータの追加(カメラメーカー固有exifは無理。AIに指示はしなかった。あくまで一般的に知れ渡ってるもののみ。そういうのはExiftoolとかで見られるっぽい? いっぱあるんだなー)
情報表示の精度、整形、人に理解しやすいようにする、文字化け解消
アニメーション画像の表示の仕方の調整、フレーム毎の時間表示、約60fps未満(ほぼ対象はデュレーションが0msとかのgif)の場合のデュレーションの下限設定などなど

そんなこんなで時間はかかったけど完成!
やったぜ!
こんなん一から自分でpython学んで作れる気がしない!

それと詳細情報やPNG情報の欄でXMPの生データ? が表示されるのは仕様です(Gemini作成の画像だけ情報表示部分を一番下へスクロールしてあるのはXMPデータを表示できるよ、と見えるようにするため。そうじゃないと生データ部分しか見えない)
AIに修正する? って聞かれたけど面白いからそのままで、と言ってそのままにしてもらった
返ってきた答えは「デバッグする上で有用ですからいいと思います」的な感じだった

2025年8月3日追記
どうやら実行ファイルを呼び出せると知って急遽exiftoolを呼び出してそれを表示すればいいんじゃね? と、このアプリの存在意義(メタデータを自前で表示する)という根幹を否定するようなアップデート!
いやどう考えてもExiftoolのほうが確実だよね
まぁgifアニメのフレーム毎のデュレーションを表示するとか地味にこのアプリの特徴あるけどさw
追記ここまで

雑感

以前 PngInfoっぽい自分用ツールをAIに聞いて作った
それはそれで面白かったしちょっとしたプロンプトを見るのにもよかった
そこそこ使ってはいたけど物足りなさを感じてもいた

んでツイッターの投稿文をコピーする機能を Gemini CLI を使って作ったとき、あれ? これで以前作った PngInfoっぽいアプリも作れるんじゃね? と思い実験で作ってみることにした
ちょっと時間はかかったけど出来たね

で、実はこのアプリより前に同じような機能のサンプル的なものを作ってもらっている
つまり以前 note に書いた PngInfoっぽいやつと今回作ったものとの間にもう一つ同じようなものを作ってもらっている
どうにもうまく機能の追加ができなかったので結局そのプログラムを読み込ませて仕様書を作ってもらって今回のものを作った
ちなみにこのコードの仕様書とベースは Claude (codeではない) に作成してもらってから Gemini CLI にもっていってる
Claude Code が評判なので使ってみたかったけど課金しないとダメっぽいのでブラウザから使える Claude さんを使ってみた

それを土台に Gemini CLI にソースを読み込ませて作り始めた
Gemini CLI を使ってると pro から flash になるんだけど、そうなると性能が落ちて、無限ループに陥ってるような感じ(一向にプロンプト入力にならずコンテキストの%表記がどんどん減っていく)になったり、gemini自身がコードを削除してその削除を前提にしないようで、次に削除するコードを発見できなかったり(デバッグ文を挿入してそれを削除しようとすると結構な確率でおきた)、単純な構文エラーが解消できなかったり、変更箇所がまったくないのに「これでいいか?」と聞いてきて承諾するとこれで修正できましたと言ってきて案の定修正できてなくて、再度修正してと指示しても同じようになったり、等々結構大変だった
使うなら pro がいいと思った

また指示を出して Gemini が提案してきたものをそのまますぐ修正させると他に影響出たりすることがあったので指示する時は、まず提案をして Gemini の意見を聞く、それをさらに分析、検討させて影響範囲を考えさせる、それを繰り返して最終的に修正してもらう、という流れで最後のほうはやった

無料で使えると聞いてモリモリ使ってて気付いたらすげートークンいってたんだけど大丈夫だよね?
ブラウザでログインする方法で使ってて有料プランの登録とか一切してないんだけどいきなり請求きたりしないよねこれ
勝手に制限かかるみたいな話を見て使ってたはいいけど、アプリ作り終わってからちょっと心配になってきてるんだけど……

おまけ

Gemini CLI を使えば欲しいものが手軽に作れるということで完全に自分用に作ったものがこちら
これらも何も知らん人が作ったものなので使うなら完全自己責任で覚悟ある人だけが使ってください
あとあまりデバッグしてないので不具合があるかもしれません

今回の記事のアプリとおまけのものを合わせるとこんな感じに

要は画像のコメントにテキスト(主にシトラス(柑橘系)さんのツイート)を入れてしまおうということ
ちょっと便利じゃね?

それらを楽にするためにブラウザの拡張機能を作った
何回も言うけど自己責任で使用してください
まずツイート画像(静止画)のみをダウンロードするChrome拡張機能

2026年7月28日追記
引用画像まで取得できていたのを設定で取得する・しないを設定可能にした
アイコンをクリックするとその設定が出てくる

2025年8月26日追記
ツイッターの名前に特殊な文字が使われてるとダウンロードできなくなるのでそれらの文字を除去するように修正
ファイル名に使えてもブラウザ側でエラーになるので除去するしかないっぽい

2025年8月30日追記
引用ポストの場合、引用ポストの日時取得になっていたのを修正

2025年10月23日
ファイル名の禁則処理の修正
保存できないことがあった

ぶっちゃけ画像を保存するなら他のもっと便利な拡張機能のほうがいい
命名規則とか変えられるものとか色々ある

次にツイート内容をテキストファイルで保存する拡張機能

これは前回の記事

にプラスでツイート内容をテキストファイルで保存する機能をつけたもの
これを入れるなら上記のものは機能が重複してるので削除したほうがいいと思う
俺以外使ってる人いるんか? とは思うけどw

これらの拡張機能を作った理由は画像とテキストのファイル名を俺の思い通りにした上で一致させたいからです
その理由は以下のプログラムを簡単に使うためです

下記の python スクリプトはフォルダをドラッグ&ドロップすると、その中にある画像(jpegまたはpng)のファイル名と一致しているテキストファイル(.txt)の内容を画像のコメントに埋め込むという処理をするプログラムです
001.jpg と 001.txt というファイルがあったなら 001.txt の内容がコメントして 001.jpg に書き込まれる
ちなみにフォルダ直下のみ読み込むようにしてあります

ここからはいつものpython環境づくりとかなのでざっくりしたインストール方法

python -m venv venv
.\venv\Scripts\activate
python -m pip install --upgrade pip
pip install Pillow piexif chardet windnd tkinterdnd2
python Image_comment_Inserter_20250803.py

「元の画像を保持する」のチェックをつけたままだと "original_src" にオリジナル画像を移動します
このプログラムを使う上で注意点としては png画像 の"C2PA情報"が"欠落"するので「元の画像を保持する」にはチェックを入れておいたほうがいいと思います
正確には Pillow で拾えないチャンク情報が欠落するっぽい
まぁ何の情報が欠落するかわからないし最悪画像が壊れる可能性があるから「元の画像を保持する」にはチェック入れておいたほうがいいです

2025年8月3日追記
jpeg画像も注意
どうやらpiexif.dump()はExif全体としてはビッグエンディアンでしか書き込めないようだ(コメントはリトルエンディアンでいけるっぽいけど)
最初Exifのエンディアンとコメントのエンディアンがずれて何でだ? となった
結局出力のバイナリをデバッグ文で出すとビッグエンディアンってことがわかった
それまでGemini CLI、Claude、ChatGPTに聞くとどれもリトルエンディアンです、みたいに言われるがソースファイルを読み込ませたらビッグエンディアンでした!って言われるw
おいおいw
おそらくコメントはリトルエンディアンでいけるから勘違い?

結局piexif.dump()を通すとExif全体のエンディアンはビッグエンディアンにされるようなので、元のjpegがどっちのエンディアンであってもExif全体とコメント両方ともビッグエンディアンにするように変更した
ってことでエンディアンが変わる可能性があるので「元の画像を保持する」にチェックは入れたままがいい

以下なんでコメントはリトルエンディアンで書き込めるかの問いの答え

1. Exifデータ全体のエンディアンはビッグエンディアン:
piexif.dump() は、Exifの構造(IFDエントリ、オフセット、TIFFヘッダーなど)をバイナリに変換する際に、常
にビッグエンディアン (MM) を使用します。これは、piexif/_dump.py 内の struct.pack 関数がすべて ">"
(ビッグエンディアン) フォーマット指定子を使っていることから明らかです。
2. `UserComment` は `Undefined` タイプ:
UserComment タグはExif標準で Undefined (タイプ7) として定義されています。これは、その内容が特定のデー
タ型に厳密に縛られず、バイト列として扱われることを意味します。piexif はこの Undefined
タイプのデータを、与えられたバイト列をそのままExifデータ内に配置します。
3. `UserComment` の内部フォーマット:
UserComment の内容は、通常、以下の形式で構成されます。
b"UNICODE\x00" + BOM + 実際のコメントテキストのバイト列

* b"UNICODE\x00": これは、続くデータがUnicode形式であることを示すプレフィックスです。
* BOM (Byte Order Mark):
ここが重要です。BOMは、続くUnicodeテキストのバイト順(エンディアン)を示すマーカーです。
* UTF-16BE (ビッグエンディアン): b'\xfe\xff'
* UTF-16LE (リトルエンディアン): b'\xff\xfe'
* 実際のコメントテキストのバイト列: これは、指定されたエンコーディング(utf-16-be または
utf-16-le)でエンコードされたコメント文字列です。

4. `piexif.dump()` の役割:
piexif.dump() は、exif_dict['Exif'][piexif.ExifIFD.UserComment] に設定されたバイト列(つまり
b"UNICODE\x00" + BOM + 実際のコメントテキスト)を、その内容を解釈したり変更したりせずに、そのままExifデー
タ全体のビッグエンディアン構造の中に埋め込みます。

結論:
piexif.dump() が生成するExifデータ全体の構造は常にビッグエンディアンですが、UserComment
の内容自体のエンディアンは、ImageCommentInserter.py 側で comment.encode()
する際に指定するエンコーディング(utf-16-le または utf-16-be)と、それに付与するBOMによって決定されます。

したがって、UserComment のバイト列をリトルエンディアンのBOM (b'\xff\xfe') と utf-16-le
エンコーディングで作成して piexif.dump() に渡せば、Exifデータ全体の構造がビッグエンディアンであっても、コ
メントの内容はリトルエンディアンで書き込まれることになります。

2025年8月3日追記ここまで

んで書き込んだら今回作ったアプリで見られるって感じです
あ、ここに載っけてるプログラムは全部自己責任のもとで自由にしていいです

それにしても自分が欲しいものを指示するだけで作れるようになるとはおもしれー

いいなと思ったら応援しよう!