0

我一直在研究这个问题一段时间。
我正在尝试将 JPEG 支持添加到带有 libjpeg 的程序中。
在大多数情况下,它工作得相当好,但对于一些 JPEG,它们会像左边的图片一样显示出来。

(与原始图像比较。)

这可能不明显,但背景显示为交替的红绿和蓝行。如果有人以前见过这种行为并知道可能的原因,我将不胜感激。

我已将行填充为 4 个字节的倍数,它对问题的帮助很小。

代码:

  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;
      }
   }
}

它就像一个魅力。感谢roygbiv

4

4 回答 4

1

左图像最常见的原因之一是未正确对齐的缓冲区。

我相信 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 代码。)

于 2010-03-26T01:55:44.720 回答
0

看起来您正在接受应该是 RGB 的输入并将其视为 RGBA(32 位位图而不是 24 位)。

于 2010-03-26T01:55:25.203 回答
0

也许您忘记填充每行像素以占用整数个 DWORD。

于 2010-03-26T01:57:40.613 回答
-1

也许问题 jpeg 不是 rgb,而是 cmyk(甚至是灰度)。并非所有的 jpeg 都是 rgb。

PS,(是的,我知道 jpegs 实际上不是 rgb - 是 yuv,只是试图保持这个答案简单)

于 2010-03-26T02:11:16.530 回答