SHOEISHA iD

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

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

特集記事

JavaにおけるGIFファイルの取り扱い

Image I/OでGIF画像の読み込み・保存を行う


  • X ポスト
  • このエントリーをはてなブックマークに追加

Image I/Oで画像を書き込む

 GraphicsExplorerは、Image I/Oの機能を使って、表示中の画像をファイルに書き込むことができます。GraphicsExplorerクラスのコンストラクタでは、Image I/Oで書き込める画像形式の名前すべてをImageIO.getWriterFormatNamesメソッドで取得し、プルダウンリストの形で選択できるようにしています。

GraphicsExplorerクラスのコンストラクタ
public GraphicsExplorer() {
    initComponents();
    // canvasの描画ルーチンを設定
    drawView = new DrawView();
    canvas.setDrawCommand(drawView);
    // 書き込める画像形式の一覧をchoiceSaveTypeに設定する
    String[] saveTypes = ImageIO.getWriterFormatNames();
    Arrays.sort(saveTypes);
    for(String saveType : saveTypes)
        choiceSaveType.add(saveType);
    if(choiceSaveType.getItemCount() > 0)
        getImageWriters(choiceSaveType.getSelectedItem());
    // 読み込める画像形式の一覧から、読み込める画像の一覧を生成し、
    // choiceFilenameに設定する
    createFileList();
}

 保存形式を選択すると、選ばれた画像形式を書き込めるplugin(を表すImageWriter型オブジェクト)のリストをImageIO.getImageWritersByFormatNameメソッドで取得し、その中の1つを選ぶことになります。pluginの一覧は、プルダウンリストの形で選択できますが、読み込みの時と同様に、標準ライブラリに組み込まれているpluginは、1つの画像形式につき1つなので、外部のpluginを導入しない限り、選択の余地はありません。

GraphicsExplorer#getImageWriters(String type)
HashMap<String, ImageWriter> imageWriters = null;
/** 指定された型を保存できるImageWriterの一覧を取得する */
private void getImageWriters(String type) {
    imageWriters = new HashMap<String, ImageWriter>();
    Iterator<ImageWriter> tmpWriters =
        ImageIO.getImageWritersByFormatName(type);
    choiceIW.removeAll();
    while(tmpWriters.hasNext()) {
        ImageWriter imageWriter = tmpWriters.next();
        imageWriters.put(
            imageWriter.getClass().getName(), imageWriter);
        choiceIW.add(imageWriter.getClass().getName());
    }
}

 どのpluginを使って書き込むかを決定し、[保存]ボタンを押すと、画像ファイルの書き込みが行われます。まず、pluginであるImageWriter型オブジェクトに、ImageWriter#setOutputメソッドで書き込むファイルを指定します。次に、ImageWriter#writeメソッドで画像の書き込みを行い、ファイルを閉じれば、保存が完了します。

GraphicsExplorer#buttonSaveActionPerformed(java.awt.event.ActionEvent evt)
/** 保存ボタンが押されたら */
private void buttonSaveActionPerformed(
    java.awt.event.ActionEvent evt) {
    ImageWriter imageWriter =
        imageWriters.get(choiceIW.getSelectedItem());
    if(image == null || imageWriter == null) {
        JOptionPane.showMessageDialog(this, "保存できませんでした");
        return;
    }
    String filename = choiceFilename.getSelectedItem();
    filename = filename.substring(0, filename.lastIndexOf('.'))
        + (Integer)spinnerGraphicsNumber.getValue()
        + "." + choiceSaveType.getSelectedItem();
    try {
        ImageOutputStream ios =
            ImageIO.createImageOutputStream(new File(filename));
        imageWriter.setOutput(ios);
        imageWriter.write(image);
        ios.flush();
        ios.close();
    } catch (IOException e) {
        e.printStackTrace();
        JOptionPane.showMessageDialog(this, "保存できませんでした");
        imageWriter.reset();
        return;
    }
    imageWriter.reset();
    createFileList();
}

 もっと手軽なImage I/Oによる書き込み方法として、ImageIOクラスのwriteメソッドを使うことができます。保存形式を指定するだけで、適切なpluginを自動的に選択し、画像の保存を行います。ただし、条件を満たすpluginが複数あった場合の選択基準については、ドキュメントに記述がないので、注意が必要かも知れません。

