Как создать мейлиста из PNG?

Я видел здесь, что вы можете создать список изображений с прозрачностью. Он работает... вроде.

Я использовал это, чтобы создать список изображений для элемента управления списком. Результаты были немного разочаровывающими:

view of actual list imageview of list image

Слева - как он должен выглядеть. Справа видно, как отображает его элемент управления списком. Похоже, что он просто пытался использовать альфу в качестве маски, и любая смешанная область пыталась аппроксимироваться сглаживанием. Есть ли способ получить это лучше, чтобы получить фактическое альфа-смешанное изображение?

Вот источник, если это имеет значение:

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 посмотрите здесь.

Исходное изображение с прозрачностью: введите описание изображения здесь

@Barmak попробовал с другим изображением, и все выглядит отлично. Я думаю, это потому, что прозрачность находится рядом с краем и не находится внутри изображения. См. Здесь:

введите описание изображения здесь

Ответ 1

Изменить ----------

Первый параметр в 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.

Тестовое изображение с прозрачным фоном:

введите описание изображения здесь

Ответ 2

Изображение PNG содержит пиксели, которые частично прозрачны (альфа < 255). Это довольно распространенная авария с программой, например Photoshop, наиболее вероятной причиной является наложение изображения подзорного ложа поверх изображения документа и неправильное слияние слоев.

Как указано, изображение может выглядеть только хорошо, когда оно отображается поверх светло-серого или белого фона. Но этого не произошло, фон был черным. Теперь, делая антиалиасинговые пиксели вокруг подзорки болезненно очевидными, они превратили различные оттенки темно-серого в зависимости от их альфа-значения и больше не смешиваются с белым фоном изображения документа. Очень типичная неудача при использовании функций GDI, она не похожа на альфа.

Вы можете лечить его с помощью GDI +, гарантируя, что цвет фона правильный. Но это довольно много работы, и это все равно оставляет вам проблему с правильной угадыванием исходного цвета фона.

На самом деле лучше всего вернуться к любому инструменту рисования, который вы использовали, и устранить проблему. Самое быстрое исправление должно быть повторно сохранено в виде файла изображения BMP 24bpp, ymmv.