Solved

How to display Windows bitmap (.bmp)?

Posted on 1997-11-07
11
424 Views
Last Modified: 2013-11-19
I need to load, display and save a Windows
bitmap (.bmp). Does anybody know how to do
this (source code)?

As far as I understand it the Java getImage()
method is only capable of loading .gif and
.jpeg.

Lewis
0
Comment
Question by:Lewis
  • 6
  • 4
11 Comments
 
LVL 3

Accepted Solution

by:
gwalters earned 250 total points
ID: 1230187
I couldn't find one, so I wrote one.  It doesn't cover every possible BMP file, but it does get the most common ones (and the unsupported modes could easily be added; I have a BMP spec I can send you if you need these other modes).

What it handles:
 1, 4, 8, 24 bit-per-pixel images

What it doesn't:
 16, 32 bit-per-pixel images (which the Windows paint program seems to know nothing about).  These could be added, but they're more complicated as they support bitmap compressions (the above supported modes are straight bitmap).

Here it is.  It's got a main() method for testing, which takes a BMP file as its argument and displays it on a Frame.  If this is unreadable/unusable I can mail it to you:

----------------------CUT_HERE-------------------------------
import java.awt.*;
import java.awt.image.*;
import java.util.*;
import java.io.*;

public class BMPDecoder
{
  private int width;
  private int height;
  private int planes;
  private int bpp;
  private byte[] data;
  private int pos;
  private int[] pixels;
  private int[] colormap;

  public BMPDecoder(String filename) throws FileNotFoundException, IOException
  {
    File f=new File(filename);
    if (!f.exists())
      throw new FileNotFoundException();
    data=new byte[(int)f.length()];
    InputStream in=new FileInputStream(filename);
    in.read(data);
    in.close();
    init();
    decode();
  }

  public BMPDecoder(byte[] data)
  {
    this.data=data;
    init();
    decode();
  }

  private void init()
  {
    String id=""+((char)nextByte())+((char)nextByte());
    if (!"BM".equals(id))
      throw new RuntimeException("Not a Windows Bitmap");
    System.out.println("File size: "+getDWord());
    System.out.println("Reserved: "+getDWord());
    System.out.println("Offset: "+getDWord());
    if (getDWord()!=0x28)
      throw new RuntimeException("Expected 0x28 for Windows Bitmap");
    System.out.println("Width: "+(width=getDWord()));
    System.out.println("Height: "+(height=getDWord()));
    System.out.println("Planes: "+(planes=getWord()));
    System.out.println("BPP: "+(bpp=getWord()));
    if (getDWord()!=0)
      throw new RuntimeException("Compression not supported yet");
    System.out.println("Bitmap size: "+getDWord());
    System.out.println("Horiz resolution: "+getDWord());
    System.out.println("Vert resolution: "+getDWord());
    int colors=getDWord();
    System.out.println("Number of Colors: "+colors);
    System.out.println("Number of Important Colors: "+getDWord());
    if (bpp<24) {
      if (colors==0)
        System.out.println("Number of Colors: "+(colors=1<<bpp));      
      colormap=new int[colors];
      for (int i=0; i<colors; i++) {
        colormap[i]=0xff000000 + (nextByte()&0xff) + (nextByte()&0xff)*0x100 + (nextByte()&0xff)*0x10000;
        nextByte(); //skip padding
      }
    }
  }

  private byte nextByte()
  {
    return data[pos++];
  }

  private void skip(int num)
  {
    pos+=num;
  }

  private void decode()
  {
    pixels=new int[width*height];
    switch (bpp) {
    case 1:
      decode1bit();
      break;

    case 4:
      decode4bit();
      break;

    case 8:
      decode8bit();
      break;

    case 24:
      decode24bit();
      break;

    default:
      throw new RuntimeException(bpp+" bit decoding not supported");
    }
  }

  private void decode1bit()
  {
    int data=nextByte();
    int pos=0x80;
    for (int y=height-1; y>=0; y--)
      for (int x=0; x<width; x++) {
        if ((data&pos)!=0)
          pixels[y*width+x]=colormap[1];
        else
          pixels[y*width+x]=colormap[0];
        if (pos==0x01 && (y!=0 || x!=width-1)) {
          data=nextByte();
          pos=0x80;
        } else {
          pos>>=1;
        }
      }            
  }

  private void decode4bit()
  {
    int w=width;
    while ((w%8)!=0)
      w++;
    int data=nextByte();
    for (int y=height-1; y>=0; y--) {
      for (int x=0; x<w; x++) {
        int idx,i=y*width+x;
        if ((x&1)==0)
          idx=data>>4;
        else {
          idx=data&0x0f;
          if (x!=w-1 || y!=0)
            data=nextByte();
        }
        if (x<width)
          pixels[i]=colormap[idx];
      }
    }

  }

  private void decode8bit()
  {
    for (int y=height-1; y>=0; y--)
      for (int x=0; x<width; x++)
        pixels[y*width+x]=colormap[nextByte()];
  }

