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

C++ C++;Gdi+;将图像转换为灰度,c++,gdi+,grayscale,C++,Gdi+,Grayscale,尝试将32、24、16、8位图像转换为灰度显示。我读过关于使用BitBlt的文章,但可能存在一些轻松的内置机会 在GDI+中 代码: #包括 ... 类gdiplus_init { ULONG_PTR令牌; 公众: gdiplus_init() { Gdiplus::GDIPlusStartupInputTMP; Gdiplus::Gdiplus启动(&token,&tmp,NULL); } ~gdiplus_init() { Gdiplus::GdiplusShutdown(令牌); } };

尝试将32、24、16、8位图像转换为灰度显示。我读过关于使用BitBlt的文章,但可能存在一些轻松的内置机会 在GDI+中

代码:

#包括
...
类gdiplus_init
{
ULONG_PTR令牌;
公众:
gdiplus_init()
{
Gdiplus::GDIPlusStartupInputTMP;
Gdiplus::Gdiplus启动(&token,&tmp,NULL);
}
~gdiplus_init()
{
Gdiplus::GdiplusShutdown(令牌);
}
};
bool getbits(const wchar_t*文件名,Gdiplus::PixelFormat PixelFormat,
std::vector&bitmapinfo,std::vector&bits,int&w,int&h)
{
gdiplus_init init;
单词bpp=0;
int用法=DIB_RGB_颜色;
int paletesize=0;
开关(像素格式)
{
已编制索引的案例像素:
bpp=8;
用法=DIB_PAL_颜色;
调色板大小=256*sizeof(RGBQUAD);
打破
案例PixelFormat16bppRGB555:bpp=16;中断;
案例PixelFormat16bppRGB565:bpp=16;中断;
案例像素格式24bpprgb:bpp=24;中断;
案例像素格式32bpprgb:bpp=32;中断;
默认:返回false;
}
auto src=Gdiplus::Bitmap::FromFile(文件名);
如果(src->GetLastStatus()!=Gdiplus::Status::Ok)
返回false;
自动dst=src->Clone(0,0,src->GetWidth(),src->GetHeight(),0,0),
像素格式);
w=src->GetWidth();
h=src->GetHeight();
HBITMAP HBITMAP;
Gdiplus::颜色;
dst->GetHBITMAP(颜色和hbitmap);
//为bitmapinfo分配足够的内存并初始化为零
//它是BITMAPINFO结构的大小+调色板的大小
调整大小(sizeof(bitmapinfo)+调色板大小,0);
//填写前6个参数
BITMAPINFO*ptr=(BITMAPINFO*)BITMAPINFO.data();
ptr->bmiHeader.biSize=sizeof(BitMapInfo头);//不要跳过
ptr->bmiHeader.biWidth=w;
ptr->bmiHeader.biHeight=h;
ptr->bmiHeader.biPlanes=1;
ptr->bmiHeader.biBitCount=bpp;
ptr->bmiHeader.biCompression=BI_RGB;
//计算尺寸的神奇公式:
//这大约是每像素w*h*bytes,是这样写的
//解释“位图填充”的步骤
双字尺寸=((w*bpp+31)/32)*4*h;
//为图像分配内存
调整大小(大小,0);
//最后调用GetDIBits来填充bits和bitmapinfo
HDC HDC=GetDC(0);
GetDIBits(hdc、hbitmap、0、h和位[0],(BITMAPINFO*)和BITMAPINFO[0],用法);
释放DC(0,hdc);
//清理
删除src;
删除dst;
返回true;
}
无效CMFCApplicationColorsView::OnDraw(CDC*pDC)
{
...
std::vector bi;//自动存储
std::向量位;
int w,h;
//24位测试
if(获取比特(L“c:\\test\\24bit.bmp”,像素格式24bpprgb,bi,比特,w,h))
拉伸阻力(dc,0,0,w,h,0,0,w,h,
bits.data(),(BITMAPINFO*)bi.data(),DIB_RGB_颜色,SRCCOPY);
//8位测试
if(获取位(L“c:\\test\\8bit.bmp”,像素格式8bppinged,bi,位,w,h))
拉伸阻力(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);
}
注意,我对灰度矩阵使用了粗略值。有关更好的矩阵,请参阅

要转换文件,过程类似,除了使用
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");
int GetEncoderClsid(常量WCHAR*格式,CLSID*CLSID)
{
int结果=-1;
UINT num=0;//图像编码器的数量
UINT size=0;//图像编码器数组的大小(字节)
Gdiplus::GetImageEncodersSize(&num,&size);
如果(尺寸)
{
Gdiplus::ImageCodecInfo*编解码器=(Gdiplus::ImageCodecInfo*)(malloc(size));
GetImageEncoder(num、size、codec);
对于(UINT j=0;j
Edit:添加了
extension.MakeLower()以防文件扩展名为大写。
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");