Код Jpeglib дает искаженный вывод, даже в комплекте пример кода? - PullRequest
2 голосов
/ 04 февраля 2009

Я на Ubuntu Intrepid и использую jpeglib62 6b-14. Я работал над некоторым кодом, который выдавал черный экран с искаженным выводом вверху, когда пытался его запустить. После нескольких часов отладки я перешел к основам JPEG, поэтому я взял пример кода, написал небольшой фрагмент кода вокруг него, и результат был точно таким же.

Я убежден, что jpeglib используется в гораздо большем количестве мест в этой системе, и это просто версия из репозиториев, поэтому я не решаюсь сказать, что это ошибка в jpeglib или упаковке Ubuntu.

Я поместил пример кода ниже (большинство комментариев удалено). Входной файл JPEG представляет собой несжатый файл 640x480 с 3 каналами, поэтому он должен быть 921600 байт (и он есть). Выходное изображение - JFIF и около 9000 байт.

Если бы вы могли мне помочь даже с подсказкой, я был бы очень благодарен.

Спасибо!

#include <stdio.h>
#include <stdlib.h>
#include "jpeglib.h"
#include <setjmp.h>

int main ()
{
  // read data
  FILE *input = fopen("input.jpg", "rb");
  JSAMPLE *image_buffer = (JSAMPLE*) malloc(sizeof(JSAMPLE) * 640 * 480 * 3);
  if(input == NULL or image_buffer == NULL)
    exit(1);
  fread(image_buffer, 640 * 3, 480, input);

  // initialise jpeg library
  struct jpeg_compress_struct cinfo;
  struct jpeg_error_mgr jerr;
  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_compress(&cinfo);

  // write to foo.jpg
  FILE *outfile = fopen("foo.jpg", "wb");
  if (outfile == NULL)
    exit(1);
  jpeg_stdio_dest(&cinfo, outfile);

  // setup library
  cinfo.image_width = 640;
  cinfo.image_height = 480;
  cinfo.input_components = 3; // 3 components (R, G, B)
  cinfo.in_color_space = JCS_RGB; // RGB
  jpeg_set_defaults(&cinfo); // set defaults

  // start compressing
  int row_stride = 640 * 3; // number of characters in a row
  JSAMPROW row_pointer[1]; // pointer to the current row data
  jpeg_start_compress(&cinfo, TRUE); // start compressing to jpeg

  while (cinfo.next_scanline < cinfo.image_height) {
    row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
    (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
  }

  jpeg_finish_compress(&cinfo);

  // clean up
  fclose(outfile);
  jpeg_destroy_compress(&cinfo);
}

Ответы [ 3 ]

2 голосов
/ 04 февраля 2009

Вы читаете файл JPEG в память (не распаковывая его) и записываете этот буфер, как если бы он был несжатым, поэтому вы получаете мусор. Вам нужно сначала распаковать изображение, прежде чем вы сможете подать его в компрессор JPEG.

Другими словами, компрессор JPEG предполагает, что его входные данные являются необработанными пикселями.

Вы можете преобразовать ваше входное изображение в необработанный RGB, используя ImageMagick:

convert input.jpg rgb:input.raw

Это должно быть точно 921600 байт.

РЕДАКТИРОВАТЬ: Ваш вопрос вводит в заблуждение, когда вы заявляете, что ваш входной JPEG файл в без сжатия . Во всяком случае, я скомпилировал ваш код, и он отлично работает, правильно сжимает изображение. Если вы можете загрузить файл, который вы используете в качестве входных данных, возможно, будет возможна дальнейшая отладка. Если нет, я предлагаю вам протестировать вашу программу, используя изображение, созданное из известного JPEG с использованием ImageMagick:

convert some_image_that_is_really_a_jpg.jpg -resize 640x480! rgb:input.jpg
1 голос
/ 04 февраля 2009

Что именно вы подразумеваете под "входной файл JPEG является несжатым"? JPEG все сжаты.

В вашем коде кажется, что в цикле вы отдаете один ряд пикселей libjpeg и просите его сжать его. Это не работает таким образом. В libjpeg должно быть не менее 8 строк, чтобы начать сжатие (иногда даже больше, в зависимости от параметров). Поэтому лучше оставить libjpeg для контроля входного буфера и не выполнять свою работу за него.

Предлагаю вам прочитать, как cjpeg.c выполняет свою работу. Я думаю, что самый простой способ - поместить ваши данные в необработанный тип, известный libjpeg (скажем, BMP), и использовать libjpeg, чтобы прочитать изображение BMP во его внутреннем представлении и сжать оттуда.

1 голос
/ 04 февраля 2009

Вы читаете входной файл в сжатой памяти, а затем повторно сжимаете его перед тем, как исправить файл. Вам нужно распаковать image_buffer перед тем, как снова сжать его. Или вместо чтения в формате JPEG читать .raw изображение

...