CreateDIBSection图形工件或如何正确访问位图位

时间:2014-01-15 17:49:36

标签: c++ winapi gdi

更新

感谢Denis Anisimov,我通过替换:

解决了我的问题
for (int i = 0; i < Width * Height; i++)
    {
        pRgb[0] = RValue;
        pRgb[1] = GValue;
        pRgb[2] = BValue;
        pRgb += 3;
    }

使用:

int BytesPerLine = Width * 3;
if (BytesPerLine % 4 != 0)
    BytesPerLine += 4 - BytesPerLine % 4;
PBYTE Line = NULL;
for (int y = 0; y < Height; y++) 
{
    Line = pRgb;
    for (int x = 0; x < Width; x++) 
    {
        Line[0] = RValue;
        Line[1] = GValue;
        Line[2] = BValue;
        Line += 3;
    }
    pRgb += BytesPerLine;
}

创建独立于设备的位图时,我有时会得到奇怪的线条伪影。它只发生在我改变窗口时,我画画,宽度。在调整大小期间,我删除旧位图并使用自定义函数创建新位图。因为我可以直接访问位图的位,所以我直接改变颜色,但这就是问题发生的地方(我认为),因为FillRect工作得很好。我可能没有正确访问位指针。以下是有效的图片和其他带有文物的图片:

enter image description here enter image description here

此代码显示了我在窗口中的绘制方式:

case WM_PAINT:
    {
        PAINTSTRUCT ps;
        BeginPaint(hWnd, &ps);
        Painter Paint;
        if (temp != NULL)
        {
            DeleteObject(temp);
            temp = NULL;
        }
        temp = Paint.Create24BitBitmap(NULL, ps.rcPaint.right - ps.rcPaint.left - 5, ps.rcPaint.bottom - ps.rcPaint.top - 5, 20, 70, 0);
        HDC MemoryDC = CreateCompatibleDC(ps.hdc);
        SelectObject(MemoryDC, temp);
        BitBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left - 5, ps.rcPaint.bottom - ps.rcPaint.top - 5, MemoryDC, 0, 0, SRCCOPY);
        DeleteDC(MemoryDC);
        EndPaint(hWnd, &ps);
    }
    break;
case WM_NCPAINT:
    {
        RedrawWindow(hWnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE | RDW_INTERNALPAINT);
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    break;

这个展示了我如何创建位图:

HBITMAP Create24BitBitmap(HDC *hDC, int Width, int Height, BYTE RValue, BYTE GValue, BYTE BValue)
    {
        Width = ((Width < 1)?1:Width);
        Height = ((Height < 1)?1:Height);
        RValue = ((RValue > 254)?255:((RValue < 0)?0:RValue));
        GValue = ((GValue > 254)?255:((GValue < 0)?0:GValue));
        BValue = ((BValue > 254)?255:((BValue < 0)?0:BValue));

        HDC MemoryDC = NULL;
        if (hDC != NULL)
            MemoryDC = CreateCompatibleDC(*hDC);
        else
            MemoryDC = CreateCompatibleDC(NULL);

        BITMAPINFO BitmapInfo;
        ZeroMemory(&BitmapInfo,sizeof(BITMAPINFO));
        BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        BitmapInfo.bmiHeader.biWidth = Width;
        BitmapInfo.bmiHeader.biHeight = Height;
        BitmapInfo.bmiHeader.biPlanes = 1;
        BitmapInfo.bmiHeader.biBitCount = 24;
        BitmapInfo.bmiHeader.biCompression = BI_RGB;

        PBYTE pRgb = NULL;
        HBITMAP hBitmap = CreateDIBSection(MemoryDC, &BitmapInfo, DIB_RGB_COLORS, (void**)&pRgb, NULL, NULL);

        DeleteDC(MemoryDC);

        if (hBitmap == NULL)
        {
            MessageBox(NULL, TEXT("\"Create24BitBitmap\" function failed."), TEXT("ERROR!"), MB_ICONERROR);
            exit(EXIT_FAILURE);
        }

        for (int i = 0; i < Width * Height; i++)
        {
            pRgb[0] = RValue;
            pRgb[1] = GValue;
            pRgb[2] = BValue;
            pRgb += 3;
        }
        return hBitmap;
    }

那么问题是如何正确访问位图位?或者是否有其他可能导致此伪影的事情?

在这里你可以找到编译的程序: http://www.putlocker.com/file/D555A03E41032615

1 个答案:

答案 0 :(得分:6)

此代码错误:

for (int i = 0; i < Width * Height; i++)
    {
        pRgb[0] = RValue;
        pRgb[1] = GValue;
        pRgb[2] = BValue;
        pRgb += 3;
    }

位图的每一行的开头必须与4字节边界对齐。

<强>更新

你应该使用这样的东西:

BytesPerLine := Width * 3;
if BytesPerLine mod 4 <> 0 then
  Inc(BytesPerLine, 4 - BytesPerLine mod 4);
for y := 0 to Height - 1 do
  begin
    Line := pRgb;
    for x := 0 to Width - 1 do
      begin
        Line[0] := RValue;
        Line[1] := GValue;
        Line[2] := BValue;
        Inc(Line, 3);
      end;
    Inc(pRgb, BytesPerLine);
  end;