|
What I noticed is that the Tooltip stops showing after the first time you click on the Iconit. Once clicked, the tooltip won't show up again.
Ideas?
|
|
|
|
|
I noticed your routeen to update the alpha of the bitmap is using a slower method (actually, about the slowest there is). Here is a significantly faster version of your routeen. It uses an unsafe code function, which allows the use of pointers. This function will adjust the original alpha by the input alpha amount. Since it uses pointers to directly edit the memory of the copied bitmap, it is hundreds of times faster than using the GetPixel/SetPixel method of GDI+. In fact, GDI+ essentially does the first and last parts of my function (locking pixels, finding the pixel in memory, reading/writing it, and unlocking), every time you call GetPixel or SetPixel. By using an unsafe function with pointers, you eliminate the repetitive locking/seeking/unlocking of pixel data in memory, which greatly improves performance.
public unsafe Bitmap returnAlpha(Bitmap bmp, int alpha)
{
if (bmp.PixelFormat != PixelFormat.Format24bppRgb
&& bmp.PixelFormat != PixelFormat.Format32bppArgb)
throw new ArgumentException();
Bitmap bmpCopy = new Bitmap(bmp.Width, bmp.Height, PixelFormat.32bppArgb);
GraphicsUnit gu = GraphicsUnit.Pixel;
RectangleF rectF = bmp.GetBounds(ref gu);
Rectangle rect = Rectangle.Round(rectF);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.Read, bmp.PixelFormat);
rectF = bmpCopy.GetBounds(ref gu);
rect = Rectangle.Round(rectF);
BitmapData copyData = bmpCopy.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
byte* oPx = (byte*)bmpData.Scan0;
byte* cPx = (byte*)copyData.Scan0;
uint black = 255;
byte b, a;
for (int y=0; y<bmpData.Height; y++)
{
for (int x=0; x<bmpData.Width; x++)
{
*cPx = *oPx;
*(cPx+1) = *(oPx+1);
*(cPx+2) = *(oPx+2);
if (bmpData.PixelFormat == PixelFormat.Format32bppArgb)
{
b = *(oPx+3);
}
else
{
b = (byte)((*cPx + *(cPx+1) + *(cPx+2)) / 3);
}
a = 0;
if (b > 0)
{
a = (byte)Math.Min(255, Math.Max(0, b-alpha));
}
*(cPx+3) = a;
cPx += 4;
if (bmpData.PixelFormat == PixelFormat.Format24bppRgb)
oPx += 3;
else
oPx += 4;
}
if (bmpData.PixelFormat == PixelFormat.Format24bppRgb)
oPx += bmpData.Width;
}
copyBmp.UnlockBits(copyData);
bmp.UnlockBits(bmpData);
return copyBmp;
}
-- modified at 23:23 Thursday 20th April, 2006
|
|
|
|
|
For some reason, CodeProject is stripping whitespace from my code. Sorry for it being all packed together.
|
|
|
|
|
I've tested your method, it's fanstastic.
Just in case people donn't, above Jon Rista method need to add
using System.Drawing.Imaging;
******************************************
I alterred the iconits.cs few place to remove those resources killer
namespace alterred<br />
{ <br />
public class Iconits : System.Windows.Forms.UserControl<br />
{<br />
private System.ComponentModel.IContainer components;<br />
private System.Windows.Forms.Timer timer1;<br />
private System.Windows.Forms.ToolTip t=new ToolTip();<br />
Bitmap[] bmp; <br />
int flag;<br />
bool enter;<br />
Graphics g,g2;<br />
<br />
int imwidth,imheight;<br />
double curwidth,curheight;<br />
double addx,addy;<br />
Bitmap dblbuffer;<br />
bool blur=true;<br />
<br />
public Iconits()<br />
{<br />
InitializeComponent();<br />
bmp=new Bitmap[4]; <br />
for (int i=0;i<4;i++)<br />
bmp[i]=new Bitmap(Width,Height);<br />
dblbuffer=new Bitmap(Width,Height);
g2=Graphics.FromImage(dblbuffer); <br />
<br />
IconSize=new Size(Width/2,Height/2); <br />
g=this.CreateGraphics(); <br />
}<br />
<br />
<br />
protected override void Dispose( bool disposing )<br />
{<br />
if( disposing )<br />
{<br />
if(components != null)<br />
{<br />
components.Dispose();<br />
}<br />
}<br />
base.Dispose( disposing );<br />
}<br />
<br />
#region Component Designer generated code<br />
<br />
private void InitializeComponent()<br />
{<br />
this.components = new System.ComponentModel.Container();<br />
this.timer1 = new System.Windows.Forms.Timer(this.components);<br />
this.timer1.Interval = 10;<br />
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);<br />
this.BackColor = System.Drawing.SystemColors.Control;<br />
this.Name = "Iconits";<br />
this.Size = new System.Drawing.Size(160, 128);<br />
this.Paint += new System.Windows.Forms.PaintEventHandler(this.Iconits_Paint);<br />
this.MouseEnter += new System.EventHandler(this.Iconits_MouseEnter);<br />
this.MouseLeave += new System.EventHandler(this.Iconits_MouseLeave);<br />
<br />
}<br />
#endregion<br />
<br />
private void Iconits_Paint(object sender, System.Windows.Forms.PaintEventArgs e)<br />
{ <br />
<br />
draw(3); <br />
}<br />
<br />
private void calc()<br />
{<br />
curwidth=imwidth;<br />
curheight=imheight;<br />
<br />
addx=(double)(Width-imwidth)/10;<br />
addy=(double)(Height-imheight)/10;<br />
}<br />
<br />
<br />
private void draw(int state)<br />
{<br />
int st;<br />
<br />
if (blur)<br />
st=state;<br />
else<br />
st=0;<br />
<br />
<br />
g2.Clear(this.BackColor);<br />
g2.DrawImage(bmp[st],(int)((double)Width-curwidth)/2,(int)((double)Height-curheight)/2,(int)curwidth,(int)curheight); <br />
g.DrawImageUnscaled(dblbuffer,0,0); }<br />
<br />
private void timer1_Tick(object sender, System.EventArgs e)<br />
{ <br />
if (enter)<br />
{<br />
if (curwidth<Width)<br />
{<br />
curwidth+=addx;<br />
}<br />
<br />
if (curheight<Height)<br />
{<br />
curheight+=addy;<br />
}<br />
<br />
if (curwidth>=Width&&curheight>=Height) timer1.Enabled = false; flag++;<br />
}<br />
else<br />
{<br />
if (curwidth>imwidth)<br />
{<br />
curwidth-=addx;<br />
}<br />
<br />
if (curheight>imheight)<br />
{<br />
curheight-=addy;<br />
}<br />
<br />
if (curwidth<=imwidth&&curheight<=imheight) timer1.Enabled = false;<br />
<br />
flag--;<br />
}<br />
<br />
if (flag>9) draw(0); <br />
else if (flag>6) draw(1);<br />
else if (flag>3) draw(2);<br />
else draw(3); <br />
}<br />
<br />
private void Iconits_MouseEnter(object sender, System.EventArgs e)<br />
{ <br />
enter=true;<br />
timer1.Enabled=true;<br />
}<br />
<br />
private void Iconits_MouseLeave(object sender, System.EventArgs e)<br />
{<br />
enter=false; <br />
timer1.Enabled = true;<br />
}<br />
<br />
public Bitmap Icon<br />
{<br />
get { return bmp[0]; }<br />
set { <br />
<br />
bmp[0]=value; <br />
alpha.returnAlpha3(ref bmp[0],60, ref bmp[1]);
alpha.returnAlpha3(ref bmp[0],120,ref bmp[2]);<br />
alpha.returnAlpha3(ref bmp[0],180,ref bmp[3]); draw(0); <br />
}<br />
}<br />
<br />
public new Size Size<br />
{<br />
get { return new Size(Width,Height); }<br />
set <br />
{<br />
Width = ((Size)value).Width;<br />
Height= ((Size)value).Height; <br />
if (Width>160) <br />
{<br />
Width=160;<br />
}<br />
if (Height>128) <br />
{<br />
Height=128; <br />
}<br />
calc();<br />
}<br />
} <br />
<br />
public Size IconSize<br />
{<br />
get { return new Size(imwidth,imheight); }<br />
set<br />
{<br />
imwidth=((Size)value).Width;<br />
imheight=((Size)value).Height;<br />
if (imwidth>Width) imwidth=Width;<br />
if (imheight>Height) imheight=Height;<br />
calc();<br />
}<br />
}<br />
<br />
public bool Blur<br />
{<br />
get { return blur; }<br />
set<br />
{<br />
blur=value;<br />
if (!blur)<br />
{<br />
bmp[1].Dispose();<br />
bmp[2].Dispose();<br />
bmp[3].Dispose();<br />
}<br />
else<br />
{<br />
alpha.returnAlpha3(ref bmp[0], 60 ,ref bmp[1]);<br />
alpha.returnAlpha3(ref bmp[0], 120 ,ref bmp[2]);<br />
alpha.returnAlpha3(ref bmp[0], 180 ,ref bmp[3]);<br />
<br />
}<br />
}<br />
}<br />
<br />
public string About<br />
{<br />
get { return "Iconits 0.1.0 - ITS Informatics Surabaya, author: Yojana Hanif. Jayoscar Modify Abit"; }<br />
}<br />
<br />
public string TooltipText<br />
{<br />
get { return t.GetToolTip(this); }<br />
set { t.SetToolTip(this,value); <br />
}<br />
}<br />
}<br />
}<br />
<br />
This part on the alpha.cs<br />
public static void returnAlpha2(ref Bitmap bmp, int alpha, ref Bitmap bmpModify)<br />
{<br />
Color col; <br />
<br />
for (int i=0;i<bmp.Width;i++)<br />
for (int j=0;j<bmp.Height;j++) <br />
{<br />
col=bmp.GetPixel(i,j); <br />
if (col.A>0)<br />
bmpModify.SetPixel(i,j,Color.FromArgb(min(col.A-alpha),col.R,col.G,col.B)); <br />
} <br />
}
Well, everyone give some feedback see how this change you feel. Comment/suggestion welcome.
-- modified at 7:02 Friday 21st April, 2006
|
|
|
|
|
Another quick note, if you use the alphatizing routeen I wrote. You will need to enable unsafe code blocks in your projects properties, otherwise it won't compile.
|
|
|
|
|
Don't you mean 'routine'???
|
|
|
|
|
Probably a mistake in copying and pasting ?
Timer1_Tick :
You have a couple of conditional expressions that are not complete like :
if (enter)
{
if (curwidth {
curwidth+=addx;
}
if (curheight {
curheight+=addy;
}
In the alpha modification the nested for loops are not filled out and framed as needed :
public static void returnAlpha2(ref Bitmap bmp, int alpha, ref Bitmap bmpModify)
{
Color col;
//Bitmap bmp2=new Bitmap(bmp);
for (int i=0;i for (int j=0;j {
col=bmp.GetPixel(i,j);
if (col.A>0)
bmpModify.SetPixel(i,j,Color.FromArgb(min(col.A-alpha),col.R,col.G,col.B));
}
//return bmp2;
}
"The greater the social and cultural distances between people, the more magical the light that can spring from their contact." Milan Kundera in Testaments Trahis
|
|
|
|
|
Hello,
please check this Code-Block!
There's some mismatch happens
eg. :
change:
"for (int i=0;i for (int j=0;j {" ???
to:
for (int i=0;i<bmp.width;i++)
for="" (int="" j="0;j<bmp.Height;j++)"
="" {
...
eg1.="" :
change:
"if="" (curwidth="" {
curwidth+="addx;
}
if" (curheight="" {
curheight+="addy;
}"
to:
if">imwidth)
{
curwidth-=addx;
}
if (curheight>imheight)
{
curheight-=addy;
}
Best Regards
Tim
|
|
|
|
|
returnAlpha3 - the 3? What am I missing? Where is the method defined?
thanks
Ralph
|
|
|
|
|
Hi, Jon, nice mod.
In 'returnAlpha :
Bitmap bmpCopy = new Bitmap(bmp.Width, bmp.Height, PixelFormat.32bppArgb);
... should be ... PixelFormat.Format32bppArgb
At the end of 'returnAlpha : you are unlocking bmpCopy, not copyBmp ?
copyBmp.UnlockBits(copyData);<br />
bmp.UnlockBits(bmpData);<br />
return copyBmp;
"The greater the social and cultural distances between people, the more magical the light that can spring from their contact." Milan Kundera in Testaments Trahis
|
|
|
|
|
Looks like your correct about both errors. I just typed all that into the forum post box from memory as best I could, I never actually compiled it. As for the second error you mentioned, I just typoed. It is supposed to be bmpCopy, not copyBmp. Sorry about that.
|
|
|
|
|
Cool !!! Simple but Effective ... Keep it up
Babu Aboobabacker E.I
-- modified at 16:29 Thursday 20th April, 2006
|
|
|
|
|
Thank you very much, for an excellent piece of code
Regards,
Santosh Ku Sahoo
|
|
|
|
|
Great work
|
|
|
|
|
I've had a look at Task Manager whilst the demo is running, and each time I mouse over one of the icons, the memory usage increases by about 60k.
Is there anyway to combat this? You could imagin someone could have alot of fun with this code but some one would soon run out of memory?
Regards
Gav
|
|
|
|
|
Ridiculous as it sounds, minimize the window. I have no idea what's going on but what the memory drop when it's minimized, when you restore the window again, the memory usage is much less. I'm guessing that it's the GC kicking in but honestly don't know. This may even be something completley different.
It's just weird.
|
|
|
|
|
The rate of memory consumption dramatically decreases if you cache the 'g2' Graphics variable, instead of creating a new Graphics from 'dblbuffer' in the draw() method. One of the problems is that g2 was never being disposed. Rather than creating a new Graphics from 'dblbuffer' every time the draw() method is called, set g2 whenever the dblbuffer variable is set (such as in the constructor and in the Icon property setter). And be sure to dispose of g2 before setting it to a new value.
Josh
|
|
|
|
|
|
yay, thanks for the great info!
going to rewrite it...soon
(well, I dunno any trick to optimize stuff, going to learn it...)
|
|
|
|
|
Yes it is indeed a very cool effect, now i have to find somewhere to use it
But instead of making bitmaps with different alpha, you couls also use this[^] method from Bob Powell (bottom of the page). I think this saves a lot of memory, and not too much speed increase. Bobs site is a great resource btw, it helped me a lot. Hope this helps
"..Commit yourself to quality from day one..it's better to do nothing at all than to do something badly.."
-- Mark McCormick || Fold With Us! || Pensieve || VG.Net ||
-- modified at 18:56 Saturday 15th April, 2006
|
|
|
|
|
This is very cool. Thanks a bunch for sharing it.
You got my 5.
Just curious to know if you've done the rewrite yet. I'm hoping you'll post a message when you do so that we all know.
This little control is awesome!
|
|
|
|
|
Hi,
I find a ¿bug? in your class Iconits...
when you move the mouse over the icons very rapidly, those appear with blur effect,because the variable "flag" increments always...
I´ve find a solution: in timer_Tick when enter = false are executed some sentences,before the last sentence (flag--)is this sentence:
...
if (curwidth <= imwidth && curheight <= imheight)
{
timer1.Stop();
}
so it must look like this:
...
if (curwidth <= imwidth && curheight <= imheight)
{
flag = 0;
timer1.Stop();
}
Cheers!
|
|
|
|
|
The "problem" is windows (or the framework not sure) is not recalculating free space untill it really needs to, for performance reasons obviosly. So when you request a chunk of memory, if there is free space available on the managed heap, you simply get it, its not going to go search for little chunks. If there is no free memory available on the managed heap, then it will recalculate and recover some free space for you.
I forgot why exactly minimizing updates the correct memory usage in task manager, but its not a bug or error in any sense. And I am fairly sure its not the GC kicking in. Its just the way it works. A .NET program will "consume" new chunks of memory while they are available vs searching for free space in the memory it used (and released) before.
Bottom line, if you really want to know how much memory your program is using, releasing, and leaking, USE USE USE a profiler. In my opinion it is THE best way to optimize memory usage and find memory leaks.
-- modified at 16:58 Tuesday 18th April, 2006
|
|
|
|
|
The reason specified by the "Josh Smith" is one of the reason of memory leakage.
The Task Manager
-- In the Process View it shows the amount of "main memory (RAM)" associated with the process.
-- In the Performance tab it shows the memory in use, including Virtual memory.
So even when you minimize the application you will not notice any difference in the Performance tab. This is because when you minimize the application it swaps out the pages to the virtual memory. This the reason for dramatic decrease in memory shown in the Process tab (because the RAM has freed the pages) but no difference to oveall memory (because RAM + Virtual memory is still same)
|
|
|
|
|
Simple but powerful.
Really good looking control and really smooth animation.
Thanks a lot for this great piece of code!
|
|
|
|
|