In a fast animation done by repeatedly displaying a bitmap on a picture box ... what is better: 1. to recreate, each time, the bitmap and graphics object (disposing the previous ones) or 2. to "clean up" the existing bitmap and redraw on it ? And, in case what is the faster way to clean the bitmap up. (I am wondering whether the filling done by a clear is more time consuming than just recreating the bitmap.) Further, I guess that if the picture box gets resized I have no choice but to recreate the bitmap. Right? or is there a better way ? -P
Joergen Bech ha scritto: Hi Joergen ! :) [quoted text, click to view] > Think about it: A new bitmap would automatically be filled with 0's > (black) so if you need a different background color, you would be > filling it anyway. So by recreating it you would have the additional > overhead of - well - recreating it. Won't save you anything.
The new bitmap has always a trasparent background (as far I can "see"), which is just what I need. Infact I always draw on a trasparent bitmap. When I show the bitmap in the picture box the user sees images and text on "white" pages, because the background of the control where is the picture box where I load the bitmap is white. So I never need actually any "clear" in the sense of "fill with a color". If there was a fast clear which turned all to a transparent bitmap it would be perfectly fine for me. Is there ? I could not find it around. At the present I recreate bitmap and graphics each time. What I was wondering if this is correct or it would be better to "erase" (turn to transparent) the bitmap so that I can write on it again. [quoted text, click to view] > > >Further, I guess that if the picture box gets resized I have no choice > >but to recreate the bitmap. Right? or is there a better way ? > > Yes, in this case it should be recreated. Of course, if we are talking > about a buffer (which I presume is the case), you could just recreate > it whenever the new size is larger (on either axis) than the existing > buffer, then use a subsection of the buffer if the size gets smaller.
This seems a nice strategy for the case of resize. Then I would split in 2 cases: - resize needed (recreate the bitmap) - resize not needed (cleanup the bitmap or recreate ? ) I am not sure I would be able to use the fact that only a small portion of a page may need to be drawn because my minimum entity for computation is a "page". I split all the objects of the document in pieces that lay on pages. Then I am able to draw a sigle page anytime, based on the overall computations. I am not able to consider less than one page: that's the minimum entity I draw. I do not have data on portion of pages. I only memorize objects for the whole page. Every time an object is moved a repagination occurs to compute all the object portion position. Mere scrolling of zooming does not cause any page computation. [quoted text, click to view] > > There is, however, a price to pay: Getting a 10x10 pixel image from > a 1000x1000 pixel buffer can be more expensive than if the buffer > had been just the 10x10 pixels, due to the way the pixels are stored > in memory. One way to see this is to measure the time it takes to > loop through a bitmap byte array (LockBits) horizontally x vertically > vs. vertically x horizontally. If the inner loop goes vertically, it > takes significantly longer than when processing the bytes horizontally > first. > > Another price to pay is higher memory consumption. > > For buffers that do not vary widely in size over their lifetime, I > would use the "recreate when larger" approach. > > For buffers that vary widely in size over their lifetime, you might > consider expanding by a percentage (not necessarily double) > when larger and contract by another percentage when smaller. > This scheme ensures that there is some wiggle room for small > size adjustments and the buffer is only recreated when large > size changes occur. > > So the questions are: > > - How much do the buffers vary in size?
I expect that the user will rarely cause resize. Because usually work keeping the editor always magnified. Those rare times I could just recreate all. [quoted text, click to view] > > - How much memory am I willing to assign to those buffers?
My buffer is as large as the vievable portion of the screen where the user does his editing. could be 1280 x 1024 or smaller. [quoted text, click to view] > > - What is the cost of recreating the buffers? > > - Is it better to pay the price of recreating the buffers if it means > that the application runs at a consistent pace without "stuttering" > when big changes take place (consistent = steady, but slower pace). > In games, this would be the same as keeping the framerate at a > steady low rate at all times in order to accommodate a few scenes > with lots of activity). > > Measure. Measure. Measure. > > /Joergen Bech
Joergen Bech ha scritto: [quoted text, click to view] > The test below indicates that FillRectangle on an existing 1000x1000 > bitmap is three times faster than recreating the bitmap and doing > nothing with it.
Thanks! Very interesting, and instructive Joergen. I did not mean you to make the test :) I meant just checking if I was missing something well know among graphics experts. But anyway, thank you very much for caring. Your test is very interesting (to me) and has some unexpected points. I am noticing the fill rectangle, which to me would not be a natural choice, but I can see it's faster than clear, for big bitmaps. Although for small size it turns out that clear() is again faster ! On my pc I get: 2780 1047 (fill) 1287 (clear) and for size 128px (break even point): 64 61 (fill) 46 (clear) for size 10 as you noticed it's more convenient to recreate the bitma and to use clear (I would add) 20 39 (fill) 28 (clear) [quoted text, click to view] > > Change the loops to 50.000 and the bitmap size to 10x10, the > story is entirely different: FillRectangle takes twice as long as > recreating the rectangle. > > So this quick, unscientific test indicates that small bitmaps favor > recreation and large bitmaps are better off being wiped with > FillRectangle. > > But most importantly: Both are pretty fast and whatever else > you are doing with those bitmaps is likely to render this choice > irrelevant. > > I suggest just getting everything to work. If you find that you need > to speed things up, measure each step and figure out where the time > goes. In the case of my own print engine, I found that most of the > time was spent in the MeasureString function, then the DrawString > method, and way down the list came the rectangles and other > drawing primitives.
That's true. Infact the computation /measurement and redrawing of grids and other complicate objects are terribly expensive. Anyway your test is important to me, because I think that forst of all a 3 times faster graphics generation is not bad, but above all I am concerned about memory usage, corruption and fragmentation. Creating and disposing continuosly a 1024x1280 bitmap should not to be a relief for the ps memory. I think that just wiping it out would make the program much more stable. I could recreate it just on resize. [quoted text, click to view] > > Methinks you are optimizing prematurely if you are worried about > recreate vs. fill.
I just try to establsih once for all the best strategy, so that I do not have to care about it anymore and concentrate on other things :) Very helpful Joergen. Many thanks and if you have more remarks please just let me know, I love them ... -P [quoted text, click to view] > > /Joergen Bech > > ---snip--- > > Option Explicit On > Option Strict On > > Public Class Form1 > > Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As > System.EventArgs) Handles MyBase.Load > Dim swa As New Stopwatch > > '=== Test 1 === > > swa.Start() > > For i As Integer = 1 To 500 > Dim bm As New Bitmap(1000, 1000, > Imaging.PixelFormat.Format32bppPArgb) > bm.Dispose() > Next > > swa.Stop() > Debug.WriteLine(swa.ElapsedMilliseconds.ToString) > > > '=== Test 2 === > > Dim bm2 As New Bitmap(1000, 1000, > Imaging.PixelFormat.Format32bppPArgb) > > swa.Reset() > swa.Start() > > For i As Integer = 1 To 500 > Dim g As Graphics = Graphics.FromImage(bm2) > g.FillRectangle(Brushes.Transparent, 0, 0, bm2.Width, > bm2.Height) > g.Dispose() > Next > > swa.Stop() > Debug.WriteLine(swa.ElapsedMilliseconds.ToString) > > bm2.Dispose() > > End Sub > > End Class
ThunderMusic ha scritto: [quoted text, click to view] > I post the idea just so you can evaluate if you can use it in your case... > your test for FillRectangle vs Clear gave me an idea... Would it be > possible for you to profile what's best fot the user's computer and use the > methods accordingly? I mean, you say, FillRectangle is faster in some case > and clear is faster in some other cases. So at the start of your > application, why don't you run a small test to know which method should be > used and set a flag somewhere in the application that says "Use > FillRectangle" or "Use Clear".... this applies to FillRectangle and Clear, > but could be applied to other things too, like "Do I wipe or recreate?" > > Just an idea... > > I hope it helps
Hello ThunderMusic , thanks for the contribution :) well, I think it is certainly possible and actually easy to implement your idea. In my specific case, having observed that the break even point is low (128px) and since we are talking about an editor, where the user needs a large screen to work, it would not seem (at least at a first superficial examination) useful to take the time. Further, the really time-consuming operations are actually other, such as those related to string (measurement, splitting, computation of object position etc.). In any case if one really needs some really lightning speed, I guess there are other tools other than the gdi+. For my purposes, which are not writing complex 3D games, I experienced that the gdi+ is sufficient. In my application I have even implemented (for charting) a 3D engine with an arcball controller and the animation of even complex poliedra with thousands of faces is smooth and acceptable. And, of course, if Microsoft "hardware-accelerate" it I would ne even more happy :)) ... probably all of us ... -P [quoted text, click to view] > > ThunderMusic > > "pamela fluente" <pamelafluente@libero.it> wrote in message > news:1162330160.989736.223610@e64g2000cwd.googlegroups.com... > > > > Joergen Bech ha scritto: > > > >> The test below indicates that FillRectangle on an existing 1000x1000 > >> bitmap is three times faster than recreating the bitmap and doing > >> nothing with it. > > > > Thanks! Very interesting, and instructive Joergen. > > > > I did not mean you to make the test :) I meant just checking if I was > > missing something well know among graphics experts. But anyway, thank > > you very much for caring. > > > > Your test is very interesting (to me) and has some unexpected points. > > > > I am noticing the fill rectangle, which to me would not be a natural > > choice, but I can see it's faster than clear, for big bitmaps. Although > > for small size it turns out that clear() is again faster ! > > > > On my pc I get: > > 2780 > > 1047 (fill) 1287 (clear) > > > > and for size 128px (break even point): > > > > 64 > > 61 (fill) 46 (clear) > > > > for size 10 as you noticed it's more convenient to recreate the bitma > > and to use clear (I would add) > > > > 20 > > 39 (fill) 28 (clear) > > > > > >> > >> Change the loops to 50.000 and the bitmap size to 10x10, the > >> story is entirely different: FillRectangle takes twice as long as > >> recreating the rectangle. > >> > >> So this quick, unscientific test indicates that small bitmaps favor > >> recreation and large bitmaps are better off being wiped with > >> FillRectangle. > >> > >> But most importantly: Both are pretty fast and whatever else > >> you are doing with those bitmaps is likely to render this choice > >> irrelevant. > > > >> > >> I suggest just getting everything to work. If you find that you need > >> to speed things up, measure each step and figure out where the time > >> goes. In the case of my own print engine, I found that most of the > >> time was spent in the MeasureString function, then the DrawString > >> method, and way down the list came the rectangles and other > >> drawing primitives. > > > > That's true. Infact the computation /measurement and redrawing of > > grids and other complicate objects are terribly expensive. Anyway your > > test is important to me, because I think that forst of all a 3 times > > faster graphics generation is not bad, but above all I am concerned > > about memory usage, corruption and fragmentation. Creating and > > disposing continuosly a 1024x1280 bitmap should not to be a relief for > > the ps memory. I think that just wiping it out would make the program > > much more stable. I could recreate it just on resize. > > > >> > >> Methinks you are optimizing prematurely if you are worried about > >> recreate vs. fill. > > > > I just try to establsih once for all the best strategy, so that I do > > not have to care about it anymore and concentrate on other things :) > > > > Very helpful Joergen. Many thanks and if you have more remarks please > > just let me know, I love them ... > > > > > > -P > > > >> > >> /Joergen Bech > >> > >> ---snip--- > >> > >> Option Explicit On > >> Option Strict On > >> > >> Public Class Form1 > >> > >> Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As > >> System.EventArgs) Handles MyBase.Load > >> Dim swa As New Stopwatch > >> > >> '=== Test 1 === > >> > >> swa.Start() > >> > >> For i As Integer = 1 To 500 > >> Dim bm As New Bitmap(1000, 1000, > >> Imaging.PixelFormat.Format32bppPArgb) > >> bm.Dispose() > >> Next > >> > >> swa.Stop() > >> Debug.WriteLine(swa.ElapsedMilliseconds.ToString) > >> > >> > >> '=== Test 2 === > >> > >> Dim bm2 As New Bitmap(1000, 1000, > >> Imaging.PixelFormat.Format32bppPArgb) > >> > >> swa.Reset() > >> swa.Start() > >> > >> For i As Integer = 1 To 500 > >> Dim g As Graphics = Graphics.FromImage(bm2) > >> g.FillRectangle(Brushes.Transparent, 0, 0, bm2.Width, > >> bm2.Height) > >> g.Dispose() > >> Next > >> > >> swa.Stop() > >> Debug.WriteLine(swa.ElapsedMilliseconds.ToString) > >> > >> bm2.Dispose() > >> > >> End Sub > >> > >> End Class > >
Hi I have a surprising (?) news. I have just changed my animation scheme replacing the bitmap regeneration with the neater bitmap cleaning, as we have been discussing above. To my surprise I observed that Graphics.FillRectangle(Brushes.Transparent, 0, 0, Me.Bitmap.Width, Me.Bitmap.Height) does not clear anything! The new frames get overlayed. If instead I use: Graphics.Clear(Color.Transparent) it works as expected. So it seems the 2 commands behave differently. Actually FillRectangle with a transparent color does not seem to do anything. No wonder Clear is slower ! :) How come is this so ? -P
I post the idea just so you can evaluate if you can use it in your case... your test for FillRectangle vs Clear gave me an idea... Would it be possible for you to profile what's best fot the user's computer and use the methods accordingly? I mean, you say, FillRectangle is faster in some case and clear is faster in some other cases. So at the start of your application, why don't you run a small test to know which method should be used and set a flag somewhere in the application that says "Use FillRectangle" or "Use Clear".... this applies to FillRectangle and Clear, but could be applied to other things too, like "Do I wipe or recreate?" Just an idea... I hope it helps ThunderMusic [quoted text, click to view] "pamela fluente" <pamelafluente@libero.it> wrote in message news:1162330160.989736.223610@e64g2000cwd.googlegroups.com... > > Joergen Bech ha scritto: > >> The test below indicates that FillRectangle on an existing 1000x1000 >> bitmap is three times faster than recreating the bitmap and doing >> nothing with it. > > Thanks! Very interesting, and instructive Joergen. > > I did not mean you to make the test :) I meant just checking if I was > missing something well know among graphics experts. But anyway, thank > you very much for caring. > > Your test is very interesting (to me) and has some unexpected points. > > I am noticing the fill rectangle, which to me would not be a natural > choice, but I can see it's faster than clear, for big bitmaps. Although > for small size it turns out that clear() is again faster ! > > On my pc I get: > 2780 > 1047 (fill) 1287 (clear) > > and for size 128px (break even point): > > 64 > 61 (fill) 46 (clear) > > for size 10 as you noticed it's more convenient to recreate the bitma > and to use clear (I would add) > > 20 > 39 (fill) 28 (clear) > > >> >> Change the loops to 50.000 and the bitmap size to 10x10, the >> story is entirely different: FillRectangle takes twice as long as >> recreating the rectangle. >> >> So this quick, unscientific test indicates that small bitmaps favor >> recreation and large bitmaps are better off being wiped with >> FillRectangle. >> >> But most importantly: Both are pretty fast and whatever else >> you are doing with those bitmaps is likely to render this choice >> irrelevant. > >> >> I suggest just getting everything to work. If you find that you need >> to speed things up, measure each step and figure out where the time >> goes. In the case of my own print engine, I found that most of the >> time was spent in the MeasureString function, then the DrawString >> method, and way down the list came the rectangles and other >> drawing primitives. > > That's true. Infact the computation /measurement and redrawing of > grids and other complicate objects are terribly expensive. Anyway your > test is important to me, because I think that forst of all a 3 times > faster graphics generation is not bad, but above all I am concerned > about memory usage, corruption and fragmentation. Creating and > disposing continuosly a 1024x1280 bitmap should not to be a relief for > the ps memory. I think that just wiping it out would make the program > much more stable. I could recreate it just on resize. > >> >> Methinks you are optimizing prematurely if you are worried about >> recreate vs. fill. > > I just try to establsih once for all the best strategy, so that I do > not have to care about it anymore and concentrate on other things :) > > Very helpful Joergen. Many thanks and if you have more remarks please > just let me know, I love them ... > > > -P > >> >> /Joergen Bech >> >> ---snip--- >> >> Option Explicit On >> Option Strict On >> >> Public Class Form1 >> >> Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As >> System.EventArgs) Handles MyBase.Load >> Dim swa As New Stopwatch >> >> '=== Test 1 === >> >> swa.Start() >> >> For i As Integer = 1 To 500 >> Dim bm As New Bitmap(1000, 1000, >> Imaging.PixelFormat.Format32bppPArgb) >> bm.Dispose() >> Next >> >> swa.Stop() >> Debug.WriteLine(swa.ElapsedMilliseconds.ToString) >> >> >> '=== Test 2 === >> >> Dim bm2 As New Bitmap(1000, 1000, >> Imaging.PixelFormat.Format32bppPArgb) >> >> swa.Reset() >> swa.Start() >> >> For i As Integer = 1 To 500 >> Dim g As Graphics = Graphics.FromImage(bm2) >> g.FillRectangle(Brushes.Transparent, 0, 0, bm2.Width, >> bm2.Height) >> g.Dispose() >> Next >> >> swa.Stop() >> Debug.WriteLine(swa.ElapsedMilliseconds.ToString) >> >> bm2.Dispose() >> >> End Sub >> >> End Class >
Hello Michael C, thanks! I am not sure we are talking about the same thing. I do not feel could do what I am doing by handling the on paint event. I am not designing a custom control. I do not need to repaint continuosly "on paint". I repaint when the user does something like moving an object, scrolling, zooming, and so on. I am working on an editor (imagine something like Word) with a lot of images, text, tables, etc. : I need "persistent" graphics. It is also possible I am missing completely your point. In such a case I need more explanations to understand what you are really proposing. The picture box is used to hold the second buffer. It's convenient and easily refreshed by just : Me.PictureBox1.Image = Me.PictureBox1.Image this seems quite fast to me ... My scheme is A. Initially (editor start) create the bitmap and graphic object assign the bitmap to a picture box B. during editing: -clear the current graphics - create a new image drawing on the graphics containing the current view of the page (the graphics is never filled with color: I always draw on a transparent surface) - "refresh" the view by the above command ( Me.PictureBox1.Image = Me.PictureBox1.Image). This has exactly the same effect of double buffering, with the advantage that I do not have to handle the additional buffer (note: I never user the refresh command of picture box nor any invalidate: that's a suicidal) C. On exit dispose all This seems to work quite well and smoothly so far. Let me know if you see improvements. -P Michael C ha scritto: [quoted text, click to view] > "pamela fluente" <pamelafluente@libero.it> wrote in message > news:1162337306.951235.288740@b28g2000cwb.googlegroups.com... > > Hello ThunderMusic , > > > > thanks for the contribution :) > > Hang on a sec. I think this conversation is going down the wrong path > because you asked the wrong question to start with and everyone has been > trying to answer that question. (It's always important to make sure you're > solving the right problem :-). I don't think you need a bitmap at all, just > turn on double buffering and draw straight to the screen. You could draw > straight to the form, to a panel or create your own usercontrol. Probably > the last thing you'd use is a picturebox. :-) Do all your drawing in OnPaint > of whatever you are painting to. If you need to trigger frames for an > animation then call this.refresh (this being the control being painted to). > > Michael
On 31 Oct 2006 06:18:01 -0800, "pamela fluente" [quoted text, click to view] <pamelafluente@libero.it> wrote: > >In a fast animation done by repeatedly displaying >a bitmap on a picture box ... > > what is better: > > 1. to recreate, each time, the bitmap and graphics object >(disposing the previous ones) >or > 2. to "clean up" the existing bitmap and redraw on it ? > > And, in case what is the faster way to clean the bitmap up. (I am >wondering whether the > filling done by a clear is more time consuming than just recreating >the bitmap.)
Think about it: A new bitmap would automatically be filled with 0's (black) so if you need a different background color, you would be filling it anyway. So by recreating it you would have the additional overhead of - well - recreating it. Won't save you anything. [quoted text, click to view] >Further, I guess that if the picture box gets resized I have no choice >but to recreate the bitmap. Right? or is there a better way ?
Yes, in this case it should be recreated. Of course, if we are talking about a buffer (which I presume is the case), you could just recreate it whenever the new size is larger (on either axis) than the existing buffer, then use a subsection of the buffer if the size gets smaller. There is, however, a price to pay: Getting a 10x10 pixel image from a 1000x1000 pixel buffer can be more expensive than if the buffer had been just the 10x10 pixels, due to the way the pixels are stored in memory. One way to see this is to measure the time it takes to loop through a bitmap byte array (LockBits) horizontally x vertically vs. vertically x horizontally. If the inner loop goes vertically, it takes significantly longer than when processing the bytes horizontally first. Another price to pay is higher memory consumption. For buffers that do not vary widely in size over their lifetime, I would use the "recreate when larger" approach. For buffers that vary widely in size over their lifetime, you might consider expanding by a percentage (not necessarily double) when larger and contract by another percentage when smaller. This scheme ensures that there is some wiggle room for small size adjustments and the buffer is only recreated when large size changes occur. So the questions are: - How much do the buffers vary in size? - How much memory am I willing to assign to those buffers? - What is the cost of recreating the buffers? - Is it better to pay the price of recreating the buffers if it means that the application runs at a consistent pace without "stuttering" when big changes take place (consistent = steady, but slower pace). In games, this would be the same as keeping the framerate at a steady low rate at all times in order to accommodate a few scenes with lots of activity). Measure. Measure. Measure. /Joergen Bech
[quoted text, click to view] > The new bitmap has always a trasparent background (as far I can >"see"), which is > just what I need. Infact I always draw on a trasparent bitmap. > When I show the bitmap in the picture box the user sees images and >text > on "white" pages, because the background of the control where is the >picture box where I load > the bitmap is white. So I never need actually any "clear" in the sense >of "fill with a color". > > If there was a fast clear which turned all to a transparent bitmap it >would be perfectly > fine for me. Is there ? I could not find it around.
The test below indicates that FillRectangle on an existing 1000x1000 bitmap is three times faster than recreating the bitmap and doing nothing with it. Change the loops to 50.000 and the bitmap size to 10x10, the story is entirely different: FillRectangle takes twice as long as recreating the rectangle. So this quick, unscientific test indicates that small bitmaps favor recreation and large bitmaps are better off being wiped with FillRectangle. But most importantly: Both are pretty fast and whatever else you are doing with those bitmaps is likely to render this choice irrelevant. I suggest just getting everything to work. If you find that you need to speed things up, measure each step and figure out where the time goes. In the case of my own print engine, I found that most of the time was spent in the MeasureString function, then the DrawString method, and way down the list came the rectangles and other drawing primitives. Methinks you are optimizing prematurely if you are worried about recreate vs. fill. /Joergen Bech ---snip--- Option Explicit On Option Strict On Public Class Form1 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim swa As New Stopwatch '=== Test 1 === swa.Start() For i As Integer = 1 To 500 Dim bm As New Bitmap(1000, 1000, Imaging.PixelFormat.Format32bppPArgb) bm.Dispose() Next swa.Stop() Debug.WriteLine(swa.ElapsedMilliseconds.ToString) '=== Test 2 === Dim bm2 As New Bitmap(1000, 1000, Imaging.PixelFormat.Format32bppPArgb) swa.Reset() swa.Start() For i As Integer = 1 To 500 Dim g As Graphics = Graphics.FromImage(bm2) g.FillRectangle(Brushes.Transparent, 0, 0, bm2.Width, bm2.Height) g.Dispose() Next swa.Stop() Debug.WriteLine(swa.ElapsedMilliseconds.ToString) bm2.Dispose() End Sub End Class
[quoted text, click to view] "pamela fluente" <pamelafluente@libero.it> wrote in message news:1162337306.951235.288740@b28g2000cwb.googlegroups.com... > Hello ThunderMusic , > > thanks for the contribution :)
Hang on a sec. I think this conversation is going down the wrong path because you asked the wrong question to start with and everyone has been trying to answer that question. (It's always important to make sure you're solving the right problem :-). I don't think you need a bitmap at all, just turn on double buffering and draw straight to the screen. You could draw straight to the form, to a panel or create your own usercontrol. Probably the last thing you'd use is a picturebox. :-) Do all your drawing in OnPaint of whatever you are painting to. If you need to trigger frames for an animation then call this.refresh (this being the control being painted to). Michael
[quoted text, click to view] "pamela fluente" <pamelafluente@libero.it> wrote in message news:1162340831.280560.166080@b28g2000cwb.googlegroups.com... > Hi > > I have a surprising (?) news.
Not really, it makes perfect sense. If you are drawing a partially transparent color to a surface then you want that color to be mixed with the surface color, not to replace it. The ratio in which it mixes is the transparancy, if it is 255 then all of the color will be written, if it's 128 then 50%, if 0 then there will be no change. [quoted text, click to view] > If instead I > use: > > Graphics.Clear(Color.Transparent)
Makes sense. [quoted text, click to view] > it works as expected. So it seems the 2 commands behave differently. > Actually FillRectangle with a transparent color does not seem to do > anything. No wonder Clear is slower ! :)
That doesn't make sense. Fill rectangle should be slower because it needs to combine 2 colors, clear just needs to do a replace. Michael
On Wed, 1 Nov 2006 11:59:28 +1100, "Michael C" <nospam@nospam.com> [quoted text, click to view] wrote: >"pamela fluente" <pamelafluente@libero.it> wrote in message >news:1162340831.280560.166080@b28g2000cwb.googlegroups.com... >> Hi >> >> I have a surprising (?) news. > >Not really, it makes perfect sense. If you are drawing a partially >transparent color to a surface then you want that color to be mixed with the >surface color, not to replace it. The ratio in which it mixes is the >transparancy, if it is 255 then all of the color will be written, if it's >128 then 50%, if 0 then there will be no change.
Now I'm embarrassed, but that's ok: If I was afraid to make mistakes, I would never post anything :) Thanks for pointing out that oversight. Sometimes (all the time) the most important thing is to get the discussion rolling so we all can learn from it. Replacing FillRectangle with Clear, I get 50.000 x 10x10: - Recreate = 2663 - Clear = 4087 (Fill = 5822) 500 x 1000x1000: - Recreate = 7002 - Clear = 5109 (Fill = 2473) At least the results are consistent with my first "findings", relatively speaking. [quoted text, click to view] >> If instead I >> use: >> >> Graphics.Clear(Color.Transparent) > >Makes sense. > >> it works as expected. So it seems the 2 commands behave differently. >> Actually FillRectangle with a transparent color does not seem to do >> anything. No wonder Clear is slower ! :) > >That doesn't make sense. Fill rectangle should be slower because it needs to >combine 2 colors, clear just needs to do a replace.
Under the covers, FillRectangle (eventually) calls GdipFillRectangleI(ByVal graphics As HandleRef, ByVal brush As HandleRef, ByVal x As Integer, ByVal y As Integer, ByVal width As Integer, ByVal height As Integer) and Clear calls GdipGraphicsClear(ByVal graphics As HandleRef, ByVal argb As Integer) Now it makes perfect sense that the *overhead* of calling FillRectangle the way I did it in the first test affects the results a bit. Another oversight on my part. If we do not pass the constant Brushes.Transparent (my worst mistake) but use a variable instead, things look slightly better: ---snip--- '=== Test 2 === Dim bm2 As New Bitmap(10, 10, Imaging.PixelFormat.Format32bppPArgb) swa.Reset() swa.Start() Dim b As New SolidBrush(Color.Transparent) Dim c As Color = Color.Transparent Dim w As Integer = bm2.Width Dim h As Integer = bm2.Height For i As Integer = 1 To 50000 Dim g As Graphics = Graphics.FromImage(bm2) g.FillRectangle(b, 0, 0, w, h) 'g.Clear(c) g.Dispose() Next b.Dispose() swa.Stop() Debug.WriteLine(swa.ElapsedMilliseconds.ToString) bm2.Dispose() ---snip--- The results are now 50.000 x 10x10: - Recreate = 2664 - Clear = 4125 (Fill = 4195) So Clear was not affected by substituting a variable. I presume this is because Color is a value type and the compiler just substituted it with the argb value in both cases, but in the case of the brush, 4195 vs 5822 before is quite a speed improvement. As for Fill being faster than Clear on large bitmaps. Who knows? GDI+ is supposedly not hardware-accelerated, but perhaps some pieces here and there are? Anyone who can shed some light on this? /Joergen Bech
Joergen Bech ha scritto: [quoted text, click to view] > Now I'm embarrassed, but that's ok: If I was afraid to make > mistakes, I would never post anything :)
you should not. Sometime the difeerence between being wrong or being right is very subtle :)) Take a look here: :) size 1500px g.CompositingMode = Drawing2D.CompositingMode.SourceOver g.FillRectangle(Brushes.Transparent, 0, 0, bm2.Width, bm2.Height) g.CompositingMode = Drawing2D.CompositingMode.SourceCopy 'g.Clear(Color.Transparent) Millisecs: 6077 dispose 2291 clean (fill with Drawing2D.CompositingMode.SourceCopy) 'g.CompositingMode = Drawing2D.CompositingMode.SourceOver 'g.FillRectangle(Brushes.Transparent, 0, 0, bm2.Width, bm2.Height) 'g.CompositingMode = Drawing2D.CompositingMode.SourceCopy g.Clear(Color.Transparent) Millisecs: 6112 dispose 2930 clean (clear) the 2 above are "functionally" equivalent. -P [quoted text, click to view] > /Joergen Bech
oops I meant ... g.CompositingMode = Drawing2D.CompositingMode.SourceCopy g.FillRectangle(Brushes.Transparent, 0, 0, bm2.Width, bm2.Height) g.CompositingMode = Drawing2D.CompositingMode.SourceOver :)) -P [quoted text, click to view] > > g.CompositingMode = Drawing2D.CompositingMode.SourceOver > g.FillRectangle(Brushes.Transparent, 0, 0, bm2.Width, > bm2.Height) > g.CompositingMode = Drawing2D.CompositingMode.SourceCopy > > 'g.Clear(Color.Transparent) > > Millisecs: > 6077 dispose > 2291 clean (fill with Drawing2D.CompositingMode.SourceCopy) > > > 'g.CompositingMode = Drawing2D.CompositingMode.SourceOver > 'g.FillRectangle(Brushes.Transparent, 0, 0, bm2.Width, > bm2.Height) > 'g.CompositingMode = Drawing2D.CompositingMode.SourceCopy > > g.Clear(Color.Transparent) > > Millisecs: > 6112 dispose > 2930 clean (clear) > > > > the 2 above are "functionally" equivalent. > > -P > > > /Joergen Bech
ok. So the conclusion is that Fill with SourceCopy works as required and is still faster than Clear, except for very small bitmaps where the overhead takes up a greater portion of the time, but in real terms this is irrelevant. Case closed, I suppose. Always Fill (not clear or recreate). /Joergen Bech On 1 Nov 2006 02:37:32 -0800, "pamela fluente" [quoted text, click to view] <pamelafluente@libero.it> wrote: >oops I meant ... > > g.CompositingMode = Drawing2D.CompositingMode.SourceCopy > g.FillRectangle(Brushes.Transparent, 0, 0, bm2.Width, >bm2.Height) > g.CompositingMode = Drawing2D.CompositingMode.SourceOver > >:)) > > >-P >> >> g.CompositingMode = Drawing2D.CompositingMode.SourceOver >> g.FillRectangle(Brushes.Transparent, 0, 0, bm2.Width, >> bm2.Height) >> g.CompositingMode = Drawing2D.CompositingMode.SourceCopy >> >> 'g.Clear(Color.Transparent) >> >> Millisecs: >> 6077 dispose >> 2291 clean (fill with Drawing2D.CompositingMode.SourceCopy) >> >> >> 'g.CompositingMode = Drawing2D.CompositingMode.SourceOver >> 'g.FillRectangle(Brushes.Transparent, 0, 0, bm2.Width, >> bm2.Height) >> 'g.CompositingMode = Drawing2D.CompositingMode.SourceCopy >> >> g.Clear(Color.Transparent) >> >> Millisecs: >> 6112 dispose >> 2930 clean (clear) >> >> >> >> the 2 above are "functionally" equivalent. >> >> -P >> >> > /Joergen Bech
Evidence suggests that re-using and clearing a bitmap is the best option. This is the result of a test run I wrote to create and destroy a number of bitmaps as opposed to creating one bitmap and clearing it. Creating 100 bitmaps... Total time taken=0 minutes, 0 seconds, 812 milliseconds Creating a bitmap once and wiping it 100 times... Total time taken=0 minutes, 0 seconds, 390 milliseconds In all cases the Graphics object was disposed of between draw cycles to ensure maximum authenticity with the real case. Interestingly, keeping the Graphics object around between draw cycles only removed 20 milliseconds from the total so the creation and disposal of a Graphics object attached to a bitmap is reasonably negligable. The code is after my signature for your perusal... -- Bob Powell [MVP] Visual C#, System.Drawing Ramuseco Limited .NET consulting http://www.ramuseco.com Find great Windows Forms articles in Windows Forms Tips and Tricks http://www.bobpowell.net/tipstricks.htm Answer those GDI+ questions with the GDI+ FAQ http://www.bobpowell.net/faqmain.htm All new articles provide code in C# and VB.NET. Subscribe to the RSS feeds provided and never miss a new article. ----------------------------------------------------------------- const int loops=100; StringBuilder sb=new StringBuilder(); sb.Append(string.Format("Creating {0} bitmaps...\r\n",loops)); DateTime dt=DateTime.Now; for (int i = 0; i < loops; i++) { Bitmap bm = new Bitmap(1024, 768, PixelFormat.Format32bppPArgb); Graphics g = Graphics.FromImage(bm); g.FillRectangle(Brushes.Black, 10, 10, 1004, 748); g.Dispose(); bm.Dispose(); } TimeSpan ts = DateTime.Now - dt; sb.Append(string.Format("Total time taken={0} minutes, {1} seconds, {2} milliseconds\r\n", ts.Minutes, ts.Seconds - 60 * ts.Minutes, ts.Milliseconds - ((60000 * ts.Minutes) + (1000 * ts.Seconds)))); sb.Append(string.Format("Creating a bitmap once and wiping it {0} times...\r\n", loops)); dt = DateTime.Now; Bitmap bm1 = new Bitmap(1024, 678, PixelFormat.Format32bppPArgb); for (int i = 0; i < loops; i++) { Graphics g1 = Graphics.FromImage(bm1); g1.FillRectangle(Brushes.Black, 10, 10, 1004, 748); g1.Clear(Color.White); g1.Dispose(); } ts = DateTime.Now - dt; sb.Append(string.Format("Total time taken={0} minutes, {1} seconds, {2} milliseconds\r\n", ts.Minutes, ts.Seconds - 60 * ts.Minutes, ts.Milliseconds - ((60000 * ts.Minutes) + (1000 * ts.Seconds)))); this.textBox1.Text = sb.ToString(); [quoted text, click to view] "pamela fluente" <pamelafluente@libero.it> wrote in message news:1162304281.401244.153630@e64g2000cwd.googlegroups.com... > > In a fast animation done by repeatedly displaying > a bitmap on a picture box ... > > what is better: > > 1. to recreate, each time, the bitmap and graphics object > (disposing the previous ones) > or > 2. to "clean up" the existing bitmap and redraw on it ? > > And, in case what is the faster way to clean the bitmap up. (I am > wondering whether the > filling done by a clear is more time consuming than just recreating > the bitmap.) > > Further, I guess that if the picture box gets resized I have no choice > but to recreate the bitmap. Right? or is there a better way ? > > -P >
Bob Powell [MVP] ha scritto: [quoted text, click to view] > Evidence suggests that re-using and clearing a bitmap is the best option. > > This is the result of a test run I wrote to create and destroy a number of > bitmaps as opposed to creating one bitmap and clearing it. > > Creating 100 bitmaps... > Total time taken=0 minutes, 0 seconds, 812 milliseconds > Creating a bitmap once and wiping it 100 times... > Total time taken=0 minutes, 0 seconds, 390 milliseconds > > In all cases the Graphics object was disposed of between draw cycles to > ensure maximum authenticity with the real case. > > Interestingly, keeping the Graphics object around between draw cycles only > removed 20 milliseconds from the total so the creation and disposal of a > Graphics object attached to a bitmap is reasonably negligable.
Thanks. Bob. That's actually interesting and good to know. Ciao :) , P [quoted text, click to view] > > The code is after my signature for your perusal... > > -- > Bob Powell [MVP] > Visual C#, System.Drawing > > Ramuseco Limited .NET consulting > http://www.ramuseco.com > > Find great Windows Forms articles in Windows Forms Tips and Tricks > http://www.bobpowell.net/tipstricks.htm > > Answer those GDI+ questions with the GDI+ FAQ > http://www.bobpowell.net/faqmain.htm > > All new articles provide code in C# and VB.NET. > Subscribe to the RSS feeds provided and never miss a new article. > ----------------------------------------------------------------- > > const int loops=100; > > StringBuilder sb=new StringBuilder(); > > sb.Append(string.Format("Creating {0} bitmaps...\r\n",loops)); > > DateTime dt=DateTime.Now; > > for (int i = 0; i < loops; i++) > > { > > Bitmap bm = new Bitmap(1024, 768, PixelFormat.Format32bppPArgb); > > Graphics g = Graphics.FromImage(bm); > > g.FillRectangle(Brushes.Black, 10, 10, 1004, 748); > > g.Dispose(); > > bm.Dispose(); > > } > > TimeSpan ts = DateTime.Now - dt; > > sb.Append(string.Format("Total time taken={0} minutes, {1} seconds, {2} > milliseconds\r\n", ts.Minutes, ts.Seconds - 60 * ts.Minutes, > ts.Milliseconds - ((60000 * ts.Minutes) + (1000 * ts.Seconds)))); > > sb.Append(string.Format("Creating a bitmap once and wiping it {0} > times...\r\n", loops)); > > dt = DateTime.Now; > > Bitmap bm1 = new Bitmap(1024, 678, PixelFormat.Format32bppPArgb); > > for (int i = 0; i < loops; i++) > > { > > Graphics g1 = Graphics.FromImage(bm1); > > g1.FillRectangle(Brushes.Black, 10, 10, 1004, 748); > > g1.Clear(Color.White); > > g1.Dispose(); > > } > > ts = DateTime.Now - dt; > > sb.Append(string.Format("Total time taken={0} minutes, {1} seconds, {2} > milliseconds\r\n", ts.Minutes, ts.Seconds - 60 * ts.Minutes, > ts.Milliseconds - ((60000 * ts.Minutes) + (1000 * ts.Seconds)))); > > this.textBox1.Text = sb.ToString(); > > > > "pamela fluente" <pamelafluente@libero.it> wrote in message > news:1162304281.401244.153630@e64g2000cwd.googlegroups.com... > > > > In a fast animation done by repeatedly displaying > > a bitmap on a picture box ... > > > > what is better: > > > > 1. to recreate, each time, the bitmap and graphics object > > (disposing the previous ones) > > or > > 2. to "clean up" the existing bitmap and redraw on it ? > > > > And, in case what is the faster way to clean the bitmap up. (I am > > wondering whether the > > filling done by a clear is more time consuming than just recreating > > the bitmap.) > > > > Further, I guess that if the picture box gets resized I have no choice > > but to recreate the bitmap. Right? or is there a better way ? > > > > -P > >
On 2 Nov 2006 07:15:13 -0800, "pamela fluente" [quoted text, click to view] <pamelafluente@libero.it> wrote: > >Bob Powell [MVP] ha scritto: > >> Interestingly, keeping the Graphics object around between draw cycles only >> removed 20 milliseconds from the total so the creation and disposal of a >> Graphics object attached to a bitmap is reasonably negligable. > > Thanks. Bob. That's actually interesting and good to know. > >Ciao :) , > >P
On my machine, I can create and dispose a Graphics object 20,000 times per second, i.e. For i As Integer = 1 To 20000 g = Graphics.FromImage(bm) g.Dispose() Next i Importantly, the size of the bitmap does not matter, nor does it seem to affect the number handle count of the process. Little effect on memory, even if the Dispose line in the sample above is removed. Multiple Graphics objects can reference the same image at the same time. Nothing to think about here. Just keep the code clean. /JB
Me.Picturebox1.Invalidate is probably faster. -- Bob Powell [MVP] Visual C#, System.Drawing Ramuseco Limited .NET consulting http://www.ramuseco.com Find great Windows Forms articles in Windows Forms Tips and Tricks http://www.bobpowell.net/tipstricks.htm Answer those GDI+ questions with the GDI+ FAQ http://www.bobpowell.net/faqmain.htm All new articles provide code in C# and VB.NET. Subscribe to the RSS feeds provided and never miss a new article. [quoted text, click to view] "pamela fluente" <pamelafluente@libero.it> wrote in message news:1162343467.133908.319280@b28g2000cwb.googlegroups.com... > Hello Michael C, thanks! > > I am not sure we are talking about the same thing. I do not feel could > do what I am doing by handling the on paint event. I am not designing a > custom control. I do not need to repaint continuosly "on paint". I > repaint when the user does something like moving an object, scrolling, > zooming, and so on. I am working on an editor (imagine something like > Word) with a lot of images, text, tables, etc. : I need "persistent" > graphics. > > It is also possible I am missing completely your point. In such a case > I need more explanations to understand what you are really proposing. > > The picture box is used to hold the second buffer. It's convenient and > easily refreshed by just : > Me.PictureBox1.Image = Me.PictureBox1.Image > > this seems quite fast to me ... > > > > My scheme is > > A. Initially (editor start) create the bitmap and graphic > object assign the bitmap to > a picture box > > B. during editing: > -clear the current graphics > - create a new image drawing on the graphics containing > the current view of the > page (the graphics is never filled with color: I > always draw on a transparent surface) > - "refresh" the view by the above command ( > Me.PictureBox1.Image = Me.PictureBox1.Image). This has exactly the same > effect of double buffering, with the advantage that I do not have to > handle the additional buffer (note: I never user the refresh command of > picture box nor any invalidate: that's a suicidal) > > C. On exit dispose all > > This seems to work quite well and smoothly so far. Let me know if you > see improvements. > > -P > > Michael C ha scritto: > >> "pamela fluente" <pamelafluente@libero.it> wrote in message >> news:1162337306.951235.288740@b28g2000cwb.googlegroups.com... >> > Hello ThunderMusic , >> > >> > thanks for the contribution :) >> >> Hang on a sec. I think this conversation is going down the wrong path >> because you asked the wrong question to start with and everyone has been >> trying to answer that question. (It's always important to make sure >> you're >> solving the right problem :-). I don't think you need a bitmap at all, >> just >> turn on double buffering and draw straight to the screen. You could draw >> straight to the form, to a panel or create your own usercontrol. Probably >> the last thing you'd use is a picturebox. :-) Do all your drawing in >> OnPaint >> of whatever you are painting to. If you need to trigger frames for an >> animation then call this.refresh (this being the control being painted >> to). >> >> Michael >
Don't see what you're looking for? Try a search.
|