Delirous_A

Hi,

I'm having trouble getting a correct HBITMAP through use of the Imaging API.
I can get the HBITMAP but when I bitBlt it on screen it shows only a black rectangle instead of the actual image loaded (bmp, jpeg or png).

Here's how I try to retreive it:
Code Block

HBITMAP withImaging(LPCTSTR filename)

{

IImagingFactory* pImageFactory = 0;
IImage* pImage = 0;


CoInitializeEx(0, COINIT_MULTITHREADED);
HBITMAP hBitmap = 0;

if (SUCCEEDED(CoCreateInstance(CLSID_ImagingFactory, 0, CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void**)&pImageFactory)))

{
ImageInfo imageInfo;

if (SUCCEEDED(pImageFactory->CreateImageFromFile(filename, &pImage)) && SUCCEEDED(pImage->GetImageInfo(&imageInfo)))

{

HDC bmpDC = CreateCompatibleDC(0);
if (hBitmap = CreateCompatibleBitmap(bmpDC, imageInfo.Width, imageInfo.Height))
{
HGDIOBJ hOldBitmap = SelectObject(bmpDC, hBitmap);
RECT rect = {0, 0, imageInfo.Width, imageInfo.Height};
pImage->Draw(bmpDC, &rect, 0);
SelectObject(bmpDC, hOldBitmap);
}
pImage->Release();
DeleteDC(bmpDC);
}
pImageFactory->Release();
}
CoUninitialize();


return hBitmap;

}

Now if I instead of pImage->Draw(bmpDC, &rect, 0) do pImage->Draw(hdc, &rect, 0) where hdc is the current DC passed as an extra parameter to the function above. The image does get correctly drawn on the display, but at the time this function is called it doesn't need to be drawn on the display yet, hence I need only a handle to it so I can draw it later (scaled/stretched if necessary).
I've also tried to pass the current DC to create the memory DC -- hBitmap = CreateCompatibleDC(hdc) -- but this gives the same result.


Re: Smart Devices Native C++ Development Problem getting a HBITMAP through Imaging API

Delirous_A

ok, I've tried a slightly different approach and now I have fine results for jpeg and png images, but for some reason bmp images are still shown incorrectly.
But they don't look entirely black anymore, they obviously show their scanlines now and it seems there is an offset which increases as you go from top to bottom of the picture (e.g. first line is drawn ok, the second is moved slightly to the right and wrapping around back to the left side and it has its colors inverted, etc...).

This is how I do it so far: (it would be nice if it could also load bmp files correctly)
Code Block

HBITMAP withImaging(LPCTSTR filename)

{

IImagingFactory* pImageFactory = 0;
IImage* pImage = 0;
IBitmapImage* pBitmapImage = 0;
BitmapData bitmapData = {0};


CoInitializeEx(0, COINIT_MULTITHREADED);
HBITMAP hBitmap = 0;
if (SUCCEEDED(CoCreateInstance(CLSID_ImagingFactory, 0, CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void**)&pImageFactory)))
{
ImageInfo imageInfo;
if (SUCCEEDED(pImageFactory->CreateImageFromFile(filename, &pImage)) && SUCCEEDED(pImage->GetImageInfo(&imageInfo)) && SUCCEEDED(pImageFactory->CreateBitmapFromImage(pImage, imageInfo.Width, imageInfo.Height, imageInfo.PixelFormat, InterpolationHintDefault, &pBitmapImage)))
{

RECT rect = {0, 0, imageInfo.Width, imageInfo.Height};
bitmapData.Width = imageInfo.Width;
bitmapData.Height = imageInfo.Height;
bitmapData.PixelFormat = imageInfo.PixelFormat;


pBitmapImage->LockBits(&rect, ImageLockModeRead, PixelFormatDontCare, &bitmapData);
hBitmap = CreateBitmap(bitmapData.Width, bitmapData.Height, 1, GetPixelFormatSize(bitmapData.PixelFormat), bitmapData.Scan0); pBitmapImage->UnlockBits(&bitmapData);
}
pImageFactory->Release();
}
CoUninitialize();


