普段Javaはあまり使わないのですが、大学の授業の関係で久しぶりに触りました。
いつもはC++で画像処理をやっているのですが、Javaで画像を扱おうとするとどんな感じになるのかと疑問に思ったので、簡単な画像データ用のクラスを作ってみました。
以下が作成したクラスです。機能的には画像用メモリの確保とRGBAデータのget & setだけです。
/*!
* WspImage is a class which access to some of manipulation of image
*/
public class WspImage
{
private int width_=0, height_=0;
private int[] rgba_data_=null;
//** Constructors -------------------
WspImage(int width, int height){
Resize(width, height);
}
//** Accessors ----------------------
int width(){ return width_; }
int height(){ return height_; }
int[] rgba_data(){ return rgba_data_; }
int GetR(int index)
{ return (rgba_data_[index] & 0xff000000)>>24; }
int GetG(int index)
{ return (rgba_data_[index] & 0x00ff0000)>>16; }
int GetB(int index)
{ return (rgba_data_[index] & 0x0000ff00)>>8; }
int GetA(int index)
{ return (rgba_data_[index] & 0x000000ff); }
int GetR(int x, int y){ return GetR(y*width_+x); }
int GetG(int x, int y){ return GetG(y*width_+x); }
int GetB(int x, int y){ return GetB(y*width_+x); }
int GetA(int x, int y){ return GetA(y*width_+x); }
//** Mutators -----------------------
void Resize(int width, int height){
rgba_data_ = new int[width*height];
width_ = width;
height_ = height;
}
void SetR(int r, int index)
{ rgba_data_[index] = (rgba_data_[index] & 0x00ffffff) + (r<<24); }
void SetG(int g, int index)
{ rgba_data_[index] = (rgba_data_[index] & 0xff00ffff) + (g<<16); }
void SetB(int b, int index)
{ rgba_data_[index] = (rgba_data_[index] & 0xffff00ff) + (b<<8); }
void SetA(int a, int index)
{ rgba_data_[index] = (rgba_data_[index] & 0xffffff00) + a; }
void SetR(int r, int x, int y){ SetR(r, y*width_+x); }
void SetG(int g, int x, int y){ SetG(g, y*width_+x); }
void SetB(int b, int x, int y){ SetB(b, y*width_+x); }
void SetA(int a, int x, int y){ SetA(a, y*width_+x); }
};
この画像用データクラスを作ってJavaとC++の違いから感じた利点・欠点を以下に挙げます。
- 符号なしbyteデータ型がJavaにはないのでintなどで代用する必要がある
- オペレータオーバーロードがJavaはできないので要素アクセスに[]が使えないのが不便
- JavaはGCのおかげでメモリ開放操作が不要なのが楽
- Javaは引数の既定値の設定ができないのが不便
- Javaは1ファイルにクラス1つなので小さいクラスも別ファイルに書かなければならない
思ったより実装の違いは多くありませんでしたが、やはりメモリ開放を考えなくていいのはかなり楽です。でも、このメモリ操作をいかに効率よくやるのかという部分も慣れてくるとプログラミングの楽しみになってくるんですけどね。
ついでに、あまり役には立たないですが、RGBAひとつのデータだけを扱うデータクラスも載せておきます。
public class WspRgba
{
private int data_;
WspRgba(int r, int g, int b, int a){
data_ = (r<<24) | (g<<16) | (b<<8) | a;
}
//** accessors
int data(){ return data_; }
int r(){ return ((data_ & 0xff000000)>>24);}
int g(){ return ((data_ & 0x00ff0000)>>16);}
int b(){ return ((data_ & 0x0000ff00)>>8);}
int a(){ return ((data_ & 0x000000ff));}
//** mutators
void set_r(int r){ data_ = (data_ & 0x00ffffff) + (r<<24); }
void set_g(int g){ data_ = (data_ & 0xff00ffff) + (g<<16); }
void set_b(int b){ data_ = (data_ & 0xffff00ff) + (b<<8); }
void set_a(int a){ data_ = (data_ & 0xffffff00) + a; }
};
最初はこのWspRgbクラスを要素にした画像クラスを作ろうと思ったのですが、Javaだとクラスで配列を作ろうとすると強制的にポインタの配列になってしまい、要素ひとつずつに別個メモリ確保が必要になってしまい、効率を悪くなってしまうので素直にint配列にしました。