ImageI/OでGIFを書き込む

 Image I/Oで画像を書き込めるのは良いのですが、このままではGIFのpluginがないので、GIFで保存できません。どこからか、pluginを持ってくる必要があります。

 本稿では、オープンソースのGIF書き込みpluginとして、gif-pluginFreeHEP Java Library 1.2.2を紹介します。

 gif-pluginは、java.netに登録されたプロジェクトで、ライセンスはApache License, Version 2.0となっています。2005年8月末にリリースされたバージョン0.1が最新版です(2006/9/8現在)。gif-plugin-0.1.jarがplugin本体ですので、ダウンロードしてください。GIFの書き込み処理については、Acme.JPM.Encoders.GifEncoderをベースにしているようです。

 FreeHEP Java Libraryは、高エネルギー物理学のためのライブラリで、ライセンスはLGPLとなっています。現在、2.x系の開発が進められているようですが、成果物の供給がMavenに依存しているため、手軽に使える1.2.2を使います。freehep-v1.2.2.zipをダウンロードし、その中に含まれるfreehep-base.jar、freehep-graphics2d.jar、freehep-graphicsio.jar、freehep-graphicsio-gif.jarの4ファイルを取り出してください。

 pluginを使うのは簡単です。実行時のクラスパスに含めれば、自動的にpluginが認識され、GIFを保存できるようになります。例えば、入手した5つのjarファイルをGraphicsExplorer.jarと同じ場所に置き、

クラスパスを指定して実行
> java -cp "freehep-base.jar;freehep-graphics2d.jar;freehep-graphicsio.jar;
freehep-graphicsio-gif.jar;gif-plugin-0.1.jar;GraphicsExplorer.jar" GraphicsExplorer

 で実行することができます。保存形式でGIFを選ぶと、読み込んだ2つのImageWriterが選べるのが確認できるでしょう。何れかを選んで、GIFを保存することができます。

 めでたし、めでたし。と、言いたいところですが、実は、2つのpluginはともに、小さい画像を保存できないという不具合があります。4x4以下のサイズの画像を保存できないことを確認しています。携帯電話用の画素材として、小さい画像を扱うこともあるので、この点は困りものです。

 もし、紹介したpluginが、利用に際して問題を持っている場合は、自分でソースを修正する、問題を作者に報告して対処してもらう、商用pluginを買ってくる、といった対応が必要になるでしょう。

さいごに

 PNGの普及が進んでいない現在、GIFはまだまだ現役ですが、人によって認識はマチマチなので、JavaでGIFが保存できないという状況も生まれてしまっています。10年前なら、GIFの仕様書を読みながら、読み書きするコードを自前で書いていたと思いますが、今は他の選択肢があります。

 画像はImageに読み込んでdrawImageするだけという人も多いと思いますが、本稿をきっかけに、コンピュータで画像を扱うことの根本的な概念なども勉強してもらえると、プログラミングの幅が広がるのではないかと思います。

 ちなみに、Image I/OのJPEGサポートでは、JPEG2000で規格化された、透過可能なJPEGが読み書きできるようです。お好みでどうぞ。

貼り付けられるCanvas
 NetBeansは、ウィンドウ上に部品をペタペタ貼り付けていくのが楽しいのですが、1つ残念なことがあります。画像を表示したり、描画することのできるCanvasを、ちゃんと使えないのです。
 部品としてCanvasクラスがパレットに置いてあるので、貼り付けることはできます。しかし、よく知られているように、Canvasクラスは、継承したクラスのpaintメソッドを上書きして使うものなので、Canvasクラスそのもののオブジェクトを使うことはありません。Canvasクラスのpaintメソッドには、塗り潰す処理が書かれているので、CanvasクラスそのもののオブジェクトからGraphics型の描画面を取得して描画処理をしても、その上から塗り潰しが実行されてしまいます。
 そこで、Canvasクラスを改造して、外部から与えられた処理で描画を行う仕組みを実装した、部品(beans)を作ることにしました。NetBeansでは、新規ファイル作成で、JavaBeansコンポーネントの雛型が得られるので、Canvasを継承させ、paintメソッドとupdateメソッドを上書きした、DrawableCanvasクラスを作成しました。描画処理本体は、DrawCommandインターフェイスを実装したオブジェクトから得られるようにしています。GraphicsExplorerでは、内部クラスDrawViewが描画処理本体となっています。
 このように処理本体を分離したデザインは、Strategyパターンとして知られています。

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

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

長久 勝(ナガク マサル)

1972年1月10日生まれ。京都府出身。1994年龍谷大学理工学部数理情報学科卒業。ゲーム会社に入社。「ワンダースワンゲームプログラミング」「Javaゲームプログラミング」等を執筆。早稲田大学MNC非常勤講師。神楽坂酔っ払い研究所所長。ホームページはhttp://www6.plala.or.jp/mnagaku/。blog「mnagakuのx86_64地獄」も毎日更新中。

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

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

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/497 2007/10/03 00:14

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング