@IT会議室は、ITエンジニアに特化した質問・回答コミュニティ「QA@IT」に生まれ変わりました。ぜひご利用ください。
- PR -

Javaでの画像変換処理で困ってます。

投稿者投稿内容
シミー
会議室デビュー日: 2004/02/22
投稿数: 16
投稿日時: 2004-02-23 01:00
Javaを使って画像データの変換(gif・jpeg対応、画像サイズ、容量、解像度、色数)をしたいのですが、ImageReader、ImageWriterクラスを使用してるのですが、なかなかうまくいきません。

容量の変換は、圧縮をするとこにより変換できました。
ImageWriterオブジェクトを生成して、

ImageOutputStream stream = ImageIO.createImageOutputStream(new File(filename));
writer.setOutput(stream);

ImageWriteParam param = writer.getDefaultWriteParam();
if (param.canWriteCompressed()) {
  param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality); // quality 圧縮率
} else {
System.out.println("Compression is not supported.");
}

writer.write(null, new IIOImage(image, null, null), param);

ですが、画像サイズ、色数の変更はどのようにやったらよいのかわかりません。
ImageReader、ImageWriterクラス以外での、画像変換できるクラスなどありましたら、お聞かせください。
どなたか、よいアドバイスをいただけると幸いです。
さくらば
大ベテラン
会議室デビュー日: 2002/11/12
投稿数: 145
投稿日時: 2004-02-25 05:08
こんにちは、さくらばです。

引用:

ImageReader、ImageWriterクラス以外での、画像変換できるクラスなどありましたら、お聞かせください。



画像処理には Java2D か JAI (Java Advanced Imaging) を使うのが定番だと思います。
Java2D に関しての概論は次の URL にあります。

http://java.sun.com/j2se/1.4/ja/docs/ja/guide/2d/spec/j2d-title.fm.html

JAI は日本語のドキュメントがあまりなく、英語になってしまいますが次のページに
Tutorial があります。

http://java.sun.com/developer/releases/jai/

引用:

画像サイズ、色数の変更はどのようにやったらよいのかわかりません。



画像サイズの変更はいろいろと方法があります

1 変更したいサイズの BufferedImage オブジェクトを作成し、そこから Graphics
 オブジェクトをとりだして、drawImage メソッドのスケーリングできるものを
 使って描画する。
2 java.awt.image.AffineTransformOp を使用して、スケーリングした BufferedImage
 を生成する。
3 JAI を使う

色数の変更は減色アルゴリズムが必要ですが、これがインプリされているクラスは
残念ながら知りません。もしかしたら、JAI だとできるかもしれません。

自分で減色アルゴリズムを実装できるのであれば、インデックスカラーモデルの
カラーインデックスを変更することで減色できると思います。

グレイイメージにするのであれば、次のように書けます。

コード:
    Image orig = ....   // オリジナルのイメージ
    BufferedImage dest = new BufferedImage(orig.getWidth(), orig.getHeight(),
                                           BufferedImage.TYPE_BYTE_GRAY);
    Graphics g = dest.getGraphics();
    g.drawImage(orig, 0, 0, null);
    g.dispose();


シミー
会議室デビュー日: 2004/02/22
投稿数: 16
投稿日時: 2004-02-25 19:57
さくらばさん、ご返信、良いアドバイスをありがとうございます。

私は、Javaを始めてからまだ1年にも満たないひよっこでして、しかも画像処理などはやったこともなく、すべてが手探り状態でやっていました。
いろいろ調べていくうちにわかったことなんですが、Javaでの画像処理に関するの情報が限りなく少なく、ようやく見つけたページを参考にして、画像の圧縮はできました。

さくらばさんのアドバイスをもとに、画像サイズの変更をいろいろ試してみたいと思います。

これは、私の言葉足らずだったのですが,画像変換後にイメージファイルとして出力しなければならないので、さきほど教えていただいたやり方で画像サイズを変更したものを、イメージファイルをして出力することは可能なのでしょうか?(jpegなどに)
また、画像のリサイズはこちらが任意とした数値に変更は可能なのでしょうか?
(例:800×600px 、132×176px などの数値に)
減色に関してですが、画像ファイルを読み込んだときに、その画像が何ビットカラーで構成されているかを知る方法はあるのでしょうか?

