gpt4 book ai didi

C++ Gdi+ 将图像转换为灰度

转载 作者:行者123 更新时间:2023-11-30 02:18:48 26 4
gpt4 key购买 nike

尝试将 32、24、16、8 位图像转换为灰度显示。我阅读了有关使用 BitBlt 的信息,但可能存在一些内置机会在 GDI+ 中?

代码:

 #include <vector>
...

class gdiplus_init
{
ULONG_PTR token;
public:
gdiplus_init()
{
Gdiplus::GdiplusStartupInput tmp;
Gdiplus::GdiplusStartup(&token, &tmp, NULL);
}
~gdiplus_init()
{
Gdiplus::GdiplusShutdown(token);
}
};

bool getbits(const wchar_t *filename, Gdiplus::PixelFormat pixelformat,
std::vector<BYTE> &bitmapinfo, std::vector<BYTE> &bits, int &w, int &h)
{
gdiplus_init init;

WORD bpp = 0;
int usage = DIB_RGB_COLORS;
int palettesize = 0;

switch(pixelformat)
{
case PixelFormat8bppIndexed:
bpp = 8;
usage = DIB_PAL_COLORS;
palettesize = 256 * sizeof(RGBQUAD);
break;
case PixelFormat16bppRGB555: bpp = 16; break;
case PixelFormat16bppRGB565: bpp = 16; break;
case PixelFormat24bppRGB: bpp = 24; break;
case PixelFormat32bppRGB: bpp = 32; break;
default:return false;
}

auto src = Gdiplus::Bitmap::FromFile(filename);
if(src->GetLastStatus() != Gdiplus::Status::Ok)
return false;

auto dst = src->Clone(0, 0, src->GetWidth(), src->GetHeight(),
pixelformat);

w = src->GetWidth();
h = src->GetHeight();

HBITMAP hbitmap;
Gdiplus::Color color;
dst->GetHBITMAP(color, &hbitmap);

//allocate enough memory for bitmapinfo and initialize to zero
//it's sizeof BITMAPINFO structure + size of palette
bitmapinfo.resize(sizeof(BITMAPINFO) + palettesize, 0);

//fill the first 6 parameters
BITMAPINFO* ptr = (BITMAPINFO*)bitmapinfo.data();
ptr->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); //don't skip
ptr->bmiHeader.biWidth = w;
ptr->bmiHeader.biHeight = h;
ptr->bmiHeader.biPlanes = 1;
ptr->bmiHeader.biBitCount = bpp;
ptr->bmiHeader.biCompression = BI_RGB;

//magic formula to calculate the size:
//this is roughly w * h * bytes_per_pixel, it's written this way
//to account for "bitmap padding"
DWORD size = ((w * bpp + 31) / 32) * 4 * h;

//allocate memory for image
bits.resize(size, 0);

//finally call GetDIBits to fill bits and bitmapinfo
HDC hdc = GetDC(0);
GetDIBits(hdc, hbitmap, 0, h, &bits[0], (BITMAPINFO*)&bitmapinfo[0], usage);
ReleaseDC(0, hdc);

//cleanup
delete src;
delete dst;

return true;
}

void CMFCApplicationColorsView::OnDraw(CDC* pDC)
{
...
std::vector<BYTE> bi; //automatic storage
std::vector<BYTE> bits;
int w, h;

//24-bit test
if(getbits(L"c:\\test\\24bit.bmp", PixelFormat24bppRGB, bi, bits, w, h))
StretchDIBits(dc, 0, 0, w, h, 0, 0, w, h,
bits.data(), (BITMAPINFO*)bi.data(), DIB_RGB_COLORS, SRCCOPY);

//8-bit test
if(getbits(L"c:\\test\\8bit.bmp", PixelFormat8bppIndexed, bi, bits, w, h))
StretchDIBits(dc, 0, 220, w, h, 0, 0, w, h,
bits.data(), (BITMAPINFO*)bi.data(), DIB_PAL_COLORS, SRCCOPY);
}

