このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
続いて、画素形式に PIXEL_FORMAT を表すクラスを作る。
Java の命名規則に準じて PixelFormat クラスとしよう。
Java には、java.awt.image に類似のクラスが存在し、
DirectColorModel クラスなどが近い意味となるが、
変換用のメソッド等は作らずに、単純な POJO としよう。
========== PixelFormat.java ==========
package jp.loafer.rfb.message;
import java.io.IOException;
import jp.loafer.rfb.RFBContext;
import jp.loafer.rfb.io.RFBInputStream;
import jp.loafer.rfb.io.RFBOutputStream;
/**
* 画素の形式を表すクラス。
* 便宜上 Message を実装しているが不変クラスとする。
* @author kes
*/
public class PixelFormat implements Message {
/**
* 永続化用既定コンストラクタ。
* 既定値はビッグエンディアンの 24 ビット RGB 構造。
*/
public PixelFormat() {
bitPerPixel = 32;
depth = 24;
bigEndian = true;
trueColor = true;
redMax = 0xff;
greenMax = 0xff;
blueMax = 0xff;
redShift = 16;
greenShift = 8;
blueShift = 0;
}
/**
* {@link PixelFormat} のインスタンスを作成。
* @param bitPerPixel 1 画素を格納するビット数。
* @param depth 1 画素を表現するビット数。
* @param bigEndian 色値がビッグエンディアンで格納されているかどうか。
* @param trueColor 色そのものを表しているかどうか。
* @param redMax 赤要素の最大値。
* @param greenMax 緑要素の最大値。
* @param blueMax 青要素の最大値。
* @param redShift 赤要素を取り出す右シフト量。
* @param greenShift 緑要素を取り出す右シフト量。
* @param blueShift 青要素を取り出す右シフト量。
*/
public PixelFormat(int bitPerPixel, int depth,
boolean bigEndian, boolean trueColor,
int redMax, int greenMax, int blueMax,
int redShift, int greenShift, int blueShift) {
this.bitPerPixel = bitPerPixel;
this.depth = depth;
this.bigEndian = bigEndian;
this.trueColor = trueColor;
this.redMax = redMax;
this.greenMax = greenMax;
this.blueMax = blueMax;
this.redShift = redShift;
this.greenShift = greenShift;
this.blueShift = blueShift;
validate();
}
/**
* 1 画素を格納するビット数を取得。
* 1 画素は 1, 2, 4 バイト境界に整列されるため、
* この値は 8 か 16 か 32 である必要がある。
* @return 画素を格納するビット数。
*/
public int getBitPerPixel() {
return bitPerPixel;
}
/**
* 1 画素を表現するビット数を取得。
* この値には詰め物は含まれないため、
* 常に {@link #getBitPerPixel()} 以下になる。
* @return 画素を表現するビット数。
*/
public int getDepth() {
return depth;
}
/**
* パッキングされた画素のバイトオーダーがビッグエンディアンかどうかを取得。
* @return ビッグエンディアンなら true。
*/
public boolean isBigEndian() {
return bigEndian;
}
/**
* 画素が直接的な RGB 表現かどうかを取得。
* @return RGB 表現なら true。
*/
public boolean isTrueColor() {
return trueColor;
}
/**
* 赤要素の最大値(右寄せビットマスク)を取得。
* @return 赤要素の最大値。
*/
public int getRedMax() {
return redMax;
}
/**
* 緑要素の最大値(右寄せビットマスク)を取得。
* @return 緑要素の最大値。
*/
public int getGreenMax() {
return greenMax;
}
/**
* 青要素の最大値(右寄せビットマスク)を取得。
* @return 青要素の最大値。
*/
public int getBlueMax() {
return blueMax;
}
/**
* 赤要素を取り出す右シフト量を取得。
* @return 赤要素を取り出す右シフト量。
*/
public int getRedShift() {
return redShift;
}
/**
* 緑要素を取り出す右シフト量を取得。
* @return 緑要素を取り出す右シフト量。
*/
public int getGreenShift() {
return greenShift;
}
/**
* 青要素を取り出す右シフト量を取得。
* @return 青要素を取り出す右シフト量。
*/
public int getBlueShift() {
return blueShift;
}
/**
* @see Message#read(RFBContext, RFBInputStream)
*/
public void read(RFBContext context, RFBInputStream in) throws IOException {
bitPerPixel = in.readU8();
depth = in.readU8();
bigEndian = in.readU8() != 0;
trueColor = in.readU8() != 0;
redMax = in.readU16();
greenMax = in.readU16();
blueMax = in.readU16();
redShift = in.readU8();
greenShift = in.readU8();
blueShift = in.readU8();
in.readU8();
in.readU8();
in.readU8();
try {
validate();
} catch (IllegalArgumentException ex) {
throw new IOException(ex);
}
}
/**
* @see Message#write(RFBContext, RFBOutputStream)
*/
public void write(RFBContext context, RFBOutputStream out) throws IOException {
out.writeU8(bitPerPixel);
out.writeU8(depth);
out.writeU8(bigEndian ? 1 : 0);
out.writeU8(trueColor ? 1 : 0);
out.writeU16(redMax);
out.writeU16(greenMax);
out.writeU16(blueMax);
out.writeU8(redShift);
out.writeU8(greenShift);
out.writeU8(blueShift);
out.writeU8(0);
out.writeU8(0);
out.writeU8(0);
}
protected void validate() {
// フィールド値の検証
if (bitPerPixel != 8 && bitPerPixel != 16 && bitPerPixel != 32)
throw new IllegalArgumentException("Invalid bitPerPixel.");
if (depth > bitPerPixel)
throw new IllegalArgumentException("Invalid depth.");
if (trueColor) {
if (redMax < 1 || redMax > 0xffff)
throw new IllegalArgumentException("Invalid redMax.");
if (greenMax < 1 || greenMax > 0xffff)
throw new IllegalArgumentException("Invalid greenMax.");
if (blueMax < 1 || blueMax > 0xffff)
throw new IllegalArgumentException("Invalid blueMax.");
if (redShift < 0 || redShift > 31)
throw new IllegalArgumentException("Invalid redShift.");
if (greenShift < 0 || greenShift > 31)
throw new IllegalArgumentException("Invalid greenShift.");
if (blueShift < 0 || blueShift > 31)
throw new IllegalArgumentException("Invalid blueShift.");
}
int redMask = redMax << redShift;
int greenMask = greenMax << greenShift;
int blueMask = blueMax << blueShift;
if (redMask + greenMask + blueMask != (redMask | greenMask | blueMask))
throw new IllegalArgumentException("Conflict field values.");
}
private int bitPerPixel; // 8, 16, 32
private int depth; // 1-32
private boolean bigEndian;
private boolean trueColor;
private int redMax; // 1-ffff
private int greenMax; // 1-ffff
private int blueMax; // 1-ffff
private int redShift; // 0-31
private int greenShift; // 0-31
private int blueShift; // 0-31
}
========== end of PixelFormat.java ==========
非常に単純なクラスとなっている。
単にフィールドを全て引数に取るコンストラクタと、
それらを取得する getter だけで構成されている。
利便性を考えて、PixelFormat は
Message インタフェースを実装している。
PIXEL_FORMAT には詰め物(意味のない値)が含まれるので、
自身で読み書きさせた方が楽であるためだ。
こういったクラスを作成する場合、
eclipse は本当に楽である。
フィールドを定義しておくだけで、
getter とコンストラクタはあっさり自動生成できた。