Solved

C# - Duplicating PNG Picturebox - problem carrying over transparency to new image

Posted on 2007-04-06
21
496 Views
Last Modified: 2012-06-27
Hey guys 'n gals,

I need some help with some code...

I have some code which allows me to duplicate an image, which works almost perfectly...

The source image is a PNG (contains transparency)
The newly cloned image does not carry over this transparency, and replaces the transparent areas with white.


Anybody come across this before? Any thoughts on how to fix this? I am more than happy to give an example of the code, if nobody else has this problem.


Cheers!
0
Comment
Question by:Cyber-Drugs
  • 12
  • 9
21 Comments
 
LVL 5

Expert Comment

by:Yttribium
ID: 18867722
If you could show me what you've done, then I can see if I can do anything.
0
 
LVL 5

Expert Comment

by:Yttribium
ID: 18867781
In the mean time, I did this:
             Image i = Image.FromFile(@"C:\test.png");
                  PictureBox p = new PictureBox();
                  p.Width = 200;
                  p.Height = 200;
                  p.Top = 205;
                  p.Left = 205;
                  p.Image = (Image)i.Clone();

                  PictureBox p2 = new PictureBox();
                  p2.Image = (Image)p.Image.Clone();
                  p2.Width = 200;
                  p2.Height = 200;
                  p2.Left = 0;
                  p2.Top = 0;

                  p2.Image.Save(@"c:\ta.png");
                  
                  panel2.Controls.Add(p);
                  panel2.Controls.Add(p2);

Both the clone displayed on the panel and saved had the transparency preserved.

So they both worked fine, so I'm very curious what the problem is, unless I misunderstood your question.
0
 
LVL 4

Author Comment

by:Cyber-Drugs
ID: 18870319
Sorry for the delayed reply...

You understood my question perfectly and it seems you are using a slightly different method for duplicating the images than me, here is the method I am using:

        void ctl_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                startX = e.X;
                startY = e.Y;
                PictureBox source = (PictureBox)sender;
                pb = new PictureBox();
                pb.Size = source.Size;
                pb.Location = this.PointToClient(panel2.PointToScreen(source.Location));
                pb.Image = source.Image;
                this.Controls.Add(pb);
                pb.BringToFront();
            }
        }



As you can see, I am referencing the image in a slightly different way to you. Hopefully you can see the issue and help me rectify it, it's nothing deadly serious as this is a personal project, but would be good to know how to rectify.


Cheers!
0
 
LVL 5

Expert Comment

by:Yttribium
ID: 18870345
I'm not losing transparency at all... I'm a bit surprised.  Maybe you can send me your project zipped up, I can take a look.  Because I don't get the transparency problem at all.

 If you show me the link to your project when you've uploaded it, I'll try compile and run and see if I get the same problem.  It maybe context dependent.
0
 
LVL 4

Author Comment

by:Cyber-Drugs
ID: 18870500
Sure thing, here it is:

http://ww.cyber-lane.com/CartoLogix.zip

Basically, drag and drop images from the right hand panel to the middle area. While they are being dragged, the transparency is hidden... After they have been dragged and left on top of other images, the transparency is hidden...

I have left a temporary login to the MySQL database so that you can see it working, but you possibly will need the MySQL DLL, if so, here is the one I'm using:


http://www.cyber-lane.com/MySql.Data.dll


Thanks yet again!
0
 
LVL 4

Author Comment

by:Cyber-Drugs
ID: 18870507
By the way, if you are any good with treeViews, I have a question open at the moment which has had 2 replies but they haven't actually solved the problem as of yet, in case you may be interested? I also, have a DataGridView one with pretty much the same.
0
 
LVL 5

Expert Comment

by:Yttribium
ID: 18870524
Can't connect unfortunately, ACCESS DENIED  =/
0
 
LVL 4

Author Comment

by:Cyber-Drugs
ID: 18870538
Ah yeah, sorry forgot...

Can you possibly email your IP address to me so I can grant access: developer@cyber-lane.com
0
 
LVL 5

Expert Comment

by:Yttribium
ID: 18870552
done *waits* hehe
0
 
LVL 5

Expert Comment

