当图像大小超过255像素时,如何在DIB标题中设置BMP文件的宽度和高度?

时间:2015-01-11 22:32:33

标签: java image bitmap bmp density-independent-pixel

我用Java创建简单的BMP图像。不幸的是,当宽度或高度的大小超过255的十进制值(十六进制的FF值)时,我不知道如何将宽度和高度大小信息存储到DIB头中。要创建小尺寸图像(255x255),我只需输入

表示宽度: FF 00 00 00

表示身高: FF 00 00 00

我可以在一个地方输入的最大值是十六进制的FF(十进制数为255)。如何在这四个位置 00 00 00 00 中输入大于255(十六进制FF)的值,以便创建任何大尺寸图像,例如513x513像素?不知怎的,我必须使用其他零,但我无法在任何地方找到任何合适的解释。我应该如何在Java代码中实现这个原则?我会非常感谢任何帮助。

这是我的Java代码的一部分,用于向DIB标头输入大小值以创建不大于255x255的图像。

writer = new FileOutputStream(new File(onName));
        // width
        writer.write(255);
        writer.write(0);
        writer.write(0);
        writer.write(0);

        // height
        writer.write(255);
        writer.write(0);
        writer.write(0);
        writer.write(0);

这是我的完整Java代码:

package fractalTerrain.midpointDisplacement;
import java.io.*;
import java.util.Random;

// User: Fataho
// Date: 2015-01-10
public class MonochromeMidpointDisplacement {
    private static final String onName = "src\\fractalTerrain\\midpointDisplacement\\test2.bmp";
    private Random random = new Random();
    private static final int H_GRID = 256;
    private static final int V_GRID = 256;
    public static void main(String[] args) {
        MonochromeMidpointDisplacement midpointDisplacement = new MonochromeMidpointDisplacement();
        midpointDisplacement.go();

    }
    private void go(){
      //  fillMap(map, min, max);
        printMap();
    }

