Как установить альфа-значение для всех пикселей в растровом изображении, используя MFC или GDI или GDI + - PullRequest
0 голосов
/ 04 июля 2018

Я нахожусь в приложении MFC. Я создал растровое изображение, используя память DC. Я хочу сохранить его в DIB-файле.

Мне покажется, что этот код самый элегантный:

void Save(CBitmap * bitmap) {
  CImage image;
  image.Attach((HBITMAP)pcBitmap->GetSafeHandle());
  image.Save("bla.bmp", Gdiplus::ImageFormatBMP);
}

Полученный файл имеет цветовое пространство 32 BPP со всеми альфа-значениями, установленными в '0'.

Теперь я хочу использовать растровое изображение как растровое изображение панели инструментов:

CMFCToolbar::GetImages()->Load("bla.bmp");

Но все значки исчезли.

MFC внутренне вызывает PreMultiplyAlpha () при импорте растрового изображения. Тогда компоненты RGB всех пикселей равны '0'. Фактически все растровое изображение было обнулено.

Как мне установить альфа-значение для каждого пикселя в 0xFF перед сохранением?

Я пытался:

void Save(CBitmap * bitmap) {
  CImage image;
  image.Attach((HBITMAP)pcBitmap->GetSafeHandle());
  image.SetHasAlphaChannel(true);
  image.AlphaBlend(myBitmapDC, 0, 0);
  image.Save("bla.bmp", Gdiplus::ImageFormatBMP);
}

Но это влияет только на значения RGB пикселей.

До сих пор я сопротивлялся итерации по каждому пикселю и изменял память растрового изображения. Я прошу элегантного решения. Возможно однострочник.

1 Ответ

0 голосов
/ 05 июля 2018

Используйте GetDIBits для чтения 32-битных данных пикселей и циклически перебирайте биты, чтобы установить альфа на 0xFF.

bool Save(CBitmap *bitmap)
{
    if(!bitmap)
        return false;

    BITMAP bm;
    bitmap->GetBitmap(&bm);
        if(bm.bmBitsPixel < 16)
            return false;

    DWORD size = bm.bmWidth * bm.bmHeight * 4;
    BITMAPINFOHEADER bih = { sizeof(bih), bm.bmWidth, bm.bmHeight, 1, 32, BI_RGB };
    BITMAPFILEHEADER bfh = { 'MB', 54 + size, 0, 0, 54 };

    CClientDC dc(0);
    std::vector<BYTE> vec(size, 0xFF);
    int test = GetDIBits(dc, *bitmap, 0, bm.bmHeight, &vec[0],
            (BITMAPINFO*)&bih, DIB_RGB_COLORS);
    for(DWORD i = 0; i < size; i += 4)
        vec[i + 3] = 0xFF;

    CFile fout;
    if(fout.Open(filename, CFile::modeCreate | CFile::modeWrite))
    {
        fout.Write(&bfh, sizeof(bfh));
        fout.Write(&bih, sizeof(bih));
        fout.Write(&vec[0], size);
        return true;
    }

    return false;
}


В качестве альтернативы (но я не уверен, что это надежно) инициализируйте память с 0xFF. GetDIBits устанавливает часть RGB, но не перезаписывает альфа-значения:
std::vector<BYTE> vec(size, 0xFF);
GetDIBits...


Или используя GDI +
bool Save(CBitmap *bitmap)
{
    if(!bitmap)
        return false;

    BITMAP bm;
    bitmap->GetBitmap(&bm);
    if(bm.bmBitsPixel < 16)
        return false; //needs palette

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

    Gdiplus::Bitmap *src = Gdiplus::Bitmap::FromHBITMAP(*bitmap, NULL);
    Gdiplus::Bitmap *dst = src->Clone(0, 0, src->GetWidth(), src->GetHeight(), 
        PixelFormat32bppARGB);

    LPCOLESTR clsid_bmp = L"{557cf400-1a04-11d3-9a73-0000f81ef32e}";
    CLSID clsid;
    CLSIDFromString(clsid_bmp, &clsid);
    bool result = dst->Save(L"file.bmp", &clsid) == 0;
    delete src;
    delete dst;

    Gdiplus::GdiplusShutdown(token);

    return result;
}
...