C: WinAPI CreateDIBitmap () из проблемы byte [] - PullRequest
0 голосов
/ 26 марта 2010

Я уже некоторое время работаю над этой проблемой.
Я пытаюсь добавить поддержку JPEG в программу с помощью libjpeg.
По большей части это работает довольно хорошо, но для некоторых JPEG они отображаются как на картинке слева.

image

(Compare with the исходное изображение .)

Это может быть неочевидно, но фон показывает чередующиеся красно-зеленые и синие строки. Если кто-то видел такое поведение раньше и знает вероятную причину, я был бы признателен за любой вклад.

Я добавил строки, чтобы они были кратны четырем байтам, и это только немного помогло в проблеме.

Код:

  rowSize = cinfo.output_width * cinfo.num_components;
  /* Windows needs bitmaps to be defined on Four Byte Boundaries */
  winRowSize = (rowSize + 3) & -4;
  imgSize = (cinfo.output_height * winRowSize + 3) & -4;
  while(cinfo.output_scanline < cinfo.output_height){
        jpeg_read_scanlines(&cinfo, &row_pointer, 1);

        /* stagger read to get lines Bottom->Top (As BMP Requires) */
        location = (imgSize) - (cinfo.output_scanline * winRowSize);
        rowsRead++;

        for(i = 0; i < winRowSize; i++){
           rawImage[location++] = row_pointer[i];
        }
     }

     /* Convert BGR to RGB */
     if(cinfo.num_components == 3){
        for(i = 0; i < imgSize; i += 3){
           tmp = rawImage[i+2];
           rawImage[i+2] = rawImage[i];
           rawImage[i] = tmp;
        }
     }

     biSize = sizeof(BITMAPINFOHEADER);
     if(cinfo.num_components == 1){ /* Greyscale */
        biPallete = 32 * 256;
        biSize += biPallete;
     }

     bitInf = (BITMAPINFO *)malloc(biSize);

     bitInf->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
     bitInf->bmiHeader.biWidth = cinfo.output_width;
     bitInf->bmiHeader.biHeight = cinfo.output_height;
     bitInf->bmiHeader.biPlanes = 1;
     bitInf->bmiHeader.biBitCount = 8*cinfo.num_components;
     bitInf->bmiHeader.biCompression = BI_RGB;
     bitInf->bmiHeader.biSizeImage = 0;
     bitInf->bmiHeader.biXPelsPerMeter = 0;
     bitInf->bmiHeader.biYPelsPerMeter = 0;
     bitInf->bmiHeader.biClrUsed       = 0;
     bitInf->bmiHeader.biClrImportant  = 0;

     if(cinfo.num_components == 1){
        for(i = 0; i < 256; i++){
           bitInf->bmiColors[i].rgbBlue = i;
           bitInf->bmiColors[i].rgbGreen = i;
           bitInf->bmiColors[i].rgbRed = i;
           bitInf->bmiColors[i].rgbReserved = 0;
        }
     }

     /* Loads rawImage into an HBITMAP */
     /* retval = CreateDIBitmap(inDC, &bitInf->bmiHeader, CBM_INIT, rawImage, bitInf, DIB_RGB_COLORS); */
     retval = CreateCompatibleBitmap(inDC, cinfo.output_width, cinfo.output_height);
     errorCode = SetDIBits(inDC, retval, 0, cinfo.output_height, rawImage, bitInf, DIB_RGB_COLORS);

Решение: я изменил конвертер RGB / BGR так:

if(cinfo.num_components == 3){
   for(i = 0; i < cinfo.output_height; i++){
      location = (i * winRowSize);
      for(j = 0; j < rowSize; j += 3){
         tmp = rawImage[location+2];
         rawImage[location+2] = rawImage[location];
         rawImage[location] = tmp;
         location += 3;
      }
   }
}

И это сработало как шарм. Благодаря Ройгбив .

Ответы [ 4 ]

1 голос
/ 26 марта 2010

Одной из наиболее распространенных причин левого изображения является буфер, который не выровнен должным образом.

Я полагаю, что Windows ожидает буфер с выравниванием DWORD.

Одна проблема, которую я вижу с приведенным выше кодом, заключается в том, что вы не хотите использовать winRowSize для копирования фактических пикселей, вы хотите использовать переменную с (ширина изображения * байтов на пиксель). winRowSize копирует размер, выровненный по DWORD, который, вероятно, слишком велик (хотя некоторые изображения могут работать, поскольку они по умолчанию соответствуют выравниванию DWORD).

Изменить цикл for:

        for(i = 0; i < (width of the image * bytes per pixel); i++){ 
           rawImage[location++] = row_pointer[i]; 
        }

(Возможно, вам также придется настроить код rgb на bgr.)

0 голосов
/ 26 марта 2010

возможно, проблема в том, что jpeg не в rgb, а в cmyk (или даже в градациях серого). Не все JPEG являются RGB.

PS, (да, я знаю, что jpegs на самом деле не rgb - вместо этого yuv, просто пытаюсь сделать этот ответ простым)

0 голосов
/ 26 марта 2010

Может быть, вы забыли заполнить каждую строку пикселей, чтобы они занимали целое число DWORD.

0 голосов
/ 26 марта 2010

Похоже, что вы берете ввод, который должен быть RGB, и воспринимаете его как RGBA (32-битный бит вместо 24-битного).

...