我們這一節(jié)用代碼實(shí)現(xiàn),把字符串藏入BMP文件,并且能正常讀取出來(lái)。
看這篇的同學(xué)請(qǐng)先閱讀第一篇了解理論:
http://blog.csdn.net/QQ78442761/article/details/54863034
下面開(kāi)始進(jìn)入此節(jié):
從上一節(jié),我們知道了Bmp文件的結(jié)構(gòu),如下圖所示:
其中最關(guān)鍵的兩個(gè)結(jié)構(gòu)體BITMAPFILEHEADER和BITMAPINFOHEADER,這里面保存了這個(gè)Bmp文件的很多信息。
恰好,Windows給我們提供了這個(gè)兩個(gè)結(jié)構(gòu)體,如下圖所示:
typedef struct tagBITMAPFILEHEADER { Word bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits;} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;typedef struct tagBITMAPINFOHEADER{ DWORD biSize; LONG biWidth; LONG biHeight; WORD biplanes; WORD biBitCount; DWORD biComPRession; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant;} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;我們?cè)诘?10Editor看看(圖如下):
關(guān)于高度為負(fù)的問(wèn)題,在第一節(jié)已經(jīng)說(shuō)明,不知道的同學(xué)請(qǐng)從文章最上面的鏈接進(jìn)入第一節(jié)。在此不再說(shuō)明。
那么問(wèn)題就簡(jiǎn)單了,現(xiàn)在這個(gè)程序的思路就是:
1.用C/C++代碼讀取圖片文件里面的這兩個(gè)結(jié)構(gòu)體。
2.讀取這個(gè)文件到內(nèi)存中。
3.獲取bfOffBIts,再獲取alpha通道(+4)。
4.把數(shù)據(jù)拆分,插入到alpha通道。
5.保存文件。
6.讀取被修改文件的alpha通道,組合成字符串。
理論就是這么簡(jiǎn)單:下面是程序源碼打包下載地址:
http://download.csdn.net/detail/qq78442761/9747338
下面是程序源碼:
dwBmpSize.h
#pragma once#include <string>#include <Windows.h>using namespace std;class CBMPHide{public: CBMPHide(); ~CBMPHide(); bool setBmpFileName(char* szFileName); //設(shè)置Bmp文件名 int getBmpWidth(); //獲取寬度 int getBmpHeight(); //獲取高度 int getBmpBitCount(); //獲取Bit總數(shù) bool save(); bool hideString2BMP(char* szStr2Hide); //隱藏String到BMP文件中 void showStringInBmp(char* szBmpFIleName=NULL); //展示private: DWORD dwBmpSize; //圖片文件大小 string sBmpFileName; LPBYTE pBuf; //用于存放圖片信息的內(nèi)存 BITMAPFILEHEADER* m_fileHdr; BITMAPINFOHEADER* m_infoHdr;};dwBmpSIze.cpp#include "dwBmpSize.h"CBMPHide::CBMPHide(){ sBmpFileName = ""; pBuf = 0; dwBmpSize = 0;}CBMPHide::~CBMPHide(){}bool CBMPHide::setBmpFileName(char* szFileName){ this->sBmpFileName = szFileName; if (pBuf) //如果已經(jīng)生成就釋放掉 { delete[]pBuf; } HANDLE hfile = CreateFileA(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); if (hfile == INVALID_HANDLE_VALUE) { return false; } //和struct BITMAPFILEHEADER bmfh里面的 bfSize的大小應(yīng)該是一樣的。 dwBmpSize = GetFileSize(hfile, 0); //獲取文件的大小 pBuf = new byte[dwBmpSize]; DWORD dwRead = 0; ReadFile(hfile, pBuf, dwBmpSize, &dwRead, 0); if (dwRead != dwBmpSize) { delete[]pBuf; pBuf = 0; return false; } CloseHandle(hfile); m_fileHdr = (BITMAPFILEHEADER*)pBuf; m_infoHdr = (BITMAPINFOHEADER*)(pBuf + sizeof(BITMAPFILEHEADER)); return true; //成功話就是文件的內(nèi)容讀取到pBuf里面}int CBMPHide::getBmpWidth(){ return m_infoHdr->biWidth;}int CBMPHide::getBmpHeight(){ return m_infoHdr->biHeight;}int CBMPHide::getBmpBitCount(){ return m_infoHdr->biBitCount;}bool CBMPHide::save(){ string sDstFileName = sBmpFileName + ".hide.bmp"; HANDLE hfile = CreateFileA(sDstFileName.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0); if (hfile == INVALID_HANDLE_VALUE) { return false; } DWORD dwWritten = 0; WriteFile(hfile, pBuf, dwBmpSize, &dwWritten, 0); if (dwBmpSize != dwWritten) { return false; } CloseHandle(hfile); return true;}//隱藏一個(gè)字符串到圖片中,把字符串拆成字節(jié),寫(xiě)入每個(gè)像素的alpha通道中bool CBMPHide::hideString2BMP(char* szStr2Hide){ LPBYTE pAlpha = pBuf + m_fileHdr->bfOffBits + 3; //第一個(gè)像素的通道位置 int nHide; //成功隱藏的字節(jié)數(shù) //每次循環(huán)寫(xiě)入一個(gè)字節(jié),吸入alpha通道 //(pAlpha - pBuf) < m_fileHdr->bfSize這個(gè)是判斷字符串是太大,圖片不能隱藏 for (nHide = 0; (pAlpha - pBuf) < m_fileHdr->bfSize && szStr2Hide[nHide] != 0; nHide++, pAlpha += 4) { *pAlpha = szStr2Hide[nHide]; //寫(xiě)入一個(gè)字節(jié) } return true;}void CBMPHide::showStringInBmp(char* szBmpFIleName/*=NULL*/){ string sDstFileName=""; if (szBmpFIleName == 0) { sDstFileName = sBmpFileName + ".hide.bmp"; } else sDstFileName = szBmpFIleName; HANDLE hfile = CreateFileA(sDstFileName.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); if (hfile == INVALID_HANDLE_VALUE) { return; } DWORD dwSize = GetFileSize(hfile, 0); LPBYTE pBuf1 = new byte[dwSize]; DWORD dwRead = 0; ReadFile(hfile, pBuf1, dwSize, &dwRead, 0); CloseHandle(hfile); //文件內(nèi)容讀取到pBuf1中 BITMAPFILEHEADER *pHdr = (BITMAPFILEHEADER *)pBuf1; LPBYTE pStr = pBuf1 + pHdr->bfOffBits + 3; char szTmp[1280]; RtlZeroMemory(szTmp, 1280); for (int i = 0; i < 1280; i++) { if (*pStr == 0 || *pStr == 0xFF) { break; } szTmp[i] = *pStr; pStr += 4; } printf_s(szTmp); delete[]pBuf1;}main.h#include <stdio.h>#include "dwBmpSize.h"int main(){ CBMPHide hide; hide.setBmpFileName("test.bmp"); printf_s("test.bmp width:%d,height:%d,bitCount%d/n", hide.getBmpWidth(), hide.getBmpHeight(), hide.getBmpBitCount()); hide.hideString2BMP("Hello Word"); hide.save(); hide.showStringInBmp("test.bmp.hide.bmp"); getchar(); return 0;}程序運(yùn)行結(jié)果如下:
在此不一一舉出。
在這里:可能出現(xiàn)特殊情況,比如寫(xiě)入了0或oxFF(判斷自有數(shù)據(jù)是否結(jié)束標(biāo)志)
在下面一節(jié)中,我們解決這個(gè)問(wèn)題,并且,把一個(gè)不大的txt文本插入到圖片里面去。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注