-2

I am creating simple BMP image with Java. Unfortunately I do not know how to store width and height size information into the DIB header, when the size of width or height exceeds 255 value in decimals (FF value in hex). To create small size image (255x255), I just enter

for width: FF 00 00 00,

for height: FF 00 00 00.

Maximum value that I can enter in one place is FF in hex (255 in decimals). How can I enter values larger than 255 (FF in hex) into these four places 00 00 00 00, in order to create any large size images, such as 513x513 pixels? Somehow I have to use other zeros, but I could not find any decent explanation anywhere. How should I implement this principle in Java code? I would be very grateful for any help.

This is part of my Java code that is used to enter size values to DIB header to create images not larger than 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);

This is my full Java code:

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();
        }
    }
}
Alex K
  • 8,269
  • 9
  • 39
  • 57
Fataho
  • 99
  • 3
  • 15
  • I indicated that I have additional bytes and I said that I could not find anywhere how to use them. I would be grateful for explaining how to store information into additional bytes in BMP DIB header. – Fataho Jan 12 '15 at 23:55

2 Answers2

1

Try shifting the value to write higher values

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

Could also be little endian (backwards) Check out this wikipedia about 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));
}

Also check if your writer has commands like .writeLong or .writeInt or .writeInteger So you don't have to make one yourself.

To get those commands you have to do 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();
SSpoke
  • 5,656
  • 10
  • 72
  • 124
0

I found the solution. I will tell only how to store width size information, because height information is stored in same manner. We have 4 bytes to store width information as shown below:

00 00 00 00

All information stored here must be in hexadecimals, therefore if we want to store 255 width information we put FF hexadecimal value (255 in decimals) in first two zeros such like this:

FF 00 00 00

If we want to store larger width, such as 256, we cannot simply enter 100 value (256 in hexadecimals) in the place of first two zeros as shown below:

100 00 00 00 THIS IS VERY WRONG AND NOT LOGICAL

Instead we also have to use second two zeros such like this:

00 01 00 00

If we want to store 257 or 258 or 259 width values we do this:

01 01 00 00 for 257

02 01 00 00 for 258

03 01 00 00 for 259

notice that second 2 zeros remains 01 and changes only first two values. It will happen while first two zeros are below FF, when values become higher that FF, we have to change second two values to 02 and again start adding values to first two zeros. For instance, if we want to store into DIB header 512 or 513 or 1024 or 1025 we have to do this:

00 02 00 00 for 512

01 02 00 00 for 513

00 04 00 00 for 1024

01 04 00 00 for 1025

and so on. I can be wrong, but I believe that this system is called little-endian system. As already mentioned SSpoke, more information about these endianness can be found here. Also as mentioned SSpoke, to implement this principle in Java or other language you have to shift values by using bitwise operation >>. Here is the code that implements this principle:

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

Let’s take this line of code V_GRID >> 8 % 256 and presume that V_GRID value is 257. For simplicity, to understand how this line works I will tell how I understand it, but it might be different how computer does it. 257 would is converted in to binary number 100000001, then bitwise operation >> shift this 100000001 binary number to the right by 8 values and we get 1 (100000001 >> 8 = 1). Finally 1 is converted to decimal value (in this case is 1) and we get the reminder (also 1) Then we put this value (1) in to BMP DIB header. A decent explanation about bitwise operations can be found here. Here is my final and full Java code:

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();
        }
    }
}
Community
  • 1
  • 1
Fataho
  • 99
  • 3
  • 15
  • 1
    It's just "little-endian"; the "8-bit" is somewhere between redundant and a tiny bit misleading. (Bit order within a byte isn't affected by endianness, at least not til you get down to firmware-level stuff.) For reference, you'll see these numbers a lot in binary formats native to Windows, because the x86 family of CPUs is natively little-endian. – cHao Jan 13 '15 at 02:22