2006 年 12 月 30 日 3 時 49 分

PixelFormat クラス


このアーカイブは同期化されません。 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 とコンストラクタはあっさり自動生成できた。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.