これまでも画像表示については取り扱ってきたが、今回は主に画像処理(ピクセル処理)方法についてみていく。
■ 画像表示
JavaFXでは、以下の画像ファイル形式に対応している。GIFアニメーションや、透過Gif/Pngにも対応している。
画像の表示には、ImageViewクラスを利用する。利用方法については、サンプルコードを参照のこと。
■ 画像エフェクト、画像の重ね合わせ、クリッピング
他のシーングラフ・クラスと同様、ImageViewクラスに対してエフェクトや重ね合わせ、クリッピングなどが設定できる。詳しくは以下の記事を参照のこと。
■ ピクセル操作
画像解析を行う場合や、新しい画像エフェクトを表現したい場合、ピクセルに対して直接操作することができる。ピクセルの読書には、PixelReaderおよびPixelWriterクラスを利用する。利用方法については、サンプルコードを参照のこと。
■ サンプルコード
画像を単純に表示する方法と、ピクセル操作を行うサンプルコードを以下に示す。サンプルでは、本webサイトのヘッダー画像を
- 単純に表示
- RGB値をずらして表示(1ピクセル毎に処理)
- RGB値を反転(全ピクセルを一括処理)
の3種類の方法で表示している。
◇サンプルコード
package application_fx;
import java.nio.IntBuffer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelReader;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.image.WritablePixelFormat;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TestImage extends Application {
public static void main(String[] args)
{
launch( args );
}
@Override
public void start(Stage primaryStage) throws Exception
{
// シーングラフの作成
VBox root = new VBox();
// 単純に画像を読み込んで表示。ファイルの場合はnew File( "ファイル名" ).toURI().toString()でパスを指定する
Image img = new Image( "https://blog.cnobi.jp/v1/blog/user/81fa4a2366161d008bd6cd49023192f1/1444076354" );
ImageView imgView = new ImageView( img );
root.getChildren().add( imgView );
// ピクセル処理(RGB値をずらした)画像を作成
WritableImage wImg1 = createRGBMoveImage( img );
ImageView wImg1View = new ImageView( wImg1 );
root.getChildren().add( wImg1View );
// ピクセル値を反転した画像を作成
WritableImage wImg2 = createInversionImage( img );
ImageView wImg2View = new ImageView( wImg2 );
root.getChildren().add( wImg2View );
// シーンの作成
Scene scene = new Scene( root );
// ウィンドウ表示
primaryStage.setScene( scene );
primaryStage.show();
}
/**
* RGB値をずらした画像を作成
* 赤成分を右下に、緑成分を左上に、青成分を左下に移動させている
* ピクセル毎にgetPixel,setPixel関数を呼びだす(内部でピクセル走査が発生する)ため、低速な処理となる
* @param img
* @return
*/
public WritableImage createRGBMoveImage( Image img )
{
// 白紙イメージを作成
WritableImage wImg = new WritableImage( (int) img.getWidth() , (int) img.getHeight() );
// ピクセル処理
PixelReader reader = img.getPixelReader();
PixelWriter writer = wImg.getPixelWriter();
for( int y = 0 ; y < wImg.getHeight() ; y++ )
for( int x = 0 ; x < wImg.getWidth() ; x++ )
{
// ずれ幅の設定
int gap = 5;
// ピクセル値を作成
int argb = 0x000000;
// α成分を作成
int a = ( reader.getArgb( x , y ) >> 24 ) & 0xFF ;
// 赤成分を作成
int r_x = ( x + gap ) % (int) img.getWidth();
int r_y = ( y + gap ) % (int) img.getHeight();
int r = ( reader.getArgb( r_x , r_y ) >> 16 ) & 0xFF ;
// 緑成分を作成
int g_x = ( x - gap + (int) img.getWidth() ) % (int) img.getWidth();
int g_y = ( y - gap + (int) img.getHeight() ) % (int) img.getHeight();
int g = ( reader.getArgb( g_x , g_y ) >> 8 ) & 0x0FF;
// 青成分を作成
int b_x = ( x + gap ) % (int) img.getWidth();
int b_y = ( y - gap + (int) img.getHeight() ) % (int) img.getHeight();
int b = ( reader.getArgb( b_x , b_y ) & 0xFF );
argb = ( a << 24 ) | ( r << 16 ) | ( g << 8 ) | b;
// ピクセル値を設定
writer.setArgb( x , y, argb);
}
return wImg;
}
/**
* 色を反転した画像を作成する
* ピクセル処理を一括して行うため、比較的高速な処理
* @param img
* @return
*/
public WritableImage createInversionImage( Image img )
{
// 画像サイズを取得
int width = (int) img.getWidth();
int height = (int) img.getHeight();
// 複製したイメージを作成
WritableImage wImg = new WritableImage( width , height );
PixelWriter writer = wImg.getPixelWriter();
// ピクセル配列(フォーマットはARGBの順)を取得
WritablePixelFormat<IntBuffer> format = WritablePixelFormat.getIntArgbInstance();
int[] pixels = new int[ width * height ];
img.getPixelReader().getPixels( 0 , 0 , width , height ,
format, pixels, 0 , width );
// ピクセル操作
for( int y = 0 ; y < height ; y++ )
for( int x = 0 ; x < width ; x++ )
{
// ピクセルを取得
int index = ( y * width ) + x;
int pixel = pixels[ index ];
// ピクセルを反転
// α成分を作成
int a = ( pixel >> 24 ) & 0xFF;
// 赤成分を作成
int r = 0xFF - ( ( pixel >> 16 ) & 0xFF );
// 緑成分を作成
int g = 0xFF - ( ( pixel >> 8 ) & 0xFF );
// 青成分を作成
int b = 0xFF - ( pixel & 0xFF );
// ピクセルを設定
pixel = ( a << 24 ) | ( r << 16 ) | ( g << 8 ) | b;
pixels[ index ] = pixel;
}
// ピクセル配列を設定
writer.setPixels(0 , 0 , width , height , format, pixels, 0 , width);
return wImg;
}
}
◇実行結果
◇解説
- プログラムの流れを見ると、3種類の画像の登録をstart関数で行っている(23行目~50行目)。
- 『単純に画像を表示する』場合には、Imageクラスにファイル名(URL)を指定し、ImageViewクラスに登録することで表示される。(29行目~32行目)
- 『RGB値をずらして表示(1ピクセル毎に処理)』する処理は、createRGBMoveImage関数内で行っている(59行目~101行目)。書込可能な画像はWritableImageクラスで作成(62行目)し、PixelReader.getArgb関数でピクセルのRGBA値を取得、PixelReader.setArgb関数でRGBA値を設定している。ピクセル値はアルファ値(8ビット)、赤成分値(8ビット)、緑成分値(8ビット)、青成分値(8ビット)の合計32ビット値のInt型に格納されているため、ビット操作により各成分値を分離して処理している。
- 『RGB値を反転(全ピクセルを一括処理)』する処理は、createInversionImage関数内で行っている(109行目~155行目)。一括処理する場合は、画像全体のピクセル値を持った配列をPixelReader.getPixels関数で取得し、ピクセル操作の後、PixelWriter.setPixels関数で設定している。ピクセル値はARGBの形で取得・設定するように設定している(120行目)。色の反転は、各成分の最大値0xFFから、実際の成分値を引くことで実現している。
■ 参照
- JavaDoc - Class Image
- JavaFX in the Box