C:来自byte []问题的WinAPI CreateDIBitmap()

时间:2010-03-26 01:43:14

标签: c arrays winapi jpeg libjpeg

我一直在研究这个问题 我正在尝试使用libjpeg为程序添加JPEG支持 在大多数情况下,它工作得相当好,但对于某些JPEG,它们显示为左侧的图片。

(与original image比较。)

可能不是很明显,但背景显示交替的红绿蓝行。如果有人之前已经看过这种行为并且知道可能的原因,我将不胜感激。

我已经将行填充为四个字节的倍数,这只会稍微帮助解决这个问题。

代码:

  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 个答案:

答案 0 :(得分: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代码。)

答案 1 :(得分:0)

看起来你正在接收那些意味着RGB并将其视为RGBA(32位位图而不是24位)的输入。

答案 2 :(得分:0)

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

答案 3 :(得分:-1)

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

PS,(是的,我知道jpeg实际上不是rgb - 而是yuv,只是试图让这个答案变得简单)