2007 年 1 月 11 日 23 時 56 分

FixColourMapEntries メッセージ


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


ラストは FixColourMapEntries メッセージだ。
これは種類 1 番のクライアントメッセージで、
クライアントが非 TrueColor の画素表現を使っている際に、
そのカラーテーブル(≒パレット)の一部または全部を、
特定の色に固定したい場合に送られる。

カラーテーブルを使った表現を使う場合、
常に最適な画面表示を行うためには、
状況に応じてカラーテーブルの内容を変更する必要がある。

画面を管理するのはサーバなので、
通常カラーテーブルの管理はサーバが行い、
クライアントに対して通知してくることになる。

しかしながら、クライアントの処理能力によっては、
パレットを固定した方がよい場合もある。
その際にこのメッセージが利用されるのだ。

このメッセージは可変長で、以下のような構造を持つ。

    U8 messageType; // 常に 1
    U8 reserved; // 1 バイトの詰め物
    U16 firstColor; // 範囲の最初のインデックス
    U16 count; // メッセージに含まれる色の数
    ColorEntry colors[]; // カラーテーブル

firstColor と count は、カラーテーブルの
どの部分を固定するかどうかを示している。
firstIndex = 10, count = 4 ならば、
カラーテーブルの 10 番から 13 番までを示すことになる。

colors 配列には count の数の色情報が入る。
色情報は、RGB 各 U16 で構成される組み合わせだ。
ばらばらにすると面倒なので、
ColorEntry というクラスにしておこう。

========== ColorEntry.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;

/**
* カラーテーブルの要素を表す不変クラス。
* @author kes
*/
public class ColorEntry implements Message {

    /**
     * 永続化用既定コンストラクタ。
     */
    public ColorEntry() {
        //
    }
   
    /**
     * {@link ColorEntry} のインスタンスを作成。
     * @param red 赤の値。
     * @param green 緑の値。
     * @param blue 青の値。
     */
    public ColorEntry(int red, int green, int blue) {
        if (red < 0 || red > 0xffff)
                throw new IllegalArgumentException("bad red value.");
        if (green < 0 || green > 0xffff)
                throw new IllegalArgumentException("bad green value.");
        if (blue < 0 || blue > 0xffff)
                throw new IllegalArgumentException("bad blue value.");
        this.red = red;
        this.green = green;
        this.blue = blue;
    }

    /**
     * 赤の値を取得。
     * @return 赤の値。
     */
    public int getRed() {
        return red;
    }

    /**
     * 青の値を取得。
     * @return 青の値。
     */
    public int getBlue() {
        return blue;
    }
   
    /**
     * 緑の値を取得。
     * @return 緑の値。
     */
    public int getGreen() {
        return green;
    }

    /**
     * @see Message#read(RFBContext, RFBInputStream)
     */
    public void read(RFBContext context, RFBInputStream in) throws IOException {
        red = in.readU16();
        green = in.readU16();
        blue = in.readU16();
    }

    /**
     * @see Message#write(RFBContext, RFBOutputStream)
     */
    public void write(RFBContext context, RFBOutputStream out) throws IOException {
        out.writeU16(red);
        out.writeU16(green);
        out.writeU16(blue);
    }

    protected int red;
    protected int green;
    protected int blue;

}

========== end of ColorEntry.java ==========

ColorEntry は、単に RGB を格納するだけのクラスだ。
PixelFormat と同じように、Message を実装させている。

では、肝心のメッセージクラスを作る。

========== FixColorMapEntriesMessage.java ==========

package jp.loafer.rfb.message.client;

import java.io.IOException;

import jp.loafer.rfb.RFBContext;
import jp.loafer.rfb.io.RFBInputStream;
import jp.loafer.rfb.io.RFBOutputStream;
import jp.loafer.rfb.message.ColorEntry;

/**
* FixColourMapEntries  クライアントメッセージ。。
* @author kes
*/
public class FixColorMapEntriesMessage extends BaseClientMessage {

    /**
     * 永続化用既定コンストラクタ。
     */
    public FixColorMapEntriesMessage() {
        //
    }

    /**
     * FixColourMapEntries メッセージを作成。
     * @param firstIndex カラーテーブルが示す色の最初のインデックス。
     * @param colors カラーテーブルの配列。
     */
    public FixColorMapEntriesMessage(int firstIndex, ColorEntry[] colors) {
        if (firstIndex < 0) throw new IndexOutOfBoundsException();
        if (colors == null) throw new NullPointerException();
        this.firstIndex = firstIndex;
        this.colors = colors;
    }
   
    /**
     * カラーテーブルが示す色の最初のインデックスを取得。
     * @return 最初のインデックス。
     */
    public int getFirstIndex() {
        return firstIndex;
    }

    /**
     * カラーテーブルの配列を取得。
     * @return カラーテーブルの配列。
     */
    public ColorEntry[] getColors() {
        return colors.clone();
    }
    /**
     * カラーテーブルの要素を取得。
     * インデックスは {@link #getFirstIndex()} の値に関係なく 0 を基準とする。
     * @param index 0 ベースのインデックス。
     * @return カラーテーブルの要素。
     */
    public ColorEntry getColors(int index) {
        return colors[index];
    }

    /**
     * @see ClientMessage#getType()
     */
    public int getType() {
        return ClientMessage.FIX_COLOR_MAP_ENTRIES;
    }

    /**
     * @see ClientMessage#read(RFBContext, RFBInputStream)
     */
    @Override
    public void read(RFBContext context, RFBInputStream in) throws IOException {
        super.read(context, in);
        in.readU8();
        int length = in.readU16();
        colors = new ColorEntry[length];
        for (int i = 0; i < length; ++i) {
            colors[i] = in.readMessage(context, ColorEntry.class);
        }
    }

    /**
     * @see ClientMessage#write(RFBContext, RFBOutputStream)
     */
    @Override
    public void write(RFBContext context, RFBOutputStream out) throws IOException {
        super.write(context, out);
        out.writeU8(0);
        out.writeU16(colors.length);
        for (int i = 0; i < colors.length; ++i) {
            out.writeMessage(context, colors[i]);
        }
    }

    private int firstIndex;
    private ColorEntry[] colors;

}

========== end of FixColorMapEntriesMessage.java ==========

SetEncodingsMessage クラスと同様、
配列をフィールドとしているので、
複数の getter を用意している。
ColorEntry クラスは(ほぼ)不変クラスなので、
単に配列を clone するだけで特に問題はない。

なお、このメッセージは RFB 3.3 の初期には存在したが、
3.3 の改訂版以降は非推奨となっている。
そのため最近のクライアントはこのメッセージを使わないが、
3.3 をサポートするサーバであれば、
このメッセージを読み出せるようにしておく必要がある。



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