このスレッドを投稿しているのは、Javaで写真を扱うのが難しいからです。画像をbyte []配列に変換し、逆の操作を実行できるようにしたいので、各ピクセルのRGBを変更して、新しい画像を作成できます。 BufferedImageのsetRGB()およびgetRGB()は、巨大な写真には遅すぎる可能性があるため、このソリューションを使用します(間違っている場合は修正してください)。
ここでいくつかの投稿を読んでbyte []配列( hereなど )を取得し、各ピクセルが赤、緑、青の値を含む配列の3つまたは4つのセルで表されるようにします( 4つのセルがある場合の追加のアルファ値)、これは非常に便利で使いやすいです。この配列を取得するために使用するコードは次のとおりです(作成したPixelArrayクラスに格納されています)。
public PixelArray(BufferedImage image)
{
width = image.getWidth();
height = image.getHeight();
DataBuffer toArray = image.getRaster().getDataBuffer();
array = ((DataBufferByte) toArray).getData();
hasAlphaChannel = image.getAlphaRaster() != null;
}
私の大きな問題は、画像を変換したい場合(たとえば、青/緑の値を削除し、赤の値のみを保持する場合)、このbyte []配列を新しい画像に変換する効率的な方法が見つからないことです。私はそれらのソリューションを試しました:
1)DataBufferオブジェクトを作成し、次にSampleModelを作成して、最終的にWritableRasterを作成し、次にBufferedImage(追加のColorModelおよびHashtableオブジェクトを含む)を作成します。どうしても必要な情報がすべて揃っていないので、うまくいきませんでした(BufferedImage()コンストラクターのHashtableが何であるかわかりません)。
2)ByteArrayInputStreamを使用します。 ByteArrayInputStreamで期待されるbyte []配列は私のものとは関係ないため、これは機能しませんでした。ファイルの各バイトを表し、各ピクセルの各コンポーネントではありません(各ピクセルに3〜4バイト)。
誰かが私を助けることができますか?
これを試して:
private BufferedImage createImageFromBytes(byte[] imageData) {
ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
try {
return ImageIO.read(bais);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
ここで説明したアプローチを試しましたが、何らかの理由でどちらも機能しませんでした。 ByteArrayInputStream
およびImageIO.read(...)
を使用するとnullが返されますが、byte[] array = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
は画像データの直接の参照ではなく、画像データのコピーを返します( here も参照) =)。
しかし、私にとっては次のことがうまくいきました。画像データの寸法とタイプがわかっていると仮定しましょう。またbyte[] srcbuf
は、BufferedImage
に変換されるデータのバッファです。次に、
たとえば、空白の画像を作成します
img=new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
データ配列をRaster
に変換し、setData
を使用して画像を塗りつぶします。
img.setData(Raster.createRaster(img.getSampleModel(), new DataBufferByte(srcbuf, srcbuf.length), new Point() ) );
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
byte[] array = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(pixelArray, 0, array, 0, array.length);
結果の画像のGraphicsオブジェクトを使用しようとすると、このメソッドは同期しなくなる傾向があります。画像の上に描画する必要がある場合は、2番目の画像を作成します(永続的である可能性がありますie毎回作成するのではなく、再利用します)drawImage
最初の画像。
何人かの人々は、受け入れられた答えが間違っているというコメントを支持しました。
受け入れられた答えが機能しない場合は、Image.IOが、試行している画像のタイプ(tiffなど)をサポートしていない可能性があります。
これをpomに追加します(別名、jai-imageio-core-1.3.1.jarをクラスパスに入れます):
<!-- https://mvnrepository.com/artifact/com.github.jai-imageio/jai-imageio-core -->
<dependency>
<groupId>com.github.jai-imageio</groupId>
<artifactId>jai-imageio-core</artifactId>
<version>1.3.1</version>
</dependency>
以下のサポートを追加するには:
サポートされている形式のリストは、次の方法で確認できます。
for(String format : ImageIO.getReaderFormatNames())
System.out.println(format);
たとえば、jai-imageio-core-1.3.1.jarをクラスパスにドロップするだけで機能することに注意してください。
追加のサポートを追加する他のプロジェクトには次のものがあります。
ImageIO.readを直接使用するアプローチは、場合によっては正しくありません。私の場合、生のbyte []には画像の幅と高さ、フォーマットに関する情報は含まれていません。 ImageIO.readを使用するだけでは、プログラムが有効なイメージを作成することは不可能です。
画像の基本情報をBufferedImageオブジェクトに渡す必要があります。
BufferedImage outBufImg = new BufferedImage(width、height、bufferedImage.TYPE_3BYTE_BGR);
次に、setRGBまたはsetDataを使用して、BufferedImageオブジェクトのデータを設定します。 (setRGBを使用する場合、最初にbyte []をint []に変換する必要があるようです。そのため、ソースイメージデータが大きい場合、パフォーマンスの問題が発生する可能性があります。 )