我们这一节用代码实现,把字符串藏入BMP文件,并且能正常读取出来。

看这篇的同学请先阅读第一篇了解理论:

http://blog.csdn.net/qq78442761/article/details/54863034

下面开始进入此节:

从上一节,我们知道了Bmp文件的结构,如下图所示:

其中最关键的两个结构体BITMAPFILEHEADER和BITMAPINFOHEADER,这里面保存了这个Bmp文件的很多信息。

恰好,Windows给我们提供了这个两个结构体,如下图所示:

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;

我们在到010Editor看看(图如下):

关于高度为负的问题,在第一节已经说明,不知道的同学请从文章最上面的链接进入第一节。在此不再说明。

那么问题就简单了,现在这个程序的思路就是:

1.用C/C++代码读取图片文件里面的这两个结构体。

2.读取这个文件到内存中。

3.获取bfOffBIts,再获取alpha通道(+4)。

4.把数据拆分,插入到alpha通道。

5.保存文件。

6.读取被修改文件的alpha通道,组合成字符串。

理论就是这么简单:

下面是程序源码打包下载地址:

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);    //设置Bmp文件名int getBmpWidth();    //获取宽度int getBmpHeight();   //获取高度int getBmpBitCount(); //获取Bit总数bool save();bool hideString2BMP(char* szStr2Hide); //隐藏String到BMP文件中void showStringInBmp(char* szBmpFIleName=NULL);   //展示
private:DWORD dwBmpSize;    //图片文件大小string sBmpFileName;LPBYTE pBuf;    //用于存放图片信息的内存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)  //如果已经生成就释放掉{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的大小应该是一样的。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;  //成功话就是文件的内容读取到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;
}
//隐藏一个字符串到图片中,把字符串拆成字节,写入每个像素的alpha通道中
bool CBMPHide::hideString2BMP(char* szStr2Hide)
{LPBYTE pAlpha = pBuf + m_fileHdr->bfOffBits + 3; //第一个像素的通道位置int nHide;  //成功隐藏的字节数//每次循环写入一个字节,吸入alpha通道//(pAlpha - pBuf) < m_fileHdr->bfSize这个是判断字符串是太大,图片不能隐藏for (nHide = 0; (pAlpha - pBuf) < m_fileHdr->bfSize && szStr2Hide[nHide] != 0; nHide++, pAlpha += 4){*pAlpha = szStr2Hide[nHide];   //写入一个字节}return true;
}void CBMPHide::showStringInBmp(char* szBmpFIleName/*=NULL*/)
{string sDstFileName="";if (szBmpFIleName == 0){sDstFileName = sBmpFileName + ".hide.bmp";}elsesDstFileName = 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);//文件内容读取到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;
}

程序运行结果如下:

在此不一一举出。

在这里:可能出现特殊情况,比如写入了0或oxFF(判断自有数据是否结束标志)

在下面一节中,我们解决这个问题,并且,把一个不大的txt文本插入到图片里面去。

C/C++信息隐写术(二)之字符串藏入BMP文件相关推荐

  1. C/C++信息隐写术(四)之大程序藏入BMP文件

    在阅读这篇文章时请先阅读第三篇,第三篇链接如下: http://blog.csdn.net/qq78442761/article/details/54893792 这一节里面我们要做的是 把一个exe ...

  2. [python爬虫] 招聘信息定时系统 (二).调用pyinstaller包生成exe文件

    前面一篇文章主要讲述,如何通过Python爬取招聘信息,且爬取的日期为前一天的,同时将爬取的内容保存到数据库中:这篇文章主要讲述如何将python文件压缩成exe可执行文件,供后面的操作.       ...

  3. C/C++信息隐写术(一)之认识文件结构

    所谓的隐写术就是在不"破坏"(指正常打开,并不指修改二进制文件)文件的情况下,把机密信息写入进文件,然后经过处理后,把文件的信息提取出来. 举一个例子: 在抗日战争时期,我方在偷取 ...

  4. 小程序生成带信息的二维码

    我的需求是,循环生成多个核销码,每个核销码自带字符串信息.注意,是要带信息,而不是单纯的生成二维码,但微信小程序并没有提供相应的生成二维码的接口. 此处提供两种解决方案: 方案一:采用weapp.qr ...

  5. 算法训练二(字符串、模式匹配、堆栈、队列)(含解题思路)(上)

    目录 7-1 好前缀 AC代码: 7-2 好后缀 AC代码: 7-3 [模板]KMP字符串匹配 AC代码: 7-5 接话茬 AC代码: 7-6 串的模式匹配 AC代码: 7-7 词频统计 AC代码: ...

  6. Java获取12306余票信息(二)

    接上 前面我们说到如何用Firefox浏览器抓取数据,并 对json进行了分析,下面就是用Java代码来进行操作.以下代码都没有导入包,有需要自行导入 Java获取12306余票信息(一) Java获 ...

  7. python:获取微信好友列表信息(二)进行导出微信好友到csv数据读取与处理

    接上一篇:https://blog.csdn.net/seoyundu/article/details/81543656 代码中:对csv文件读取,并利用pandas库处理,统计出好友信息. pand ...

  8. 数据结构与算法Java(二)——字符串、矩阵压缩、递归、动态规划

    不定期补充.修正.更新:欢迎大家讨论和指正 本文以数据结构(C语言版)第三版 李云清 杨庆红编著为主要参考资料,用Java来实现 数据结构与算法Java(一)--线性表 数据结构与算法Java(二)- ...

  9. 【C语言】动态分配二维字符串数组

    动态分配一个二维字符串数组 (1) 分配可能不连续的内存 申请 char**pps8Output = (char **) malloc(n * sizeof(char *)); 对于pps8Outpu ...

最新文章

  1. 详解 Python 如何将爬取到的数据分别存储到 txt、excel、mysql 中!
  2. 2022年,我该用JAX吗?GitHub 1.6万星,这个年轻的工具并不完美
  3. 13.配置 influxDB 鉴权及 HTTP API 写数据的方法
  4. Leet Code OJ 21. Merge Two Sorted Lists [Difficulty: Easy]
  5. java做一个客房管理系统定制_管理皮孩子很难?来,教你一个java设计简单的学生管理系统...
  6. java 集合(Set接口)
  7. MMU内存管理单元(看书笔记)
  8. mysql------explain工具
  9. 使用SQL Server数据工具进行SQL单元测试
  10. Kotlin 1.5 新特性:密封接口有啥用?
  11. 16.了解如何把vector和string数据传给旧的API
  12. mysql8 docker镜像源_Docker 搭建 MySQL 8版本
  13. 【项目实践】充电台灯电路拆解
  14. 应用之星教你制作高下载量的App
  15. SSM框架二手车交易网站源码+文档
  16. 秉火429笔记之十三 通信基本概念
  17. MakerDAO亚洲区负责人王奇君:我的DAI很稳!
  18. 2020电脑蓝屏代码大全
  19. ubuntu - 安装QQ国际版
  20. ESD防静电保护管PESDHC2FD4V5BH原装芯导Prisemi,DFN1006-2反向关断电压4.5V,箝位电压5.8V,PESDHC2FD4V5BH双向静电保护

热门文章

  1. 有了报表FineReport,为什么还要上FineBI?
  2. BlueCatTools 批量查询网站的百度收录量,快照和外链的工具
  3. 一颗接一颗的飞鸽传书
  4. 安静的飞鸽传书2011绿色版地方
  5. 如何实现开关CD-ROM
  6. 学习编程的过程中可能会走哪些弯路,有哪些经验可以参考?
  7. 一个程序员的逗逼瞬间(四)
  8. rpm安装mysql5.7.16_【CentOS 6.6 RPM方式安装MySQL 5.7.16 】
  9. git reset后本地拉取_Git 代码防丢指南
  10. 图像处理------图像细化