by:Yttribium
ID: 18870633
Problem is a little more complex now, the PictureBox in which the image is dispalyed, is NOT transparent (even if BackColor = Color.Transparent) it isn't.  The png images indeed ARE transparent (to the picturebox background)   I'll have to think about this problem now, it's a little more tricky with this issue.  How badly does it have to be "free-form" placement?  Are there other alternative ways of displaying the images on the middle panel?  It would be pretty easy say to put them into a large-icon ListView for instance.

 These are just options for you to consider.
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 5

Expert Comment

by:Yttribium
ID: 18870675
Here is a solution:

//from some MSDN Forum I found a while back
      public class TransparentPictureBox : Control
      {
            private Timer refresher;
            private Image _image = null;

            public TransparentPictureBox()
            {
                  refresher = new Timer();
                  refresher.Tick += new EventHandler(this.TimerOnTick);
                  refresher.Interval = 50;
                  refresher.Start();
            }

            protected override CreateParams CreateParams
            {
                  get
                  {
                        CreateParams cp = base.CreateParams;
                        cp.ExStyle |= 0x20;
                        return cp;
                  }
            }

            protected override void OnMove(EventArgs e)
            {
                  base.RecreateHandle();
            }

            protected override void OnPaint(PaintEventArgs e)
            {
                  if (_image != null)
                        e.Graphics.DrawImage(_image, (Width / 2) - (_image.Width / 2), (Height / 2) - (_image.Height / 2));
            }

            protected override void OnPaintBackground(PaintEventArgs e)
            {
            }

            private void TimerOnTick(object source, EventArgs e)
            {
                  base.RecreateHandle();
                  refresher.Stop();
            }

            public Image Image
            {
                  get
                  {
                        return _image;
                  }
                  set
                  {
                        _image = value;
                        base.RecreateHandle();
                  }
            }
      }

Add this class to your program, replace all mentions of PictureBox with TransparentPictureBox.
You will need to comment out some of the properties that are not implemented, and if you need them, find a way to implement them.  But this worked nicely, I've checked that.

Thanks goes to the guy that wrote this thing (somewhere down the thread)
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=53191&SiteID=1
0
 
LVL 4

Author Comment

by:Cyber-Drugs
ID: 18872091
Hey, looks like a good solution, but I got the following errors (due to 2 properties not being available)

Error      1      'CartoLogix.TransparentPictureBox' does not contain a definition for 'BorderStyle'      C:\Documents and Settings\Justin Nel\My Documents\Visual Studio 2005\Projects\CartoLogix\CartoLogix\Form1.cs      130      28      CartoLogix
Error      2      'CartoLogix.TransparentPictureBox' does not contain a definition for 'BorderStyle'      C:\Documents and Settings\Justin Nel\My Documents\Visual Studio 2005\Projects\CartoLogix\CartoLogix\Form1.cs      216      32      CartoLogix
Error      3      'CartoLogix.TransparentPictureBox' does not contain a definition for 'BorderStyle'      C:\Documents and Settings\Justin Nel\My Documents\Visual Studio 2005\Projects\CartoLogix\CartoLogix\Form1.cs      222      28      CartoLogix
Error      4      'CartoLogix.TransparentPictureBox' does not contain a definition for 'SizeMode'      C:\Documents and Settings\Justin Nel\My Documents\Visual Studio 2005\Projects\CartoLogix\CartoLogix\Form1.cs      330      20      CartoLogix


Would it be difficult to manually add 'BorderStyle' and 'SizeMode' to this class?


Thanks again, and Happy Easter!!!
0
 
LVL 5

Accepted Solution

