0

画像をJPEGに保存しようとしています。以下のコードは、画像の幅が4の倍数の場合は正常に機能しますが、それ以外の場合は画像が歪んでいます。それはパディングと関係があります。デバッグ中は、各行に0を埋め込むことで、画像をビットマップとして正しく保存できました。ただし、これはJPEGでは機能しませんでした。

覚えておくべき主なポイントは、私の画像がネイティブコールから受け取ったbgr(青緑赤各1バイト)バイト配列として表されていることです。

byte[] data = captureImage(OpenGLCanvas.getLastFocused().getViewId(), x, y);
if (data.length != 3*x*y)
{
  // 3 bytes per pixel
  return false;
}

// create buffered image from raw data
DataBufferByte buffer = new DataBufferByte(data, 3*x*y);
ComponentSampleModel csm = new ComponentSampleModel(DataBuffer.TYPE_BYTE, x, y, 3, 3*x, new int[]{0,1,2} );
WritableRaster raster = Raster.createWritableRaster(csm, buffer, new Point(0,0));
BufferedImage buff_image = new BufferedImage(x, y, BufferedImage.TYPE_INT_BGR); // because windows goes the wrong way...
buff_image.setData(raster);

//save the BufferedImage as a jpeg
try
{
  File file = new File(file_name);
  FileOutputStream out = new FileOutputStream(file);

  JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
  JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(buff_image);
  param.setQuality(1.0f, false);
  encoder.setJPEGEncodeParam(param);
  encoder.encode(buff_image);
  out.close();
  // or JDK 1.4
  // ImageIO.write(image, "JPEG", out);
}
catch (Exception ex)
{
  // Write permissions on "file_name"
  return false;
}

また、C ++でJPEGを作成することも検討しましたが、その内容はさらに少なくなりましたが、それでもオプションです。

どんな助けでも大いに感謝します。レオン

4

3 に答える 3

2

あなたの提案に感謝します、しかし私はそれをなんとか解決することができました。

C++でWINGDIAPIHBITMAPWINAPI CreateDIBSectionを使用していた画像をキャプチャするために、OpenGLはそのビットマップに描画します。知られていないが、ビットマップに自動的にパディングが追加され、幅は4の倍数ではなかった。

したがって、Javaはバイト配列を誤って解釈していました。

正しい方法はバイトを解釈することです

byte[] data = captureImage(OpenGLCanvas.getLastFocused().getViewId(), x, y);
int x_padding = x%4;
BufferedImage buff_image = new BufferedImage(x, y, BufferedImage.TYPE_INT_RGB);

int val;
for (int j = 0; j < y; j++) 
{
  for (int i = 0; i < x; i++) 
  {
    val =  ( data[(i + j*x)*3 + j*x_padding + 2]& 0xff) + 
           ((data[(i + j*x)*3 + j*x_padding + 1]& 0xff) << 8) +
           ((data[(i + j*x)*3 + j*x_padding + 0]& 0xff) << 16);
    buff_image.setRGB(i, j, val);
  }
}

//save the BufferedImage as a jpeg
try
{
  File file = new File(file_name);
  FileOutputStream out = new FileOutputStream(file);

  JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
  JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(buff_image);
  param.setQuality(1.0f, false);
  encoder.setJPEGEncodeParam(param);
  encoder.encode(buff_image);
  out.close();
}
于 2010-12-30T08:29:56.773 に答える
0

JPEG標準は非常に複雑です。どういうわけか、DCTの出力をパディングすることに問題があるのではないかと思います。DCTは、コンテンツをYCrCb 4:2:2から、チャネルごとに1つのDCT、Y、Cr、およびCbを使用して信号空間に変換するために実行されます。DCTは、コンテキストに応じて「マクロブロック」または「最小コード化ブロック」で実行されます。JPEGには通常8x8のマクロブロックがあります。エッジ上にあり、十分なピクセルがない場合、エッジ値をクランプして「ドラッグ」し、その上でDCTを実行します。

これが役立つかどうかはわかりませんが、非標準の準拠ファイルのように聞こえます。詳細については、 JPEGSnoopを使用することをお勧めします。JPEG圧縮がどのように機能するかについてもいくつかの説明があります。

1つの可能性は、サンプルレートが正しくエンコードされていない可能性があることです。4:2:1などのエキゾチックなものである可能性があるため、実際の2倍のXサンプルを取得して、画像を歪ませている可能性があります。

于 2010-12-29T06:22:42.800 に答える
0

画面からキャプチャした画像です

たぶん、ScreenImageクラスの方が使いやすいでしょう。

于 2010-12-29T06:43:49.663 に答える