简体   繁体   English

C ++ GDI + SelectPalette

[英]C++ GDI+ SelectPalette

I am playing with GDI+. 我正在玩GDI +。 Trying to use 尝试使用

pDC->SelectPalette(CPalette::FromHandle(hLogPal), FALSE);
pDC->RealizePalette();

instead of 代替

memcpy(newBitmapInfo + sizeof(BITMAPINFO), rgbquad, palettesize);

But it seem that with it's working with memcpy(newBitmapInfo + sizeof(BITMAPINFO), rgbquad, palettesize); 但是似乎可以与memcpy(newBitmapInfo + sizeof(BITMAPINFO), rgbquad, palettesize); but with SelectPalette only black screen. 但是使用SelectPalette只能黑屏。

I thought that information about color can be used from bitmapinfo or from pallet. 我认为可以从bitmapinfo或托盘使用有关颜色的信息。

All code: 所有代码:

void ConvertTo8BitImage(BYTE** pBitmapInfo, BYTE** imageData)
{
    Gdiplus::GdiplusStartupInput tmp;
    ULONG_PTR token;
    Gdiplus::GdiplusStartup(&token, &tmp, NULL);

    Gdiplus::Bitmap *source = Gdiplus::Bitmap::FromFile(L"D:/TestImage.bmp");
    Gdiplus::Bitmap *destination = source->Clone(0, 0, source->GetWidth(), source->GetHeight(),
        PixelFormat8bppIndexed);

    int width = source->GetWidth();
    int height = source->GetHeight();

    HBITMAP hBitmap;
    Gdiplus::Color color;
    destination->GetHBITMAP(color, &hBitmap);
    int palettesize = 256 * sizeof(RGBQUAD);

    CLSID clsid_bmp;
    CLSIDFromString(L"{557cf400-1a04-11d3-9a73-0000f81ef32e}", &clsid_bmp);
    *pBitmapInfo = new BYTE[(sizeof(BITMAPINFO) + palettesize)];

    BITMAPINFO* ptr = (BITMAPINFO*)*pBitmapInfo;
    ptr->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    ptr->bmiHeader.biWidth = width;
    ptr->bmiHeader.biHeight = height;
    ptr->bmiHeader.biPlanes = 1;

    ptr->bmiHeader.biBitCount = 8;
    ptr->bmiHeader.biCompression = BI_RGB;
    ptr->bmiColors[0].rgbRed = 0;
    DWORD size = ((width * 8 + 31) / 32) * 4 * height;

    *imageData = new BYTE[size];

    HDC hdc = GetDC(0);
    GetDIBits(hdc, hBitmap, 0, height, *imageData, (BITMAPINFO*)*pBitmapInfo, DIB_PAL_COLORS);
    ReleaseDC(0, hdc);

    Gdiplus::GdiplusShutdown(token);
}

void CMFCApplicationColorsView::OnDraw(CDC* pDC)
{
    CMFCApplicationColorsDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    BYTE *bitmapInfo = NULL;
    BYTE *imageData = NULL;

    ConvertTo8BitImage(&bitmapInfo, &imageData);

    int palettesize = 256 * sizeof(RGBQUAD);
    BYTE *newBitmapInfo = new BYTE[(sizeof(BITMAPINFO) + palettesize)];
    ZeroMemory(newBitmapInfo, (sizeof(BITMAPINFO) + palettesize));

    BITMAPINFO *ptr = (BITMAPINFO*)newBitmapInfo;
    ptr->bmiHeader.biBitCount = ((BITMAPINFO*)bitmapInfo)->bmiHeader.biBitCount;
    ptr->bmiHeader.biClrImportant = ((BITMAPINFO*)bitmapInfo)->bmiHeader.biClrImportant;
    ptr->bmiHeader.biClrUsed = ((BITMAPINFO*)bitmapInfo)->bmiHeader.biClrUsed;
    ptr->bmiHeader.biCompression = ((BITMAPINFO*)bitmapInfo)->bmiHeader.biCompression;
    ptr->bmiHeader.biHeight = ((BITMAPINFO*)bitmapInfo)->bmiHeader.biHeight;
    ptr->bmiHeader.biPlanes = ((BITMAPINFO*)bitmapInfo)->bmiHeader.biPlanes;
    ptr->bmiHeader.biSize = ((BITMAPINFO*)bitmapInfo)->bmiHeader.biSize;
    ptr->bmiHeader.biSizeImage = ((BITMAPINFO*)bitmapInfo)->bmiHeader.biSizeImage;
    ptr->bmiHeader.biWidth = ((BITMAPINFO*)bitmapInfo)->bmiHeader.biWidth;
    ptr->bmiHeader.biXPelsPerMeter = ((BITMAPINFO*)bitmapInfo)->bmiHeader.biXPelsPerMeter;
    ptr->bmiHeader.biYPelsPerMeter = ((BITMAPINFO*)bitmapInfo)->bmiHeader.biYPelsPerMeter;
    ptr->bmiColors[0] = ((BITMAPINFO*)bitmapInfo)->bmiColors[0];

    RGBQUAD rgbquad[256];
    memcpy(rgbquad, bitmapInfo + sizeof(BITMAPINFO), palettesize);
    //memcpy(newBitmapInfo + sizeof(BITMAPINFO), rgbquad, palettesize);

    NPLOGPALETTE pPal = (NPLOGPALETTE)LocalAlloc(LMEM_FIXED,
        (sizeof(LOGPALETTE) +
        (sizeof(PALETTEENTRY) * (palettesize))));

    pPal->palVersion = 0x300;
    pPal->palNumEntries = 256;
    for (int i = 0; i < 256; i++)
    {
        pPal->palPalEntry[i].peRed = rgbquad[i].rgbRed;
        pPal->palPalEntry[i].peGreen = rgbquad[i].rgbGreen;
        pPal->palPalEntry[i].peBlue = rgbquad[i].rgbBlue;
        pPal->palPalEntry[i].peFlags = 0;
    }

    HPALETTE hLogPal = CreatePalette((LPLOGPALETTE)pPal);

    pDC->SelectPalette(CPalette::FromHandle(hLogPal), FALSE);
    pDC->RealizePalette();

    StretchDIBits(pDC->GetSafeHdc(), 0, 0, 1920, 1080, 0, 0, 1920, 1080,
        imageData, ptr, DIB_PAL_COLORS, SRCCOPY);


    delete[] bitmapInfo;
    delete[] imageData;
}
 HBITMAP hBitmap; Gdiplus::Color color; destination->GetHBITMAP(color, &hBitmap); 

