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++ 中使用 WINGDIAPI HBITMAP WINAPI 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

这是我从屏幕上捕获的图像

也许Screen Image类会更容易使用。

于 2010-12-29T06:43:49.663 回答
0

JPEG 标准非常复杂。我认为以某种方式填充 DCT 的输出可能是一个问题。DCT 用于将内容从 YCrCb 4:2:2 转换到信号空间,每个通道 Y、Cr 和 Cb 都有一个 DCT。DCT 在“宏块”或“最小编码块”上完成,具体取决于您的上下文。JPEG 通常具有 8x8 宏块。当在边缘并且没有足够的像素时,它会钳制边缘值并“将其拖过”并对其进行 DCT。

我不确定这是否有帮助,但它听起来像是一个不符合标准的文件。我建议您使用JPEGSnoop来了解更多信息。还有一些关于 JPEG 压缩如何工作的解释。

一种可能性是采样率可能被错误地编码。它可能是一些奇特的东西,例如 4:2:1 所以你可能会提取两倍于实际数量的 X 样本,从而扭曲图像。

于 2010-12-29T06:22:42.800 回答