【问题标题】:Errors in bitmap creation in JavaJava 中的位图创建错误
【发布时间】:2026-01-22 04:30:01
【问题描述】:

我正在尝试从二维像素值数组创建位图。我在网上找到了一些代码(取自http://forum.codecall.net/topic/62457-creating-a-bmp-image-in-java/):

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class BMP {
    private final static int BMP_CODE = 19778;

    byte [] bytes;

    public void saveBMP(String filename, int [][] rgbValues){
        try {
            FileOutputStream fos = new FileOutputStream(new File(filename));

            bytes = new byte[54 + 3*rgbValues.length*rgbValues[0].length + getPadding(rgbValues[0].length)*rgbValues.length];

            saveFileHeader();
            saveInfoHeader(rgbValues.length, rgbValues[0].length);
            saveRgbQuad();
            saveBitmapData(rgbValues);

            fos.write(bytes);

            fos.close();

        } catch (FileNotFoundException e) {

        } catch (IOException e) {

        }

    }

    private void saveFileHeader() {
        byte[]a=intToByteCouple(BMP_CODE);
        bytes[0]=a[1];
        bytes[1]=a[0];

        a=intToFourBytes(bytes.length);
        bytes[5]=a[0];
        bytes[4]=a[1];
        bytes[3]=a[2];
        bytes[2]=a[3];

        //data offset
        bytes[10]=54;
    }

    private void saveInfoHeader(int height, int width) {
        bytes[14]=40;

        byte[]a=intToFourBytes(width);
        bytes[22]=a[3];
        bytes[23]=a[2];
        bytes[24]=a[1];
        bytes[25]=a[0];

        a=intToFourBytes(height);
        bytes[18]=a[3];
        bytes[19]=a[2];
        bytes[20]=a[1];
        bytes[21]=a[0];

        bytes[26]=1;

        bytes[28]=24;
    }

    private void saveRgbQuad() {

    }

    private void saveBitmapData(int[][]rgbValues) {
        int i;

        for(i=0;i<rgbValues.length;i++){
            writeLine(i, rgbValues);
        }

    }

    private void writeLine(int row, int [][] rgbValues) {
        final int offset=54;
        final int rowLength=rgbValues[row].length;
        final int padding = getPadding(rgbValues[0].length);
        int i;

        for(i=0;i<rowLength;i++){
            int rgb=rgbValues[row][i];
            int temp=offset + 3*(i+rowLength*row) + row*padding;

            bytes[temp]    = (byte) (rgb>>16);
            bytes[temp +1] = (byte) (rgb>>8);
            bytes[temp +2] = (byte) rgb;
        }
        i--;
        int temp=offset + 3*(i+rowLength*row) + row*padding+3;

        for(int j=0;j<padding;j++)
            bytes[temp +j]=0;

    }

    private byte[] intToByteCouple(int x){
        byte [] array = new byte[2];

        array[1]=(byte)  x;
        array[0]=(byte) (x>>8);

        return array;
    }

    private byte[] intToFourBytes(int x){
        byte [] array = new byte[4];

        array[3]=(byte)  x;
        array[2]=(byte) (x>>8);
        array[1]=(byte) (x>>16);
        array[0]=(byte) (x>>24);

        return array;
    }

    private int getPadding(int rowLength){

        int padding = (3*rowLength)%4;
        if(padding!=0)
            padding=4-padding;


        return padding;
    }

}

现在我尝试使用以下代码创建大小为 10x5 的位图:

int[][] bmpData = new int[10][5];
for(int x = 0; x < 10; x++) {
    for(int y = 0; y < 5; y++) {
        bmpData[x][y] = 127 | 127 << 8 | 127 << 16;
    }
}
new BMP().saveBMP("test.bmp", bmpData);

我得到的结果是不正确的。我希望有一个 10x5 灰色 bmp,但相反,我在图像中看到一条淡黄色的垂直线。绘制更大的图像(100x50)时,我得到了这个:

看起来列被绘制为行。我不确定这是为什么。我在源代码中发现了一些关于填充的内容,但我很难理解它是如何工作的。

谁能解释这种行为?请注意,我不在 Android 上工作,所以我无法使用 Bitmap 类。

【问题讨论】:

  • bmpData 显然是统一的,所以基本上你是在要求 * 调试某人的 BMP 类。我不确定,但也许你需要在这里发布。

标签: java bitmap drawing bmp


【解决方案1】:

在我看来,这段代码没有按预期工作。

查看这部分,例如:

saveInfoHeader(rgbValues.length, rgbValues[0].length);

saveInfoHeader 有这个签名:

saveInfoHeader(int height, int width)

所以,当你通过int[100][50]; 时,你应该得到高 100 宽 50 的 bmp。

我认为这部分代码不正确:

byte[]a=intToFourBytes(width);
bytes[22]=a[3];
bytes[23]=a[2];
bytes[24]=a[1];
bytes[25]=a[0];

a=intToFourBytes(height);
bytes[18]=a[3];
bytes[19]=a[2];
bytes[20]=a[1];
bytes[21]=a[0];

BMP 标准的宽度应该在高度之前声明,这里的宽度是更早处理的,但是(我想是由于编辑错误)它是用更大的偏移量编写的。

如果您将其更改为:

byte[]a=intToFourBytes(width);
bytes[18]=a[3];
bytes[19]=a[2];
bytes[20]=a[1];
bytes[21]=a[0];

a=intToFourBytes(height);
bytes[22]=a[3];
bytes[23]=a[2];
bytes[24]=a[1];
bytes[25]=a[0];

,你会得到这样的结果:

您得到的图案是由于高度/宽度不匹配而导致 BMP 填充错误计算的结果。

【讨论】:

  • 是的,BMP 类有著名的 x/y 与行/列混淆。
  • 确实是这个问题!我现在得到了我预期的位图。谢谢你的回答。