如何从PNG创建图像列表?

时间:2014-10-29 17:04:24

标签: winapi mfc

我看过here您可以创建一个透明的图片列表。它的工作......有点像。

我用它来创建列表控件的图像列表。结果有点令人失望:

view of actual list image view of list image

左边的那个应该是它的样子。右边的那个是列表控件如何显示它。看起来它只是试图使用alpha作为掩模,并且尝试通过抖动来近似任何混合区域。有没有办法让这个更好,以便我得到一个真正的alpha混合图像?

如果这有任何不同,这是来源:

class CDlg : public CDialog
{
    DECLARE_DYNCREATE(CDlg)

public:
    CDlg(CWnd* pParent = NULL);   // standard constructor
    virtual ~CDlg();

    // Dialog Data
    enum { IDD = IDD_BS_PRINT };
    CGdiPlusBitmapResource m_pBitmap;

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    virtual BOOL OnInitDialog();

    DECLARE_MESSAGE_MAP()
public:
    CListCtrl m_printOptions;
};

BOOL CDlg::OnInitDialog()
{
    __super::OnInitDialog();

    m_pBitmap.Load(IDB_RIBBON_HOMELARGE, _T("PNG"), AfxGetResourceHandle());
    HBITMAP hBitmap;
    m_pBitmap.m_pBitmap->GetHBITMAP(RGB(0, 0, 0), &hBitmap);

    CImageList *pList = new CImageList;
    CBitmap bm;
    bm.Attach(hBitmap);
    pList->Create(32, 32, ILC_COLOR32, 0, 4);
    pList->Add(&bm, RGB(255, 0, 255));
    m_printOptions.SetImageList(pList, LVSIL_NORMAL);

//...
    return TRUE;
}

IMPLEMENT_DYNCREATE(CDlg, CDialog)

CBSPrintDlg::CBSPrintDlg(CWnd* pParent /*=NULL*/)
: CBCGPDialog(CBSPrintDlg::IDD, pParent)
{
}

CBSPrintDlg::~CBSPrintDlg()
{
}

void CBSPrintDlg::DoDataExchange(CDataExchange* pDX)
{
    CBCGPDialog::DoDataExchange(pDX);

    DDX_Control(pDX, IDC_PRINT_OPTIONS, m_printOptions);
}

对于CGdiPlusBitmapResource实现的源代码,请查看here

具有透明度的原始图片是:enter image description here

@Barmak尝试使用不同的图像,看起来很好。我认为这是因为透明度靠近边缘而不是位于图像内。见这里:

enter image description here

2 个答案:

答案 0 :(得分:5)

编辑----------

Gdiplus::GetHBITMAP中的第一个参数应为背景颜色。使用RGB(0, 0, 0)作为背景颜色会导致半透明像素与黑色匹配。

使用Gdiplus::Color(255,255,255,255)(白色)会改善外观(因为ListView背景也是白色的)。但最好将背景更改为Gdiplus::Color(0,255,255,255)(透明)以匹配任何背景。

{
    CGdiPlusBitmapResource gdibmp;
    if (gdibmp.Load(IDB_RIBBON_HOMELARGE, _T("PNG"), AfxGetResourceHandle()))
    {
        HBITMAP hBitmap;
        gdibmp.m_pBitmap->GetHBITMAP(Gdiplus::Color::Transparent, &hBitmap);
        ImageList_AddMasked(*pList, hBitmap, 0);
    }
}

这假设图像都是32x32像素。如果图像大小不同,则必须先将它们调整大小,然后才能添加到图像列表中。

{
    CGdiPlusBitmapResource gdibmp;
    if (gdibmp.Load(id, _T("PNG"), AfxGetResourceHandle()))
    {
        //resize image to 32x32 pixels
        Gdiplus::Bitmap newBmp(32, 32, PixelFormat32bppPARGB);
        double oldh = (double)gdibmp.m_pBitmap->GetHeight();
        double oldw = (double)gdibmp.m_pBitmap->GetWidth();
        double neww = 32;
        double newh = 32;

        double ratio = oldw / oldh;
        if (oldw > oldh)
            newh = neww / ratio;
        else
            neww = newh * ratio;

        Gdiplus::Graphics graphics(&newBmp);
        graphics.SetInterpolationMode(Gdiplus::InterpolationMode::InterpolationModeHighQualityBicubic);
        graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
        graphics.DrawImage(gdibmp.m_pBitmap, 0, 0, (int)neww, (int)newh);

        //add `newBmp` to image list
        HBITMAP hBitmap;
        newBmp.GetHBITMAP(Gdiplus::Color::Transparent, &hBitmap);
        ImageList_AddMasked(m_ImageList, hBitmap, 0);
    }
}

<小时/> 使用GdiPlus::GetHICON获取图标句柄...使用CGdiPlusBitmapResource类,应该可以使用以下内容:

HICON hicon;
m_pBitmap.Load(IDB_RIBBON_HOMELARGE, _T("PNG"), AfxGetResourceHandle());
m_pBitmap.m_pBitmap->GetHICON(&hicon);
pList->Add(hicon);

或使用GetHBITMAP

还要确保启用Visual Styles以改善ListView图标的外观。

以透明背景测试图像:

enter image description here

答案 1 :(得分:-1)

PNG图像包含部分透明的像素(α<255)。这是像Photoshop这样的程序非常常见的事故,最可能的原因是将望远镜图像覆盖在文档图像的顶部而不是正确地合并图层。

如图所示,当图像显示在浅灰色或白色背景上时,图像只能看起来很好。但事情没有发生,背景是黑色的。现在,在小望远镜周围制作抗锯齿像素非常明显,它们会根据其alpha值变成各种深灰色,并且不再与文档图像的白色背景混合。使用GDI函数时非常典型的事故,它不喜欢alpha。

您可以使用GDI +对其进行操作,确保背景颜色正确。但这是相当多的工作,它仍然让您无法正确猜测原始背景颜色。

真的最好回到你使用的任何绘画工具并解决问题。最快的修复应该是将其重新保存为24bpp的BMP图像文件,ymmv。