  private void decode24bit()
  {
    for (int y=height-1; y>=0; y--)
      for (int x=0; x<width; x++)
        pixels[y*width+x]=0xff000000 + (nextByte()&0xff) + (nextByte()&0xff)*0x100 + (nextByte()&0xff)*0x10000;
  }

  private int getWord()
  {
    return (nextByte()&0xff) + (nextByte()&0xff)*0x100;
  }

  private int getDWord()
  {
    return (nextByte()&0xff) + (nextByte()&0xff)*0x100 +
           (nextByte()&0xff)*0x10000 + (nextByte()&0xff)*0x1000000;
  }

  public Image getImage()
  {
    return Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(width,height,pixels,0,width));
  }

  public static void main(String argv[]) throws FileNotFoundException, IOException
  {
    BMPDecoder bmp=new BMPDecoder(argv[0]);
    Frame f=new Frame();
    f.resize(640,400);
    f.show();
    Image img=bmp.getImage();
    while (true) {
      Graphics g=f.getGraphics();
      g.drawImage(img,0,0,f);
      try {Thread.sleep(500);} catch (Exception e) {}
    }
  }
}
----------------------CUT_HERE-------------------------------
0
 

Author Comment

by:Lewis
ID: 1230188
Hi,
I get the following message in my DOs box:

C:\Lewis\Listings>java BMPDecoder List.bmp
File size: 14406
Reserved: 0
Offset: 118
Width: 371
Height: 76
Planes: 1
BPP: 4
Bitmap size: 14288
Horiz resolution: 0
Vert resolution: 0
Number of Colors: 16
Number of Important Colors: 16
java.lang.ArrayIndexOutOfBoundsException: -1
        at BMPDecoder.decode4bit(BMPDecoder.java
        at BMPDecoder.decode(BMPDecoder.java:90)
        at BMPDecoder.<init>(BMPDecoder.java:27)
        at BMPDecoder.main(BMPDecoder.java:182)
0
 
LVL 3

Expert Comment

by:gwalters
ID: 1230189
Could you send me that image (list.bmp): walters@ct.net

It works on all my 4-bit images, but I'm sure there are bugs in it.
0
 
LVL 3

Expert Comment

by:gwalters
ID: 1230190
Oops, disregard my previous comment.  I'm pretty sure this should fix it (stupid mistake):

Change the following line in the decode4bit() method:

BEFORE:   idx=data>>4;
AFTER:    idx=(data>>4)&0x0f;

Sorry about that (only fails if a 4-bit image uses the 16th color).


0
 
LVL 4

Expert Comment

by:rembo
ID: 1230191

Just FYI, if you look at the source for the JDK, it
has code for reading in .bmp files.  If you just
do a getImage(), it should work.

-Tony

0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 3

Expert Comment

by:gwalters
ID: 1230192
Rembo,

Didn't work for me (beleive me, I wouldn't have written this if I could have answered "use getImage()").

Are you talking about sun.awt.image.XbmImageDecoder?  That's for X bitmaps, not the same as Windows bitmaps.


0
 

Author Comment

by:Lewis
ID: 1230193
Hi Tony,
it works pretty well so far. It displays most of
my bitmaps.

Could you send me the BMP spec you talked about
earlier? I will try to figure out why it still
does not depict certain BMPs correctly. They
are displayed distorted (at a certain angle) and
with weird colors (looks like some kind of photo
negative).

My email is

utsch@pd.et-inf.uni-siegen.de

Regards, Lewis
0
 
LVL 3

Expert Comment

by:gwalters
ID: 1230194
I sent you the spec.
0
 

Author Comment

by:Lewis
ID: 1230195
Here are your points. They are well deserved.

Lewis
0
 

Author Comment

by:Lewis
ID: 1230196
Here are your points. They are well deserved.

Lewis
0
 
LVL 3

Expert Comment

by:gwalters
ID: 1230197
For anyone who may buy this as a <PAQ>, here are the required fixes:




  private void decode8bit()
  {
    for (int y=height-1; y>=0; y--) {
      for (int x=0; x<width; x++)
        pixels[y*width+x]=colormap[nextByte()&0xff];
      //skip padding so that lines begin on DWord boundaries:
      for (int x=0; x<4-width%4; x++)
        nextByte();
    }
  }

  private void decode24bit()
  {
    for (int y=height-1; y>=0; y--) {
      for (int x=0; x<width; x++)
        pixels[y*width+x]=0xff000000 + (nextByte()&0xff) + (nextByte()&0xff)*0x100 + (nextByte()&0xff)*0x10000;
      //skip padding so that lines begin on DWord boundaries:
      for (int x=0; x<width%4; x++)
        nextByte();
    }
  }


0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
Introduction This article is the first of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article explains our test automation goals. Then rationale is given for the tools we use to a…
This tutorial explains how to use the VisualVM tool for the Java platform application. This video goes into detail on the Threads, Sampler, and Profiler tabs.
HTML5 has deprecated a few of the older ways of showing media as well as offering up a new way to create games and animations. Audio, video, and canvas are just a few of the adjustments made between XHTML and HTML5. As we learned in our last micr…

912 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now