DrawImage(..) Method decrease the performance too much

Hello,

Ima using the DrawImage Method to drow multi Images on a pictureBox control using a timer but i found that this method make the performance too bad,
There is another method in .Net i can use instead???

Please help,

Thanks
LVL 1
amrelgarhy81Asked:
Who is Participating?
 
PigtorConnect With a Mentor Commented:
Do not use the PictureBox control, use a Panel control or a UserControl instead.

About PictureBox:
- The PictureBox control is for displaying images. It is not a handy placeholder for a graphics surface.

- Windows is an event driven system in which each event must be serviced in the correct context and events destined to handle button click or mouse move events must not be used to do drawing on screen or other weird stuff.

- The PictureBox refreshes itself by drawing the System.Drawing.Image based object stored in it's Image property. If there is no image, it will show the background colour.

- Stealing and drawing upon the Graphics object of any control is not good practice, should be strongly discouraged and breaks the rules of handling events in the right place at the right time. Basically if you do this it will cause you pain. When you bang your head against a wall it causes you pain. that is a sign that you should stop doing it. It's the same for the PictureBox.CreateGraphics call.


Check this link for more information:
http://www.bobpowell.net/picturebox.htm



0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Can you give us a bigger picture of what you are doing so we can suggest possible different approaches?
0
 
amrelgarhy81Author Commented:
What iam doing is a user control:
It is inherited from pictureBox control and i use a timer to change the images in the picture box and i do some effects while changing beween images so i use the drawImage method to do that effects.
And that made me see the lake in performance.
Please ask if you need more.
0
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

 
amrelgarhy81Author Commented:
Understood me??
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Yes...but it's too vague to really make any good suggestions off of...

How big are your images?
How often are you changing them?
Where are you storing the different images?
What kind of effects are you making?

Etc...

There are many things that can affect "performance"...
0
 
amrelgarhy81Author Commented:
Yes i Know tha manythings can affect the performance but what iam asking about is that the drawImage method make decrease in performance, there is another function in .Net that can replace it?

Some effects like:
Draw a new image moving and scaling from left to right or up to left
You know somthing near to powerPoint effects.
0
 
amrelgarhy81Author Commented:
So Pigtor
Should i draw on another control or donn't use the drawImage method,
Note i need it to be a control because i will deal with it  as a user control later,
And i found that the big performance problem is in the DrawImage method.
0
 
PigtorCommented:
DrawImage is not slow, GDI+ is slow
You could find a lot of information on bobpowell website:
http://www.bobpowell.net/why_so_slow.htm

If your component demand a lot of graphics, you should better use DirectX.

Answering your question, DrawImage is not slow, but you should better use DrawImageUnscaled, because scaling an image can slow down the rendering.

I hope that information helps.

Victor
0
 
amrelgarhy81Author Commented:
Ok, but small question:
PowerPoint and flash uses directx?
I tryed the DrawImageUnscaled method but nothing happened new

What can i do?
0
 
CuSo4Commented:
On wich thread are you calling DrawImage? I believe it shouldn't be used in the timer-thread itself, as it will result in semi-freezing windows. Can you give us a sample of your code?
0
 
amrelgarhy81Author Commented:
Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick

            Dim mx As New Matrix()
            mx.Translate(0, mH, MatrixOrder.Append)
            g.Transform = mx
            mH = mH + (Me.Height / 10)
            g.DrawImage(Me.currentImage, 0, 0, Me.Width, Me.Height)
            If mH > 0 Then
                Me.Image = Me.currentImage
                mH = -Me.Height              
                Me.Timer2.Enabled = False
            End If


End Sub
0
 
CuSo4Connect With a Mentor Commented:
It seems like you are trying to draw from within the timer-thread. This is probably the reason for the poor performance.
Try using the following structure:

 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        AddHandler Me.Image.Paint, New PaintEventHandler(AddressOf Image_OnPaint)
    End Sub

    Private Sub Image_OnPaint(ByVal sender As Object, ByVal e As PaintEventArgs)
        Dim mx As New Matrix()
        mx.Translate(0, mH, MatrixOrder.Append)
        e.Graphics.Transform = mx
        mH = mH + (Me.Height / 10)
        e.Graphics.DrawImage(Me.currentImage, 0, 0, Me.Width, Me.Height)

        If mH > 0 Then
            Me.Image = Me.currentImage
            mH = -Me.Height
            Me.Timer2.Enabled = False
        End If

    Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick
        Me.Image.Invalidate()
    End Sub


This way the Timer will request a redraw of the image with the Invalidate() method, and the Painting itself will happen on the right thread.
         
0
 
amrelgarhy81Author Commented:
I found no diffrence in the performance.
0
 
Mike TomlinsonConnect With a Mentor Middle School Assistant TeacherCommented:
CuSo4...

It was already running on the same thread as the main UI thread.  The code clearly shows that Timer2 has a Tick() event indicating that it is a System.Windows.Forms.Timer and therefore runs in the same thread as the form containing it.  You are correct that you should use the Paint() event instead of storing a "global" graphics object to use in other subroutines.  You're just off base with the different thread comments...

amrelgarhy81...

Out of curiousity, what is the Interval on your Timer set to?
0
 
amrelgarhy81Author Commented:
Timer  Interval  = 1
0
 
amrelgarhy81Author Commented:
we can use e-mails here to sent the sample i have?
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
You won't get the Timer control to fire properly with an Interval of 1!

The lowest you will likely see "proper" timing is somewhere around 25, but it may be as high as 50 on some older systems.
0
 
amrelgarhy81Author Commented:
by the way thats not the problem
the problem the my processor get very hight while running the draw image method, in a timer , on a new thread, or on the main thread.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Of course...your processor is probably pinged at 100% because there isn't any "pause" between events with a Timer interval that low.  The events are all stacked up against each other in your message queue making them run essentially as if they were in an inifinite loop.  

