Transparent PNG

P

Peter Carlson

I have searched all the articles and tried various things, but cant seem
to get this to work. I have a png in a picturebox. Then I have another
png that is transparent. the background is a compass frame and the
foreground is the compass rose. I update the image like this:

Bitmap b2 = Properties.Resources.pngRose;
Graphics gpCompass = Graphics.FromImage(pbCompass.Image);
gpCompass.DrawImage(b2, 0, 0,
new Rectangle(0, 0, b2.Width, b2.Height),
GraphicsUnit.Pixel );
pbCompass.Refresh();

However it draws the rose with a solid white background.

So I thought maybe I need to load the png from a file, but I am not sure
how to do this in the emulator?

So 2 questions:
1. can this be done by embedding the resource?
2. Where do I place the png in the file system of the project in order
to get it onto the emulator?

Peter
 
P

Peter Duniho

Peter said:
I should have noted this is CF, 3.5 targeting WinMo 6+

You should post to a newsgroup or other forum specific to Compact
Framework questions.

There is no practical difference between storing the PNG in a resource
versus reading from a file. So I'm sure that line of experimentation
will be a dead-end. But, it's entirely possible that CF doesn't support
transparency in bitmaps at all.

Your code example is insufficient to know whether your problem is
related to bad input, bad usage, or lack of feature support in CF. But
given the likelihood that you are running into a limitation of the CF,
you need to post your question where people experienced with the CF will
see it.

What I can tell you from the code you posted is that you are failing to
properly dispose of the Graphics instance you're using for drawing. I'm
also not particularly fond of the technique you're using with respect to
the PictureBox control, but that's less important. You definitely need
to remember to dispose disposable objects though (preferably with the
"using" statement).

Pete
 
P

Peter Carlson

Peter,

I will try and find a CF group to post to.
I am disposing of the resources, the snippet of code was simply to show
how I am loading the resource and putting it into the picturebox.

Thanks for responding
Peter
 
P

Peter Duniho

Peter said:
Peter,

I will try and find a CF group to post to.
I am disposing of the resources, the snippet of code was simply to show
how I am loading the resource and putting it into the picturebox.

For what it's worth, I spent a few minutes with Google, and at least as
of a few years ago, it appears CF does not support your desired approach
in at least two ways:

– .NET CF doesn't use GDI+ so doesn't support alpha blending
– The unmanaged Windows Mobile API now supports alpha blending, but
the .NET CF bitmap-loading code converts all loaded bitmaps to the
display format, which doesn't have alpha and so you lose any alpha
channel information loading bitmaps

Of course, I have no idea whether the current versions of Windows Mobile
or .NET CF have improved things. But it's a place to start.

My main source of information was from this message topic:
http://social.msdn.microsoft.com/Fo...s/thread/5624c89d-0e57-4d3f-90c4-eabc676e05f1

…and two links from that message:
http://blogs.msdn.com/chrislorton/archive/2006/04/07/570649.aspx
http://johan.andersson.net/blog/2007/10/solution-for-transparent-images-on.html

(Though, the latter has a really awful, obnoxious Twitter widget in the
nav bar that actually extends all the way across the browser window on
both Safari and Firefox, and maybe other browsers too, so it's difficult
to read and use the links contained within).

Pete
 
K

kndg

I have searched all the articles and tried various things, but cant seem
to get this to work. I have a png in a picturebox. Then I have another
png that is transparent. the background is a compass frame and the
foreground is the compass rose. I update the image like this:

Bitmap b2 = Properties.Resources.pngRose;
Graphics gpCompass = Graphics.FromImage(pbCompass.Image);
gpCompass.DrawImage(b2, 0, 0,
new Rectangle(0, 0, b2.Width, b2.Height),
GraphicsUnit.Pixel );
pbCompass.Refresh();

However it draws the rose with a solid white background.

So I thought maybe I need to load the png from a file, but I am not sure
how to do this in the emulator?

So 2 questions:
1. can this be done by embedding the resource?
2. Where do I place the png in the file system of the project in order
to get it onto the emulator?

Peter

Hi Peter,

I had done a similar project before (as a hobby project) but the way I
do it is not to have the png image as transparent. I just set the
background color to any color that you will use it as a "transparent"
color. My preference is Magenta (R:255,G:0,B:255). Then just use one of
the DrawImage overloads that take ImageAttributes as it parameter.

Example:

private ImageAttributes imageAttrib;
private Bitmap compassRose;

// call this from your form constructor
private void LoadImage()
{
pictureBox.Image = Properties.Resources.pngFrame;
compassRose = Properties.Resources.pngRose;

imageAttrib = new ImageAttributes();
imageAttrib.SetColorKey(compassRose.GetPixel(0, 0),
compassRose.GetPixel(0, 0));
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawImage(compassRose,
new Rectangle(0, 0, compassRose.Width, compassRose.Height),
0, 0, compassRose.Width, compassRose.Height,
GraphicsUnit.Pixel,
imageAttrib);
}

