- PR -

Graphics2D#drawImage()の挙動について

1
投稿者投稿内容
enu11
会議室デビュー日: 2007/04/06
投稿数: 2
投稿日時: 2007-04-06 11:53
はじめまして。掲題の件についてご質問いたします。
Java2Dを初心者のため、よく理解できていないのが現状です。
長文となり申し訳ありませんが、ご助力いただけますようお願いいたします。


【現象概要】
2つのBufferedImageがあり、一方から他方へGraphics2D#drawImage()を使用して画像を書き込む。
このとき、書き込んだ画像と異なる画像が作成される。
下記のimage1(対角線)の画像とならずに、階段状の画像が作成されます。
後述の【実行結果】を参照ください。

【BufferedImageの説明】
・BufferedImageの1(image1)
 白地に右上隅から左下隅へかけて、黒の対角線が描かれている。
 BufferedImageの構成は以下の通り
 width, height = 16
 imageType = BufferedImage#TYPE_BYTE_BINARY
 IndexColorModel
  bits = 1
  size = 2
  r, g, b = byte[]{(byte)255, 0}

・BufferedImageの2(image2)
 すべて白地。
 BufferedImageの構成はimage1と同じ

【質問】
どのような理由により上記現象が発生しているかご教授ください。
回避手段があるようでしたらご教授願います。

【補足】
・BufferedImageのIndexColorModelのr,g,bを「byte[]{0, (byte)255}」とすると上記現象は発生しません。
・BufferedImageのsetRGB()、getRGB()を使用すれば上記現象が起きないのは確認できているのですが、上記現象の発生理由がわからないので、知りたい限りです。
・RenderingHints、BufferedImageOpを色々と試したのですが、現状と変わりませんでした。

【環境】
JDK1.4.2_06(少々古いですが、他の制約のためVer変更できず)

【コード】
コード:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.IndexColorModel;
import java.awt.image.WritableRaster;

public class DrawImageTest {
    public static void main(String[] args) {
        DrawImageTest test = new DrawImageTest();
        test.doMain();
    }
    
    private void doMain() {
        // IndexColorModelの作成
        // 0が白、1が黒のIndexColorModel
        byte[] colorArray = new byte[]{(byte)0xff, 0};
        IndexColorModel colorModel = new IndexColorModel(
                1, colorArray.length, colorArray, colorArray, colorArray);
        
        // BufferedImage作成(image1)
        BufferedImage image1 = new BufferedImage(
                16, 16, BufferedImage.TYPE_BYTE_BINARY, colorModel);
        // 白地に右上から左下に掛けて黒の線を引く。
        for (int y = 0; y < 16; y++) {
            for (int x = 0; x < 16; x++) {
                if (x == 15 - y) {
                    image1.setRGB(x, y, Color.black.getRGB());
                } else {
                    image1.setRGB(x, y, Color.white.getRGB());
                }
            }
        }
        
        // BufferedImage作成(image2)
        BufferedImage image2 = new BufferedImage(
                16, 16, BufferedImage.TYPE_BYTE_BINARY, colorModel);
        
        // image1のデータを出力
        System.out.println("image1");
        this.printElementData(image1);
        System.out.println("");
        
        // image2のデータを出力
        System.out.println("image2");
        this.printElementData(image2);
        System.out.println("");
        
        // image2からGraphics2Dを取得し、image1をdraw
        Graphics2D graphics = image2.createGraphics();
        graphics.drawImage(image1, null, 0, 0);
        
        // image2のデータを出力
        System.out.println("image2 <- image1.");
        this.printElementData(image2);
    }
    
    private void printElementData(BufferedImage image) {
        WritableRaster raster = image.getRaster();
        byte[] data = (byte[])raster.getDataElements(
                0, 0, raster.getWidth(), raster.getHeight(), null);
        System.out.println("--------------------------------");
        for (int i = 0; i < data.length; i++) {
            if (i != 0 && i % raster.getWidth() == 0) {
                // 改行
                System.out.println("");
            }
            System.out.print(data[i]);
        }
        System.out.println("");
        System.out.println("--------------------------------");
    }
}




【実行結果】
image1
--------------------------------
0000000000000001
0000000000000010
0000000000000100
0000000000001000
0000000000010000
0000000000100000
0000000001000000
0000000010000000
0000000100000000
0000001000000000
0000010000000000
0000100000000000
0001000000000000
0010000000000000
0100000000000000
1000000000000000
--------------------------------

image2
--------------------------------
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
--------------------------------

image2 <- image1.
--------------------------------
0000000011111111
0000000011111110
0000000011111100
0000000011111000
0000000011110000
0000000011100000
0000000011000000
0000000010000000
1111111100000000
1111111000000000
1111110000000000
1111100000000000
1111000000000000
1110000000000000
1100000000000000
1000000000000000
--------------------------------
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2007-04-06 13:16
引用:

enu11さんの書き込み (2007-04-06 11:53) より:
【環境】
JDK1.4.2_06(少々古いですが、他の制約のためVer変更できず)


1.6.0 あたりで試してみましたが、この現象が起きました。
提示されたソースコードを見てみましたが、私にはこの現象がソースコードに起因して起きているとは思えませんでした。(もっとも IndexColorModel は使った経験がないのですが。)

image2 に drawImage した直後の時点で、その内容がおかしいようです。image2 を JPanel などに paint してもやはり階段状に表示されます。

Java2D のバグなんじゃないでしょうか。

--
unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86}
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-04-06 13:24
私の環境でも発生しましたが…
気になる点が少々。

引用:

・BufferedImageのIndexColorModelのr,g,bを「byte[]{0, (byte)255}」とすると上記現象は発生しません。


この部分と、TYPE_BYTE_BINARY のjavadocの以下の部分です。
http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/awt/image/BufferedImage.html#TYPE_BYTE_BINARY
引用:

色データをこの型のイメージに格納する場合、IndexColorModel によって、カラーマップのもっとも近い色が判断され、結果のインデックスが格納されます。IndexColorModel カラーマップの色によっては、アルファ成分または色成分の近似および損失が発生する可能性があります。


憶測ですが、
drawImageの過程でColorModelがTYPE_BYTE_BINARYのまま処理されるのではなく
ほかのカラーモードで処理された後に変換されているのではないだろうか?
と思いました。
(でもBufferedImageってそういうものだったっけ?)

ちゃんとソースを追わないと原因究明はできなさそうですが
さすがにそこまで手を出している時間が今はとれませんね…
enu11
会議室デビュー日: 2007/04/06
投稿数: 2
投稿日時: 2007-04-06 17:27
お世話になります。
unibonさん、nagiseさん、ご確認ならびにご返答いただきましてありがとうございました。
また調査まで頂きまして本当にありがとうございます。

Java2Dの初心者ということもあり、バグの疑いは持っておりませんでした。
(私の知識不足が原因との認識でした。)

簡単にSunのBug Databaseの検索を行いましたところ、IndexColorModelでの色変換に関して、問題がいくつか残っているようです。
この後、もう少し詳細に調べてみたいと思います。
あとはソースも追ってみたいと思います。

何かわかりましたら、こちらに記載させていただきます。
以上、ありがとうございました。
1

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