わからないことだらけで、申し訳ありませんが、お聞かせくださると幸いです。
さくらば
大ベテラン
会議室デビュー日: 2002/11/12
投稿数: 145
投稿日時: 2004-02-26 13:32
こんにちは、さくらばです。

引用:

谷 勝さんの書き込み (2004-02-25 19:57) より:

これは、私の言葉足らずだったのですが,画像変換後にイメージファイルとして出力しなければならないので、さきほど教えていただいたやり方で画像サイズを変更したものを、イメージファイルをして出力することは可能なのでしょうか?(jpegなどに)



ImageWriter クラスを使えば可能です。Image I/O については私の Web を見て
いただけないでしょうか。(ImageReader/ImageWriter は Image I/O のクラスです)

http://www5.airnet.ne.jp/sakuraba/java/laboratory/JDK1.4/Graphics/ImageIO/ImageIO.html


引用:

また、画像のリサイズはこちらが任意とした数値に変更は可能なのでしょうか?
(例:800×600px 、132×176px などの数値に)



前に書いた 3 種類の方法すべて任意の大きさにリサイズできます。

任意の大きさにはできないのですが、半分とか 1/3 であれば ImageReader クラス
でサブサンプリングすることもできます。詳しくは上述した URL を参照してください。

引用:

減色に関してですが、画像ファイルを読み込んだときに、その画像が何ビットカラーで構成されているかを知る方法はあるのでしょうか?



このような情報は通常画像ファイルのヘッダ部分に書き込まれているのですが、
IIOMetadata クラスを使用すればこれを見ることができます。

PNG だったらこんな形になります。PNG の部分を JPG や GIF に変えれば、画像フォーマットを
変更できます。

