将文件内容隐藏到png图片中
来源:互联网 发布:finebi商业智能软件 编辑:程序博客网 时间:2024/05/22 08:21
要想更好的实现该功能,你可以阅读将文件内容隐藏到bmp图片中
要实现这个功能,你得了解png文件的格式,详情:http://www.w3.org/TR/PNG/
实现原理:
png文件格式包括固定的文件头部+ 必要的数据块和辅助数据块
每一个数据块包括四个字节的数据块数据长度,4个字节的类型码,可变长度的数据块数据,4个字节的CRC
其中的IEND数据块为最后一块数据块,且默认情况下是不存储数据的,除非人为加入,我们就可以将自己的数据
写入到IEND的数据块数据区域
隐藏实现思路:
1、解析png文件格式(为了验证后期的数据的正确性,也为了学习png格式)
2、获取隐藏文件的大小
3、修改IEND数据块的数据长度信息
4、写入png文件的其它信息,直到IEND数据块的数据区域
5、写入隐藏文件的内容
6、写入IEND数据块的CRC信息(该处记录要隐藏文件的大小,方便恢复数据时使用)
恢复隐藏数据实现思路:
1、定位到png格式中IEND数据块的CRC,获取其值
2、根据获取到的值,定位到写入隐藏文件数据的开始位置
3、读取隐藏文件的数据,直到遇到IEND数据块的CRC
下面给出关键代码:
package com.pan.utils;import java.io.BufferedInputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import com.pan.entity.CommonBlock;import com.pan.entity.DataBlock;import com.pan.entity.Png;import com.pan.entity.PngHeader;import com.pan.factory.BlockFactory;/** * @author yp2 * @date 2015-11-19 * @decription 隐藏文件内容到png格式图片中 */public class PngUtil {/** * 读取指定png文件的信息 * @param pngFileName * @return * @throws IOException */private static Png readPng(String pngFileName) throws IOException {Png png = new Png();File pngFile = new File(pngFileName);InputStream pngIn = null;//记录输入流读取位置(字节为单位)long pos = 0;try {pngIn = new FileInputStream(pngFile);//读取头部信息PngHeader pngHeader = new PngHeader();pngIn.read(pngHeader.getFlag());png.setPngHeader(pngHeader);pos += pngHeader.getFlag().length;while(pos < pngFile.length()) {DataBlock realDataBlock = null;//读取数据块DataBlock dataBlock = new CommonBlock();//先读取长度,4个字节pngIn.read(dataBlock.getLength());pos += dataBlock.getLength().length;//再读取类型码,4个字节pngIn.read(dataBlock.getChunkTypeCode());pos += dataBlock.getChunkTypeCode().length;//如果有数据再读取数据//读取数据realDataBlock = BlockFactory.readBlock(pngIn, png, dataBlock);pos += ByteUtil.highByteToInt(dataBlock.getLength());//读取crc,4个字节pngIn.read(realDataBlock.getCrc());//添加读取到的数据块png.getDataBlocks().add(realDataBlock);pos += realDataBlock.getCrc().length;dataBlock = null;}} catch (IOException e) {e.printStackTrace();throw e;} finally {try {if(pngIn != null) {pngIn.close();}} catch (IOException e) {e.printStackTrace();throw e;}}return png;}/** * 将读取到的文件信息写入到指定png的文件中,并指定输出文件 * @param pngPng信息对象 * @param pngFileNamepng文件名 * @param inputFileName要隐藏的文件名 * @param outFileName输出文件名,内容包括png数据和要隐藏文件的信息 * @throws IOException */private static void wirteFileToPng(Png png, String pngFileName, String inputFileName, String outFileName) throws IOException {File pngFile = new File(pngFileName);File inputFile = new File(inputFileName);File outFile = new File(outFileName);InputStream pngIn = null;InputStream inputIn = null;OutputStream out = null;int len = -1;byte[] buf = new byte[1024];try {if(!outFile.exists()) {outFile.createNewFile();}pngIn = new FileInputStream(pngFile);inputIn = new FileInputStream(inputFile);out = new FileOutputStream(outFile);//获取最后一个数据块,即IEND数据块DataBlock iendBlock = png.getDataBlocks().get(png.getDataBlocks().size() - 1);//修改IEND数据块数据长度:原来的长度+要隐藏文件的长度long iendLength = ByteUtil.highByteToLong(iendBlock.getLength());iendLength += inputFile.length();iendBlock.setLength(ByteUtil.longToHighByte(iendLength, iendBlock.getLength().length));//修改IEND crc信息:保存隐藏文件的大小(字节),方便后面读取png时找到文件内容的位置,并读取iendBlock.setCrc(ByteUtil.longToHighByte(inputFile.length(), iendBlock.getCrc().length));//写入文件头部信息out.write(png.getPngHeader().getFlag());//写入数据块信息String hexCode = null;for(int i = 0; i < png.getDataBlocks().size(); i++) {DataBlock dataBlock = png.getDataBlocks().get(i);hexCode = ByteUtil.byteToHex(dataBlock.getChunkTypeCode(), 0, dataBlock.getChunkTypeCode().length);hexCode = hexCode.toUpperCase();out.write(dataBlock.getLength());out.write(dataBlock.getChunkTypeCode());//写数据块数据if(BlockUtil.isIEND(hexCode)) {//写原来IEND数据块的数据if(dataBlock.getData() != null) {out.write(dataBlock.getData());}//如果是IEND数据块,那么将文件内容写入IEND数据块的数据中去len = -1;while((len = inputIn.read(buf)) > 0) {out.write(buf, 0, len);}} else {out.write(dataBlock.getData());}out.write(dataBlock.getCrc());}} catch (Exception e) {e.printStackTrace();throw e;} finally {try {if(pngIn != null) {pngIn.close();}if(inputIn != null) {inputIn.close();}if(out != null) {out.close();}} catch (IOException e) {e.printStackTrace();throw e;}}}/** * 将指定的文件信息写入到png文件中,并输出到指定的文件中 * @param pngFileNamepng文件名 * @param inputFileName要隐藏的文件名 * @param outFileName输出文件名 * @throws IOException */public static void writeFileToPng(String pngFileName, String inputFileName, String outFileName) throws IOException {Png png = readPng(pngFileName);wirteFileToPng(png, pngFileName, inputFileName, outFileName);}/** * 读取png文件中存储的信息,并写入到指定指定输出文件中 * @param pngFileNamepng文件名 * @param outFileName指定输出文件名 * @throws IOException */public static void readFileFromPng(String pngFileName, String outFileName) throws IOException {File pngFile = new File(pngFileName);File outFile = new File(outFileName);InputStream pngIn = null;OutputStream out = null;//记录输入流读取位置long pos = 0;int len = -1;byte[] buf = new byte[1024];try {if(!outFile.exists()) {outFile.createNewFile();}pngIn = new BufferedInputStream(new FileInputStream(pngFile));out = new FileOutputStream(outFile);DataBlock dataBlock = new CommonBlock();//获取crc的长度信息,因为不能写死,所以额外获取一下int crcLength = dataBlock.getCrc().length;byte[] fileLengthByte = new byte[crcLength];pngIn.mark(0);//定位到IEND数据块的crc信息位置,因为写入的时候我们往crc写入的是隐藏文件的大小信息pngIn.skip(pngFile.length() - crcLength);//读取crc信息pngIn.read(fileLengthByte);//获取到隐藏文件的大小(字节)int fileLength = ByteUtil.highByteToInt(fileLengthByte);//重新定位到开始部分 pngIn.reset();//定位到隐藏文件的第一个字节pngIn.skip(pngFile.length() - fileLength - crcLength);pos = pngFile.length() - fileLength - crcLength;//读取隐藏文件数据while((len = pngIn.read(buf)) > 0) {if( (pos + len) > (pngFile.length() - crcLength) ) {out.write(buf, 0, (int) (pngFile.length() - crcLength - pos));break;} else {out.write(buf, 0, len);}pos += len;}} catch (IOException e) {e.printStackTrace();throw e;} finally {try {if(pngIn != null) {pngIn.close();}if(out != null) {out.close();}} catch (IOException e) {e.printStackTrace();throw e;}}}public static void main(String[] args) throws IOException {String filePath = PngUtil.class.getClassLoader().getResource("resource/sound_wav.png").getPath();Png png = readPng(filePath);wirteFileToPng(png, filePath, PngUtil.class.getClassLoader().getResource("resource/").getPath() + "screct.txt",PngUtil.class.getClassLoader().getResource("resource/").getPath() + "sound_wavout.png");readFileFromPng(PngUtil.class.getClassLoader().getResource("resource/").getPath() + "sound_wavout.png",PngUtil.class.getClassLoader().getResource("resource/").getPath() + "sound_wavscrect.txt");System.out.println(ByteUtil.byteToHexforPrint(png.getPngHeader().getFlag(), 0, png.getPngHeader().getFlag().length));for(DataBlock dataBlock : png.getDataBlocks()) {System.out.println(ByteUtil.byteToHexforPrint(dataBlock.getLength(), 0, dataBlock.getLength().length));System.out.println(ByteUtil.byteToHexforPrint(dataBlock.getChunkTypeCode(), 0, dataBlock.getChunkTypeCode().length));if(dataBlock.getData() != null) {System.out.println(ByteUtil.byteToHexforPrint(dataBlock.getData(), 0, dataBlock.getData().length));}System.out.println(ByteUtil.byteToHexforPrint(dataBlock.getCrc(), 0, dataBlock.getCrc().length));}System.out.println();}}
package com.pan.factory;import java.io.IOException;import java.io.InputStream;import com.pan.entity.DataBlock;import com.pan.entity.IDATBlock;import com.pan.entity.IENDBlock;import com.pan.entity.IHDRBlock;import com.pan.entity.PHYSBlock;import com.pan.entity.PLTEBlock;import com.pan.entity.Png;import com.pan.entity.SRGBBlock;import com.pan.entity.TEXTBlock;import com.pan.entity.TRNSBlock;import com.pan.utils.BlockUtil;import com.pan.utils.ByteUtil;/** * @author yp2 * @date 2015-11-19 * @description 数据块工厂 */public class BlockFactory {/** * 读取输入流中的数据块的数据 * @param in 输入流 * @param pngpng对象 * @param dataBlock数据块 * @return具体细节的数据块 * @throws IOException */public static DataBlock readBlock(InputStream in, Png png, DataBlock dataBlock) throws IOException {String hexCode = ByteUtil.byteToHex(dataBlock.getChunkTypeCode(), 0, dataBlock.getChunkTypeCode().length);hexCode = hexCode.toUpperCase();DataBlock realDataBlock = null;if(BlockUtil.isIHDR(hexCode)) {//IHDR数据块realDataBlock = new IHDRBlock();} else if(BlockUtil.isPLTE(hexCode)) {//PLTE数据块realDataBlock = new PLTEBlock();} else if(BlockUtil.isIDAT(hexCode)) {//IDAT数据块realDataBlock = new IDATBlock();} else if(BlockUtil.isIEND(hexCode)) {//IEND数据块realDataBlock = new IENDBlock();} else if(BlockUtil.isSRGB(hexCode)) {//sRGB数据块realDataBlock = new SRGBBlock();} else if(BlockUtil.istEXt(hexCode)) {//tEXt数据块realDataBlock = new TEXTBlock();} else if(BlockUtil.isPHYS(hexCode)) {//pHYs数据块realDataBlock = new PHYSBlock();} else if(BlockUtil.istRNS(hexCode)) {//tRNS数据块realDataBlock = new TRNSBlock();} else {//其它数据块realDataBlock = dataBlock;}realDataBlock.setLength(dataBlock.getLength());realDataBlock.setChunkTypeCode(dataBlock.getChunkTypeCode());//读取数据,这里的测试版做法是: 把所有数据读取进内存来int len = -1;byte[] data = new byte[8096];len = in.read(data, 0, ByteUtil.highByteToInt(dataBlock.getLength()));realDataBlock.setData(ByteUtil.cutByte(data, 0, len));return realDataBlock;}}
源码下载:源码
0 0
- 将文件内容隐藏到png图片中
- 将文件隐藏到图片中
- 将文件隐藏到图片
- 如何将文字隐藏到图片中
- 将文件秘密隐藏在图片中
- 如何将文件隐藏在图片中
- 如何将文件隐藏在图片中
- 将UIWebView内容保存为png图片
- 将UIImage对象保存到JPG或者PNG文件中
- 将内容写入到文件中
- 将任意文件隐藏到一张图片内
- 将文件内容隐藏在bmp位图中
- 将xxx.rar隐藏到一张图片中
- 将压缩包隐藏在图片文件中
- 利用DOS命令将txt文件隐藏在图片中
- png图片像素隐藏
- 将'文件1'的内容复制到'文件2'中
- 将assets文件中内容复制到SDCard中
- 在textarea指定位置插入字符或表情
- linux设置ip地址以及dns
- Android实现全屏显示的方法
- Hadoop2.5.2 HA高可靠性集群搭建(Hadoop+Zookeeper)
- 使用OpenGL和GLUT,结合双缓冲区生成动画
- 将文件内容隐藏到png图片中
- Oracle 增加修改删除字段
- [转]淘宝内部分享:怎么跳出MySQL的10个大坑
- mybatis用$和用#的区别
- Proguard混淆Android项目所遇问题及总结
- 记录
- java 排序
- js中与Java代码及ajax的执行顺序问题
- yum安装已经下载的包以及只下载不安装