Eventually, I abandoned the project because the CF doesn't suppport
image transformation (you can't rotate the image to any degree you want,
so either you have to manually draw the compass needle, or have a 360
images but this will increase the executable size very much). I don't
know whether it can be done through P/Invoke either.

You can also look at http://www.freewarepocketpc.net/ website. I believe
there are a lot of compass applications that use CF and you can examine
the source code through reflector (better ask the author's permission
first).

Regards.
 
P

Peter Duniho

kndg said:
[...]
Eventually, I abandoned the project because the CF doesn't suppport
image transformation (you can't rotate the image to any degree you want,
so either you have to manually draw the compass needle, or have a 360
images but this will increase the executable size very much). I don't
know whether it can be done through P/Invoke either.

Not sure if, after my suggestion that Peter check other forums, whether
he's still following this. But in case he is…

As far as dealing with the rotation issue goes, if the platform doesn't
support arbitrarily rotated drawing, you still don't really need 360
different images for a compass overlay.

For one, IMHO the precision of the compass is unlikely to be usable to
the nearest degree anyway. So you probably only need 180 or 120
discrete positions for the needle.

Then, you also need at most a quarter that number because even without
fancy API support, it's trivial to do 90 degree bitmap rotations. So
then you only need 30-45 images.

I would guess the images should be reasonably small saved as PNG. But
if size is still a problem at that point, there is also the point that
the overlay probably doesn't need to be at full resolution. So you can
get an additional 75% reduction in size just by halving the number of
pixels in each direction in the stored bitmap and then doing a trivial
stretch when using it.

Finally, there is the option to abandon a bitmap-based solution
altogether. Instead, store the compass needle outline as vector data,
which can be stored _much_ more efficiently than a bitmap, and use
Graphics.FillPolygon() to draw the needle (the docs say this is
supported on CF).

In fact, while bitmap rotation done properly can be a bit of a pain,
it's trivial to rotate individual coordinates with matrix math. So a
vector-based compass needle only really needs a single copy of the basic
coordinates. The space savings would be so vast as compared to having
individual bitmaps for even a single position for the compass needle,
never mind the storage required for a bitmap-based solution that can
achieve the same quality output as a vector-based solution, that you
could easily afford to design a vector-based needle representation that
involves multiple fills and/or outlines, to make it prettier as needed.

Pete
 
K

kndg

kndg said:
[...]
Eventually, I abandoned the project because the CF doesn't suppport
image transformation (you can't rotate the image to any degree you
want, so either you have to manually draw the compass needle, or have
a 360 images but this will increase the executable size very much). I
don't know whether it can be done through P/Invoke either.

Not sure if, after my suggestion that Peter check other forums, whether
he's still following this. But in case he is…

As far as dealing with the rotation issue goes, if the platform doesn't
support arbitrarily rotated drawing, you still don't really need 360
different images for a compass overlay.

For one, IMHO the precision of the compass is unlikely to be usable to
the nearest degree anyway. So you probably only need 180 or 120 discrete
positions for the needle.

Then, you also need at most a quarter that number because even without
fancy API support, it's trivial to do 90 degree bitmap rotations. So
then you only need 30-45 images.

I would guess the images should be reasonably small saved as PNG. But if
size is still a problem at that point, there is also the point that the
overlay probably doesn't need to be at full resolution. So you can get
an additional 75% reduction in size just by halving the number of pixels
in each direction in the stored bitmap and then doing a trivial stretch
when using it.

Hi Pete,

Good thoughts!
I started the project when I saw a very cool compass application that
bundled on iPhone so I though whether I could make the same on my WinMob
device. Having a compass face(rose) save as png gives me about 50K bytes
file. 30 images of this accumulates to 1.5M bytes which is IMO way too
big for a smart device application. Having a image reduce to quarter
resolution would reduce the size to about 375K bytes (which maybe
acceptable) but I don't know whether stretching back the image would
preserve the transparency (especially around the edge).
Finally, there is the option to abandon a bitmap-based solution
altogether. Instead, store the compass needle outline as vector data,
which can be stored _much_ more efficiently than a bitmap, and use
Graphics.FillPolygon() to draw the needle (the docs say this is
supported on CF).

In fact, while bitmap rotation done properly can be a bit of a pain,
it's trivial to rotate individual coordinates with matrix math. So a
vector-based compass needle only really needs a single copy of the basic
coordinates. The space savings would be so vast as compared to having
individual bitmaps for even a single position for the compass needle,
never mind the storage required for a bitmap-based solution that can
achieve the same quality output as a vector-based solution, that you
could easily afford to design a vector-based needle representation that
involves multiple fills and/or outlines, to make it prettier as needed.

Yes, at first I would go this way, but I would lost the cool-ness of the
compass interface. I prefer having the compass face to rotate instead of
the needle. That's why I abandoned the project.

I heard that on CF 4.0, they will be a subset of WPF included on the
framework (though I don't remember where I got that info) and it would
be very interesting if they support image rotation also...(maybe I could
revive back my dead projects).

Regards.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top