コード:
        Iterator readers = ImageIO.getImageReadersBySuffix("PNG");
        
        if (readers.hasNext()) {
            ImageReader reader = (ImageReader)readers.next();

            try {
                ImageInputStream stream = ImageIO.createImageInputStream(new File(filename));
                reader.setInput(stream);

                System.out.println("Image Metadata");
                IIOMetadata metadata = reader.getImageMetadata(0);
                IIOMetadaNode node = metadata.getAsTree(metadata.getNativeMetadataFormatName());

                // node は org.w3c.dom.Node をインプリメントしているので、
                // シブリングするなり、XSLT を使うなりして node を出力する
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }



これを実行するとつぎのように出力されます。IHDR の属性 bitDepth から 8 bit の
色深度ということが分かります。

コード:
<javax_imageio_png_1.0>
  <IHDR width="600" height="800" bitDepth="8" colorType="RGB" compressionMethod="deflate" filterMethod="adaptive" interlaceMethod="none"/>
  <cHRM whitePointX="31269" whitePointY="32899" redX="63999" redY="33001" greenX="30000" greenY="60000" blueX="15000" blueY="5999"/>
  <gAMA value="45454"/>
  <iCCP profileName="Photoshop ICC profile" compressionMethod="deflate"/>
  <pHYs pixelsPerUnitXAxis="2835" pixelsPerUnitYAxis="2835" unitSpecifier="meter"/>
</javax_imageio_png_1>



GIF の場合は ImageReader#getImageMetadata の代わりに ImageReader#getStreamMetadata
メソッドを使用します。

これを実行すれば、色数が分かるだけでなく、カラーパレットを取得することもできます。

コード:
<javax_imageio_gif_stream_1.0>
  <Version value="89a"/>
  <LogicalScreenDescriptor logicalScreenWidth="600" logicalScreenHeight="800" colorResolution="8" pixelAspectRatio="0"/>
  <GlobalColorTable sizeOfGlobalColorTable="256" backgroundColorIndex="0" sortFlag="FALSE">
    <ColorTableEntry index="0" red="0" green="0" blue="0"/>
    <ColorTableEntry index="1" red="128" green="0" blue="0"/>
    <ColorTableEntry index="2" red="0" green="128" blue="0"/>
    <ColorTableEntry index="3" red="128" green="128" blue="0"/>
             ... 以下、省略 ...



JPEG の画像を読み込むと生成された BufferedImage オブジェクトはカラーモデルが
RGB それぞれ 8bit のものを使用するようです。アルファはありません。
シミー
会議室デビュー日: 2004/02/22
投稿数: 16
投稿日時: 2004-02-27 15:12
さくらばさん、ご返信ありがとうございます。

さくらばさんに、教えていただきましたページを拝見したところ、非常に勉強になりました。私のやりたかったことが、わかりやすく記載されていましたし、新しい発見が数多くありました。
前回、いただいたアドバイスと、ページを参考にさせていただきましたところ、java.awt.image.AffineTransformOp を使用して、スケーリングした BufferedImage を生成し、ImageWriter クラスを使用して出力する方法で、元画像から任意のサイズに変換し、それをイメージファイルに出力することができました。

ありがとうございました。やっと1つ問題が解決できました。

あと2つ悩んでいるところがります。
1つは、サイズ変換後の画像データの容量を取得するようなメソッドはあるのでしょうか?その変換後のデータが、どの程度の領域を使用しているががわかれば、取得できそうな気がするのですが・・・。

もう1つが減色処理のことです。
前回、読み込んだ画像が何ビットカラーで構成されているかなどの情報は、画像ファイルのヘッダ部分に書き込まれていて、IIOMetadata クラスを使用すれば、見ることができると教えていただきましたが、その説明をされているソースコードの部分に、「シブリングする」、「XSLT を使う」とありましたが、「シブリング」とはどうすることなのでしょうか?「XSLT を使う」ともありましたが、「XSLT」は、「Extensible Stylesheet Language Transformations」。XSLTはXSLから文書の変換機能を抜き出したもので、XML文書を他のXML文書やHTML文書に変換することのことでしょうか?初めて耳にする言葉なのでいろいろ調べましたが、どのようにしたらよいのか、よくわかりませんでした。どこか良いページがございましたら、お教えください。
さくらば
大ベテラン
会議室デビュー日: 2002/11/12
投稿数: 145
投稿日時: 2004-03-01 05:00
こんにちは、さくらばです。

引用:

谷 勝さんの書き込み (2004-02-27 15:12) より:
前回、いただいたアドバイスと、ページを参考にさせていただきましたところ、java.awt.image.AffineTransformOp を使用して、スケーリングした BufferedImage を生成し、ImageWriter クラスを使用して出力する方法で、元画像から任意のサイズに変換し、それをイメージファイルに出力することができました。



よかったですね。

引用:

あと2つ悩んでいるところがります。
1つは、サイズ変換後の画像データの容量を取得するようなメソッドはあるのでしょうか?その変換後のデータが、どの程度の領域を使用しているががわかれば、取得できそうな気がするのですが・・・。



これは分かりません。たぶん、難しいのではないかと。
カラーモデルや java.awt.image.DataBuffer に何を使うかなどでずいぶん
違ってしまいます。

引用:

「シブリング」とはどうすることなのでしょうか?「XSLT を使う」ともありましたが、「XSLT」は、「Extensible Stylesheet Language Transformations」。XSLTはXSLから文書の変換機能を抜き出したもので、XML文書を他のXML文書やHTML文書に変換することのことでしょうか?



すいません。不親切でした。両方とも XML でよく使われる言葉です。
XML を解釈する (パースする) には 2 つの種類があって、DOM というと SAX という
ものがあります。DOM は XML ドキュメントをツリー状にメモリに保持する方法で、
このツリーをたどっていくことをシブリングといいました。

メソッド的には org.w3c.dom.Node クラスの getFirstChild と getNextSibling
を使います。たとえば、Image I/O のチュートリアルにあるサンプルがそのまま
使えると思います。

http://java.sun.com/j2se/1.4/ja/docs/ja/guide/imageio/spec/apps.fm5.html

XSLT は谷勝さんが仰られるとおり XML を他の形式に変換するためのもので、
通常はスタイルシートという変換規則を記述したドキュメントを使用して変換を
行います。

ただ、スタイルシートを設定しないと単に XML をそのまま出力できます。出力結
果は先ほどの DOM か SAX もしくはストリームが使えるので、ストリームを使え
ばテキストファイルに出力することができます。
佐々木
大ベテラン
会議室デビュー日: 2003/03/30
投稿数: 121
投稿日時: 2004-03-01 15:08
本筋とぜんぜん関係ないのですが...

さくらばさんの書き込み (2004-03-01 05:00) より(適当に削っています)
引用:

引用:

「シブリング」とはどうすることなのでしょうか?


DOM は XML ドキュメントをツリー状にメモリに保持する方法で、
このツリーをたどっていくことをシブリングといいました。


「シブリングする」より「トラバースする」という方が普通じゃないでしょうか。
そもそも"sibling"は「きょうだい」といった意味の名詞ですし。

なんか揚げ足取りみたいですみません。知らない人が 「シブル + ing」 だと勘違いしちゃうとまずいな、と思ったので。。。
シミー
会議室デビュー日: 2004/02/22
投稿数: 16
投稿日時: 2004-03-02 18:48
さくらばさん、サさん、ご返信ありがとうございます。

--------------------------------------------------------------------------------

サイズ変換後の画像データの容量を取得するのは、とても困難なようなんですねぇ。
なんとかして、byte型に変換できないだろうか?とか、容量取得できそうなメソッドを見つけ
ては、試してみたりもしましたが、どれもうまくはいきませんでした。
こうなると、この方法は取りたくないのですが、サイズ変換後の画像データを1度イメージフ
ァイルに出力した上で再読み込みをかけ、ファイルサイズを取得するしかないのでしょうか?
ファイルサイズによっての判定するする必要がありますので。

--------------------------------------------------------------------------------

画像が何ビットカラーで構成されているかの情報を取得するために、前々回の返信で教えていた
だきました、IIOMetadata クラスを使用し、その画像ファイルのヘッダ部分の情報を抽出しよ
うと思いまして、記載していただきました下記のコードを引用させていただき、gifの色数・カラーパレットの取得いたしました。

コード------------------------------------------------------------------------

  Iterator readers = ImageIO.getImageReadersBySuffix("gif);
    if (readers.hasNext()) {
      ImageReader reader = (ImageReader)readers.next();

      try {
        ImageInputStream stream = ImageIO.createImageInputStream(new File(filename));
        reader.setInput(stream);
        
        IIOMetadata metadata = reader.getStreamMetadata();
        IIOMetadataNode node = (IIOMetadataNode)metadata.getAsTree(metadata.getNativeMetadataFormatName());

        System.out.println("Image Metadata:" + node.getNodeName()); // Dosに出力する。

------------------------------------------------------------------------------

「シブリング」、「トラバース」をしてみようと思いまして、教えていただいたように
org.w3c.dom.Node クラスの getFirstChild、getNextSiblingメソッドを使用して、Nodeを追ってはみましたが、まだ XM Lの出力、あるいは DOM か SAX もしくはストリームを使用して
のテキストファイルに出力までには至っておりません。

--------------------------------------------------------------------------------

減色の処理のモジュールなんですが、今現在やりたいと思っていることは、jpeg形式でのRGBに
24ビットに割り当てられているものを、16ビットに変更し、減色しようと思っています。
インデックスカラーモデルのカラーインデックスを変更することで減色できると教えていただき
まして、記載していただきましたコードを参考に、

 コード------------------------------------------------------------------------

  BufferedImage oriImg = ・・・ // 元画像データ

  BufferedImage newImg = new BufferedImage(oriImg.getWidth(), oriImg.getHeight(),BufferedImage.TYPE_BYTE_GRAY); // 新しくグレースケールのイメージを生成
Graphics g = newImg.createGraphics();
 g.drawImage(oriImg, 0, 0, null);
  g.dispose();

newImg をファイルに出力する。
 
 ------------------------------------------------------------------------------

このようにして、まずはグレイイメージに変換した画像ファイルを出力することができました。

gif形式のイメージファイルを、jpeg形式としてファイル出力するには、新しくBufferedImageを生成する際に、イメージタイプの値(TYPE_BYTE_GRAY)を、jpeg形式(TYPE_INT_RGB)に変換することで、変換できました。

ここで考えてみたのですが、ここのイメージタイプの値を変えることで、減色はできないのでしょうか?
jpeg形式なら、RGBに24ビットを割り当てる(TYPE_INT_RGB)などのように、イメージタイプの値
を変更することで、RGBに16ビットを割り当てるようにすることは可能なのでしょうか?

さきほどまで、イメージタイプの値を変更してやってみましたが、RGBに割り当てられるビット数
は変更されていませんでした。

他にも良い方法がございましたら、お聞かせください。


[ メッセージ編集済み 編集者: 谷 勝 編集日時 2004-03-02 18:55 ]

スキルアップ/キャリアアップ(JOB@IT)