ダイレクトカラーモデル画像をビット調のインデックス付き画像(1ピクセルあたり1ビット)に変換し、インデックス付き画像をBMPとして保存しようとしています。
Java Advanced Imaging APIホームページに記載されているように:
エンコードされた出力のビット深度は、ソース画像のビット深度によって決まります。
のソースコードをBMPImageWriter
見ると、このメカニズムはColorModel#getPixelSize()の戻り値です。
ウィキメディアコモンズの画像の縮小コピーを使用して、最初に色の量子化を実行してカラールックアップテーブルを取得し、次に誤差拡散を実行してフロイド-スタインバーグディザリングを適用します。
PlanarImage surrogateImage = PlanarImage.wrapRenderedImage(image);
PlanarImage op = ColorQuantizerDescriptor.create(surrogateImage, ColorQuantizerDescriptor.OCTTREE, 2, null, null, null, null, null);
LookupTableJAI lut = (LookupTableJAI)op.getProperty("LUT");
IndexColorModel cm = new IndexColorModel(1, lut.getByteData()[0].length, lut.getByteData()[0], lut.getByteData()[1], lut.getByteData()[2]);
op = ErrorDiffusionDescriptor.create(surrogateImage, lut, KernelJAI.ERROR_FILTER_FLOYD_STEINBERG, null);
image = op.getAsBufferedImage();
問題は、image.getColorModel().getPixelSize()
8を返すため、画像が8bppビットマップとして保存されることです。
この画像のサイズは167KiBです。
カラーモデルを誤差拡散に渡す1つの方法は、JAI.KEY_IMAGE_LAYOUTレンダリングヒントを設定することです。
ImageLayout layout = new ImageLayout();
layout.setTileWidth(image.getWidth());
layout.setTileHeight(image.getHeight());
layout.setColorModel(cm);
layout.setSampleModel(op.getSampleModel());
RenderingHints rh = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);
op = ErrorDiffusionDescriptor.create(surrogateImage, lut, KernelJAI.ERROR_FILTER_FLOYD_STEINBERG, rh);
image.getColorModel().getPixelSize()
現在は1を返しますが、結果の画像は大幅に変更されます。
ただし、この画像のサイズは21 KiBで、MSペイントを使用してサンプル画像をモノクロビットマップに変換した場合とほぼ同じです。したがって、JAIBMPImageWriter
は正しいエンコーディングを使用しているように見えますが、2番目の画像をよく見ると、隣接するピクセルの列は8ピクセル離れています。実際、最初の画像を見ることができます。最初の画像のピクセルの各列のみが8列のピクセルに展開されます。
これはJAIのバグですか?これらの8幅のピクセル列を単一列のピクセルに折りたたむためにできることはありますか?