    public void printMap(){
        // 3.0 output to file
        // 3.1 Begin the file
        // 3.1.1 open output file

        FileOutputStream writer = null;
        try {
            writer = new FileOutputStream(new File(onName));

            // 3.1.2 copy the header
            // 3.1.2.1 magic number
            writer.write(66);
            writer.write(77);

            // 3.1.2.2 file size/unused space
            for (int i = 0; i < 8; i++){
                writer.write(0);
            }
            // 3.1.2.3 data offset
            writer.write(54);

            // 3.1.2.4 unused space
            for (int i = 0; i < 3; i++){
                writer.write(0);
            }

            // 3.1.2.5 header size
            writer.write(40);
            // 3.1.2.6 unused space
            for (int i = 0; i < 3; i++){
                writer.write(0);
            }


            // 3.1.2.7 file width (trickier)
            writer.write(255);
            writer.write(0);
            writer.write(0);
            writer.write(0);

            // 3.1.2.8 file height (trickier)
            writer.write(255);
            writer.write(0);
            writer.write(0);
            writer.write(0);

            // 3.1.2.9 color planes
            writer.write(1);
            writer.write(0);

            // 3.1.2.10 bit depth
            writer.write(24);

            // 3.1.2.11 the rest
            for (int i = 0; i < 25; i++){
                writer.write(0);
            }
                for(int g = 0; g < ((V_GRID)  * (H_GRID )); g++){
                    writer.write(255);
                    writer.write(0);
                    writer.write(0);
                }
            for (int k = 0; k < (H_GRID % 4); k++){
                writer.write(0);
            }

            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2 个答案:

答案 0 :(得分:1)

尝试移动值以写入更高的值

public void WriteDWORD(int i)
{
    writer.write((byte)(i >> 24));
    writer.write((byte)(i >> 16));
    writer.write((byte)(i >> 8));
    writer.write((byte)i);
}

也可能是小端(向后) 查看此维基百科有关endianness http://en.wikipedia.org/wiki/Endianness

的信息
public void WriteDWORDLittleEndian(int i)
{
    writer.write((byte)i);
    writer.write((byte)(i >> 8));
    writer.write((byte)(i >> 16));
    writer.write((byte)(i >> 24));
}

同时检查您的作者是否有.writeLong.writeInt.writeInteger等命令 所以你不必自己制作一个。

要获得这些命令,您必须执行http://docs.oracle.com/javase/7/docs/api/java/io/DataOutputStream.html

import java.io.DataOutputStream;
DataOutputStream dos = new DataOutputStream(writer);
dos.writeInt(1234567);
dos.close();

答案 1 :(得分:0)

我找到了解决方案。我将仅告诉如何存储宽度信息,因为高度信息以相同的方式存储。我们有4个字节来存储宽度信息,如下所示:

<00> 00 00 00 00

此处存储的所有信息必须是十六进制,因此如果我们要存储255个宽度信息,我们会在前两个零中放置FF十六进制值(小数点为255),如下所示:

FF 00 00 00

如果我们想要存储更大的宽度,例如256,我们不能简单地在前两个零的位置输入100值(十六进制为256),如下所示:

100 00 00 00 这是非常错误而不是逻辑

相反,我们还必须使用这样的第二个零:

00 01 00 00

如果我们要存储257或258或259个宽度值,我们会这样做:

01 01 00 00 for 257

02 01 00 00 for 258

03 01 00 00 for 259

注意第二个2的零保持为01并且只改变前两个值。当前两个零点低于FF时会发生这种情况,当值变得高于FF时,我们必须将后两个值更改为02并再次开始向前两个零添加值。例如,如果我们想要存储到DIB头512或513或1024或1025中,我们必须这样做:

00 02 00 00 for 512

01 02 00 00 for 513

00 04 00 00 for 1024

01 04 00 00 for 1025

等等。我错了,但我相信这个系统被称为little-endian系统。正如已经提到的SSpoke,可以找到关于这些字节顺序的更多信息here。同样如SSpoke所述,要以Java或其他语言实现此原则,您必须使用按位运算&gt;&gt;来移动值。以下是实现此原则的代码:

 writer.write(H_GRID % 256);
 writer.write(H_GRID >> 8 % 256);
 writer.write(H_GRID >> 16 % 256);
 writer.write(H_GRID >> 24 % 256);

让我们使用这行代码V_GRID >> 8 % 256并假设V_GRID值为257。 为简单起见,要理解这条线是如何工作的,我将告诉我如何理解它,但它可能与计算机的不同之处有所不同。将257转换为二进制数100000001,然后按位运算&gt;&gt;将此100000001二进制数向右移动8个值,得到1(100000001>&gt; 8 = 1)。最后1转换为十进制值(在本例中为1),我们得到提醒(也是1)然后我们将此值(1)放入BMP DIB头。可以找到关于按位运算的合适解释here。这是我的最终和完整的Java代码:

package fractalTerrain.midpointDisplacement;
import java.io.*;
import java.util.Random;

public class MonochromeMidpointDisplacement {
    private static final String onName = "src\\fractalTerrain\\midpointDisplacement\\test2.bmp";
    private Random random = new Random();
    private static final int H_GRID = 257;
    private static final int V_GRID = H_GRID;
    public static void main(String[] args) {
        MonochromeMidpointDisplacement midpointDisplacement = new MonochromeMidpointDisplacement();
        midpointDisplacement.go();   
    }
    private void go(){
      //  fillMap(map, min, max);
        printMap();
    }

    public void printMap(){
        // 3.0 output to file
        // 3.1 Begin the file
        // 3.1.1 open output file
        FileOutputStream writer = null;
        try {
            writer = new FileOutputStream(new File(onName));

            // 3.1.2 copy the header
            // 3.1.2.1 magic number
            writer.write(66);
            writer.write(77);

            // 3.1.2.2 file size/unused space
            for (int i = 0; i < 8; i++){
                writer.write(0);
            }
            // 3.1.2.3 data offset
            writer.write(54);

            // 3.1.2.4 unused space
            for (int i = 0; i < 3; i++){
                writer.write(0);
            }

            // 3.1.2.5 header size
            writer.write(40);
            // 3.1.2.6 unused space
            for (int i = 0; i < 3; i++){
                writer.write(0);
            }

            // 3.1.2.7 file width (trickier)
            writer.write(H_GRID % 256);
            writer.write(H_GRID >> 8 % 256);
            writer.write(H_GRID >> 16 % 256);
            writer.write(H_GRID >> 24 % 256);

            // 3.1.2.8 file height (trickier)
            writer.write(V_GRID % 256);
            writer.write(V_GRID >> 8 % 256);
            writer.write(V_GRID >> 16 % 256);
            writer.write(V_GRID >> 24 % 256);

            // 3.1.2.9 color planes
            writer.write(1);
            writer.write(0);

            // 3.1.2.10 bit depth
            writer.write(24);

            // 3.1.2.11 the rest
            for (int i = 0; i < 25; i++){
                writer.write(0);
            }

            for(int i = 0; i < V_GRID; i++){
                for(int g = 0; g < H_GRID; g++){
                    writer.write(255);
                    writer.write(0);
                    writer.write(0);
                }
                for (int k = 0; k < (H_GRID % 4); k++){
                    writer.write(0);
                }
            }
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}