You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ByteBuffer创建黑色BMP图片时文件损坏问题排查

问题分析与修复方案

核心问题与修复步骤

1. 字节序不匹配(导致图片参数异常)

BMP格式要求所有多字节字段(文件大小、宽高、像素深度等)必须用小端字节序存储,但Java的ByteBuffer默认是大端字节序,这会让图片解析工具读取到错误的文件头参数,直接判定图片损坏。

修复:创建ByteBuffer时强制指定小端序:

ByteBuffer buffer = ByteBuffer.wrap(header).order(ByteOrder.LITTLE_ENDIAN);

2. 缺失保留字段写入

BMP文件头偏移4-7字节的两个保留字段(reserved1和reserved2),即使值为0也必须显式写入,原代码跳过这部分导致文件头结构不完整。

修复:在文件头写入流程中添加:

buffer.putShort(reserved1);
buffer.putShort(reserved2);

3. 图像行未按4字节对齐(导致数据长度错误)

BMP规范要求每行像素数据的字节数必须是4的倍数,不足部分用0填充。原代码直接用width * height * 3计算图像大小,未考虑对齐,导致图像数据总长度不符合规范。

修复:

  • 计算对齐后的单行字节数:int rowSize = (width * 3 + 3) / 4 * 4
  • 重新计算总图像大小:imageSize = rowSize * height
  • 生成图像数据时按对齐后的行结构填充(补0部分数组初始化时默认是0,无需额外操作)

4. 其他细节修正

  • 修正变量名拼写错误:heigth改为height
  • 明确BMP像素存储顺序是BGR(蓝-绿-红),后续修改颜色时需遵循此顺序

修复后的完整代码

package co.edu.uptc.persistence;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public class BMFile {
    private String fileName;
    private int width;
    private int height;
    private int imageSize;
    private int fileSize;

    private short reserved1;
    private short reserved2;
    private int dataBegin;
    private int headSize;
    private short layers;
    private short pixelSize;
    private int compression;
    private int horizontalResolution;
    private int verticalResolution;
    private int colorTableSize;
    private int countMainColor;

    public BMFile(String fileName, int width, int height) {
        this.fileName = fileName;
        this.width = width;
        this.height = height;
        
        // 计算每行对齐后的字节数
        int rowSize = (width * 3 + 3) / 4 * 4;
        this.imageSize = rowSize * height;
        this.fileSize = imageSize + 54; // 文件头固定54字节
        
        this.reserved1 = 0;
        this.reserved2 = 0;
        this.dataBegin = 54;
        this.headSize = 40;
        this.layers = 1;
        this.pixelSize = 24;
        this.compression = 0;
        this.horizontalResolution = 0;
        this.verticalResolution = 0;
        this.colorTableSize = 0;
        this.countMainColor = 0;
    }

    public void saveFile() throws Exception {
        createFile(fileName, createHeader(), createImage());
    }

    private void createFile(String objectFile, byte[] header, byte[] image) throws Exception {
        try (FileOutputStream fuente = new FileOutputStream(objectFile)) {
            fuente.write(header);
            fuente.write(image);
        } catch (FileNotFoundException e) {
            throw new Exception("Ha ocurrido un error archivo no encontrado");
        } catch (IOException e) {
            throw new Exception("Ha ocurrido un error I/O");
        }
    }

    private byte[] createHeader() {
        byte[] header = new byte[54];
        ByteBuffer buffer = ByteBuffer.wrap(header).order(ByteOrder.LITTLE_ENDIAN);
        
        // BMP文件头(14字节)
        buffer.put((byte)'B');
        buffer.put((byte)'M');
        buffer.putInt(fileSize);
        buffer.putShort(reserved1);
        buffer.putShort(reserved2);
        buffer.putInt(dataBegin);
        
        // BMP信息头(40字节)
        buffer.putInt(headSize);
        buffer.putInt(width);
        buffer.putInt(height);
        buffer.putShort(layers);
        buffer.putShort(pixelSize);
        buffer.putInt(compression);
        buffer.putInt(imageSize);
        buffer.putInt(horizontalResolution);
        buffer.putInt(verticalResolution);
        buffer.putInt(colorTableSize);
        buffer.putInt(countMainColor);
        
        return header;
    }

    private byte[] createImage() {
        int rowSize = (width * 3 + 3) / 4 * 4;
        byte[] image = new byte[this.imageSize];
        
        for (int y = 0; y < height; y++) {
            int rowStart = y * rowSize;
            for (int x = 0; x < width; x++) {
                int pixelIndex = rowStart + x * 3;
                // BMP像素格式:BGR顺序
                image[pixelIndex] = 0;     // 蓝色通道
                image[pixelIndex + 1] = 0; // 绿色通道
                image[pixelIndex + 2] = 0; // 红色通道
            }
        }
        return image;
    }
}

内容的提问来源于stack exchange,提问作者Julian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 02:35:03