开发者

C: WinAPI CreateDIBitmap() from byte[] problem

I have been working on this problem for a while now.

I am trying to add JPEG support to a program with libjpeg.

For the most part, it is working fairly well, But for some JPEGs, they show up like the picture on the left.

C: WinAPI CreateDIBitmap() from byte[] problem

(Compare with the original image.)

It may not be obvious, but the background shows up with alternating red green and blue rows. If anyone has seen this behavior before and knows a probable cause, I would appreciate any input.

I have padded the rows to be multiples of four bytes, and it only slightly helped the issue.

Code:

  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 * wi开发者_运维知识库nRowSize);
        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);

Solution: I changed the RGB/BGR converter to this:

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

And it worked like a charm. Thanks to roygbiv.


One of the most common causes of the left image is a buffer that is not properly aligned.

I believe Windows expects a DWORD aligned buffer.

One issue I see with the above code is that you do not want to use winRowSize to copy the actual pixels, you want to use a variable with the (width of the image * bytes per pixel). winRowSize copies the DWORD aligned size which is probably too big (although some images may work as they fall on DWORD alignment by default.)

Change the for loop:

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

(You may also have to adjust the rgb to bgr code.)


It looks like you're taking input that's meant to be RGB and treating it as RGBA (32-bit bitmap instead of 24-bit).


Maybe you forgot to pad each row of pixels to occupy an integral number of DWORDs.


maybe the problem jpeg is not is rgb, but is cmyk instead (or even grayscale). not all jpegs are rgb.

PS, (yes I know jpegs are not actually rgb - are yuv instead, just trying to keep this answer simple)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