概要
最近、エクスプローラーの背景機能を実装する際に、情報をDLLに渡す必要がありました。
主に画像のフィット感や透明度などの比較的シンプルなパラメータを渡すものです。通信方法は複数ありますが、練習用の機能なので、これまで使ったことのない方法を試してみたいと思いました。
以前の記事で、画像ファイルにデータを埋め込む2つの方法を含むデジタルウォーターマーク技術を紹介しました。
https://www.cnblogs.com/zhaotianff/p/17222056.html
そこで今回も、これらのデータを画像ファイルに直接書き込み、DLLで読み取ることにしました。
ネットで調べたところ、JPGファイルに独自データを書き込む比較的簡単な方法が確かにありました。
しかも、この方法は理論上、サイズ制限なくデータを書き込めます。
余談ですが、どのような形式のファイルでも、標準的なフォーマットがあります。通常はファイルヘッダーやファイルボディなどがあり、ファイル構造を理解すれば、元のファイル構造を壊さずにヘッダーに独自データを書き込むことは理論的に可能です。
ただし、このプロセスには多少の時間がかかります。
今回は直接NVISO Labs の既存の方法を使用しました。必要な方への共有として紹介します。
実装原理
まず、16進エディタで通常のJPGファイルを開きます。

最初の2バイトは FF D8 です。
FF D8 => JPEGデータストリームの開始マーカー
JPEGデータストリームの開始マーカーを見つけたら、その後に「コメント」マーカーを挿入できます。
FF FE => これは「コメント」マーカーであり、JPEGデコーダーもこれを無視します。これらのマーカーが、データを挿入しても有効な画像を維持する方法です。
FF FEの直後には2バイトが続き、「コメント」内容のサイズを示します。
例
JPGファイルに HelloWorld を書き込むとします。「HelloWorld」は10バイトなので、FF FE の後に以下を書き込みます。
00 0A(10バイト) 48 65 6C 6C 6F 57 6F 72 6C 64
合計14バイトで、FF FE の2バイトのヘッダー、00 0A の2バイトのサイズ、10バイトの内容が含まれます。
したがって、16進エディタで FF D8 の後に14バイトを挿入します。


次にデータを埋め込みます。以下のようになります。

ファイルを保存すると、JPGファイルは正常に開けます。

コード実装
ここではC#を例にします。他の言語でも実装方法はほぼ同じです。今回はopacityとstretchのデータを書き込んでいます。
private void WriteImageInfoToFile(string filePath, double opacity, int stretch)
{
// ファイルデータを読み込む
var buffer = System.IO.File.ReadAllBytes(filePath);
// JPGファイルかどうか判定
if (buffer[0] == 0xFF && buffer[1] == 0xD8)
{
// 元のデータを6バイト拡張
var newBuffer = new byte[buffer.Length + 6];
// JPGファイル開始マーカー FF D8 をコピー
Array.Copy(buffer, 0, newBuffer, 0, 2);
// データ設定
// コメントマーカー
newBuffer[2] = 0xFF;
newBuffer[3] = 0xFE;
// サイズ 0x02
newBuffer[4] = 0;
newBuffer[5] = 0x02;
// データ
newBuffer[6] = (byte)nOpacity;
newBuffer[7] = (byte)stretch;
// 元画像の残りデータを新しいバッファにコピー
Array.Copy(buffer, 2, newBuffer, 7, buffer.Length - 2);
// ファイルに書き込む
System.IO.File.WriteAllBytes(filePath, newBuffer);
}
}
読み取り時も同様の規則で読み取れば問題ありません。
参考資料
https://blog.nviso.eu/2020/07/13/how-to-embed-secret-data-in-jpeg-files/