You did convert to 8-bit bitmap, however GetHBITMAP will return a bitmap handle compatible with your video card, which is probably 32-bit. 您确实已转换为8位位图,但是GetHBITMAP将返回与您的视频卡兼容的位图句柄(可能是32位)。 GDI+ has already processed the palette and returned a bitmap handle which is turned back in to 32-bit. GDI +已经处理了调色板,并返回了一个位图句柄,该句柄被转回了32位。 HBITMAP handle can be painted directly, for example using CreateCompatibleDC and BitBlt . HBITMAP句柄可以直接绘制,例如使用CreateCompatibleDCBitBlt So there is no need to obtaining the palette and passing it to GDI, and no need for 8-bit conversion in the first place. 因此,无需获取调色板并将其传递给GDI,也无需进行8位转换。

If this is necessary for some reason, you can get the bits and palette from 32-bit bitmap, put that in 8-bit bitmap, and draw with StretchDIBits 如果出于某种原因这是必要的,则可以从32位位图中获取位和调色板,将其放入8位位图中,并使用StretchDIBits绘制

The main issue in your code is that it should use DIB_RGB_COLORS flag for GetDIBits/StretchDIBits , because the device context is most likely 32-bit. 您的代码中的主要问题是它应该对GetDIBits/StretchDIBits使用DIB_RGB_COLORS标志,因为设备上下文很可能是32位的。 There is no need for SelectPalette/RealizePalette either (unless it's 8-bit display from 30 years ago) 也不需要SelectPalette/RealizePalette (除非它是30年前的8位显示器)

It makes more sense to get the bits directly from GDI+ using LockBits , and get the palette directly using GetPalette , as seen in the example below. 如下面的示例所示,使用LockBits直接从GDI +获取位,并使用GetPalette直接获取调色板更有意义。

Aside, source and destination have to be deleted before exit. 另外,在退出之前必须删除sourcedestination

void draw(HDC hdc)
{
    Gdiplus::Bitmap *source = Gdiplus::Bitmap::FromFile(L"D:/TestImage.bmp");
    if(!source)
        return;
    int width = source->GetWidth();
    int height = source->GetHeight();

    Gdiplus::Bitmap *destination = source->Clone(0, 0, width, height,
        PixelFormat8bppIndexed);

    //get bitmap bits from GDI+
    Gdiplus::BitmapData data;
    Gdiplus::Rect rect(0, 0, width, height);
    destination->LockBits(&rect, Gdiplus::ImageLockModeRead,
        destination->GetPixelFormat(), &data);
    int bufsize = data.Stride * data.Height;
    BYTE *buf = new BYTE[bufsize];
    memcpy(buf, data.Scan0, bufsize);
    destination->UnlockBits(&data);

    //setup BITMAPINFO
    int bmpinfo_size = sizeof(BITMAPINFO) + 256 * 4;
    BITMAPINFO* bmpinfo = (BITMAPINFO*)new BYTE[bmpinfo_size];
    memset(bmpinfo, 0, bmpinfo_size);
    bmpinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmpinfo->bmiHeader.biWidth = width;
    bmpinfo->bmiHeader.biHeight = -height;
    bmpinfo->bmiHeader.biPlanes = 1;
    bmpinfo->bmiHeader.biBitCount = 8;
    bmpinfo->bmiHeader.biCompression = BI_RGB;
    bmpinfo->bmiHeader.biSizeImage = bufsize;

    //get palette from GDI+
    int palsize = destination->GetPaletteSize();
    Gdiplus::ColorPalette *palette = (Gdiplus::ColorPalette*)new BYTE[palsize];
    destination->GetPalette(palette, palsize);

    //set palette for BITMAPINFO
    memset(&bmpinfo->bmiColors[0], 0, 256 * 4);
    for(int i = 0; i < palette->Count; i++)
    {
        auto clr = Gdiplus::Color(palette->Entries[i]);
        bmpinfo->bmiColors[i].rgbRed = clr.GetR();
        bmpinfo->bmiColors[i].rgbGreen = clr.GetG();
        bmpinfo->bmiColors[i].rgbBlue = clr.GetB();
        bmpinfo->bmiColors[i].rgbReserved = 0;      
    }

    StretchDIBits(hdc, 0, 0, width, height, 0, 0, width, height,
        buf, bmpinfo, DIB_RGB_COLORS, SRCCOPY);

    delete[] buf;
    delete[] bmpinfo;
    delete[] palette;
    delete destination;
    delete source;
}

void CMFCApplicationColorsView::OnDraw(CDC* pDC)
{
    CMFCApplicationColorsDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    Gdiplus::GdiplusStartupInput tmp;
    ULONG_PTR token;
    Gdiplus::GdiplusStartup(&token, &tmp, NULL);

    draw(pDC->GetSafeHdc());

    Gdiplus::GdiplusShutdown(token);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM