`
zhaozj02
  • 浏览: 35928 次
  • 性别: Icon_minigender_1
  • 来自: 青岛
文章分类
社区版块
存档分类
最新评论

Java实现在bmp图像文件中隐藏与导出信息

阅读更多
文章来源:【http://tech.sina.com.cn/s/2008-07-04/0923720265.shtml】


BMP图像文件,即所谓的位图文件。在位图中,其表示方式是将一幅图像分割成栅格,栅格的每一点称为像素,每一个像素具有自己的RGB值,以此构成图形。所以从本质上讲,一幅位图不过是由一系列像素点构成的点阵罢了。

  位图文件支持4位RLE(行程长度编码)以及8位和24位编码。本人在此类中只处理了24位格式。

  24位BMP图像文件的结构特点为:

  (1)每个文件只能非压缩地存放一幅彩色图像;

  (2)文件头由54个字节的数据段组成,其中包含有该位图文件的类型、大小、图像尺寸及打印格式等;

  (3)从第55个字节开始,是该文件的图像数据部分,数据的排列顺序以图像的左下角为起点,从左到右、从下到上,每连续3个字节便描述图像一个像素点的颜色信息,这三个字节分别代表蓝、绿、红三基色在此像素中的亮度,若某连续三个字节为:00H,00H,FFH,则表示该像素的颜色为纯红色。

  要将文件隐藏在图片中,有两种模型方法可供参考:

  一是将文件附在载体图片之后,利用BMP文件的特殊性质(系统在读取BMP文件的时候,是读取它的第3~6个字节为文件长度,对超出这个长度的部分会忽略),将目标图片的二进制文件直接附着在载体之后,来实现文件的隐藏,此方法简单易行,不会破坏载体与目标图片的任何信息,且对隐藏文件的大小没有限制,但隐蔽性有待加强。

  二是采用LSB算法,将所得目标文件化整为零分别隐藏在载体的位图信息的每个字节的最低位,使得文件的隐蔽性大大提高,但可能因为载体的容量有限导致目标文件无法装入且对隐藏文件的长度且有严格限制,此时一是用无损压缩的办法使隐藏文件变小,二是放大载体图像,三是增加在载体文件每字节存放的位数。

  但这两种模型的优缺点在一定程度上可以互补,对于实际问题,可根据特定情况将以上两种想法结合起来,得到更理想的模型,即当载体图片大小满足做法二的要求时,则按位加入,否则将剩余的二进制位按照第一种做法直接加在载体图片后。

  (1)模型1 ——尾部附加法。通过对BMP图像文件的数据结构的分析在BMP图像的头文件中有指示文件大小的数值bfSIZE。它指定了一般的图片浏览器所能读取的范围。若不改变该数值的大小,则一般的图片浏览器只能够读取原文件。即便在该文件的尾部接上其他的文件,图片浏览器所显示的仍然只是原文件。这就相当于把后续文件给屏蔽掉了,可以达到隐藏信息的目的。一旦图片被截获者截获,一般的图片浏览器对图片的读取也只能进行到载体部分,目标图片不会被暴露出来,达到隐藏的效果。

  (2)模型2 ——内部嵌入法。对第一种模型的不足,即截获者可以用一些特殊方式发觉载体图片隐藏着一些信息,那么隐蔽性就大打折扣。通过研究发现,对一幅用多比特值表示其灰度的图像来说,其中每个比特可看作表示了一个二值平面,也称作“位面”。“1幅灰度级用8bit表示的图像有8个位面,一般用0代表最低位面,位面7代表最高位面。基本上5个最高面含有视觉可见的有意义的信息,在其余的位面中几乎没有任何视觉信息,这些位面所显示的只是图像中很细小的局部,在很多情况下,它们可看作噪声”正因为图像具有位面这种性质,因此信息往往隐藏在不为人视觉所察觉的位置,这样位面就为信息隐藏提供了一种很好的实施方案。将信息隐藏在这些看似噪声的位置,其对图像的破坏就不会太大,当然,在嵌入信息之前,首先要选择好信息具体加入的位面位置,不能将信息加入在存在图像视觉信息的位面上,因此,一般的LSB算法中,信息一般加在图像的后4位。

  (1)嵌入秘密信息的具体步骤:

  第一步:读入载体文件,并显示它;

  第二步:决定载体的LSB及嵌入的位数,本文采用嵌入图像中所有象素的最后一位,即第8位;

  第三步:对载体图像做预处理,置其LSB为0;

  第四步:将秘密信息以ACILL码的形式读入,并存储;

  第五步:在每一个象素的第LSB位上,存储秘密信息的一个bit;

  第六步:显示嵌入秘密文件的图像;

  (2)读取秘密信息的具体步骤:

  第一步:读入含有秘密文件的图像;

  第二步:得到每一个象素点的LSB位;

  第三步:由每8个LSB位组成一个ASILL还原秘密信息。

  实现起来其实很简单,无论使用哪种理论模型,大体都是利用数据偏移罢了,偶用的内部嵌入法,大家可以根据自己的需要变更偶的代码,也欢迎大家创造的隐藏方法,那位大侠有时间更改的话给偶也寄一份,我的Email:ceponline@yahoo.com.cn。

  本类从功能上讲,可以把任意文件(不能超过bmp文件大小)隐藏到BMP图片中,图片大小基本不变,浏览图片也看不出变化。当然,也可以把隐藏在图片中的文件提取出来。

  代码如下,由3个类构成:

  BitmapInput.java

  package org.loon.framework.test.encode;
  import java.awt.image.BufferedImage;
  /** *//**
  * * Title: LoonFramework
  * Description:
  *
  * Copyright: Copyright (c) 2007
  *
  * Company: LoonFramework
  *
  * @author chenpeng
  * @email:ceponline@yahoo.com.cn
  * @version 0.1
  */
  public class BitmapInput {
  private BufferedImage _bmp;
  private int curX, curY, iRGB;
  private int bitsLeft;
  public BitmapInput(BufferedImage bmp) {
  curX = curY = iRGB = 0;
  this._bmp = bmp;
  bitsLeft = bmp.getHeight() * bmp.getWidth() * 3;
  }
  public BufferedImage getBufferedImage() {
  return _bmp;
  }
  public synchronized Object[] readByte(int body) {
  body = 0;
  if (bitsLeft < {
  return new Object[] { "false", "0" };
  }
  int bit = 0;
  int bits2Do = 8;
  for (; curX < _bmp.getWidth(); curX++) {
  if (curY >= _bmp.getHeight())
  curY = 0;
  for (; curY < _bmp.getHeight(); curY++) {
  if (bits2Do == 0) {
  return new Object[] { "true", String.valueOf(body) };
  }
  int rgb = _bmp.getRGB(curX, curY);
  int r = (rgb & 0x00ff0000) >> 16;
  int g = (rgb & 0x0000ff00) >> 8;
  int b = (rgb & 0x000000ff);
  while(true) {
  switch (iRGB) {
  case 0:
  bit = (r & 1);
  break;
  case 1:
  bit = (g & 1);
  break;
  case 2:
  bit = (b & 1);
  break;
  }
  --bits2Do;
  --bitsLeft;
  body |= (int) (bit << 7);
  if (bits2Do != 0) {
  body >>= 1;
  }
  if (iRGB == 2) {
  iRGB = 0;
  break;
  }
  iRGB++;
  if (bits2Do == 0) {
  return new Object[] { "true", String.valueOf(body) };
  }
  }
  }
  }
  return new Object[] { "true", String.valueOf(body) };
  }
  }

  BitmapOutput.java

  package org.loon.framework.test.encode;
  import java.awt.image.BufferedImage;
  /** *//**
  * Title: LoonFramework
  *
  * Description:
  *
  * Copyright: Copyright (c) 2007
  *
  * Company: LoonFramework
  * @author chenpeng
  * @email:ceponline@yahoo.com.cn
  * @version 0.1
  */
  public class BitmapOutput {
  private BufferedImage _bmp;
  private int curX, curY, iRGB;
  private int bitsLeft;
  private int r, g, b;
  public BitmapOutput(BufferedImage bmp) {
  this._bmp = bmp;
  curX = curY = iRGB = 0;
  bitsLeft = (bmp.getHeight() * bmp.getWidth() * 3);
  }
  public BufferedImage getBufferedImage() {
  return _bmp;
  }
  public synchronized boolean writeByte(int body) {
  if (bitsLeft <
  return false;
  int bits2Do = 8;
  for (; curX < _bmp.getWidth(); curX++) {
  if (curY >= _bmp.getHeight()) {
  curY = 0;
  }
  for (; curY < _bmp.getHeight(); curY++) {
  if (bits2Do == 0)
  return true;
  int rgb = _bmp.getRGB(curX, curY);
  //转化为r,g,b格式

  r = (rgb & 0x00ff0000) >> 16;
  g = (rgb & 0x0000ff00) >> 8;
  b = (rgb & 0x000000ff);
  while (true) {
  int curBit = (body & 1);
  switch (iRGB) {
  case 0:
  r = (r & 0xFE);
  r |= curBit;
  break;
  case 1:
  g = (g & 0xFE);
  g |= curBit;
  break;
  case 2:
  b = (b & 0xFE);
  b |= curBit;
  break;
  }
  --bits2Do;
  --bitsLeft;
  body >>= 1;
  //还原

  rgb = (r << 16) | (g << | b;
  //重新注入

  _bmp.setRGB(curX, curY, rgb);
  if (iRGB == 2) {
  iRGB = 0;
  break;
  }
  iRGB++;
  if (bits2Do == 0)
  return true;
  }
  }
  }
  return true;
  }
  }

  BitmapExecute.java

  package org.loon.framework.test.encode;
  import java.awt.image.BufferedImage;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.util.Iterator;
  import javax.imageio.ImageIO;
  import javax.imageio.ImageWriter;
  import javax.imageio.stream.ImageOutputStream;
  /** *//**
  *
  * Title: LoonFramework
  *
  * Description: 利用bmp文件进行数据的隐藏与导出
  *
  * Copyright: Copyright (c) 2007
  *
  * Company: LoonFramework
  *
  *
  * @author chenpeng
  * @email:ceponline@yahoo.com.cn
  * @version 0.1
  */
  public class BitmapExecute {
  /** *//**
  * 将BufferedImage转化为bmp文件保存在指定位置
  *
  * @param image
  * @param file
  * @return
  */
  private static boolean saveBMP(BufferedImage image, File file) {
  // 格式化为bmp文件

  Iterator writers = ImageIO.getImageWritersByFormatName("bmp");
  ImageWriter writer = (ImageWriter) writers.next();
  ImageOutputStream ios = null;
  try {
  ios = ImageIO.createImageOutputStream(new FileOutputStream(file));
  } catch (IOException ioe) {
  return false;
  }
  writer.setOutput(ios);
  try {
  writer.write(image);
  } catch (IOException ioe) {
  return false;
  }
  return true;
  }
  /** *//**
  * 将数据文件隐藏入bmp文件中
  *
  * @param dataFileName
  * @param bmpFileName
  * @param outFileName
  * @return
  * @throws IOException
  */
  public static boolean DataSourceToBMP(String dataFileName,
  String bmpFileName, String outFileName) throws IOException {
  return DataSourceToBMP(new File(dataFileName), new File(bmpFileName),
  outFileName);
  }
  /** *//**
  * 将数据文件隐藏入bmp文件中
  *
  * @param dataFileName
  * @param bmpFileName
  * @param outFileName
  * @return
  * @throws IOException
  */
  public static boolean DataSourceToBMP(File dataFile, File bmpFile,
  String outFileName) throws IOException {
  FileInputStream dataStream = new FileInputStream(dataFile);
  BufferedImage bmp;
  try {
  bmp = ImageIO.read(bmpFile);
  } catch (Exception ex) {
  return false;
  }
  if (dataStream.available() == 0) {
  return false;
  }
  int maxByteStorage = (bmp.getHeight() * bmp.getWidth() * 3) / 8;
  // bmp文件必须较要隐藏的文件为大,否则无法注入文件

  if (maxByteStorage < dataStream.available() + 500) {
  return false;
  }
  BitmapOutput bmpWriter = new BitmapOutput(bmp);
  int dataSize = dataStream.available();
  try {
  for (int u = 0; u < 500; u++) {
  bmpWriter.writeByte(dataSize);
  }
  // 标记出完整数据

  bmpWriter.writeByte(91);
  for (int u = 0; u < dataSize; u++) {
  int result = dataStream.read();
  if (result == 91) {
  bmpWriter.writeByte(123);
  } else if (result == 93) {
  bmpWriter.writeByte(125);
  } else {
  bmpWriter.writeByte(result);
  }
  }
  bmpWriter.writeByte(93);
  } catch (Exception ex) {
  ex.getStackTrace();
  return false;
  }
  try {
  File file = new File(outFileName);
  if (file.exists()) {
  file.delete();
  }
  // 保存BufferedImage为bmp文件

  saveBMP(bmpWriter.getBufferedImage(), new File(outFileName));
  } catch (Exception ex) {
  ex.getStackTrace();
  return false;
  }
  return true;
  }
  /** *//**
  * 从bmp文件中导出隐藏数据(由于隐藏数据的方式不同,只对此类隐藏的有效)
  *
  * @param bmpFileName
  * @param outFName
  * @return
  * @throws IOException
  */
  public static boolean BMPToDataSource(String bmpFileName, String outFName)
  throws IOException {
  return BMPToDataSource(new File(bmpFileName), outFName);
  }
  /** *//**
  * 从bmp文件中导出隐藏数据(由于隐藏数据的方式不同,只对此类隐藏的有效)
  *
  * @param bmpFile
  * @param outFName
  * @return
  * @throws IOException
  */
  public static boolean BMPToDataSource(File bmpFile, String outFName)
  throws IOException {
  BufferedImage image = ImageIO.read(bmpFile);
  BitmapInput bmpReader;
  try {
  bmpReader = new BitmapInput(image);
  } catch (Exception ex) {
  return false;
  }
  FileOutputStream outStream;
  try {
  File file = new File(outFName);
  if (!file.exists()) {
  file.createNewFile();
  }
  outStream = new FileOutputStream(file);
  } catch (Exception ex) {
  return false;
  }
  int dataSize = 0;
  int outByte = 0;
  int count = 0;
  try {
  for (int u = 0; u < 500; u++) {
  // 以对象数组返回body和验证布尔值

  Object[] object = bmpReader.readByte(outByte);
  boolean header = Boolean.parseBoolean((String) object[0]);
  outByte = Integer.parseInt((String) object[1]);
  if (!header) {
  throw new Exception();
  }
  dataSize |= (int) (outByte << 8 * 3);
  if (u != 3) {
  dataSize >>= 8;
  }
  }
  for (int u = 0; u < dataSize; u++) {
  Object[] object = bmpReader.readByte(outByte);
  boolean header = Boolean.parseBoolean((String) object[0]);
  outByte = Integer.parseInt((String) object[1]);
  if (!header) {
  throw new Exception();
  }
  if (outByte == 93) {
  return true;
  }
  if (outByte == 91) {
  count += 1;
  }
  if (count > 0) {
  if (outByte == 123) {
  outStream.write(91);
  } else if (outByte != 91) {
  outStream.write(outByte);
  }
  }
  }
  } catch (Exception ex) {
  return false;
  } finally {
  try {
  outStream.flush();
  outStream.close();
  outStream = null;
  } catch (IOException e) {
  e.printStackTrace();
  }
  }
  return true;
  }
  }

  测试用类,BMPHiedData.java:

  package org.loon.framework.test.encode;
  import java.io.IOException;
  /** *//**
  *Title: LoonFramework
  *Description:利用bmp文件隐藏数据
  *Copyright: Copyright (c) 2007
  *Company: LoonFramework
  * @author chenpeng
  * @email:ceponline@yahoo.com.cn
  * @version 0.1
  */
  public class BMPHiedData {
  public static void main(String[]args){
  //导出为bmp

  try {
  //参数分别为:
  //1.要隐藏的数据
  //2.隐藏数据用图
  //3.导出位置

  BitmapExecute.DataSourceToBMP( "c:/temp/txt.txt","c:/temp/12193.BMP", "c:/temp/temp.bmp");
  } catch (IOException e) {
  e.printStackTrace();
  }
  //导出bmp中隐藏的数据

  try {
  //参数分别为:
  //1.隐藏数据用图
  //2.导出数据位置

  BitmapExecute.BMPToDataSource("c:/temp/temp.bmp", "c:/temp/txt_temp.txt");
  } catch (IOException e) {
  e.printStackTrace();
  }
  }
  }
分享到:
评论

相关推荐

    Java实现在bmp图像文件中隐藏与导出信息.doc

    Java 实现 BMP 图像文件中的信息隐藏与导出主要涉及到图像处理和数据隐藏技术。BMP 是一种常见的位图文件格式,它的结构由文件头和图像数据两部分组成。文件头包含了关于图像的元信息,如文件大小、图像尺寸等,而...

    BMP图的绘制和保存,EXCEL报表的导出

    在描述中提到的“BMP图的绘制和保存”,可能是指在应用程序中创建或修改BMP图像,并将其保存到本地文件系统。 首先,要绘制BMP图,你需要了解像素的概念以及如何通过编程语言来设置每个像素的颜色。例如,在C++中,...

    图片转化单色,位深度为1的BMP文件

    在BMP文件结构中,数据部分是以行优先的方式存储,每行像素是右对齐的,不足的部分用0填充。 这个过程中可能遇到的问题包括图像边缘的锯齿效应、细节丢失、文字识别困难等。解决这些问题可能需要使用更复杂的算法,...

    JAVA数字图像处理常用算法.pdf

    在Java中处理BMP图像通常需要读取文件头和信息头来获取图像的元数据,例如宽度、高度、位深和图像数据大小等信息。 2. Java文件I/O操作 在文档中,使用了FileInputStream来打开和读取BMP文件。FileInputStream是...

    把真彩色BMP位图转化为二维数组

    在计算机编程与图像处理领域,将BMP格式的位图转换为二维数组是一项非常实用的技术。这种技术不仅能够帮助开发者更好地理解和操作图像数据,还在诸如机器人视觉识别等应用中扮演着重要角色。 #### BMP格式简介 BMP...

    利用GDAL把TIF文件转换为bmp,png等格式图片并对图片进行压缩

    在IT行业中,图像处理是一项非常重要的任务,尤其是在地理信息系统(GIS)和遥感领域。GDAL(Geospatial Data Abstraction Library)是一个强大的开源库,它支持多种地理空间数据格式,包括TIFF(Tagged Image File ...

    代码控制导出OBJ

    在代码实现OBJ导出时,你需要指定一个目标路径,以便保存生成的OBJ文件。这通常涉及到操作系统相关的文件操作API,如在Windows上使用`CreateFile`,在Unix系统上使用`open`函数。确保路径是绝对路径或相对于程序...

    BMP格式转换为JPG格式!!

    2. **解码BMP图像数据**:BMP数据通常是RGB格式,即红绿蓝三原色的像素值,按照特定顺序排列。根据颜色深度,可能每个像素由8、16、24或32位表示。 3. **颜色空间转换**:在转换前,有时需要进行颜色空间转换,比如...

    java制作工作证和调用斑马打印.rar

    在Java中,可以使用`java.awt`和`java.awt.image`包中的类来创建和操作BMP图像。开发者可能使用了`BufferedImage`类来创建图像,然后通过`Graphics2D`对象绘制文本、图像和其他元素到工作证的模板上。这包括员工的...

    sql server中的image类型的数据导出到oracle的clob字段中

    我们使用了 Java 语言和 JDBC 驱动程序来实现数据的导出,并将 Image 类型数据写到文件中,然后将文件中的数据读取出来,并将其设置到 Oracle 的 CLOB 字段中。这种方法可以帮助我们实现不同数据库管理系统之间的...

    基于AE输出JPG等格式的图片

    值得注意的是,代码中使用了`ExportJPEG`和`ExportBMP`类来实现不同格式的图像导出。这些类可能来自于某种第三方库或自定义的封装,专门用于处理AE图像的导出工作。在实际应用中,开发者需要确保导入了正确的命名...

    屏幕截图成bmp-jpg

    JPG(JPEG)则是一种有损压缩的图像格式,它通过丢弃人眼难以察觉的图像数据来实现文件的小型化。JPG格式广泛用于网络图像和照片,因为它能以相对较小的文件大小提供较高的视觉质量。然而,多次保存为JPG格式可能会...

    jpg转换bmp图片

    在图像处理领域,格式转换是常见的操作之一,例如将.jpg(JPEG)格式的图片转换为.bmp(Bitmap)格式。这两种格式都有其特定的用途和特点,理解它们的区别和转换过程对于进行图像处理工作至关重要。 首先,JPEG...

    Java Jsp 调用ireport动态模板打印

    Java JSP调用iReport动态模板打印是一种在Web应用程序中实现报表打印的常见技术。iReport是一款开源的报表设计工具,它可以与Java、JSP、Servlets等进行集成,为开发者提供灵活的报表生成和打印功能。在这个场景下,...

    图片转点阵16进制数据工具

    总的来说,“图片转点阵16进制数据工具”是一个帮助开发者将BMP图像优化并适应低资源环境的实用工具,通过将图像转换为点阵数据和16进制格式,简化了嵌入式系统的图形处理工作。PCtoLCD2002作为这样一个工具,能够极...

    一个多功能Java画图板

    Java画图板是一种基于Java图形用户界面(GUI)技术实现的程序,允许用户在屏幕上绘制图形。这个"多功能Java画图板"项目可能是为教育、设计或者编程练习目的而创建的,它集成了多种功能,使得用户能够进行复杂的绘图...

    TestJava python java usm

    1. "dot_red.bmp" 和 "dot_green.bmp":这两个文件可能是位图图像,通常用于图形用户界面(GUI)中的指示器或图标,例如在测试过程中表示成功或失败的状态。 2. "TOPENG_CSP60_FOR_UNIX.csv":这是一个CSV(逗号...

    pdf-word-excel-ppt转bmp图片源码

    在IT行业中,转换文档格式是一项常见的任务,尤其在数据处理、报告制作以及信息共享时。本文将详细讨论如何将PDF、Word、Excel和PPT文档转换为BMP图片格式,这是一种广泛使用的位图图像格式。以下是对每个转换过程的...

    java游戏地图编辑器

    5. **地图导出与导入**:编辑器应提供将地图导出为游戏可读格式的功能,以便在游戏中使用。例如,`mapwin.exe`可能是一个用于查看或导出地图的实用程序。 6. **教程与帮助**:`游戏下载说明.txt`可能包含关于如何...

    jmagick-win-6.3.9-Q16

    `jmagick.dll`是一个动态链接库(Dynamic Link Library),它是JMagick在Windows系统中的实现,负责与Java虚拟机交互,执行底层的图像处理任务。而`jmagick.jar`则包含了JMagick的Java类库,提供了Java开发者所需的...

Global site tag (gtag.js) - Google Analytics