by:
Yttribium earned 500 total points
ID: 18872110
I've added a border now for you and a colour for the border:

      public class TransparentPictureBox : Control
      {
            private Timer refresher;
            private Image _image = null;
            private BorderStyle _borderStyle;
            private Brush _borderColor = Brushes.Black;

            /// <summary>
            /// Example Brushes.Color  (Brushes is a static class)
            /// </summary>
            public Brush BorderColor
            {
                  get { return _borderColor; }
                  set { _borderColor = value; }
            }

            public BorderStyle BorderStyle
            {
                  get { return _borderStyle; }
                  set { _borderStyle = value; }
            }      

            public TransparentPictureBox()
            {
                  refresher = new Timer();
                  refresher.Tick += new EventHandler(this.TimerOnTick);
                  refresher.Interval = 50;
                  refresher.Start();
            }

            protected override CreateParams CreateParams
            {
                  get
                  {
                        CreateParams cp = base.CreateParams;
                        cp.ExStyle |= 0x20;
                        return cp;
                  }
            }

            protected override void OnMove(EventArgs e)
            {
                  base.RecreateHandle();
            }

            protected override void OnPaint(PaintEventArgs e)
            {
                  if (_image != null)
                  {
                        e.Graphics.DrawImage(_image, (Width / 2) - (_image.Width / 2), (Height / 2) - (_image.Height / 2));
                  }
                  
                  if (_borderStyle == BorderStyle.FixedSingle)
                  {
                        e.Graphics.DrawRectangle(new Pen(_borderColor, 1), 0, 0, _image.Width - 1, _image.Height - 1);
                  }

            }

            protected override void OnPaintBackground(PaintEventArgs e)
            {
            }

            private void TimerOnTick(object source, EventArgs e)
            {
                  base.RecreateHandle();
                  refresher.Stop();
            }

            public Image Image
            {
                  get
                  {
                        return _image;
                  }
                  set
                  {
                        _image = value;
                        base.RecreateHandle();
                  }
            }
      }

Hope this helps.
0
 
LVL 5

Expert Comment

by:Yttribium
ID: 18872113
The size mode would take a bit too much time (at least I can't think of anything immediately), but I think you can probably figure it out, you just modify the paint place where I placed the border and do some calculations on the image placement and size.
0
 
LVL 4

Author Comment

by:Cyber-Drugs
ID: 18872967
Thank you yet again for taking all the time you did to help me with this issue!!!

After checking it out, I don't really need the SizeMode property, as I merely wanted to set the image to stretch with the size of it's container, and this seems to do that already.



Thank you!!

At this rate, won't be too long before you get an Expert Ranking in C#! ;o)
0
 
LVL 4

Author Comment

by:Cyber-Drugs
ID: 18872980
Oh no, wait... the drag and drop function isn't working and the images are not resized correctly...

Resizing I'm sure I can fix, but the drag and drop....
0
 
LVL 5

Expert Comment

by:Yttribium
ID: 18872989
What happened?  Drag and drop still works for me I think... what do you mean - it doesn't work? :s
0
 
LVL 4

Author Comment

by:Cyber-Drugs
ID: 18873001
Maybe I've done something wrong?


It compiles fine... Here's the updated code:


http://www.cyber-lane.com/CartoLogix.zip
0
 
LVL 5

Expert Comment

by:Yttribium
ID: 18873080
Took me a few minutes to pin point ONE line of code...

I saw that none of your events were attaching, and it all boiled down to your adding the events ctl_...
foreach (Control ctl in panel2.Controls)
   {
                if (ctl is PictureBox)
                {
                    ctl.MouseDown += new MouseEventHandler(ctl_MouseDown);
                    ctl.MouseMove += new MouseEventHandler(ctl_MouseMove);
                    ctl.MouseUp += new MouseEventHandler(ctl_MouseUp);
                }
            }

SHOULD read:

foreach (Control ctl in panel2.Controls)
   {
                if (ctl is TransparentPictureBox) // <-------- this little bugger is the source of pain
                {
                    ctl.MouseDown += new MouseEventHandler(ctl_MouseDown);
                    ctl.MouseMove += new MouseEventHandler(ctl_MouseMove);
                    ctl.MouseUp += new MouseEventHandler(ctl_MouseUp);
                }
            }

Hope this helps, and we can call this one solved lol
0
 
LVL 4

Author Comment

by:Cyber-Drugs
ID: 18873139
That fixed, cheers!

I'm going to do some playing around with it though, as it flickers a lot, so I think I may add the transparency on the dropped image, but when the image is moving, keep the transparency off.


Anyway, sorry to have kept this one open so long, thanks again!
0
 
LVL 5

Expert Comment

by:Yttribium
ID: 18873196
No problem, the flickering is just because of the delay, and the refresh rate, not much I can image you could do about that, other than do what you suggest.
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Suggested Solutions

Article by: Najam
Having new technologies does not mean they will completely replace old components.  Recently I had to create WCF that will be called by VB6 component.  Here I will describe what steps one should follow while doing so, please feel free to post any qu…
We all know that functional code is the leg that any good program stands on when it comes right down to it, however, if your program lacks a good user interface your product may not have the appeal needed to keep your customers happy. This issue can…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now