最佳答案

您可以通过各种变换直接绘制GDI+。使用 Gdiplus::Graphics 绘制设备上下文。

对于灰度转换,RGB 值都必须相同。 Gdiplus::ColorMatrix 可以转换颜色。绿色通常更重要,它的权重更大。

void draw(CDC *pdc)
{
//this line should be in OnCreate or somewhere other than paint routine
Gdiplus::Bitmap source(L"file.jpg");

//gray scale conversion:
Gdiplus::ColorMatrix matrix =
{
.3f, .3f, .3f, 0, 0,
.6f, .6f, .6f, 0, 0,
.1f, .1f, .1f, 0, 0,
0, 0, 0, 1, 0,
0, 0, 0, 0, 1
};
Gdiplus::ImageAttributes attr;
attr.SetColorMatrix(&matrix,
Gdiplus::ColorMatrixFlagsDefault, Gdiplus::ColorAdjustTypeBitmap);

Gdiplus::Graphics gr(pdc->GetSafeHdc());
Gdiplus::REAL w = (Gdiplus::REAL)source.GetWidth();
Gdiplus::REAL h = (Gdiplus::REAL)source.GetHeight();
Gdiplus::RectF rect(0, 0, w, h);
gr.DrawImage(&source, rect, 0, 0, w, h, Gdiplus::UnitPixel, &attr);
}

请注意,我对灰度矩阵使用了粗略值。参见 the answer mentioned in comment以获得更好的矩阵。

转换文件,过程类似,只是使用Gdiplus::Graphics创建内存dc并保存。

int GetEncoderClsid(const WCHAR* format, CLSID* clsid)
{
int result = -1;
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes
Gdiplus::GetImageEncodersSize(&num, &size);
if(size)
{
Gdiplus::ImageCodecInfo* codec = (Gdiplus::ImageCodecInfo*)(malloc(size));
GetImageEncoders(num, size, codec);
for(UINT j = 0; j < num; ++j)
if(wcscmp(codec[j].MimeType, format) == 0)
{
*clsid = codec[j].Clsid;
result = j;
}
free(codec);
}
return result;
}

bool convert_grayscale(const wchar_t *file_in, const wchar_t *file_out)
{
CStringW extension = PathFindExtensionW(file_out);
extension.Remove(L'.');
extension.MakeLower();
if(extension == L"jpg") extension = L"jpeg";
extension = L"image/" + extension;

CLSID clsid;
if(GetEncoderClsid(extension, &clsid) == -1)
return false;

Gdiplus::Bitmap source(file_in);
if(source.GetLastStatus() != Gdiplus::Status::Ok)
return false;

Gdiplus::REAL w = (Gdiplus::REAL)source.GetWidth();
Gdiplus::REAL h = (Gdiplus::REAL)source.GetHeight();
Gdiplus::RectF rect(0, 0, w, h);
Gdiplus::Bitmap copy((INT)w, (INT)h, source.GetPixelFormat());

Gdiplus::ColorMatrix matrix =
{
.3f, .3f, .3f, 0, 0,
.6f, .6f, .6f, 0, 0,
.1f, .1f, .1f, 0, 0,
0, 0, 0, 1, 0,
0, 0, 0, 0, 1
};

Gdiplus::ImageAttributes attr;
attr.SetColorMatrix(&matrix,
Gdiplus::ColorMatrixFlagsDefault, Gdiplus::ColorAdjustTypeBitmap);
Gdiplus::Graphics gr(&copy);
gr.DrawImage(&source, rect, 0, 0, w, h, Gdiplus::UnitPixel, &attr);

auto st = copy.Save(file_out, &clsid);
return st == Gdiplus::Status::Ok;
}

...
convert_grayscale(L"source.jpg", L"destination.jpg");

关于C++ Gdi+ 将图像转换为灰度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51836869/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com