BMPファイルの読み込み

 今回は、WindowsBMPファイルをJavaのBufferedImageに読み込んでみます。これまでBMPの読み込みは何度もやってきたし、ファイルからの読み込みやBufferedImageも試してみたばかりなので、後はそれらを組み合わせるだけですね。バッファの構造に注意してBufferedImageDataBufferにRGBを設定してみましょう。

BMPの読み込み

 今回は、24ビットBMPを読み込んでみます。この形式のBMPは、DIBとグラフィック処理で遊ぶで何度も扱ってきたので、同様に読み込むだけ。また、BufferedImageも24ビット形式ならRGBの配置と上下が逆になっている点に気をつければ24ビットDIBに近い感覚で扱う事が出来ます。

 というわけで、早速読み込んでみましょう。まず、ファイルの大きさを調べてその分のバッファ(byte型配列dat)を確保します。

  File f=new File(fn);

  size=(int)(f.length()); // ファイルサイズ取得

  dat=new byte[size]; // ファイルサイズ分のバッファ生成

 これで、ファイルfnの大きさ分のbyte型配列datが出来ましたので、このバッファにファイルを読み込みます。

  FileInputStream fs=new FileInputStream(fn);

  fs.read(dat);

  fs.close();

 ファイルを読み込んだら、まず先頭2バイトとビット数を調べファイルが24ビットBMPである事を確認しましょう。

  // 24BitBMPでなければ戻る
  if (dat[0]!='B' || dat[1]!='M' || dat[28]!=24)
      return;

 次に、ピクセル列までのオフセットを取得。本当はオフセットは4バイトなのですが、今回は24ビットフルカラーのみを扱うので、256バイト以上になる事はないはず。というわけで、先頭(最下位)1バイトだけを見る事にします。

  offset=dat[10]; // ピクセル列までのオフセット

 ビットマップの大きさも4バイトですが、そんなに大きなビットマップはないでしょうから下位2バイトのみを取得します。ここでは、バッファがbyte型、つまり符号付整数である点に注意してください。上位が負(128以上)になる事はないでしょうから、下位のみの符号を調べます。ついでに、4バイト境界に基づいたバッファの横幅も計算しておきましょう。

  // ビットマップサイズ取得
  if (dat[18]<0)
      width=(256+dat[18])+(int)dat[19]*256;
  else
      width=dat[18]+(int)dat[19]*256;

  if (dat[22]<0)
      height=(256+dat[22])+(int)dat[23]*256;
  else
      height=dat[22]+(int)dat[23]*256;

  if ((width*3) % 4==0) /* バッファの1ラインの長さを計算 */
      length=width*3;
  else
      length=width*3+(4-(width*3) % 4);

 ビットマップの大きさが求まったら、バッファを確保しピクセル列をバッファに書き込みます。BMPと今回のTYPE_3BYTE_BGRタイプのBufferedImageでは、RとB、座標の上下が逆なので、反転しながら書き込んでいきましょう。

  // ピクセル列配列取得
  pixel=new byte[width*3*height];

  // ピクセル列設定
  for (int i=0;i<height;i++)
      for (int j=0;j<width;j++) {

          int adr=j*3+(height-i-1)*width*3;
          int adr2=offset+j*3+i*length;

          pixel[adr]=dat[adr2+2];
          pixel[adr+1]=dat[adr2+1];
          pixel[adr+2]=dat[adr2];

      }

 以上で、ビットマップの大きさとピクセル列が用意できたので、BufferedImageを作ります。

  // BufferedImage生成
  biImg=new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);
  // BufferedImageのピクセル列設定
  biImg.getRaster().setDataElements(0,0,width,height,pixel);

 以上の事をまとめると、BMPファイルfnを読み込んでBufferedImageオブジェクトbiImgを作る関数は以下のようになります。

  public void readBMP(String fn) { // BMP読み込み

      int size=0,offset=0,width=0,height=0,length=0;
      byte dat[]=new byte[10],pixel[]=new byte[10];

      try {

          File f=new File(fn);

          size=(int)(f.length());

          dat=new byte[size];
 
          FileInputStream fs=new FileInputStream(fn);

          fs.read(dat);

          fs.close();

      } catch (FileNotFoundException e) {}
        catch (IOException e) { return; }

      // 24BitBMPでなければ戻る
      if (dat[0]!='B' || dat[1]!='M' || dat[28]!=24)
          return;

      offset=dat[10]; // ピクセル列までのオフセット

      // ビットマップサイズ取得
      if (dat[18]<<0)
          width=(256+dat[18])+(int)dat[19]*256;
      else
          width=dat[18]+(int)dat[19]*256;

      if (dat[22]<0)
          height=(256+dat[22])+(int)dat[23]*256;
      else
          height=dat[22]+(int)dat[23]*256;

      if ((width*3) % 4==0) /* バッファの1ラインの長さを計算 */
          length=width*3;
      else
          length=width*3+(4-(width*3) % 4);

      // ピクセル列配列取得
      pixel=new byte[width*3*height];

      // ピクセル列設定
      for (int i=0;i<height;i++)
          for (int j=0;j<width;j++) {

              int adr=j*3+(height-i-1)*width*3;
              int adr2=offset+j*3+i*length;

              pixel[adr]=dat[adr2+2];
              pixel[adr+1]=dat[adr2+1];
              pixel[adr+2]=dat[adr2];

          }

      // BufferedImage生成
      biImg=new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);
      // BufferedImageのピクセル列設定
      biImg.getRaster().setDataElements(0,0,width,height,pixel);

      // コンソールにビットマップの情報表示
      System.out.println("Name:"+fn);
      System.out.println("Width:"+String.valueOf(width));

      repaint();

  }

プログラム

 今回はJava2アプリケーションです。ソースのファイル名をjbmp.javaとしてJDK1.2でコンパイル・実行してみてください。アプリケーションのウインドウがFrameのサブクラスとして生成され、Loadボタンをクリックするとファイル選択ダイアログが表示されます。ダイアログでファイルを選べばそのファイルが表示されるのですが、今回は「ファイル名」しか見ていないので、他のディレクトリのファイルは読み込めません。必ず「クラスと同じディレクトリのBMPファイル」を指定してください。

プログラムソース表示


Javaプログラミング実験室 > プログラミング資料庫