|
Thanks for sharing this excellent class.
I use the demo to show an icon (16 pixels wide, 16 pixels high and 16 colors). The demo works fine when the Painting mode is top-left and stretched, respectively. However, when I change the Painting mode to center mode, the icon is not painted transparently.
|
|
|
|
|
I just wanted to thank you for sharing your efforts. This is great work.
|
|
|
|
|
I have now used this for the 2nd time and once again it performed magnificantly. A really useful and reliable class. Thanks.
Mike
Dear NYT - the fact is, the founding fathers hung traitors.
Vincent Reynolds: My opposition is as enlightened as your support, jackass.
dennisd45: My view of the world is slightly more nuanced
dennisd45 (the NAMBLA supporter) wrote: I know exactly what it means. So shut up you mother killing baby raper.
|
|
|
|
|
PJ,
When I run your demo app on my system instead of your image having a transparent background it has red cross-hatched lines. (when i click the "transparent" button of course)
Do you have any idea what could be causing this?
im using VS2003.
|
|
|
|
|
No bug. If you look in CPJAImage_demoDlg::OnPaint() you will see I fill the background of the picture with a red cross hatch brush. I just did not update the image included with the article the last time I updated the code.
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03
"Obviously ??? You're definitely a superstar!!!" - mYkel - 21 Jun '04
"There's not enough blatant self-congratulatory backslapping in the world today..." - HumblePie - 21 Jun '05
Within you lies the power for good - Use it!
|
|
|
|
|
Thanks for the quick response PJ, your awesome
|
|
|
|
|
---------------------------
Angus He
|
|
|
|
|
sorry to bug you PJ - its a great class, but I have a question. I notice your example uses a Picture control to provide the co-ordinates/CRect/DC to draw the bitmap onto (Ive never done much with drawing, so I hope Im using the correct words) ..
I did this using a Picture control, and it works well - the only issue is the Picture control has a border I cant get rid of - ideally I'd like to use a Static for the 'placeholder' and get its DC .. but I seem to get unhandled exceptions when I replace the Picture control with a Static control ..
Is there anything obvious about using a Static that I should be aware of ? - or perhaps I made a simpler mistake - I guess I'll go over it again and see what I can find ...
[Edited after a play in my lunch-break]
I think Ive found the answer - I think its the 'Frame' option I have set for the CPicture Property - I'll get to test it tonight ..... sorry if Ive messed you around
Thanks anyway, Garth
|
|
|
|
|
You can use a static control for the drawing. Just derive a class from CStatic and overide it's OnPaint member function. I used a frame control in the demo because I wanted to keep all the drawing code in the dialog class. It saved me from having to pass all the drawing info from the button clicks to a seperate CStatic class.
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03
"Obviously ??? You're definitely a superstar!!!" - mYkel - 21 Jun '04
"There's not enough blatant self-congratulatory backslapping in the world today..." - HumblePie - 21 Jun '05
Within you lies the power for good - Use it!
|
|
|
|
|
|
allmost 6 !!
thanks you vary much.
I have no imidiate work for your class, but i have been able to isolate the very much needed code to create this: HICON CreateGrayscaleIcon(HICON hIcon);
thanks a million.
|
|
|
|
|
You are very welcome
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03
"Obviously ??? You're definitely a superstar!!!" - mYkel - 21 Jun '04
"There's not enough blatant self-congratulatory backslapping in the world today..." - HumblePie - 21 Jun '05
Within you lies the power for good - Use it!
|
|
|
|
|
Hi PJ,
in short I want to convert a 32bpp (RGBA) icon to grayscale while runtime without losing the alpha channel. If I drop such an icon into your test app and convert it to grayscale the alpha channel gets lost.
Taking a short look into your code shows that you make at last a RGB copy operation of the grayed pixels. The alpha channel is not set and so the formerly transparent parts become opaque.
Is there a way to convert 32bpp icons to grayscale without losing the alpha channel AND without using GDI+? I have code for doing this with GDI+ but I cannot use it yet in my project.
Thanks in advance!
Regards, mykel
If they give you lined paper, write the other way!
|
|
|
|
|
After some nightly debugging I happily fixed the problem
The following part of CPJAImage::GrayScale() causes the problem:
int nGray = Gray(GetBValue(*dst), GetGValue(*dst), GetRValue(*dst));
*dst = (DWORD)RGB(nGray, nGray, nGray);
The RGB macro fills bit 0-24 with (BYTE)nGray . Bit 25-32 are filled with zeros and afterwards copied back into dst . So at this point the formerly alpha channel byte gets zero which is opaque.
Here is my fix:
Add the following macro at the top of pjaimage.h :
#define RGBA(r,g,b,a) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))|(((DWORD)(BYTE)(a))<<24)) This macro is similar to the RGB macro but it also accepts an alpha channel byte.
So everything is fine if we do:
int nGray = Gray(GetBValue(*dst), GetGValue(*dst), GetRValue(*dst));
BYTE* pAlpha = ((BYTE*)dst)+3;
*dst = (DWORD)RGBA(nGray, nGray, nGray, *pAlpha);
That's all. Grayscaling a 32bpp icon doesn't kill the alpha channel anymore. Hope you like it!
Regards, mykel
If they give you lined paper, write the other way!
|
|
|
|
|
Thanks Mykel.
Having others contribute bug fixes to bugs that the authors miss is part of what makes CP so great.
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03
"Obviously ??? You're definitely a superstar!!!" mYkel - 21 Jun '04
Within you lies the power for good - Use it! Honoured as one of The Most Helpful Members of 2004
|
|
|
|
|
Mykel, not that it really matters, but I changed the code to
*dst = (*dst & 0xff000000) | ((DWORD)RGB(nGray, nGray, nGray) & 0x00ffffff); Saves having to add the RGBA macro to the file.
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03
"Obviously ??? You're definitely a superstar!!!" mYkel - 21 Jun '04
Within you lies the power for good - Use it! Honoured as one of The Most Helpful Members of 2004
|
|
|
|
|
Hi PJ,
sounds good to me.
I also forgot to thank you for another nice class!
Have a nice day,
mykel
If they give you lined paper, write the other way!
|
|
|
|
|
Hi,
First all thanks for the class. I found it quite handy drawing images
transparently. I am using it in our latest project at work, but have
come across a problem.
There seems to be some confusion (or my lack of understand) over the use
w and h parameter of the DrawImage function, which lead to what I suspect to
be the weird artifacts generated of drawing two images on the same DC.
What I have tried to do is draw two transparent images adjacently on my view.
I have read that there was fix to a similar (or maybe the same) problem in 2003. I have in my code something like this...
CPJAImage img1;
CPJAImage img2;
img1.SetImage(...);
img2.SetImage(...);
// Note I treat w and h as logical offset of x and y respectively not as the width and height of the rect.
CSize img1Size = img1.GetSize();
CSize img2Size = img2.GetSize();
CPoint offset(10,10); // For example
img1.DrawImage(pDC, offset.x, offset.y, offset.x + img1Size.cx, offset.y + img1Size.cy, CPJA_TRANSPARENT);
img2.DrawImage(pDC, offset.x + img1Size.cx, offset.y + img1Size.cy, offset.x + img1Size.cx + img2Size.cx, offset.y + img1Size.cy + img2Size.cy, CPJA_TRANSPARENT);
// This produces strange artifacts when my view is resized.
// So I changed the code in these places to make it work.
// In the DrawImage function.
//old
BackGroundBitmap.CreateCompatibleBitmap(pDC, w, h);
...
BackGroundDC.BitBlt(0, 0, w, h, pDC, x, y, SRCCOPY);
...
TransparentDC.BitBlt(0, 0, w, h, &BackGroundDC, left, top, SRCCOPY);
//new changes
BackGroundBitmap.CreateCompatibleBitmap(pDC, width, height);
...
BackGroundDC.BitBlt(0, 0, width, height, pDC, x, y, SRCCOPY);
...
TransparentDC.BitBlt(0, 0, width, height, &BackGroundDC, 0, 0, SRCCOPY);
Im not sure how these changes adversely affects the rest of the code.
I have also added my own function to load a picture by a file name.
I can post it if anyone wants it.
Thanks,
Samson
Coding Monkey
|
|
|
|
|
Sawjai wrote:
TransparentDC.BitBlt(0, 0, width, height, &BackGroundDC, 0, 0, SRCCOPY);
This seems to be the only fix that is necessary as the painting is clipped to the supplied rectancle if width and height are bigger than w and h.
Thanks for the bug fix
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03
"Obviously ??? You're definitely a superstar!!!" mYkel - 21 Jun '04
Within you lies the power for good - Use it! Honoured as one of The Most Helpful Members of 2004
|
|
|
|
|
Hi PJ Arends,
Oppps, I had a mistake in my DrawImage parameters that I posted.
I will update it now.
Cheers,
Samson
|
|
|
|
|
I am new to VC++ (recently converted from Borland C++ Builder).
Does any one any suggestion/code example on how to make CPJAImage a Drag & Drop Control in VC++ 7.1? I want to replace Image control with CPJAImage. I want to load image during design time (Image property) and also a transparent property.
Len Richter
|
|
|
|
|
CPJAImage is not a windows control (It is not a wrapper around an HWND), so I would say just call CPJAImage::DrawImage() from your regular control's WM_PAINT handler. Or you can do as I did in the demo app, which does support drag 'n drop.
Sonork 100.11743 Chicken Little
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03
Within you lies the power for good - Use it!
|
|
|
|
|
I did try using Onpaint but I am missing something because I am getting a black rectangle (ie. like iti si not coping the BMP image from the Image control). Here is my code. Do you see anything I am missing?
private: System::Void ImagePaint(System::Object * sender, System::Windows::Forms::PaintEventArgs * e)
{CPJAImage PJAImage;
PictureBox *pPictureBox = dynamic_cast<picturebox *="">(sender);
// Get handle to device context.
HDC hDC = (HDC)e->Graphics->GetHdc().ToInt32();
CDC* pDC = CDC::FromHandle(hDC);
COLORREF clr = pDC->GetPixel(CPoint(0,0));
PJAImage.SetImage(hDC, PJAI_BITMAP);
PJAImage.SetTransparentColour(clr);//RGB(0,0,0));
/
CDC DC;
DC.CreateCompatibleDC(pDC);
int save = DC.SaveDC();
SelectObject(background);
CBitmap bmp;
bmp.CreateCompatibleBitmap(pDC, pPictureBox->Image->Width, pPictureBox->Image->Height);
DC.SelectObject(bmp);
PJAImage.DrawImage(&DC, 0, 0, pPictureBox->Image->Width, pPictureBox->Image->Height, PJAI_TRANSPARENT | PJAI_STRETCHED);
pDC->BitBlt(0, 0, pPictureBox->Image->Width, pPictureBox->Image->Height, &DC, 0, 0, SRCCOPY);
DC.RestoreDC(save);
DC.DeleteDC();
// Release handle to device context.
e->Graphics->ReleaseHdc(hDC);
//ReleaseDC(pDC);
}
Len
|
|
|
|
|
Len2020 wrote:
HDC hDC = (HDC)e->Graphics->GetHdc().ToInt32();
Len2020 wrote:
PJAImage.SetImage(hDC, PJAI_BITMAP);
Here is your problem, SetImage requires a HBITMAP or HICON as the first parameter, you are passing in a HDC as a HBITMAP.
Sonork 100.11743 Chicken Little
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03
Within you lies the power for good - Use it!
|
|
|
|
|
PIA WROTE:
Here is your problem, SetImage requires a HBITMAP or HICON as the first parameter, you are passing in a HDC as a HBITMAP.
I still can not get this to work due to my lack on knowledge between GDI and GDI++. I have searched on the web to get an understanding on DC and HBITMAP by it is still fuzzy to me. The problem is the handle HBITMAP and trying to get it. I did use HBITMAP operator but I am still get a black box only. I am still missing something obvious. Could you by chance correct my code. I would really appreciate it.
private: System::Void ImagePaint(System::Object * sender, System::Windows::Forms::PaintEventArgs * e)
{CPJAImage PJAImage;
PictureBox *pPictureBox = dynamic_cast<picturebox *="">(sender);
// Get handle to device context.
HDC hDC = (HDC)e->Graphics->GetHdc().ToInt32();
CDC *pCDCImage = CDC::FromHandle(hDC);
// Create an in-memory DC compatible with the display DC we're using to paint.
CDC cdcMemory;
cdcMemory.CreateCompatibleDC(pCDCImage);
int save = cdcMemory.SaveDC();
COLORREF clr = cdcMemory.GetPixel(CPoint(0,0));
CBitmap bmp;
bmp.CreateCompatibleBitmap(&cdcMemory, pPictureBox->Image->Width, pPictureBox->Image->Height);
// Select Bitmap into the new Memory DC.
cdcMemory.SelectObject(bmp);
PJAImage.SetImage(bmp.operator HBITMAP(), PJAI_BITMAP);
//PJAImage.SetTransparentColour(clr);//RGB(0,0,0));
PJAImage.DrawImage(&cdcMemory, 0, 0, pPictureBox->Image->Width, pPictureBox->Image->Height, PJAI_TRANSPARENT | PJAI_STRETCHED);
// Copy the bits from the in-memory DC into the on-screen DC to actually do the painting.
pCDCImage->BitBlt(0, 0, pPictureBox->Image->Width, pPictureBox->Image->Height, &cdcMemory, 0, 0, SRCCOPY);
cdcMemory.RestoreDC(save);
cdcMemory.DeleteDC();
// Release handle to device context.
e->Graphics->ReleaseHdc(hDC);
}
Regards,
Len Richter
|
|
|
|
|