ファイルアクセスの手順
サーブレットでは、doActionメソッドでファイルの読み込みと書き出しの処理を行っています。まず、ファイルの読み込みから見てみましょう。最初に、送信されたパラメータの値と、Webアプリケーションのパスから、読み込むファイルのパスを取得しておきます。
String fname = request.getParameter("path"); String dir = getServletContext().getRealPath("/"); File f = new File(dir + fname);
ここでは、ServletContextのgetRealPathを使ってディレクトリのパスを取得し、これを元に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; }

先の「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; }

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