SHOEISHA iD

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

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

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

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

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

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


ファイルアクセスの手順

 サーブレットでは、doActionメソッドでファイルの読み込みと書き出しの処理を行っています。まず、ファイルの読み込みから見てみましょう。最初に、送信されたパラメータの値と、Webアプリケーションのパスから、読み込むファイルのパスを取得しておきます。

String fname = request.getParameter("path");
String dir = getServletContext().getRealPath("/");

File f = new File(dir + fname);

 ここでは、ServletContextgetRealPathを使ってディレクトリのパスを取得し、これを元にFileインスタンスを作成します。

if (f.exists()) {
    try {
        im = ImageIO.read(f);
    }

 まず、existsでファイルが存在しているかどうかを調べ、存在している場合にはImageIO.read読み込みを行います。これはさまざまな使い方ができますが、最も簡単なのはFileインスタンスを引数に渡して呼び出す方法でしょう。たったこれだけで、Fileインスタンスのファイルを読み込んでBufferedImageとして得ることができます。

 続いて、書き出し処理です。これは、ファイルのパスを指定してFileOutputStreamインスタンスを作成し、ImageIO.writeを呼び出します。

out = new FileOutputStream(dir + "new_saved.png");
ImageIO.write(im,"png",out);
out.flush();

 ImageIO.writeは、引数に書き出すBufferedImage、書き出すフォーマットを示すString、書き出し先となるOutputStreamをそれぞれ指定します。FileOutputStreamを指定すれば、そのままファイルとして保存することができるというわけです。

 このImageIOクラスが用意されて以後、イメージファイルのアクセスは劇的に簡単になりました。Fileを用意し、read/writeを呼び出すだけで済んでしまうのです。

イメージの描画

 続いて、読み込んだイメージを利用した描画について説明しましょう。イメージの描画は、Graphicsクラスに用意されているdrawImageメソッドで行うのが基本です。これは、単に位置を指定して描画を行わせる他、描画元と描画先の領域を指定し拡大縮小して描かせたりすることも可能です。

イメージの縮小描画
public BufferedImage getModifiedImage(BufferedImage im){
    int w1 = im.getWidth(),h1 = im.getHeight();
    int w2 = w1 / 2,h2 = h1 / 2;
    BufferedImage im2
       = new BufferedImage(w1,h1,BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 = im2.createGraphics();
    for(int i = 0;i < 2;i++)
        for(int j = 0;j < 2;j++){
            System.out.println(w2 * i + ":" + h2 * j);
            g2.drawImage(im,w2 * i,h2 * j,w2,h2,null);
        }
    g2.dispose();
    return im2;
}
イメージを縮小し、2×2に配置する。
イメージを縮小し、2×2に配置する。

 先の「SampleGraphicsFromImageFile」に用意しておいた描画処理のメソッドgetModifiedImageを修正して、イメージの描画を行わせてみました。元になるイメージを縦横2分の1に縮小し縦横2×2に並べて描画します。

 描画を行っているdrawImageは、引数の異なるいくつかのものが用意されています。ざっと整理してみましょう。

描画位置を指定する
drawImage(Image img, int x, int y, ImageObserver io);
描画する領域を指定する
drawImage(Image img, int x, int y, int width, int height, ImageObserver io);
描画元と描画先の領域をそれぞれ指定する
drawImage(Image img, int x1, int y2, int x2, int y2, 
                     int x3, int y3, int x4, int y4, ImageObserver io);

 いずれも、最初に描画するImageインスタンスを渡すという点は同じです。その後に続く一連のintパラメータによって描画の方法が変わります。

 1つ目は最も単純な方法で、描画する位置のみを指定し、そこにイメージを描画します。

 2つ目はイメージを拡大縮小して描画したい場合のやり方で、位置と大きさをそれぞれ指定して送信します。

 3つ目は、元のイメージの特定の領域を拡大縮小して描画したい場合の方法です。ここでは、描画元の領域の左上と右下の位置、そして描画先の領域の左上と右下の位置、計4つの位置を渡します。

 全ての方法の最後にあるImageObserverというのは、描画の状態を通達するインスタンスを指定します。これは、AWTなどのGUI利用プログラムでイメージを扱う際に、描画の状況を何らかの形でプログラムが把握する必要がある場合を考えて用意されたものと言えます。

 AWTやSwingでは、コンテナは基本的にImageObserverをimplementsしていますから、これは単純にthisを指定するだけで済みます。ですが、サーブレットにはImageObserverはimplementsされていませんから、自身を指定することはできません。

 ここでは、イメージ更新の通達は不要ということでnull指定してあります。もしイメージの状況を把握する必要がある場合には、サーブレット自身にImageObserverをimplementsして対応することができます。これには、まずサーブレットの定義を、次のように修正します。

public class SampleGraphicsFromImageFile extends HttpServlet
        implements Servlet, ImageObserver {

 ImageObserverは「java.awt」にありますので、あらかじめこれをimportしておきます。こうしてサーブレット自身にImageObserverをimplementsしたら、ImageObserverに必要となるメソッドを用意します。

public boolean imageUpdate(Image im, int info,
        int x, int y, int width, int height) {
    // ここに必要な処理を用意
    return true;
}

 これがイメージ更新時に呼び出されるメソッドです。returnされる値は、さらに更新情報が必要となるか否かを示すもので、必要であればtrueを、不要であればfalseを返します(falseを返した場合、以後、imageUpdateは呼ばれません)。ネットワーク経由でイメージを読み込むような場合には、イメージの更新状況をチェックする必要が生じるでしょう。こうした場合には、このimageUpdateで状況をチェックし、処理することが可能です。

 また、ここではdrawImageを使って縮小描画を行いましたが、前回説明した「アフィン変換」を利用することも可能です。drawImageも座標変換の影響を受けるので、これを利用して図形の縮小などを行えます。

座標変換による縮小
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();
    
    for(int i = 0;i < 5;i++){
        g2.drawImage(im,0,0,null);
        g2.scale(0.9d, 0.9d);
    }
    g2.dispose();
    return im2;
}
座標変換を使い、イメージを連続縮小して描画する。
座標変換を使い、イメージを連続縮小して描画する。

 例えば、これは少しずつイメージを縮小描画する例です。このようにイメージも座標変換を使うことで、面白い効果を得ることができます。

次のページ
クリッピング処理

修正履歴

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

サーバサイドではじめるJavaグラフィック講座連載記事一覧

もっと読む

この記事の著者

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

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

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

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

この記事をシェア

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

イベント

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

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

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

メールバックナンバー