marunomaruno-memo

marunomaruno-memo

leJOS (18) BMPファイルの表示

2011年04月04日 | LEGO
2011-04-04
BMPファイルの表示
================================================================================

leJOSのAPIには、画像ファイルを表示するメソッドが実装されていないようです。

実際には、javax.microedition.lcdui.Graphics クラスの drawImage メソッドが使えそ
うな感じですが、エラーになります。
使い方が誤っているかもしれませんが、ここで、NXC でも使えるBMPファイルを使って画
像をLCDに表示するクラス・メソッド LEDEx#drawGraphic を作りました。

BMPファイルの制限は以下のとおりです。
・横100ドット × 縦64ドット 以内
・白黒(2色)
・圧縮していない

上記の条件に反した画像ファイルを使おうとすると、IllegalArgumentException をス
ローします。

LCDExクラスは、lejos.nxj.LCD クラスを継承しているので、LCDクラスのメソッドは使用
できます。

使い方は、APIを参照してください。

■サンプル・プログラム LCDExSample01
---
import java.io.File;

import jp.marunomaruno.lejos.nxt.LCDEx;
import lejos.nxt.Button;

public class LCDExSample01 {
    public static void main(String[] args) throws Exception {
        LCDEx.clear();
        LCDEx.drawGraphic(new File("mono100.bmp"), 0, 0);
        LCDEx.drawString("Hello", 10, 7);
        Button.waitForPress();
    }
}
/*
 * このプログラムを動かす前に、bmpファイルをNXTにダウンロードします。
 *    nxjupload ファイル名
 */
---



■LCDEx
---
package jp.marunomaruno.lejos.nxt;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import javax.microedition.lcdui.Graphics;

import lejos.nxt.LCD;

/**
* LCD に画像を表示したりするユーティリティです。
*
* @author marunomaruno
* @version 1.0, 2011-04-03
* @since 1.0
*/
public class LCDEx extends LCD {
private static Graphics g = new Graphics();

private LCDEx() {

}

/**
* LCDにfileで指定したBMPファイルの画像を座標(x, y)から表示します。
* BMPファイルは、幅100ピクセル、高さ64ピクセル以内の、圧縮なし2色データとします。
*
* @param file
* BMPファイル
* @param x
* 描画する開始点のx座標
* @param y
* 描画する開始点のy座標
* @param invert
* trueのとき、白黒反転して描画する
* @throws IOException
* BMPファイルがない場合など
* @throws IllegalArgumentException
* 使用できるBMPファイルでない場合
*/
public static void drawGraphic(File file, int x, int y, boolean invert)
throws IOException {
// 座標の指定が範囲外のときは例外をスローする
if (x < 0 || y < 0) {
throw new IllegalArgumentException("Illegal point.");
}

FileInputStream in = new FileInputStream(file);

byte[] info = new byte[0x3e];

in.read(info);
// int bfSize = parse4bytes(info, 0x2); // ファイルサイズ (byte)
int offBits = parse4bytes(info, 0xA); // ファイル先頭から画像データまでのオフセット (byte)
int width = parse4bytes(info, 0x12); // 画像の幅 (ピクセル)
int height = parse4bytes(info, 0x16); // 画像の高さ (ピクセル)
int bitCount = parse2bytes(info, 0x1C); // 1 画素あたりのデータサイズ (bit)
int compression = parse4bytes(info, 0x1E); // 圧縮形式

// System.out.println(" offBits = " + Integer.toHexString(offBits));
// System.out.println(" width = " + Integer.toHexString(width));
// System.out.println(" height = " + Integer.toHexString(height));
// System.out.println(" bitCount = " + Integer.toHexString(bitCount));
// System.out.println("compression = " +
// Integer.toHexString(compression));

// 描画サイズが大きいときは例外をスローする
if (width > LCD.SCREEN_WIDTH || height > LCD.SCREEN_HEIGHT) {
throw new IllegalArgumentException("Illegal file format.");
}

// モノクロでないときは例外をスローする
if (bitCount != 1) {
throw new IllegalArgumentException("Illegal file format.");
}

// 圧縮されているときは例外をスローする
if (compression != 0) {
throw new IllegalArgumentException("Illegal file format.");
}

// 描画データの先頭までスキップする
in.skip(offBits - 0x3e);

// 描画する
int byteWidth = width / 8; // あまりを含めないのバイト数
int remainderBitWidth = width % 8; // あまりビット数
int readingUnitWidth = ceil((width + 7) / 8, 4); // 4バイト単位の読み込むバイト数

byte[] widthData = new byte[readingUnitWidth];

y = height - 1 + y;
int count = -1;
while ((count = in.read(widthData)) != -1) {

// System.out.printf("%d ", count);
int i = 0;
for (i = 0; i < Math.min(byteWidth, count); i++) {
drawByte(widthData[i], x + i * 8, y, invert);
}

if (remainderBitWidth > 0) {
drawByte(widthData[i], x + i * 8, y, remainderBitWidth, invert);
}

y--;
}

in.close();
}

/**
* LCDにfileで指定したBMPファイルの画像を座標(x, y)から表示します。
* BMPファイルは、幅100ピクセル、高さ64ピクセル以内の、圧縮なし2色データとします。
*
* @param file
* BMPファイル
* @param x
* 描画する開始点のx座標
* @param y
* 描画する開始点のy座標
* @throws IOException
* BMPファイルがない場合など
* @throws IllegalArgumentException
* 使用できるBMPファイルでない場合
*/
public static void drawGraphic(File file, int x, int y) throws IOException {
drawGraphic(file, x, y, false);
}

/**
* LCDにfileで指定したBMPファイルの画像を画面左上から表示します。
* BMPファイルは、幅100ピクセル、高さ64ピクセル以内の、圧縮なし2色データとします。
*
* @param file
* BMPファイル
* @throws IOException
* BMPファイルがない場合など
* @throws IllegalArgumentException
* 使用できるBMPファイルでない場合
*/
public static void drawGraphic(File file) throws IOException {
drawGraphic(file, 0, 0);
}

private static int ceil(int byteWidthWithRemainder, int base) {
return byteWidthWithRemainder + (base - byteWidthWithRemainder % base)
% base;
}

private static int parse4bytes(byte[] data, int pos) {
return (parse2bytes(data, pos + 2) << (2 * 8))
+ parse2bytes(data, pos + 0);
}

private static int parse2bytes(byte[] data, int pos) {
return (data[pos + 1] << 8) + data[pos + 0];
}

private static void drawByte(int data, int x, int y, boolean invert) {
drawByte(data, x, y, 8, invert);
}

private static void drawByte(int data, int x, int y, int bitCount,
boolean invert) {
if (x >= LCD.SCREEN_WIDTH || y >= LCD.SCREEN_HEIGHT) {
return;
}

for (int i = 0; i < bitCount; i++) {
if (((data & 0x00000080) == 0) ^ invert) {
g.fillRect(x + i, y, 1, 1);
}
data <<= 1;
}
}

}
---</pre>


なお、BMPのフォーマットについては以下のサイトを参考にしました。

Bitmapファイルフォーマット
http://www.umekkii.jp/data/computer/file_format/bitmap.cgi

BMP ファイルフォーマット
http://www.kk.iij4u.or.jp/~kondo/bmp/


以上

最新の画像もっと見る

コメントを投稿