The same would be true if you placed the code into a different thread but did not provide a "pause" inbetween paints via the Sleep() method.

Just to prove it...bump up your interval to 100 and see if your processor usage drops down.  If it doesn't then you are attempting to do too much processing in the timer event.
0
 
amrelgarhy81Author Commented:
I heared from someone is that the problem is in the GDI+ its self becuase it dosn't work directly with the hardware like the previous GDI in vb6 and heared too that GDI+ is not a managed classes it is just API methods called from the .net
0
 
CuSo4Commented:
Idle_Mind is right about the Timer Interval, and that's probably also why your processor utilisation gets that high.

@Idle_Mind: Sorry about the thread-confusion, I didn't know Timer events ran on the Form's main thread...
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
"I didn't know Timer events ran on the Form's main thread"

The System.Windows.Forms.Timer (it is the only one with a Tick event) runs on the main UI thread.

The other two Timers (System.Timers.Timer and System.Threading.Timer) run in their own thread.
0
 
amrelgarhy81Author Commented:
Ok, good experts
I will try but small question:
suppose i used it without any timeres or threads, i used it in a loop it will be worest performance right?

And if i made "pause" between events the animation of the image will cut and continue, cut and continue.



0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
That may just depend on how long the pause is.  There may not be that much noticeable difference to the end user.  It just depends on what you're doing.  Experiment with the Interval property...



A small call to Sleep() can greatly reduce CPU usage:

    System.Threading.Thread.Sleep(25)

The problem with moving the painting to a different thread is that you need a delegate to properly marshal the call from your thread back onto the main UI thread.  This causes additional overhead on the application, especially if you are "firing events" in rapid succession as you are.

A common misconception is that threading "frees up" the main UI.  If a thread does NOT pause, and continually fires an event that the main UI must handle, then the main UI will be continually process the threads event.  This essentially nullifies the benefit of creating the thread in first place...
0
 
amrelgarhy81Author Commented:
ok, i will try and send what will happen
0
 
PigtorCommented:
Using timers and sleep is not a good idea.

You can use a Threading.Timer, but you will get the "Object is already in use" exception.  To correct this behavior you should use the SyncLock <Bitmap> statement, where <Bitmap> is a reference to the Bitmap you are drawing.
The best performance you will get is using a timer of 100 ms.  I have posted before the reason GDI+ is so slow.

You could use a non threading timer like System.Windows.Forms.Timer or a LOOP, but it will not help you so much, because when another process slows down the computer, your GDI+ graphics will have a strange behavior.
For example, your image draws in 200 ms, and your sleep or timer is 100 ms, this interval will hang your computer.  Other example, your image draws in 200 ms and your timer is in 300 ms., the same will happen when another process slows down the machine.

Other consideration you should take is the size of the image, a small image draws faster than a large image.  Try testing a large image (for exaple 4x the small image size)  The result will be more or less the same behavior it will have in slower machines.
Now, try using a larger image (16x the size of the small image) on your timer and you will understand what I'm talking about.

My sugestion, use GDI+ for images that doesn't change frequently and DirectX for advanced image manipulation like animations.
If you don't have no choice but using GDI+, I suggest using a Threading.Timer rather than Windows.Forms.Timer Or Sleep.

0
 
amrelgarhy81Author Commented:
Thanks Pigtor for your comment i will try all what you said Pigtor,  Idle_Mind  and will tell you both what i got,
Thanks alot for your effort experts.
0
 
amrelgarhy81Author Commented:
Pigtor...

How can i use the Threading.Timer?
Using events like the Windows.Timer?
Or should i use it like this sample in the .Net 2.0 Documentaion:
ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.en/cpref12/html/T_System_Threading_Timer.htm
0
 
PigtorCommented:
Use the following code. Call the StartTimer and StopTimer.
The TimerProc method is the event you are looking for.

-------------------------------------------------------------------------------------------------------

Private hTimer As System.Threading.Timer

Private Sub StartTimer(ByVal Interval As Integer)
     If Not hTimer Is Nothing Then Return
     hTimer = New System.Threading.Timer(New System.Threading.TimerCallback(AddressOf TimerProc), Nothing, Interval, Interval)
End Sub

Private Sub StopTimer()
     If Not hTimer Is Nothing Then
          hTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite)
          hTimer.Dispose()
          hTimer = Nothing
     End If
End Sub

Private Sub TimerProc(ByVal obj As Object)
'...Put here the code ...
End Sub

0
 
amrelgarhy81Author Commented:
Thanks, Will try and tell you the result, but small question:
Using this timer will give diffrent performance results than using normal threading, using sleep?
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
I really don't see how using a System.Threading.Timer will be any different than the current implementation using a System.Windows.Forms.Timer.

You won't be able to get any "faster" firing interval.

Additionally you now have the overhead of marshalling the call from your thread back onto the main UI using Delegates and the Invoke() methods.

?
0
 
amrelgarhy81Author Commented:
right, I will try and get the results,
Thanks alot
0
 
PigtorCommented:
The timer interval can be changed using the Interval parameter in the StartTimer method.
You will not find differences between both timers, because both does the same.  But the difference is in the performance with big images, slow machines or faster timers.

To get the best performance for your graphics, you should make your own tests using bigger images and faster timers.  When you get an acceptable performance on your bigger images, change your images to their normal size and you will see a very good performance.

Or maybe the reason of the bad performance is the technique you are using to draw the window.
GDI+ is very extensive to be answered in one question.  Please go to this link:
http://www.bobpowell.net
On this site you will find a lot of tricks for performance and what to NOT do in GDI+


0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.