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

发布于 2024-08-26 19:35:49 字数 3104 浏览 3 评论 0原文

我已经研究这个问题有一段时间了。
我正在尝试使用 libjpeg 将 JPEG 支持添加到程序中。
在大多数情况下,它运行得相当好,但对于某些 JPEG,它们显示如左图。

(与 原始图像。)

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

我已将行填充为四个字节的倍数,但这对解决问题仅略有帮助。

代码:

  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

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.

(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 * 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);

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

枉心 2024-09-02 19:35:49

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

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

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.)

自此以后,行同陌路 2024-09-02 19:35:49

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

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).

深居我梦 2024-09-02 19:35:49

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

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

橘寄 2024-09-02 19:35:49

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

PS,(是的,我知道 jpeg 实际上不是 rgb - 而是 yuv,只是想让这个答案简单一些)

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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文