return hBitmap;

}

I hope someone can tell me why this correctly loads jpeg and png but not bmp.




Re: Smart Devices Native C++ Development Problem getting a HBITMAP through Imaging API

Vinodkumar Ramachandran

Please try the following piece of code:-

Code Block

HBITMAP withImaging (HDC hdc, LPCTSTR filename)
{
IImagingFactory* pImageFactory = 0;
IImage* pImage = 0;

CoInitializeEx(0, COINIT_MULTITHREADED);

HBITMAP hBitmap = 0;
if (SUCCEEDED(CoCreateInstance(CLSID_ImagingFactory, 0, CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void**)&pImageFactory)))
{

ImageInfo imageInfo;

if (SUCCEEDED(pImageFactory->CreateImageFromFile(filename, &pImage)) && SUCCEEDED(pImage->GetImageInfo(&imageInfo)))
{

HDC bmpDC = CreateCompatibleDC(hdc);
if (hBitmap = CreateCompatibleBitmap(hdc, imageInfo.Width, imageInfo.Height))
{

HGDIOBJ hOldBitmap = SelectObject(bmpDC, hBitmap);
RECT rect = {0, 0, imageInfo.Width, imageInfo.Height};
pImage->Draw(bmpDC, &rect, 0);
SelectObject(bmpDC, hOldBitmap);
}
pImage->Release();
DeleteDC(bmpDC);
}
pImageFactory->Release();
}
CoUninitialize();

return hBitmap;
}

HDC passed to CreateCompatibleBitmap has been changed.





Re: Smart Devices Native C++ Development Problem getting a HBITMAP through Imaging API

Delirous_A

Thanks Vinodkumar,

a subtle difference, but it did the trick Wink




Re: Smart Devices Native C++ Development Problem getting a HBITMAP through Imaging API

Marshall07

Hi,

I tried this code and it works good.

But if I load a transparent png it will not show correctly. The IImagingFactory loads the image correctly infact it would be shown correctly if I use

Code Block

pImage->Draw(hdc, &rect, 0);



If I let the pImage draw into the bmpDC, it would probablly be drawn correctly but when I try to display with

Code Block

HDC hdcMem = CreateCompatibleDC (hdc);
hBitmap = withImaging(hdc, _T("Storage Card\\1.png"));
SelectObject (hdcMem, hBitmap);
BitBlt (hdc, imgX, imgY, imgH, imgW, hdcMem, 0, 0, SRCCOPY);



The picture is shown but with a messed background.

Any solution

Marshall









Re: Smart Devices Native C++ Development Problem getting a HBITMAP through Imaging API

AlexFeinman

Imaging API honors alpha channel when drawing. You can get the same result by substituting BitBlt with AplhaBlend






Re: Smart Devices Native C++ Development Problem getting a HBITMAP through Imaging API

Marshall07

Ok,

so I tried this:

Code Block

HDC hdcMem = CreateCompatibleDC (hdc);
hBitmap = withImaging(hdc, _T("Storage Card\\1.png"));
SelectObject (hdcMem, hBitmap);

BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
AlphaBlend(hdc, imgX, imgY, imgW, imgH, hdcMem, 0, 0, imgW, imgH, pixelblend);


But what I get is nothing.

I know that AlphaBlend is supported because I tried this other code and it works.

Code Block

HDC hdcMem = CreateCompatibleDC (hdc);
hBitmap = withImaging(hdc, _T("Storage Card\\1.png"));
SelectObject (hdcMem, hBitmap);
BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 60, 0 };
AlphaBlend(hdc, imgX, imgY, imgW, imgH, hdcMem, 0, 0, imgW, imgH, pixelblend);



Here is what I see (you can see that the image is constantly blended correctly):



So what could be the problem

Marshall





Re: Smart Devices Native C++ Development Problem getting a HBITMAP through Imaging API

Marshall07

I'm really confused!

