Java: сохранение изображения как проблема перекоса JPEG - PullRequest
0 голосов
/ 29 декабря 2010

Я пытаюсь сохранить изображение в JPEG. Приведенный ниже код отлично работает, когда ширина изображения кратна 4, но в противном случае изображение перекошено. Это как-то связано с отступами. Во время отладки я смог правильно сохранить изображение в виде растрового изображения, добавив в каждую строку нули. Однако это не сработало с 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;
}

Я также смотрел на создание JPEG в C ++, но там было еще меньше материала, но это все еще вариант.

Любая помощь с благодарностью. Leon

Ответы [ 3 ]

1 голос
/ 30 декабря 2010

Спасибо за ваши предложения, но мне удалось разобраться.

Для захвата изображения, которое я использовал WINGDIAPI HBITMAP WINAPI CreateDIBSection в C ++, 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();
}
0 голосов
/ 29 декабря 2010

это изображение, которое я получаю с экрана

Возможно, класс Screen Image будет проще в использовании.

0 голосов
/ 29 декабря 2010

Стандарт JPEG чрезвычайно сложен. Я думаю, что это может быть проблема с дополнением вывода DCT как-то. DCT выполняется для преобразования контента из YCrCb 4: 2: 2 в пространство сигналов с одним DCT для каждого канала, Y, Cr и Cb. DCT выполняется для «макроблока» или «минимально кодированного блока» в зависимости от вашего контекста. JPEG обычно имеет макроблоки 8x8. Когда на краю и не хватает пикселя, он зажимает значение края и «перетаскивает его» и выполняет DCT для этого.

Я не уверен, поможет ли это, но это звучит как нестандартный соответствующий файл. Я предлагаю вам использовать JPEGSnoop , чтобы узнать больше. Есть также несколько объяснений о том, как работает сжатие JPEG.

Одна из возможностей состоит в том, что частота дискретизации может быть закодирована неправильно. Это может быть что-то экзотическое, например 4: 2: 1. Таким образом, вы можете вытянуть вдвое больше образцов X, чем на самом деле, искажая изображение.

...