概述
最近在實作資源管理器背景的一個功能時,需要將資訊傳遞到DLL中,
主要就是傳遞一些比較簡單的參數,包括圖片的契合度、透明度之類的。通訊方式有多種,畢竟是練手的功能,就想找一些以前沒用過的方式。
在我前面的文章中,介紹過數位浮水印技術,其中的兩種方式就是在影像檔案中嵌入資料
https://www.cnblogs.com/zhaotianff/p/17222056.html
所以這裡我也想直接在圖片檔案中寫入這些資料,然後在DLL中讀取。
在網路上查了一下資料,確實有一種比較簡單的方式可以在JPG檔案中寫入自己的資料。
而且這種方式理論可以寫入不限大小的資料。
再說一些題外話,不管什麼格式的檔案,它都有一套標準的格式。一般都會包括檔案頭、檔案體之類的,我們在熟悉檔案結構以後,想在不破壞原始檔案結構的情況下,在檔案頭寫入一些我們自己的資料,理論上都是可以實現的。
但是這個過程是需要花費一些時間的。
我這裡是直接使用了NVISO Labs 現有的方式,給有需要的小夥伴做一個分享。
實作原理
我們先用十六進制編輯器打開一個普通的JPG檔案

可以看到前面兩個位元組的內容是FF D8
FF D8 => 這是表示 JPEG 資料流開始的標記
當我們找到JPEG資料流開始的標記後,可以在它後面插入一個「註解」標記。
FF FE =>這是一個「註解」標記,JPEG 解碼器也會忽略它。這些標記正是我們將要插入資料的方式,並且仍然具有有效的影像
FF FE之後緊跟2位元組,代表「註解」內容的大小。
範例
假設我們在一個jpg檔案中寫入HelloWorld,「HelloWorld」是十個位元組,所以我們在FF FE 之後寫入
00 0A(10個位元組) 48 65 6C 6C 6F 57 6F 72 6C 64
這裡總共是14個位元組,包含FF FE 2個位元組的頭 00 0A 2個位元組的大小,和10個位元組的內容。
所以我們用十六進制編輯器在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;
//將原圖片剩下的資料複製到新buffer中
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/