Как сохранить HBITMAP как 1BPP PNG - PullRequest
0 голосов
/ 13 декабря 2011

Я пишу элемент управления подписью в C ++ для Windows Mobile и Windows.На стороне Windows у меня есть много разных способов сохранить CBitmap в файл PNG (GDI +, CImage и т. Д.).Проблема, с которой я столкнулся, заключается в том, что CImage :: Save () не реализована в Windows Mobile.Хорошие части GDI + также не реализованы в Windows Mobile (в частности, Gdiplus :: Bitmap).

Я нашел API IImagingFactory и успешно загрузил PNG с этой библиотекой, но я не могу понять, каксохранить CBitmap в файл PNG в Windows Mobile.У кого-нибудь есть идеи сохранить HBITMAP или CBitmap в файл PNG?

Если это имеет какое-либо значение, CBitmap был создан для соответствия размеру элемента управления и имеет 1BPP, так как изображение подписи черно-белое и должно передаваться по сети.

Ответы [ 2 ]

1 голос
/ 14 декабря 2011

Это некоторый код, который я использую в .NET с C #.Я знаю другое животное, но я очень ржавый на своем C / C ++.Может быть, это может дать вам идеи:

public const int SRCCOPY = 0x00CC0020;
// BitBlt
#if !PocketPC
[DllImport("gdi32.dll")]
#else
[DllImport("coredll.dll")]
#endif
static extern int BitBlt(IntPtr hdcDest, int XDest, int YDest, int Width, int Height, IntPtr hdcSrc, int XSrc, int YSrc, uint dwRop);
// GetDC
#if !PocketPC
[DllImport("user32.dll")]
#else
[DllImport("coredll.dll")]
#endif
static extern IntPtr GetDC(IntPtr hWnd);

public static FileInfo ScreenCapture(Rectangle rect) {
  using (Bitmap bmp = new Bitmap(rect.Width, rect.Height)) {
    using (Graphics scrG = Graphics.FromHdc(GetDC(IntPtr.Zero))) {
      using (Graphics dest = Graphics.FromImage(bmp)) {
        BitBlt(dest.GetHdc(), 0, 0, rect.Width, rect.Height, scrG.GetHdc(), rect.Left, rect.Top, SRCCOPY);
      }
    }
    bmp.Save(screenshot.FullName, ImageFormat.Png);
  }
}

По существу, объект Bitmap имеет подпрограмму Save, которая позволяет мне выбрать формат, с которым я хочу сохранить изображение.

Доступны ли эти же функции в C ++ для CBitmap?Может быть.

Надеюсь, это поможет, ~ Джо

0 голосов
/ 15 декабря 2011

Я узнал, что кодер IImagingFactory не работает, потому что мой CBitmap - это DDB, а не DIB. Я использовал CreateDIBSection для создания растрового изображения вместо CBitmap.Create () и смог кодировать CBitmap в PNG с помощью IImagingFactory.

Надеюсь, что это поможет следующему человеку, который пойдет по этому пути (проверено только с 1BPP):

HRESULT CSignatureControl::Imaging_GetCLSID(IImagingFactory *pFactory, LPCTSTR mimeType, CLSID *clsid)
{
    if (pFactory == NULL)
        return E_INVALIDARG;
    if (mimeType == NULL || mimeType[0] == 0)
        return E_INVALIDARG;
    if (clsid == NULL)
        return E_INVALIDARG;

    UINT count = 0;
    ImageCodecInfo *pCodecInfo = NULL;
    HRESULT hr = pFactory->GetInstalledEncoders(&count, &pCodecInfo);
    if (SUCCEEDED(hr))
    {
        for (UINT i = 0; i < count; i++)
        {
            if (!_tcscmp(pCodecInfo[i].MimeType, mimeType))
            {
                *clsid = pCodecInfo[i].Clsid;
                break;
            }
        }
        CoTaskMemFree(pCodecInfo);
    }
    return hr;
}

HRESULT CSignatureControl::Imaging_IBitmapImageFromHBITMAP(IImagingFactory *pFactory, BitmapData *bmData, HBITMAP hBitmap, IBitmapImage **pBitmapImage)
{
    if (pFactory == NULL)
        return E_INVALIDARG;
    if (hBitmap == NULL)
        return E_INVALIDARG;

    BITMAP bm;
    GetObject(hBitmap, sizeof(BITMAP), &bm);

    // Map between different pixel formats
    PixelFormatID pixelFormat;
    if (bm.bmBitsPixel == 1)
        pixelFormat = PixelFormat1bppIndexed;
    else if (bm.bmBitsPixel == 4)
        pixelFormat = PixelFormat4bppIndexed;
    else if (bm.bmBitsPixel == 8)
        pixelFormat = PixelFormat8bppIndexed;
    else if (bm.bmBitsPixel == 24)
        pixelFormat = PixelFormat24bppRGB;

    bmData->Height = bm.bmHeight;
    bmData->Width = bm.bmWidth;
    bmData->Scan0 = bm.bmBits;
    bmData->PixelFormat = pixelFormat;
    bmData->Stride = ((bm.bmWidth * bm.bmBitsPixel + 31) & ~31) >> 3;

    return pFactory->CreateBitmapFromBuffer(bmData, pBitmapImage);
}

HRESULT CSignatureControl::Imaging_EncodeBitmapToFile(IImagingFactory *pFactory, IBitmapImage *pBitmap, CLSID *clsid, LPCTSTR filename)
{
    if (pFactory == NULL)
        return E_INVALIDARG;

    CComPtr<IImageEncoder> imageEncoder;
    HRESULT hr = pFactory->CreateImageEncoderToFile(clsid, filename, &imageEncoder);
    if (SUCCEEDED(hr))
    {
        CComPtr<IImageSink> imageSink;
        hr = imageEncoder->GetEncodeSink(&imageSink);
        if (SUCCEEDED(hr))
        {
            CComPtr<IImage> pImage;
            hr = pBitmap->QueryInterface(IID_IImage, (void**)&pImage);
            if (SUCCEEDED(hr))
            {
                hr = pImage->PushIntoSink(imageSink);
            }
        }
        hr = imageEncoder->TerminateEncoder();
    }
    return hr;
}

Связывая все вместе:

CoInitializeEx(NULL, COINIT_MULTITHREADED);
{
    CComPtr<IImagingFactory> pImgFactory;
    HRESULT hr = pImgFactory.CoCreateInstance(CLSID_ImagingFactory);
    if (SUCCEEDED(hr))
    {
        CLSID pngClsid = {0};
        hr = Imaging_GetCLSID(pImgFactory.p, TEXT("image/png"), &pngClsid);
        if (SUCCEEDED(hr))
        {
            CComPtr<IBitmapImage> pBitmapImg;
            BitmapData *bmData = new BitmapData();
            hr = Imaging_IBitmapImageFromHBITMAP(pImgFactory.p, bmData, m_offscreenBitmap, &pBitmapImg);
            if (SUCCEEDED(hr))
            {
                hr = Imaging_EncodeBitmapToFile(pImgFactory.p, pBitmapImg, &pngClsid, fileName);
            }
            delete bmData;
        }
    }
}
CoUninitialize();
...