コンピューターグラフィックスの宿題
bmpを読み取り
、rgbを2次元配列に格納するプログラムを作成する
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Arrays;
public class Graph {
/*
一些成员变量
*/
// 文件头
Filehead filehead = new Filehead();
byte[] fileheadByte = new byte[14];
// 信息头
byte[] mapinfoByte = new byte[40];
MapInfohead mapInfohead = new MapInfohead();
// rgb
Rgb rgb;
/*
主函数
*/
public static void main(String[] args) {
String path = "F:\\\\test1.bmp";
Graph graph = new Graph();
graph.loadBmp24(path);
}
/**
* 读取bmp文件
*
* @param path 文件路径
*/
public void loadBmp24(String path) {
// 得到文件 测试文件是像素点16*9 的bmp 文件
File file = Paths.get("F:\\\\test1.bmp").toFile();
if(!file.exists()){
try {
throw new FileNotFoundException("没找到文件");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
System.out.println("文件名为"+file.getName());
try {
FileInputStream fileInputStream = new FileInputStream(file);
// 读文件头 放入数组
fileInputStream.read(fileheadByte, 0, 14);
System.out.println("文件头Byte 14位如下");
System.out.println(Arrays.toString(fileheadByte));
unpackFileHead(fileheadByte);
// 读信息头 放入数组
fileInputStream.read(mapinfoByte, 0, 40);
System.out.println("信息头Byte 40位如下");
System.out.println(Arrays.toString(mapinfoByte));
unpackMapInfoHead(mapinfoByte);
unpackRgb(fileInputStream);
// 输出rgb矩阵
System.out.println(rgb);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 解析文件头
*
* @param fileheadByte 文件头数组
*/
public void unpackFileHead(byte[] fileheadByte) {
filehead.bfType = load2BytetoInt(fileheadByte, 1);
filehead.bfSize = load4BytetoInt(fileheadByte, 5);
filehead.bfReserverd1 = load2BytetoInt(fileheadByte, 7);
filehead.bfReserverd2 = load2BytetoInt(fileheadByte, 9);
filehead.bfOffBits = load4BytetoInt(fileheadByte, 13);
}
/**
* 解析信息头
*
* @param mapinfoByte 信息头数组
*/
public void unpackMapInfoHead(byte[] mapinfoByte) {
mapInfohead.biSize = load4BytetoInt(mapinfoByte, 3);
mapInfohead.biWidth = load4BytetoInt(mapinfoByte, 7);
mapInfohead.biHeight = load4BytetoInt(mapinfoByte, 11);
mapInfohead.biPlanes = load2BytetoInt(mapinfoByte, 13);
mapInfohead.biBitCount = load2BytetoInt(mapinfoByte, 15);
mapInfohead.biCompression = load4BytetoInt(mapinfoByte, 19);
mapInfohead.biSizeImage = load4BytetoInt(mapinfoByte, 23);
mapInfohead.biXPelsPerMeter = load4BytetoInt(mapinfoByte, 27);
mapInfohead.biYPelsPerMeter = load4BytetoInt(mapinfoByte, 31);
mapInfohead.biClrUsed = load4BytetoInt(mapinfoByte, 35);
mapInfohead.biClrImportant = load4BytetoInt(mapinfoByte, 39);
}
/**
* 解析 rgb 矩阵
*
* @param fileInputStream
*/
public void unpackRgb(FileInputStream fileInputStream) {
int width = mapInfohead.biWidth;
int height = mapInfohead.biHeight;
rgb = new Rgb(width, height);
// 字节填充
int skip_width = 0;
int m = width * 3 % 4;
if (m != 0) {
skip_width = 4 - m;
}
// 此处代码来自https://blog.csdn.net/meiyoutongguo/article/details/9243899
for (int i = height - 1; i >=0; i--) {
for (int j = 0; j < width; j++) {
try {
// 这里遍历的时候,一定要注意本来像素是有RGB来表示,
// 但是在存储的时候由于windows是小段存储,所以在内存中是BGR顺序。
rgb.blue[i][j] = fileInputStream.read();
rgb.green[i][j] = fileInputStream.read();
rgb.red[i][j] = fileInputStream.read();
// 这里一定要知道,其实系统在给位图数据中添加填充0的时候,都是加在每行的最后。
// 但是我们在使用dis.skipBytes()这个方法的时候,却不一定要在最后一列。
// 系统在填充数据的时候,在数据上加了标记。
// 所以dis.skipBytes()这个方法只要调用了,那么系统就会自动不读取填充数据。
if (j == 0) {
fileInputStream.skip(skip_width);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 4 字节转int
*
* @param head 字节数组
* @param index 开始的索引
* @return
*/
public int load4BytetoInt(byte[] head, int index) {
// 注意index 是索引位置从0 开始
return (((head[index] & 0xff) << 24)
| ((head[index - 1] & 0xff) << 16)
| ((head[index - 2] & 0xff) << 8)
| (head[index - 3] & 0xff));
}
/**
* 2 字节转int
*
* @param head 字节数组
* @param index 开始的索引
* @return
*/
public int load2BytetoInt(byte[] head, int index) {
return (((head[index] & 0xff) << 8)
| (head[index - 1] & 0xff));
}
}
class Filehead {
/*
total 14 byte
*/
public int bfType;
// size 4 byte
public int bfSize;
public int bfReserverd1;
public int bfReserverd2;
// size 4 byte
public int bfOffBits;
}
class MapInfohead {
/*
total 40 byte
*/
int biSize;
int biWidth;
int biHeight;
// size 2 byte
int biPlanes;
// size 2 byte
int biBitCount;
int biCompression;
int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
int biClrUsed;
int biClrImportant;
}
class Rgb {
int[][] red;
int[][] green;
int[][] blue;
int width;
int heigh;
Rgb(int width, int heigh) {
this.width = width;
this.heigh = heigh;
red = new int[heigh][width];
green = new int[heigh][width];
blue = new int[heigh][width];
}
@Override
public String toString() {
// 输出rgb矩阵
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < heigh; i++) {
for (int j = 0; j < width; j++) {
stringBuilder.append(String.format("(%03d,%03d,%03d)",red[i][j],green[i][j],blue[i][j]));
}
stringBuilder.append("\n");
}
return stringBuilder.toString();
}
}
結果を図に示します