首先要实现这个功能,你必须知道bmp位图文件的格式,这里我就不多说了,请看:http://www.cnblogs.com/xiehy/archive/2011/06/07/2074405.html
接下来主要讲解实现的思路和源码:
实现思路:
根据bmp的文件的格式(记录了文件大小,文件数据的位置等信息)和读取文件内容的方式(只读取指定偏移点的数据),
可得出:当我们改变数据偏移点的值和文件的大小,将要隐藏的文件内容保存在头部到偏移点的区域即可。
实现步骤:
1、解析整个文件的格式信息
2、获取偏移点位置
3、定位到调色板结束位置,将文件数据插入到调色板结束位置后面
4、修改偏移位置,加上要隐藏文件的大小
5、重新写入文件中
读取文件步骤:
1、解析bmp文件格式
2、获取偏移位置end和比特/像素和颜色索引数目
3、定位到调色板的结束位置,即数据的开始位置start
4、读取start到end之间的数据到文件中,即为原来文件的内容
根据上述实现步骤,初步的实现已完成,后期完善某些不足之处,例读取位图信息时使用byte数组存储,
这样如果文件过大,可能会溢出
优化:
1、基本类型的字节的优化,避免强制转换
2、位图数据可以不存储,在需要写入的时候再去读原文件的位图数据部分
3、调色板数据在这个方法里也可以不存储,但其实不会很大,所以也没多大关系,可做可不做
4、抽除掉重复功能的代码
思考:
可以直接将文件数据写入到位图数据的最后面?
可以,这个更加的简单
实现步骤:
1、解析总的文件大小
2、读取bmp所有的数据到新的文件中
3、读取将要隐藏的文件的内容,写入到新的文件中
读取文件内容步骤:
1、解析出原来bmp文件的大小
2、将输入流读取位置跳到bmp文件尾
3、读取输入流中剩下的内容,写入到其它文件中即可
这种实现方式的关键在于解析bmp格式中记录的bmp文件的大小,其它什么都不需要获取,数据的隐藏性较差
重要源码:
package com.pan.entity;
/**
* @author yp2
* @date 2015-11-17
* @description Bmp文件格式
*/
public class Bmp {
private BmpHeader bmpHeader;
private BmpInfoHeader bmpInfoHeader;
private BmpPalette bmpPalette;
/**
* bmp位图数据
*/
private byte[] datas;
public BmpHeader getBmpHeader() {
return bmpHeader;
}
public void setBmpHeader(BmpHeader bmpHeader) {
this.bmpHeader = bmpHeader;
}
public BmpInfoHeader getBmpInfoHeader() {
return bmpInfoHeader;
}
public void setBmpInfoHeader(BmpInfoHeader bmpInfoHeader) {
this.bmpInfoHeader = bmpInfoHeader;
}
public BmpPalette getBmpPalette() {
return bmpPalette;
}
public void setBmpPalette(BmpPalette bmpPalette) {
this.bmpPalette = bmpPalette;
}
public byte[] getDatas() {
return datas;
}
public void setDatas(byte[] datas) {
this.datas = datas;
}
}
package com.pan.entity;
/**
* @author yp2
* @date 2015-11-17
* @description Bmp文件头部
*/
public class BmpHeader {
/**
* 文件的类型,2个字节
*/
private byte[] bfType;
/**
* 位图文件的大小,字节为单位,4个字节
*/
private byte[] bfSize;
/**
* 保留,2个字节
*/
private byte[] bfReserved1;
/**
* 保留,2个字节
*/
private byte[] bfReserved2;
/**
* 说明从文件开始到实际的图像数据之间的字节的偏移量
* 4个字节
*/
private byte[] bfOffBits;
public BmpHeader() {
bfType = new byte[2];
bfSize = new byte[4];
bfReserved1 = new byte[2];
bfReserved2 = new byte[2];
bfOffBits = new byte[4];
}
public byte[] getBfType() {
return bfType;
}
public void setBfType(byte[] bfType) {
this.bfType = bfType;
}
public byte[] getBfSize() {
return bfSize;
}
public void setBfSize(byte[] bfSize) {
this.bfSize = bfSize;
}
public byte[] getBfReserved1() {
return bfReserved1;
}
public void setBfReserved1(byte[] bfReserved1) {
this.bfReserved1 = bfReserved1;
}
public byte[] getBfReserved2() {
return bfReserved2;
}
public void setBfReserved2(byte[] bfReserved2) {
this.bfReserved2 = bfReserved2;
}
public byte[] getBfOffBits() {
return bfOffBits;
}
public void setBfOffBits(byte[] bfOffBits) {
this.bfOffBits = bfOffBits;
}
}
package com.pan.entity;
/**
* @author yp2
* @date 2015-11-17
* @description Bmp文件信息头部
*/
public class BmpInfoHeader {
/**
* 位图信息头部所需要的字数,4个字节
*/
private byte[] biSize;
/**
* 图像的宽度,像素为单位,4个字节
*/
private byte[] biWidth;
/**
* 图像的高度,像素为单位,4个字节
*/
private byte[] biHeight;
/**
* 为目标设备说明颜色平面数,其值将总是设为1,2个字节
*/
private byte[] biPlans;
/**
* 说明比特数/像素,其值为1、4、8、16、24、32,2个字节
*/
private byte[] biBitCount;
/**
* 说明图像数据压缩的类型,0 不压缩,4个字节
*/
private byte[] biCompression;
/**
* 说明图像的大小,字节为单位,当压缩格式为0时,可设置为0,4个字节
*/
private byte[] biSizeImage;
/**
* 说明水平分辨率,像素/米表示,有符号整数,4个字节
*/
private byte[] biXPelsPerMeter;
/**
* 说明垂直分辨率,像素/米表示,有符号整数,4个字节
*/
private byte[] biYPelsPerMeter;
/**
* 说明位图实际使用的彩色表中的颜色索引数,4个字节
*/
private byte[] biClrUsed;
/**
* 说明对图像显示有重要影响的颜色索引的数目,如果是0,表示都重要
* 4个字节
*/
private byte[] biClrImportant;
public BmpInfoHeader() {
biSize = new byte[4];
biWidth = new byte[4];
biHeight = new byte[4];
biPlans = new byte[2];
biBitCount = new byte[2];
biCompression = new byte[4];
biSizeImage = new byte[4];
biXPelsPerMeter = new byte[4];
biYPelsPerMeter = new byte[4];
biClrUsed = new byte[4];
biClrImportant = new byte[4];
}
public byte[] getBiSize() {
return biSize;
}
public void setBiSize(byte[] biSize) {
this.biSize = biSize;
}
public byte[] getBiWidth() {
return biWidth;
}
public void setBiWidth(byte[] biWidth) {
this.biWidth = biWidth;
}
public byte[] getBiHeight() {
return biHeight;
}
public void setBiHeight(byte[] biHeight) {
this.biHeight = biHeight;
}
public byte[] getBiPlans() {
return biPlans;
}
public void setBiPlans(byte[] biPlans) {
this.biPlans = biPlans;
}
public byte[] getBiBitCount() {
return biBitCount;
}
public void setBiBitCount(byte[] biBitCount) {
this.biBitCount = biBitCount;
}
public byte[] getBiCompression() {
return biCompression;
}
public void setBiCompression(byte[] biCompression) {
this.biCompression = biCompression;
}
public byte[] getBiSizeImage() {
return biSizeImage;
}
public void setBiSizeImage(byte[] biSizeImage) {
this.biSizeImage = biSizeImage;
}
public byte[] getBiXPelsPerMeter() {
return biXPelsPerMeter;
}
public void setBiXPelsPerMeter(byte[] biXPelsPerMeter) {
this.biXPelsPerMeter = biXPelsPerMeter;
}
public byte[] getBiYPelsPerMeter() {
return biYPelsPerMeter;
}
public void setBiYPelsPerMeter(byte[] biYPelsPerMeter) {
this.biYPelsPerMeter = biYPelsPerMeter;
}
public byte[] getBiClrUsed() {
return biClrUsed;
}
public void setBiClrUsed(byte[] biClrUsed) {
this.biClrUsed = biClrUsed;
}
public byte[] getBiClrImportant() {
return biClrImportant;
}
public void setBiClrImportant(byte[] biClrImportant) {
this.biClrImportant = biClrImportant;
}
}
package com.pan.entity;
/**
* @author yp2
* @date 2015-11-17
* @description Bmp调色板
*/
public class BmpPalette {
private byte[][] palettes; //颜色索引映射表
public byte[][] getPalettes() {
return palettes;
}
public void setPalettes(byte[][] palettes) {
this.palettes = palettes;
}
}
package com.pan.utils;
/**
* @author yp2
* @date 2015-11-18
* @description 字节操作工具
*/
public class ByteUtil {
/**
* 将byte数组转换为16进制字符串
*
* 实现思路:
* 先将byte转换成int,再使用Integer.toHexString(int)
* @param data byte数组
* @return
*/
public static String byteToHex(byte[] data, int start, int end) {
StringBuilder builder = new StringBuilder();
for(int i = start; i < end; i++) {
int tmp = data[i] & 0xff;
String hv = Integer.toHexString(tmp);
if(hv.length() < 2) {
builder.append("0");
}
builder.append(hv);
/*builder.append(" ");*/
if(i % 16 == 15) {
/*builder.append("\n");*/
}
}
return builder.toString();
}
/**
* 将byte数组转换为16进制字符串(该字符串方便查看)
* 输出信息版:16个字节一行显示
* @param data
* @param start
* @param end
* @return
*/
public static String byteToHexforPrint(byte[] data, int start, int end) {
StringBuilder builder = new StringBuilder();
for(int i = start; i < end; i++) {
int tmp = data[i] & 0xff;
String hv = Integer.toHexString(tmp);
if(hv.length() < 2) {
builder.append("0");
}
builder.append(hv);
builder.append(" ");
if(i % 16 == 15) {
builder.append("\n");
}
}
return builder.toString();
}
/**
* 十六进制字符串转换为字节数组
* @param hexStr 十六进制字符串
* @return 字节数组
*/
public static byte[] hexToByte(String hexStr) {
byte[] datas = new byte[(hexStr.length() - 1) / 2 + 1];
hexStr = hexStr.toUpperCase();
int pos = 0;
for(int i = 0; i < hexStr.length(); i+=2) {
if(i + 1 < hexStr.length()) {
datas[pos] = (byte) ((indexOf(hexStr.charAt(i)+"") << 4) + indexOf(hexStr.charAt(i+1)+""));
}
pos++;
}
return datas;
}
/**
* 计算指定字符串(这里要求是字符)的16进制所表示的数字
* @param str
* @return
*/
public static int indexOf(String str) {
return "0123456789ABCDEF".indexOf(str);
}
/**
* 计算byte数组所表示的值,字节数组的值以小端表示,低位在低索引上,高位在高索引
*
* 例:data = {1,2},那么结果为: 2 << 8 + 1 = 513
* @param data byte数组
* @return 计算出的值
*/
public static long lowByteToLong(byte[] data) {
long sum = 0;
for(int i = 0; i < data.length; i++) {
long value = ((data[i] & 0xff) << (8 * i));
sum += value;
}
return sum;
}
/**
* 计算byte数组所表示的值,字节数组的值以大端表示,低位在高索引上,高位在低索引
*
* 例:data = {1,2},那么结果为: 1 << 8 + 2 = 258
* @param data byte数组
* @return 计算出的值
*/
public static long highByteToLong(byte[] data) {
long sum = 0;
for(int i = 0; i < data.length; i++) {
long value = ((data[i] & 0xff) << (8 * (data.length - i - 1)));
sum += value;
}
return sum;
}
/**
* 计算byte数组所表示的值,字节数组的值以小端表示,低位在低索引上,高位在高索引
*
* 例:data = {1,2},那么结果为: 2 << 8 + 1 = 513
* @param data byte数组
* @return 计算出的值
*/
public static int lowByteToInt(byte[] data) {
int sum = 0;
for(int i = 0; i < data.length; i++) {
long value = ((data[i] & 0xff) << (8 * i));
sum += value;
}
return sum;
}
/**
* 计算byte数组所表示的值,字节数组的值以大端表示,低位在高索引上,高位在低索引
*
* 例:data = {1,2},那么结果为: 1 << 8 + 2 = 258
* @param data byte数组
* @return 计算出的值
*/
public static int highByteToInt(byte[] data) {
int sum = 0;
for(int i = 0; i < data.length; i++) {
long value = ((data[i] & 0xff) << (8 * (data.length - i - 1)));
sum += value;
}
return sum;
}
/**
* long值转换为指定长度的小端字节数组
* @param data long值
* @param len 长度
* @return 字节数组,小端形式展示
*/
public static byte[] longToLowByte(long data, int len) {
byte[] value = new byte[len];
for(int i = 0; i < len; i++) {
value[i] = (byte) ((data >> (8 * i )) & 0xff);
}
return value;
}
/**
* long值转换为指定长度的大端字节数组
* @param data long值
* @param len 长度
* @return 字节数组,大端形式展示
*/
public static byte[] longToHighByte(long data, int len) {
byte[] value = new byte[len];
for(int i = 0; i < len; i++) {
value[i] = (byte) ((data >> (8 * (len - 1 - i) )) & 0xff);
}
return value;
}
/**
* int值转换为指定长度的小端字节数组
* @param data int值
* @param len 长度
* @return 字节数组,小端形式展示
*/
public static byte[] intToLowByte(int data, int len) {
byte[] value = new byte[len];
for(int i = 0; i < len; i++) {
value[i] = (byte) ((data >> (8 * i )) & 0xff);
}
return value;
}
/**
* int值转换为指定长度的大端字节数组
* @param data int值
* @param len 长度
* @return 字节数组,大端形式展示
*/
public static byte[] intToHighByte(int data, int len) {
byte[] value = new byte[len];
for(int i = 0; i < len; i++) {
value[i] = (byte) ((data >> (8 * (len - 1 - i) )) & 0xff);
}
return value;
}
/**
* 计算base的exponent次方
* @param base 基数
* @param exponent 指数
* @return
*/
public static long power(int base, int exponent) {
long sum = 1;
for(int i = 0; i < exponent; i++) {
sum *= base;
}
return sum;
}
public static void main(String[] args) {
byte[] data = new byte[]{1,2};
System.out.println(highByteToInt(data));
System.out.println(lowByteToInt(data));
System.out.println(byteToHex(intToHighByte(258, 4), 0, 4));
System.out.println(byteToHex(intToLowByte(258, 4), 0, 4));
}
}
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.Bmp;
import com.pan.entity.BmpHeader;
import com.pan.entity.BmpInfoHeader;
import com.pan.entity.BmpPalette;
/**
* @author yp2
* @date 2015-11-18
* @description 重构后的Bmp工具
*
* 主要做了几件事:
* 1.位图数据可以不存储,在需要写入的时候再去读原文件的位图数据部分
* 2.抽除掉重复功能的代码
*/
public class BmpUtilRefactoring {
/**
* 读取指定bmp文件的信息到对象中
* @param bmpFile bmp文件路径
* @return 代表Bmp文件信息的对象
*/
private static Bmp readBmp(String bmpFile) {
Bmp bmp = new Bmp();
File file = new File(bmpFile);
InputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(file));
in.mark(0);
readBmpHeader(bmp, in);
long bfOffBits = ByteUtil.lowByteToLong(bmp.getBmpHeader().getBfOffBits());
long biSize = ByteUtil.lowByteToLong(bmp.getBmpInfoHeader().getBiSize());
long biBitCount = ByteUtil.lowByteToLong(bmp.getBmpInfoHeader().getBiBitCount());
int index = (int) (14 + biSize);
//重新定位到调色板
in.reset();
in.skip(index);
if(bfOffBits - biSize - 14 == 0) {
//没有调色板
System.out.println(ByteUtil.lowByteToLong(bmp.getBmpInfoHeader().getBiBitCount()) + "位色无调色板");
} else {
//有调色板
byte[][] palettes = new byte[(int) ByteUtil.power(2, (int) biBitCount)][4];
for(int i = 0; i < palettes.length && index < bfOffBits; i++) {
in.read(palettes[i], 0, palettes[i].length);
index += palettes[i].length;
}
BmpPalette bmpPalette = new BmpPalette();
bmpPalette.setPalettes(palettes);
bmp.setBmpPalette(bmpPalette);
}
//记录bmp文件位图数据
/*
int len = -1;
byte[] buf = new byte[1024];
StringBuilder data = new StringBuilder();
while((len = in.read(buf, 0, buf.length)) > 0) {
data.append(ByteUtil.byteToHex(buf,0, len));
}
bmp.setDatas(ByteUtil.hexToByte(data.toString()));*/
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return bmp;
}
/**
* 读取bmp文件输入流的头部信息到Bmp中的头部信息中,要求输入流处于文件的开头
* @param bmp Bmp对象
* @param in bmp文件输入流
* @throws IOException
*/
private static void readBmpHeader(Bmp bmp, InputStream in) throws IOException {
BmpHeader bmpHeader = new BmpHeader();
in.read(bmpHeader.getBfType(), 0, bmpHeader.getBfType().length);
in.read(bmpHeader.getBfSize(), 0, bmpHeader.getBfSize().length);
in.read(bmpHeader.getBfReserved1(), 0, bmpHeader.getBfReserved1().length);
in.read(bmpHeader.getBfReserved2(), 0, bmpHeader.getBfReserved2().length);
in.read(bmpHeader.getBfOffBits(), 0, bmpHeader.getBfOffBits().length);
bmp.setBmpHeader(bmpHeader);
BmpInfoHeader bmpInfoHeader = new BmpInfoHeader();
in.read(bmpInfoHeader.getBiSize(), 0, bmpInfoHeader.getBiSize().length);
in.read(bmpInfoHeader.getBiWidth(), 0, bmpInfoHeader.getBiWidth().length);
in.read(bmpInfoHeader.getBiHeight(), 0, bmpInfoHeader.getBiHeight().length);
in.read(bmpInfoHeader.getBiPlans(), 0, bmpInfoHeader.getBiPlans().length);
in.read(bmpInfoHeader.getBiBitCount(), 0, bmpInfoHeader.getBiBitCount().length);
in.read(bmpInfoHeader.getBiCompression(), 0, bmpInfoHeader.getBiCompression().length);
in.read(bmpInfoHeader.getBiSizeImage(), 0, bmpInfoHeader.getBiSizeImage().length);
in.read(bmpInfoHeader.getBiXPelsPerMeter(), 0, bmpInfoHeader.getBiXPelsPerMeter().length);
in.read(bmpInfoHeader.getBiYPelsPerMeter(), 0, bmpInfoHeader.getBiYPelsPerMeter().length);
in.read(bmpInfoHeader.getBiClrUsed(), 0, bmpInfoHeader.getBiClrUsed().length);
in.read(bmpInfoHeader.getBiClrImportant(), 0, bmpInfoHeader.getBiClrImportant().length);
bmp.setBmpInfoHeader(bmpInfoHeader);
}
/**
* 写入要隐藏文件的内容和原Bmp文件信息到指定数据文件中
* @param bmp 原Bmp文件信息
* @param inputFileName 要隐藏的文件
* @param outFileName 输出的文件
* @throws IOException
*/
private static void writeFileToBmp(Bmp bmp, String bmpFileName, String inputFileName, String outFileName) throws IOException {
File inputFile = new File(inputFileName);
File outFile = new File(outFileName);
File bmpFile = new File(bmpFileName);
if(!outFile.exists()) {
outFile.createNewFile();
}
//记录原来bmp文件的数据偏移位置
long oldbfOffBits = ByteUtil.lowByteToLong(bmp.getBmpHeader().getBfOffBits());
//计算出新的数据偏移位置:= 原来的偏移位置 + 要隐藏文件的总字节数
long bfOffBits = inputFile.length() + ByteUtil.lowByteToLong(bmp.getBmpHeader().getBfOffBits());
//设置新的数据偏移位置,以便写入新的文件中
bmp.getBmpHeader().setBfOffBits(ByteUtil.longToLowByte(bfOffBits, 4));
InputStream in = null;
InputStream bmpIn = null;
OutputStream out = null;
try {
in = new FileInputStream(inputFile);
bmpIn = new BufferedInputStream(new FileInputStream(bmpFile));
out = new FileOutputStream(outFile);
//将bmp头部信息写入输入流中
writeBmpHeader(bmp, out);
//写入要隐藏的文件内容
int len = -1;
byte[] buf = new byte[1024];
while((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
//跳过头部和调色板信息
bmpIn.skip(oldbfOffBits);
len = -1;
//写入原有位图数据
while((len = bmpIn.read(buf)) > 0) {
out.write(buf, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
in.close();
out.close();
bmpIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 将文件内容写入到指定的位图文件内,并改变输出文件名
* @param bmpFileName 位图文件名
* @param inputFileName 要隐藏的文件名
* @param outFileName 输出文件名
* @throws IOException
*/
public static void writeFileToBmpFile(String bmpFileName, String inputFileName, String outFileName) throws IOException {
Bmp bmp = readBmp(bmpFileName);
writeFileToBmp(bmp, bmpFileName, inputFileName, outFileName);
}
/**
* 读取bmp文件中隐藏的文件内容到指定的输出文件中去
* @param bmpFileName bmp文件名
* @param outFileName 输出文件名
* @throws IOException
*/
public static void readFileFromBmpFile(String bmpFileName, String outFileName) throws IOException {
File bmpFile = new File(bmpFileName);
File outFile = new File(outFileName);
Bmp bmp = new Bmp();
if(!outFile.exists()) {
outFile.createNewFile();
}
InputStream in = null;
OutputStream out = null;
int len = -1;
try {
in = new BufferedInputStream(new FileInputStream(bmpFile));
out = new FileOutputStream(outFile);
//标记当前输入流位置,方便后面reset跳转到当前输入流读取位置
in.mark(0);
//读取输入流中包含的头部信息
readBmpHeader(bmp, in);
//数据偏移位置
long bfOffBits = ByteUtil.lowByteToLong(bmp.getBmpHeader().getBfOffBits());
//使用的颜色索引数目
long biClrUsed = ByteUtil.lowByteToLong(bmp.getBmpInfoHeader().getBiClrUsed());
//位图信息头部字节数
long biSize = ByteUtil.lowByteToLong(bmp.getBmpInfoHeader().getBiSize());
//比特/像素
long biBitCount = ByteUtil.lowByteToLong(bmp.getBmpInfoHeader().getBiBitCount());
//重置到mark标记的位置,这里是跳转到输入流的开头
in.reset();
//保存当前文件输入流位置(字节位置)
long sumLen = 0;
if(biBitCount < 24) {
if(biClrUsed == 0) {
//索引全部都重要
//跳过输入流中的54 + 调色板所占字节数 个字节,这样其实就跳转到了保存隐藏文件内容的位置
in.skip(14 + biSize + ByteUtil.power(2, (int) biBitCount) * 4);
sumLen = 14 + biSize + ByteUtil.power(2, (int) biBitCount) * 4;
} else {
//部分重要
in.skip(14 + biSize + biClrUsed * 4);
sumLen = 14 + biSize + biClrUsed * 4;
}
} else {
//没有调色板
in.skip(14 + biSize);
sumLen = 14 + biSize;
}
byte[] buf = new byte[1024];
while((len = in.read(buf)) > 0) {
if((sumLen + len) > bfOffBits) {
//如果超过了数据偏移位置,则截取剩余的字节进行保存
out.write(buf, 0, (int) (bfOffBits - sumLen));
break;
} else {
//没有超过数据偏移位置,则截取读取到的字节
out.write(buf, 0, len);
}
sumLen += len;
}
} catch (Exception e) {
e.printStackTrace();
in.close();
out.close();
}
}
/**
* 将bmp头部信息和调色板信息写入输入流中
* @param out
* @param bmp
* @throws IOException
*/
private static void writeBmpHeader(Bmp bmp, OutputStream out) throws IOException {
BmpHeader bmpHeader = bmp.getBmpHeader();
out.write(bmpHeader.getBfType());
out.write(bmpHeader.getBfSize());
out.write(bmpHeader.getBfReserved1());
out.write(bmpHeader.getBfReserved2());
out.write(bmpHeader.getBfOffBits());
BmpInfoHeader bmpInfoHeader = bmp.getBmpInfoHeader();
out.write(bmpInfoHeader.getBiSize());
out.write(bmpInfoHeader.getBiWidth());
out.write(bmpInfoHeader.getBiHeight());
out.write(bmpInfoHeader.getBiPlans());
out.write(bmpInfoHeader.getBiBitCount());
out.write(bmpInfoHeader.getBiCompression());
out.write(bmpInfoHeader.getBiSizeImage());
out.write(bmpInfoHeader.getBiXPelsPerMeter());
out.write(bmpInfoHeader.getBiYPelsPerMeter());
out.write(bmpInfoHeader.getBiClrUsed());
out.write(bmpInfoHeader.getBiClrImportant());
BmpPalette bmpPalette = bmp.getBmpPalette();
if(bmpPalette != null && bmpPalette.getPalettes() != null) {
for(int i = 0; i < bmpPalette.getPalettes().length; i++) {
out.write(bmpPalette.getPalettes()[i]);
}
}
}
}
package com.pan.main;
import java.io.IOException;
import com.pan.utils.BmpUtilRefactoring;
public class Main {
public static void main(String[] args) throws IOException {
/*1位色*/
BmpUtilRefactoring.writeFileToBmpFile(Main.class.getClassLoader().getResource("resource/SmallConfetti.bmp").getPath(),
Main.class.getClassLoader().getResource("resource/SmallConfettiscrect.txt").getPath(),
Main.class.getClassLoader().getResource("resource/").getPath() + "SmallConfettiout.bmp");
BmpUtilRefactoring.readFileFromBmpFile(Main.class.getClassLoader().getResource("resource/").getPath() + "SmallConfettiout.bmp",
Main.class.getClassLoader().getResource("resource/").getPath() + "SmallConfettiscrectout.txt");
/*4位色*/
BmpUtilRefactoring.writeFileToBmpFile(Main.class.getClassLoader().getResource("resource/verisign.bmp").getPath(),
Main.class.getClassLoader().getResource("resource/verisignscrect.txt").getPath(),
Main.class.getClassLoader().getResource("resource/").getPath() + "verisignout.bmp");
BmpUtilRefactoring.readFileFromBmpFile(Main.class.getClassLoader().getResource("resource/").getPath() + "verisignout.bmp",
Main.class.getClassLoader().getResource("resource/").getPath() + "verisignscrectout.txt");
BmpUtilRefactoring.writeFileToBmpFile(Main.class.getClassLoader().getResource("resource/srun.bmp").getPath(),
Main.class.getClassLoader().getResource("resource/srunscrect.txt").getPath(),
Main.class.getClassLoader().getResource("resource/").getPath() + "srunout.bmp");
BmpUtilRefactoring.readFileFromBmpFile(Main.class.getClassLoader().getResource("resource/").getPath() + "srunout.bmp",
Main.class.getClassLoader().getResource("resource/").getPath() + "srunscrectout.txt");
/*8位色*/
BmpUtilRefactoring.writeFileToBmpFile(Main.class.getClassLoader().getResource("resource/SplashScreen.bmp").getPath(),
Main.class.getClassLoader().getResource("resource/SplashScreenscrect.txt").getPath(),
Main.class.getClassLoader().getResource("resource/").getPath() + "SplashScreenout.bmp");
BmpUtilRefactoring.readFileFromBmpFile(Main.class.getClassLoader().getResource("resource/").getPath() + "SplashScreenout.bmp",
Main.class.getClassLoader().getResource("resource/").getPath() + "SplashScreenscrectout.txt");
/*24位色*/
BmpUtilRefactoring.writeFileToBmpFile(Main.class.getClassLoader().getResource("resource/background.bmp").getPath(),
Main.class.getClassLoader().getResource("resource/backgroundscrect.txt").getPath(),
Main.class.getClassLoader().getResource("resource/").getPath() + "backgroundout.bmp");
BmpUtilRefactoring.readFileFromBmpFile(Main.class.getClassLoader().getResource("resource/").getPath() + "backgroundout.bmp",
Main.class.getClassLoader().getResource("resource/").getPath() + "backgroundscrectout.txt");
/*32位色*/
BmpUtilRefactoring.writeFileToBmpFile(Main.class.getClassLoader().getResource("resource/WindowsMail.bmp").getPath(),
Main.class.getClassLoader().getResource("resource/WindowsMailscrect.txt").getPath(),
Main.class.getClassLoader().getResource("resource/").getPath() + "WindowsMailout.bmp");
BmpUtilRefactoring.readFileFromBmpFile(Main.class.getClassLoader().getResource("resource/").getPath() + "WindowsMailout.bmp",
Main.class.getClassLoader().getResource("resource/").getPath() + "WindowsMailscrectout.txt");
}
}
转载请注明出处,谢谢!