I read somewhere that AlphaBlend requires a 32bpp image so the PNG is not good since it has 24bpp. But why is it showed if I don't set the AC_SRC_ALPHA
Anyway, I tried with a TGA image (which is a 32bpp) but it is not showed neither without AC_SRC_ALPHA (I think that the IImagingFactory doesn't support TGA files).

It is very strange! Which APIs does the IImagingFactory use to draw the PNG correctly (with Alpha transparency) if I pass hdc to the Draw() method

Marshall





Re: Smart Devices Native C++ Development Problem getting a HBITMAP through Imaging API

AlexFeinman

Unfortunately your problem is in the function "withImaging". What it does is it loads the image, but then paints it over to a 16 bit bitmap (because it is created as a compatible bitmap). When this happens, you lose alpha information. What you need to do instead is to use SHLoadImageFile to load your bitmap






Re: Smart Devices Native C++ Development Problem getting a HBITMAP through Imaging API

Marshall07

Thanks so much for your help Alex.

I tried with SHLoadImageFile. But I have the same problems. It seems that the AlphaBlend doesn't want to work with the AC_SRC_ALPHA parameter. Here is the code:

Code Block

HWND hWnd = CreateWindowEx(WS_EX_TOPMOST, NULL, NULL, WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);

HDC hdc = GetWindowDC(hWnd);

HBITMAP bmp = SHLoadImageFile(_T("Storage Card\\1.png"));
HDC hdcMem = CreateCompatibleDC (hdc);
SelectObject (hdcMem, bmp);
BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
AlphaBlend(hdc, imgX, imgY, imgW, imgH, hdcMem, 0, 0, imgW, imgH, pixelblend);


If I don't use AC_SRC_ALPHA, the AlphaBlend API draws the image constantly blended (but with no alpha transparency as expected).
But if I use AC_SRC_ALPHA, the picture is not showed.

If I use TGA, nothing is showed even if I use constant blending. Only a black dot is showed.

I'm starting to believe that AlphaBlend doesn't support AC_SRC_ALPHA in Windows Mobile. But if so, how can the IImagingFactory handle it


Marshall




Re: Smart Devices Native C++ Development Problem getting a HBITMAP through Imaging API

herojits

Hi,

I follow these steps, it works for transparent as well as alpha-channel png.

Steps:

1. Load a png on pImage;

2. pImage->Draw(hDC, &rc, 0);

Here select a 32 bits HBITMAP on hDC.

3. Process every pixel in the HBITMAP:

r = *lpByte;

g = *(lpByte + 1);

b = *(lpByte + 2);

a = *(lpByte + 3);

r = (r * a)/255;

g = (g * a)/255;

b = (b * a)/255;

*lpByte = r;

*(lpByte + 1) = g;

*(lpByte + 2) = b;

where lpByte points to the pixels.

4. Then finally draw using AlphaBlend.

Regards,

Herojits





Re: Smart Devices Native C++ Development Problem getting a HBITMAP through Imaging API

Marshall07

Thank you very much for your reply, herojits.

It finally seems to be the right procedure. But I still have some questions.

- If I create an HBITMAP with CreateCompatibleBitmap, it will not be a 32 bits one, right So how can I create one

- How can I point to the HBITMAP pixels to modify them I remember a saw a code where this was made but I don't remember where.

Here is the code I wrote till now. Sorry if it is not correct but I'm not so dig in that topics.

Code Block

HDC LoadPngImage (HDC hdc, LPCTSTR filename)
{

IImagingFactory* pImageFactory = 0;
IImage* pImage = 0;

CoInitializeEx(0, COINIT_MULTITHREADED);

HBITMAP hBitmap;
HDC bmpDC;

if (SUCCEEDED(CoCreateInstance(CLSID_ImagingFactory, 0, CLSCTX_INPROC_SERVER,

IID_IImagingFactory, (void**)&pImageFactory)))
{
ImageInfo imageInfo;

if (SUCCEEDED(pImageFactory->CreateImageFromFile(filename, &pImage))

&& SUCCEEDED(pImage->GetImageInfo(&imageInfo)))
{
bmpDC = CreateCompatibleDC(hdc);
RECT rect = {0, 0, imageInfo.Width, imageInfo.Height};
pImage->Draw(bmpDC, &rect, 0);
SelectObject(bmpDC, hBitmap);
pImage->Release();
/*I guess I have to process the pixels here*/
}
pImageFactory->Release();
}
CoUninitialize();

return bmpDC;

}


Than you again for your help! I hope I can finally solve my problem!

Marshall





Re: Smart Devices Native C++ Development Problem getting a HBITMAP through Imaging API

herojits

Hi Marshall,

1. Create the HBITMAP using CreateDIBSection and specify

bmiHeader.biBitCount = 32;

bmiHeader.biCompression = BI_ALPHABITFIELDS;

Ank make sure, you fill this HBITMAP with some WHITE_COLOR otherwise you might see black spots

when 'pImage' starts drawing at the next step.

2. Select this HBITMAP to bmpDC before

pImage->Draw(bmpDC, &rect, 0);

3, Then select the old HBITMAP to bmpDC. Here onwards you can process the pixels at any point before

returning from 'LoadPngImage'

Regards,

Herojit





Re: Smart Devices Native C++ Development Problem getting a HBITMAP through Imaging API

herojits

Ideally we should skip the second step

2. Select this HBITMAP to bmpDC before

pImage->Draw(bmpDC, &rect, 0);

Instead we should copy the pixels directly to the 32 bits HBITMAP, so that the alpha-channel is not lost.

Regards,

Herojits





Re: Smart Devices Native C++ Development Problem getting a HBITMAP through Imaging API

Marshall07

Thanks Herojits.

So what do you suggest I refined the code in this way...

Code Block

HDC LoadPngImage (HDC hdc, LPCTSTR filename)
{
IImagingFactory* pImageFactory = 0;
IImage* pImage = 0;

CoInitializeEx(0, COINIT_MULTITHREADED);

HDC bmpDC;
if (SUCCEEDED(CoCreateInstance(CLSID_ImagingFactory, 0, CLSCTX_INPROC_SERVER,

IID_IImagingFactory, (void**)&pImageFactory)))
{
ImageInfo imageInfo;

if (SUCCEEDED(pImageFactory->CreateImageFromFile(filename, &pImage))

&& SUCCEEDED(pImage->GetImageInfo(&imageInfo)))
{
BITMAPINFO pBmi = { { sizeof(BITMAPINFOHEADER), imageInfo.Width,

imageInfo.Height, 1, 32, BI_ALPHABITFIELDS } };
void * pBits = NULL;
HBITMAP hBitmap = CreateDIBSection(NULL, & pBmi,

DIB_RGB_COLORS, & pBits, NULL, NULL);

bmpDC = CreateCompatibleDC(hdc);
RECT rect = {0, 0, imageInfo.Width, imageInfo.Height};

HGDIOBJ oldBmp = SelectObject(bmpDC, hBitmap);
pImage->Draw(bmpDC, &rect, 0);
SelectObject(bmpDC, oldBmp);
pImage->Release();

for (int y=0; y<imageInfo.Height; y++)
{
BYTE * pPixel = (BYTE *) pBits + imageInfo.Width * 4 * y;

for (int x=0; x<imageInfo.Width; x++)
{
pPixel[0] = pPixel[0] * pPixel[3] / 255;
pPixel[1] = pPixel[1] * pPixel[3] / 255;
pPixel[2] = pPixel[2] * pPixel[3] / 255;

pPixel += 4;
}
}
}
pImageFactory->Release();
}
CoUninitialize();

return bmpDC;
}


It seems to be right, but it doesn't work. I can't see anything neither with AlphaBlend, nor with BitBlt on the returned bmpDC.

If I should replace the second step, it means that I don't have to use the pImage->draw() If so, how can I copy the bits to the bmpDC

I appreciate very much your help!

Marshall