SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

サーバサイドではじめるJavaグラフィック講座

サーバサイドJavaにおける画像ファイルの読み書き

サーバサイドではじめるJavaグラフィック講座 3


クリッピング処理

 イメージの加工を行う場合、「イメージを切り抜く」という処理が必要となることも多々あります。単に原型のまま拡大縮小するなら簡単ですが、イメージの中から一部分だけを切り抜いて描画するようなことになると、「クリッピング」と呼ばれる処理を理解しておく必要があります。

 クリッピングとは、あらかじめ描画を行う領域を指定しておき、その領域内だけに描画を行う処理です。これは、Graphics2Dを利用することで比較的簡単に行うことができます。Graphics2Dではシェイプ(Shape)を利用して描画を行いますが、このシェイプを使ってクリッピングの領域を設定できる仕組みになっているのです。

 実際に、簡単なクリッピング処理の例を挙げておきましょう。

クリッピングした描画
// import java.awt.geom.*; を追加しておく

public BufferedImage getModifiedImage(BufferedImage im){
    int w1 = im.getWidth(),h1 = im.getHeight();
    BufferedImage im2
       = new BufferedImage(w1,h1,BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 = im2.createGraphics();
    g2.setColor(Color.PINK);
    g2.fillRect(0,0,w1,h1);
    
    Ellipse2D shape
       = new Ellipse2D.Double(w1 / 4,h1 / 4,w1 / 2,h1 / 2);
    g2.clip(shape);
    g2.drawImage(im, 0, 0, null);
    
    g2.dispose();
    return im2;
}
円形にクリッピング領域を設定しイメージを描画する。
円形にクリッピング領域を設定しイメージを描画する。

 これは、円形のクリッピングを設定してイメージを描画させるサンプルです。背景は淡いピンクで塗りつぶしてあります。イメージが切り抜かれて描画されているのが分かりますね。

 クリッピングの処理をしているのは、以下の部分です。

Ellipse2D shape
   = new Ellipse2D.Double(w1 / 4,h1 / 4,w1 / 2,h1 / 2);
g2.clip(shape);

 Ellipse2Dインスタンスを作成し、Graphics2Dclipでクリッピングに設定している、これだけです。これで、以後の描画はすべてクリッピング設定したシェイプの内部にのみ描かれるようになります。ここではdrawImageしていますが、基本的にはすべての描画処理はクリッピングの影響を受けます。

 clipは、連続して実行することでクリップする領域を合算できます。あるシェイプをclipした後に別のシェイプをclipすると、2つのシェイプの重なる領域がクリップされます。

 クリッピングを解除する場合は、setClipという現在のクリップ設定を変更するメソッドでnull設定します。

クリップの演算

 ただし、単純にシェイプをクリップするだけでは、描ける図形の形状も単純なものに限られてしまいます。繰り返しclipを使うことである程度の形状は作れますが、クリップの領域を追加したり削ったりをもっと柔軟に行いたい、という場合には別の方法をとった方が良いでしょう。

 「java.awt.geom」パッケージには、任意の形状を示すためのAreaというクラスが用意されています。これを利用することで、複数のシェイプを演算して領域を作成することができ、この機能を利用すれば、複雑な形でイメージを切り抜き描画できるようになります。簡単な例を挙げておきましょう。

Areaを使ったクリッピング処理
public BufferedImage getModifiedImage(BufferedImage im){
    int w1 = im.getWidth(),h1 = im.getHeight();
    BufferedImage im2
       = new BufferedImage(w1,h1,BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 = im2.createGraphics();
    g2.setColor(Color.PINK);
    g2.fillRect(0,0,w1,h1);
    
    Area area = new Area();
    Ellipse2D shape = new Ellipse2D.Double(im.getWidth() / 2 - 35,
            im.getHeight() / 2 - 35,70,70);
    area.add(new Area(shape));
    shape = new Ellipse2D.Double(im.getWidth() / 2 - 20,
            im.getHeight() / 2 - 20,40,40);
    area.subtract(new Area(shape));
    for(int i = 0;i < 16;i++){
        double x = (im.getWidth() / 2) +
                Math.sin(Math.PI / 8 * i) * 80;
        double y = (im.getHeight() / 2) +
                Math.cos(Math.PI / 8 * i) * 80;
        shape = new Ellipse2D.Double(x - 15,y - 15,30,30);
        area.add(new Area(shape));
    }
    g2.clip(area);
    g2.drawImage(im,0,0,null);
    
    g2.dispose();
    return im2;
}
Areaを使って複数の円を組み合わせたクリッピング領域を作成する。
Areaを使って複数の円を組み合わせたクリッピング領域を作成する。

 多数の円を組み合わせた形で図形をクリッピングして描画していますね。ここでは、Areaを複数作成してクリッピングの領域を作っています。Areaのインスタンス作成は、次のような形で行います。

new Area();
new Area(Shape shape);

 単純にnewするだけの他、Shapeインスタンスを引数にすることで、そのシェイプの形状のAreaを作成することができます。こうして作成したAreaは、Area同士で演算していくことが可能です。ここでは、以下の2通りの演算処理を行っています。

Areaに別のAreaの領域を加算する
[Area].add(Area area);
Areaから別のAreaの領域を減算する
[Area].subtract(Area area);

 加算すると、そのAreaの領域に引数で指定したAreaの領域を区分けた形状になります。また減算すると、そのAreaの領域から引数指定したAreaの領域を取り除いた形状となります。

 このように、Shapeを引数指定して作成した(形状情報を持っている)Areaを用意し、それらを演算することで複雑な形状を作成できます。また、ここではクリッピング領域にAreaを使いましたが、Areaはそのままfill/drawで描画に用いることもできます。複雑な図形を描くときには重宝するでしょう。

まとめ

 今回は、イメージファイルの読み書きから描画、クリッピング処理までイメージの利用全般について説明しました。単にイメージを読み込み、拡大縮小したり、切抜いて描画するだけであれば、これで十分できるようになるでしょう。

 ただし、イメージの処理には、こうした形状に関する処理だけでなく、イメージの状態をさまざまに変更する、いわゆる「フィルタ処理」と呼ばれるものもあります。本格的なイメージ処理にはこれらの知識は不可欠でしょう。

 ということで、次回は「イメージのフィルタ処理」を中心に説明を行う予定です。

修正履歴

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
サーバサイドではじめるJavaグラフィック講座連載記事一覧

もっと読む

この記事の著者

掌田 津耶乃(ショウダ ツヤノ)

三文ライター&三流プログラマ。主にビギナーに向けたプログラミング関連の執筆を中心に活動している。※現在、入門ドキュメントサイト「libro」、カード型学習サイト「CARD.tuyano.com」を公開...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/1070 2008/01/15 09:40

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー