JavaはBMPグラフを読み取り、解析します

コンピューターグラフィックスの宿題
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();
    }
}

結果を図に示します
ここに画像の説明を挿入

元の記事を22件公開 Likes2 Visits 881

おすすめ

転載: blog.csdn.net/weixin_41685373/article/details/105589422