zoom and scroll is slow

Hi,

I've run into a speed problem when I zoom in on an image. I use PIL to load an image and convert it to wxImage to display in wx. The problem is, it gets very slow when the zoom factor gets to 3 zoom steps and above (I double the image size with each zoom step). I'm using wxScrolledWindow to manage the scroll bars and everything works well except for the speed.

To zoom in, a PIL function resizes the image, which is then converted to wxImage in OnPaint(). After 3 zoom steps the image size is 4K x 4K and things get very slow, especially during scrolling.

Couple of options I've considered is to not scale the PIL image but only the wxImage or to redraw only a viewport area that is currently being displayed, neither of which I know how to do.

What is the best way to zoom and scroll to make it more responsive?

Bob

Bob Klimek wrote:

The problem is, it
gets very slow when the zoom factor gets to 3 zoom steps and above (I
double the image size with each zoom step). I'm using wxScrolledWindow to
manage the scroll bars and everything works well except for the speed.

Is the re-sizing step slow, or the scrolling?

Couple of options I've considered is to not scale the PIL image but only
the wxImage

If it's the scrolling that is slow, that will make no difference. I've
tried using a really large bitmap and scroll it with a wxScrolledWindow,
and it is nice and speedy until the bitmap gets too big.

If the scaling step is slow, you'd have to do some tests to see whether
scaling is faster with PIL or wx. In general, the image manipulation
routines in PIL produce better quality, so I'd be inclined to keep with
PIL option.

or to redraw only a viewport area that is currently being
displayed,

That's what I'd do, it should speed up both the scaling, but it might
make the scrolling slower, as you'd have to re-do the whole process with
each scroll action. At this point, you may want to use a differnt way to
zoom and scroll around, rather than using the standard scroll bar
method. I've implimented what I am thinking of in my FloatCanvas. I'm
working with draw images, but the principle is the same: you can draw a
rubber band box to select and area to zoom into, and you can move the
image by grabbing it with the mouse and dragging it. That way you only
re-draw once per zoom or move action.

Let me know if you want a copy of my code to check out an borrow from.

With either method, it should be some pretty simple math to figure out
what part of the original image you want to see. You can then extract
that part from your PIL image with the image.crop() method. You can then
either scale the result in PIL, or put it into a wxImage and scale it
there.

I'd like to here how this turns out.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                        
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Bob Klimek wrote:

To zoom in, a PIL function resizes the image, which is then converted to wxImage in OnPaint().

I'm sure this is entirely obvious, but you're caching the result of this conversion, aren't you? This stakes a while for me to generate the zoomed in image (due to low memory, mostly), but scrolling is fast.

Robb

No, I'm not doing any caching right now, but this is a good idea. Perhaps
should have been obvious.

Thanks for the idea,
Bob

···

On Monday January 6 2003 9:25 pm, Robb Shecter wrote:

Bob Klimek wrote:
> To zoom in, a PIL function resizes the image, which is then converted
> to wxImage in OnPaint().

I'm sure this is entirely obvious, but you're caching the result of this
conversion, aren't you? This stakes a while for me to generate the
zoomed in image (due to low memory, mostly), but scrolling is fast.

Bob Klimek wrote:
> The problem is, it
> gets very slow when the zoom factor gets to 3 zoom steps and above (I
> double the image size with each zoom step). I'm using wxScrolledWindow to
> manage the scroll bars and everything works well except for the speed.

Is the re-sizing step slow, or the scrolling?

Both are slow. I can understand the resizing step but for the scrolling I
would expect wxScrollWindow to handle it smoothly. Robb Shecter suggested
caching the image, which I need to look into. I would think that
wxScrollWindow should cache the image internally.

> Couple of options I've considered is to not scale the PIL image but only
> the wxImage

If it's the scrolling that is slow, that will make no difference. I've
tried using a really large bitmap and scroll it with a wxScrolledWindow,
and it is nice and speedy until the bitmap gets too big.

If the scaling step is slow, you'd have to do some tests to see whether
scaling is faster with PIL or wx. In general, the image manipulation
routines in PIL produce better quality, so I'd be inclined to keep with
PIL option.

> or to redraw only a viewport area that is currently being
> displayed,

That's what I'd do, it should speed up both the scaling, but it might
make the scrolling slower, as you'd have to re-do the whole process with
each scroll action. At this point, you may want to use a differnt way to
zoom and scroll around, rather than using the standard scroll bar
method. I've implimented what I am thinking of in my FloatCanvas. I'm
working with draw images, but the principle is the same: you can draw a
rubber band box to select and area to zoom into, and you can move the
image by grabbing it with the mouse and dragging it. That way you only
re-draw once per zoom or move action.

Let me know if you want a copy of my code to check out an borrow from.

With either method, it should be some pretty simple math to figure out
what part of the original image you want to see. You can then extract
that part from your PIL image with the image.crop() method. You can then
either scale the result in PIL, or put it into a wxImage and scale it
there.

This method is a possibility but I would prefer to do it the more traditional
way with scroll bars. For one thing, I already use rubberbanding boxes to
specify areas-of-interest and it might be confusing to use one for zooming as
well.

I'd like to here how this turns out.

Sure, I'll post it when I get something satisfactory. Thanks for your
suggestions.

Bob

···

On Monday January 6 2003 9:07 pm, Chris Barker wrote:

Robert Klimek wrote:

No, I'm not doing any caching right now, but this is a good idea. Perhaps should have been obvious.

I guess it depends what we're talking about; I'm doing what you are, but I have any code in an onpaint.

I just stick a static bitmap in a scrolled window, and let it do its thing...

···

Hi all,

When I create a wxfiledialog, I get the following error:

[Debug] 11:21:13 AM: Mailcap file /etc/mailcap, line 195: unknown field
'/usr/bin/wvHtml "${ns}" -o $
{tmp}' for the MIME type 'application/msword' ignored.
[Debug] 11:21:13 AM: Mailcap file /etc/mailcap, line 196: unknown field
'netscape "file:${tmp}"' for
the MIME type 'application/msword' ignored.
[Debug] 11:21:13 AM: Mailcap file /etc/mailcap, line 196: unknown field
'/bin/rm -f "${tmp}"' for the
MIME type 'application/msword' ignored.

It all seems to work fine otherwise.

What the heck is going on?

Python 2.1 or 2.2 with wxPython (GTK) 2.3.3.1
Redhat Linux 7.2

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                        
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Bob Klimek wrote:

Hi,

I've run into a speed problem when I zoom in on an image. I use PIL to load an image and convert it to wxImage to display in wx. The problem is, it gets very slow when the zoom factor gets to 3 zoom steps and above (I double the image size with each zoom step). I'm using wxScrolledWindow to manage the scroll bars and everything works well except for the speed.

To zoom in, a PIL function resizes the image, which is then converted to wxImage in OnPaint(). After 3 zoom steps the image size is 4K x 4K and things get very slow, especially during scrolling.

Couple of options I've considered is to not scale the PIL image but only the wxImage or to redraw only a viewport area that is currently being displayed, neither of which I know how to do.

What is the best way to zoom and scroll to make it more responsive?

In addition to the other suggestions, let me add these:

1. You should not be doing image scaling, conversion, etc in your EVT_PAINT. EVT_PAINT should only Blit the visible portion of the image and return.

2. A further optimization is to only Blit those regions of the visible portion of the window that need updating, you can use the wxPaintDC.GetUpdateRegion() method to find out what they are. See demo/ColourDB.py for a simplistic example of using the update region. This will also help scrolling since only the parts of the image "uncovered" by the scroll need repainting.

3. Do the scaling, PIL conversion, and etc. only once and save the results until you zoom again.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Robert Klimek wrote:

Both are slow. I can understand the resizing step but for the scrolling I would expect wxScrollWindow to handle it smoothly. Robb Shecter suggested caching the image, which I need to look into. I would think that wxScrollWindow should cache the image internally.

wxScrolledWindow just handles managing the scrollbars, a viewport and etc. WHat gets drawn and how is totally up to you.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Chris Barker wrote:

Hi all,

When I create a wxfiledialog, I get the following error:

[Debug] 11:21:13 AM: Mailcap file /etc/mailcap, line 195: unknown field
'/usr/bin/wvHtml "${ns}" -o $
{tmp}' for the MIME type 'application/msword' ignored.
[Debug] 11:21:13 AM: Mailcap file /etc/mailcap, line 196: unknown field
'netscape "file:${tmp}"' for
the MIME type 'application/msword' ignored.
[Debug] 11:21:13 AM: Mailcap file /etc/mailcap, line 196: unknown field
'/bin/rm -f "${tmp}"' for the
MIME type 'application/msword' ignored.

It all seems to work fine otherwise.

What the heck is going on?

Since wxPython is built with the runtime diagnositcs turned on, you are kjust getting some (annoying) debug log messages. 2.4.0 will let you turn these off with wxLog_SetLogLevel.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Robin Dunn wrote:

Chris Barker wrote:
> When I create a wxfiledialog, I get the following error:
>
> [Debug] 11:21:13 AM: Mailcap file /etc/mailcap, line 195: unknown field
> '/usr/bin/wvHtml "${ns}" -o $

Since wxPython is built with the runtime diagnositcs turned on, you are
kjust getting some (annoying) debug log messages. 2.4.0 will let you
turn these off with wxLog_SetLogLevel.

That's a nice feature. In the meantime, why is it looking at my Mailcap
file, and is there any way to turn it off? (Or fix whatever is wierd in
my mailcap file, I suppose)

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                        
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Chris Barker wrote:

Robin Dunn wrote:

Chris Barker wrote:

When I create a wxfiledialog, I get the following error:

[Debug] 11:21:13 AM: Mailcap file /etc/mailcap, line 195: unknown field
'/usr/bin/wvHtml "${ns}" -o $

Since wxPython is built with the runtime diagnositcs turned on, you are
kjust getting some (annoying) debug log messages. 2.4.0 will let you
turn these off with wxLog_SetLogLevel.

That's a nice feature. In the meantime, why is it looking at my Mailcap
file, and is there any way to turn it off?

I think it is looking there (and a couple other places IIRC,) in order to get icons for the various file types it is going to display. You probably get similar messages if you run the wxMimeTypesManager sample in the demo, right?

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Thanks for the suggestions. So far I've come half way in getting a decent zoom and scroll. I've taken Robb Shecter's suggestion of scaling and converting wxImage to a bitmap when I do the zooming and then in OnPaint() I just call "dc.DrawBitmap(self.bitmap, 0,0)". I'd imagine that DrawBitmap calls Blit internally.

That makes for a quick and responsive scrolling (so if I understand your suggestions correctly, 1 and 2 are taken care of, since they pertained to scrolling only).

But the zooming is still slow since wxPython (or PIL) still has to scale the image. After clicking the zoom button 3 times, the image size goes from 512x512 to 4096x4096. The last zoom step takes about 2 seconds. However, clicking the zoom one more time hangs the program for about 20 seconds and then prints the following traceback:

My system: (Python2.2.2, wxPython2.3.4.2, Win2000).

Did the image get too big? Is this a bug in wxPython? The code that produced it is below.

Bob

1024 1024
2048 2048
4096 4096
8192 8192
Traceback (most recent call last):
   File "SpotlightMain.py", line 255, in OnZoomIn
     self.iPanel.Zoom(2.0)
   File "SpotlightMain.py", line 91, in Zoom
     self.display2()
   File "SpotlightMain.py", line 98, in display2
     dc.DrawBitmap(self.bitmap, 0,0)
   File "D:\Python22\lib\site-packages\wxPython\gdi.py", line 784, in DrawBitmap
     val = apply(gdic.wxDC_DrawBitmap,(self,) + _args, _kwargs)
wxPython.wxc.wxPyAssertionError: C++ assertion "wxAssertFailure" failed in e:\pr
ojects\wx\src\msw\dc.cpp(907): invalid bitmap in wxDC::DrawBitmap

NOTE: The parameter "scale" is 2.0 when zooming in.

     def Zoom(self, scale):
         h = self.image.GetHeight()
         w = self.image.GetWidth()
         newWidth = int(round(float(w) * scale))
         newHeight = int(round(float(h) * scale))
         print newWidth, newHeight

         self.image.Rescale(newWidth, newHeight)
         #self.manageScrollbars(newWidth, newHeight, scale)
         self.SetScrollbars(10, 10, newWidth/10, newHeight/10)
         self.display2()

     def display2(self):
         if self.image:
             dc = wxClientDC(self)
             self.PrepareDC(dc)
             self.bitmap = self.image.ConvertToBitmap()
             dc.DrawBitmap(self.bitmap, 0,0)

     def OnPaint(self, event):
         dc = wxPaintDC(self)
         self.PrepareDC(dc)
         if self.image:
             dc.DrawBitmap(self.bitmap, 0,0)

···

At 06:01 PM 1/7/2003 -0800, you wrote:

Bob Klimek wrote:

Hi,
I've run into a speed problem when I zoom in on an image. I use PIL to load an image and convert it to wxImage to display in wx. The problem is, it gets very slow when the zoom factor gets to 3 zoom steps and above (I double the image size with each zoom step). I'm using wxScrolledWindow to manage the scroll bars and everything works well except for the speed.
To zoom in, a PIL function resizes the image, which is then converted to wxImage in OnPaint(). After 3 zoom steps the image size is 4K x 4K and things get very slow, especially during scrolling.
Couple of options I've considered is to not scale the PIL image but only the wxImage or to redraw only a viewport area that is currently being displayed, neither of which I know how to do.
What is the best way to zoom and scroll to make it more responsive?

In addition to the other suggestions, let me add these:

1. You should not be doing image scaling, conversion, etc in your EVT_PAINT. EVT_PAINT should only Blit the visible portion of the image and return.

2. A further optimization is to only Blit those regions of the visible portion of the window that need updating, you can use the wxPaintDC.GetUpdateRegion() method to find out what they are. See demo/ColourDB.py for a simplistic example of using the update region. This will also help scrolling since only the parts of the image "uncovered" by the scroll need repainting.

3. Do the scaling, PIL conversion, and etc. only once and save the results until you zoom again.

I do not know, but from what I can tell you from my knowledge of basic math
and images, at 8192 sq, for a 24bit bitmap, the memory needed is 200 meg,
unless it is intelligently clipping. Where as at 4096, the image only takes
up 50 meg.

Maybe your system can't malloc 200meg at a time? (either platform or, no
contiguous memory block exists that large)

Just guessing...
-J

···

-----Original Message-----
From: Bob Klimek [mailto:klimek@grc.nasa.gov]
Sent: Wednesday, January 08, 2003 3:59 PM
To: wxPython-users@lists.wxwindows.org
Subject: Re: [wxPython-users] zoom and scroll is slow

At 06:01 PM 1/7/2003 -0800, you wrote:

Bob Klimek wrote:

Hi,
I've run into a speed problem when I zoom in on an image. I use PIL to
load an image and convert it to wxImage to display in wx. The problem is,
it gets very slow when the zoom factor gets to 3 zoom steps and above (I
double the image size with each zoom step). I'm using wxScrolledWindow to
manage the scroll bars and everything works well except for the speed.
To zoom in, a PIL function resizes the image, which is then converted to
wxImage in OnPaint(). After 3 zoom steps the image size is 4K x 4K and
things get very slow, especially during scrolling.
Couple of options I've considered is to not scale the PIL image but only
the wxImage or to redraw only a viewport area that is currently being
displayed, neither of which I know how to do.
What is the best way to zoom and scroll to make it more responsive?

In addition to the other suggestions, let me add these:

1. You should not be doing image scaling, conversion, etc in your
EVT_PAINT. EVT_PAINT should only Blit the visible portion of the image
and return.

2. A further optimization is to only Blit those regions of the visible
portion of the window that need updating, you can use the
wxPaintDC.GetUpdateRegion() method to find out what they are. See
demo/ColourDB.py for a simplistic example of using the update region. This
will also help scrolling since only the parts of the image "uncovered" by
the scroll need repainting.

3. Do the scaling, PIL conversion, and etc. only once and save the results
until you zoom again.

Thanks for the suggestions. So far I've come half way in getting a decent
zoom and scroll. I've taken Robb Shecter's suggestion of scaling and
converting wxImage to a bitmap when I do the zooming and then in OnPaint()
I just call "dc.DrawBitmap(self.bitmap, 0,0)". I'd imagine that DrawBitmap
calls Blit internally.

That makes for a quick and responsive scrolling (so if I understand your
suggestions correctly, 1 and 2 are taken care of, since they pertained to
scrolling only).

But the zooming is still slow since wxPython (or PIL) still has to scale
the image. After clicking the zoom button 3 times, the image size goes from
512x512 to 4096x4096. The last zoom step takes about 2 seconds. However,
clicking the zoom one more time hangs the program for about 20 seconds and
then prints the following traceback:

My system: (Python2.2.2, wxPython2.3.4.2, Win2000).

Did the image get too big? Is this a bug in wxPython? The code that
produced it is below.

Bob

1024 1024
2048 2048
4096 4096
8192 8192
Traceback (most recent call last):
   File "SpotlightMain.py", line 255, in OnZoomIn
     self.iPanel.Zoom(2.0)
   File "SpotlightMain.py", line 91, in Zoom
     self.display2()
   File "SpotlightMain.py", line 98, in display2
     dc.DrawBitmap(self.bitmap, 0,0)
   File "D:\Python22\lib\site-packages\wxPython\gdi.py", line 784, in
DrawBitmap
     val = apply(gdic.wxDC_DrawBitmap,(self,) + _args, _kwargs)
wxPython.wxc.wxPyAssertionError: C++ assertion "wxAssertFailure" failed in
e:\pr
ojects\wx\src\msw\dc.cpp(907): invalid bitmap in wxDC::DrawBitmap

NOTE: The parameter "scale" is 2.0 when zooming in.

     def Zoom(self, scale):
         h = self.image.GetHeight()
         w = self.image.GetWidth()
         newWidth = int(round(float(w) * scale))
         newHeight = int(round(float(h) * scale))
         print newWidth, newHeight

         self.image.Rescale(newWidth, newHeight)
         #self.manageScrollbars(newWidth, newHeight, scale)
         self.SetScrollbars(10, 10, newWidth/10, newHeight/10)
         self.display2()

     def display2(self):
         if self.image:
             dc = wxClientDC(self)
             self.PrepareDC(dc)
             self.bitmap = self.image.ConvertToBitmap()
             dc.DrawBitmap(self.bitmap, 0,0)

     def OnPaint(self, event):
         dc = wxPaintDC(self)
         self.PrepareDC(dc)
         if self.image:
             dc.DrawBitmap(self.bitmap, 0,0)

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

Bob Klimek wrote:

But the zooming is still slow since wxPython (or PIL) still has to scale the image. After clicking the zoom button 3 times, the image size goes from 512x512 to 4096x4096. The last zoom step takes about 2 seconds. However, clicking the zoom one more time hangs the program for about 20 seconds and then prints the following traceback: ....

Well, let's presume that you're using 24-bit color bitmaps. Even if the source bitmaps aren't that depth, I suspect that PIL and wxImage will use at least that much internally.

4096x4096 is about 16.7 million pixels, and at 24-bit depth that's 48MB of data. 8192x8192 is about 67 million pixels, or about 192MB of data. Even if your machine has 256MB or more of RAM, you're likely to run into some serious memory-handling problems -- especially considering that, as you convert a 200MB PIL image into a 200MB wxImage, you're using almost 400MB of memory. And don't forget that this is *only* the raw storage for the image data, it doesn't include any other data (or code) in your program, any other processes running on the system, etc, etc.

It's possible that this might work on a system with 1GB or more of RAM, but I wouldn't be surprised if the toolkits (wxPython and PIL) just aren't capable of handling images that large.

Jeff Shannon
Technician/Programmer
Credit International

I completely overlooked that fact. That is probably the reason for the crash. Even though my machine has 750MB of RAM, I'm running on Windows2000 and its a good bet that it can't handle that.

Bob

···

At 04:14 PM 1/8/2003 -0500, you wrote:

I do not know, but from what I can tell you from my knowledge of basic math
and images, at 8192 sq, for a 24bit bitmap, the memory needed is 200 meg,
unless it is intelligently clipping. Where as at 4096, the image only takes
up 50 meg.

Maybe your system can't malloc 200meg at a time? (either platform or, no
contiguous memory block exists that large)

Just guessing...
-J

-----Original Message-----
From: Bob Klimek [mailto:klimek@grc.nasa.gov]
Sent: Wednesday, January 08, 2003 3:59 PM
To: wxPython-users@lists.wxwindows.org
Subject: Re: [wxPython-users] zoom and scroll is slow

At 06:01 PM 1/7/2003 -0800, you wrote:
>Bob Klimek wrote:
>>Hi,
>>I've run into a speed problem when I zoom in on an image. I use PIL to
>>load an image and convert it to wxImage to display in wx. The problem is,
>>it gets very slow when the zoom factor gets to 3 zoom steps and above (I
>>double the image size with each zoom step). I'm using wxScrolledWindow to
>>manage the scroll bars and everything works well except for the speed.
>>To zoom in, a PIL function resizes the image, which is then converted to
>>wxImage in OnPaint(). After 3 zoom steps the image size is 4K x 4K and
>>things get very slow, especially during scrolling.
>>Couple of options I've considered is to not scale the PIL image but only
>>the wxImage or to redraw only a viewport area that is currently being
>>displayed, neither of which I know how to do.
>>What is the best way to zoom and scroll to make it more responsive?
>
>In addition to the other suggestions, let me add these:
>
>1. You should not be doing image scaling, conversion, etc in your
>EVT_PAINT. EVT_PAINT should only Blit the visible portion of the image
>and return.
>
>2. A further optimization is to only Blit those regions of the visible
>portion of the window that need updating, you can use the
>wxPaintDC.GetUpdateRegion() method to find out what they are. See
>demo/ColourDB.py for a simplistic example of using the update region. This
>will also help scrolling since only the parts of the image "uncovered" by
>the scroll need repainting.
>
>3. Do the scaling, PIL conversion, and etc. only once and save the results
>until you zoom again.

Thanks for the suggestions. So far I've come half way in getting a decent
zoom and scroll. I've taken Robb Shecter's suggestion of scaling and
converting wxImage to a bitmap when I do the zooming and then in OnPaint()
I just call "dc.DrawBitmap(self.bitmap, 0,0)". I'd imagine that DrawBitmap
calls Blit internally.

That makes for a quick and responsive scrolling (so if I understand your
suggestions correctly, 1 and 2 are taken care of, since they pertained to
scrolling only).

But the zooming is still slow since wxPython (or PIL) still has to scale
the image. After clicking the zoom button 3 times, the image size goes from
512x512 to 4096x4096. The last zoom step takes about 2 seconds. However,
clicking the zoom one more time hangs the program for about 20 seconds and
then prints the following traceback:

My system: (Python2.2.2, wxPython2.3.4.2, Win2000).

Did the image get too big? Is this a bug in wxPython? The code that
produced it is below.

Bob

1024 1024
2048 2048
4096 4096
8192 8192
Traceback (most recent call last):
   File "SpotlightMain.py", line 255, in OnZoomIn
     self.iPanel.Zoom(2.0)
   File "SpotlightMain.py", line 91, in Zoom
     self.display2()
   File "SpotlightMain.py", line 98, in display2
     dc.DrawBitmap(self.bitmap, 0,0)
   File "D:\Python22\lib\site-packages\wxPython\gdi.py", line 784, in
DrawBitmap
     val = apply(gdic.wxDC_DrawBitmap,(self,) + _args, _kwargs)
wxPython.wxc.wxPyAssertionError: C++ assertion "wxAssertFailure" failed in
e:\pr
ojects\wx\src\msw\dc.cpp(907): invalid bitmap in wxDC::DrawBitmap

NOTE: The parameter "scale" is 2.0 when zooming in.

     def Zoom(self, scale):
         h = self.image.GetHeight()
         w = self.image.GetWidth()
         newWidth = int(round(float(w) * scale))
         newHeight = int(round(float(h) * scale))
         print newWidth, newHeight

         self.image.Rescale(newWidth, newHeight)
         #self.manageScrollbars(newWidth, newHeight, scale)
         self.SetScrollbars(10, 10, newWidth/10, newHeight/10)
         self.display2()

     def display2(self):
         if self.image:
             dc = wxClientDC(self)
             self.PrepareDC(dc)
             self.bitmap = self.image.ConvertToBitmap()
             dc.DrawBitmap(self.bitmap, 0,0)

     def OnPaint(self, event):
         dc = wxPaintDC(self)
         self.PrepareDC(dc)
         if self.image:
             dc.DrawBitmap(self.bitmap, 0,0)

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

Bob Klimek wrote:

I completely overlooked that fact. That is probably the reason for the
crash. Even though my machine has 750MB of RAM, I'm running on Windows2000
and its a good bet that it can't handle that.

Which puts you back to only re-scaling part of the image (or limiting
zoom). The problem with only scaling the part of the image that you can
see is that you would have to do that operation on every scroll event,
which could make scrolling pretty slow.

Another option is to determine a reasonable largest bitmap size, and
store the part of the image that surrounds what is being viewed. That
way, you could scroll fast if you only scrolled a little, and only have
to re-build the bitmap when the user scrolled a lot. This would take
more coding, but might work pretty well. I was going to try to implement
something like that a while ago, but I decided to go with a different
scrolling method instead. See my earlier post for that idea.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                        
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Bob Klimek wrote:

In addition to the other suggestions, let me add these:

1. You should not be doing image scaling, conversion, etc in your EVT_PAINT. EVT_PAINT should only Blit the visible portion of the image and return.

2. A further optimization is to only Blit those regions of the visible portion of the window that need updating, you can use the wxPaintDC.GetUpdateRegion() method to find out what they are. See demo/ColourDB.py for a simplistic example of using the update region. This will also help scrolling since only the parts of the image "uncovered" by the scroll need repainting.

3. Do the scaling, PIL conversion, and etc. only once and save the results until you zoom again.

Thanks for the suggestions. So far I've come half way in getting a decent zoom and scroll. I've taken Robb Shecter's suggestion of scaling and converting wxImage to a bitmap when I do the zooming and then in OnPaint() I just call "dc.DrawBitmap(self.bitmap, 0,0)". I'd imagine that DrawBitmap calls Blit internally.

That makes for a quick and responsive scrolling (so if I understand your suggestions correctly, 1 and 2 are taken care of, since they pertained to scrolling only).

No, #2 is not taken care of since DrawBitmap will draw the whole bitmap. Granted, the drawing is clipped to the visible window, but it will still go through the motions of drawing the whole thing, (more or less.) Using a little intelligence based on the image size, the viewport location and the update regions can save you orders of magnitude in drawing time. Remember, the key is to only draw the minimum required to refresh the visible part of the image, and if possible, only the portions in the update region.

But the zooming is still slow since wxPython (or PIL) still has to scale the image. After clicking the zoom button 3 times, the image size goes from 512x512 to 4096x4096. The last zoom step takes about 2 seconds. However, clicking the zoom one more time hangs the program for about 20 seconds and

As others have already said, you are using *huge* amouts of memory when doing things like this, so again using a bit of intelligence can really help you out. One way is that once the scaled image grows larger than some threshold take a different approach and not scale the whole thing. Instead you can take a subset of the original image around the area you are currently looking at and scale that. When you scroll to near the boundary of your subset then you take a new subset of the original and scale again.

···

At 06:01 PM 1/7/2003 -0800, you wrote:

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Bob Klimek wrote:

I completely overlooked that fact. That is probably the reason for the crash. Even though my machine has 750MB of RAM, I'm running on Windows2000 and its a good bet that it can't handle that.

Bob

I do not know, but from what I can tell you from my knowledge of basic math
and images, at 8192 sq, for a 24bit bitmap, the memory needed is 200 meg,
unless it is intelligently clipping. Where as at 4096, the image only takes
up 50 meg.

Maybe your system can't malloc 200meg at a time? (either platform or, no
contiguous memory block exists that large)

But the zooming is still slow since wxPython (or PIL) still has to scale
the image. After clicking the zoom button 3 times, the image size goes from
512x512 to 4096x4096. The last zoom step takes about 2 seconds. However,
clicking the zoom one more time hangs the program for about 20 seconds and
then prints the following traceback:

In any case, it is unlikely you have a screen with enough resolution to display more than 2048 pixels in either direction. You could zoom only the portion of the image which is going to be displayed (of course, then you probably can't use wxScrolledWindow).

David

···

At 04:14 PM 1/8/2003 -0500, you wrote:

Well, lets not forget that virtual memory should come to the rescue. True,
you'd be thrashing like there's not tomorrow, but it should work.

With that said, I bet there's a limit on malloc() sizes.

Try doing this:
Find the region that the zoom will show, copy that from the source and
enlarge the region. Don't forget to always work fro the original, to keep
quality high.

Speculation:
Ever noticed now Photoshop paints large images in squares? I bet they divide
the image up and each 'square' is a region obtained by a malloc. Then they
manage the resulting checkerboard.

Hope that helps!

···

-----Original Message-----
From: Bob Klimek [mailto:klimek@grc.nasa.gov]
Sent: Wednesday, January 08, 2003 4:38 PM
To: wxPython-users@lists.wxwindows.org
Subject: RE: [wxPython-users] zoom and scroll is slow

I completely overlooked that fact. That is probably the reason for the
crash. Even though my machine has 750MB of RAM, I'm running on Windows2000
and its a good bet that it can't handle that.

Bob

At 04:14 PM 1/8/2003 -0500, you wrote:

I do not know, but from what I can tell you from my knowledge of basic math
and images, at 8192 sq, for a 24bit bitmap, the memory needed is 200 meg,
unless it is intelligently clipping. Where as at 4096, the image only takes
up 50 meg.

Maybe your system can't malloc 200meg at a time? (either platform or, no
contiguous memory block exists that large)

Just guessing...
-J

-----Original Message-----
From: Bob Klimek [mailto:klimek@grc.nasa.gov]
Sent: Wednesday, January 08, 2003 3:59 PM
To: wxPython-users@lists.wxwindows.org
Subject: Re: [wxPython-users] zoom and scroll is slow

At 06:01 PM 1/7/2003 -0800, you wrote:
>Bob Klimek wrote:
>>Hi,
>>I've run into a speed problem when I zoom in on an image. I use PIL to
>>load an image and convert it to wxImage to display in wx. The problem

is,

>>it gets very slow when the zoom factor gets to 3 zoom steps and above (I
>>double the image size with each zoom step). I'm using wxScrolledWindow

to

>>manage the scroll bars and everything works well except for the speed.
>>To zoom in, a PIL function resizes the image, which is then converted to
>>wxImage in OnPaint(). After 3 zoom steps the image size is 4K x 4K and
>>things get very slow, especially during scrolling.
>>Couple of options I've considered is to not scale the PIL image but only
>>the wxImage or to redraw only a viewport area that is currently being
>>displayed, neither of which I know how to do.
>>What is the best way to zoom and scroll to make it more responsive?
>
>In addition to the other suggestions, let me add these:
>
>1. You should not be doing image scaling, conversion, etc in your
>EVT_PAINT. EVT_PAINT should only Blit the visible portion of the image
>and return.
>
>2. A further optimization is to only Blit those regions of the visible
>portion of the window that need updating, you can use the
>wxPaintDC.GetUpdateRegion() method to find out what they are. See
>demo/ColourDB.py for a simplistic example of using the update region.

This

>will also help scrolling since only the parts of the image "uncovered" by
>the scroll need repainting.
>
>3. Do the scaling, PIL conversion, and etc. only once and save the

results

>until you zoom again.

Thanks for the suggestions. So far I've come half way in getting a decent
zoom and scroll. I've taken Robb Shecter's suggestion of scaling and
converting wxImage to a bitmap when I do the zooming and then in OnPaint()
I just call "dc.DrawBitmap(self.bitmap, 0,0)". I'd imagine that DrawBitmap
calls Blit internally.

That makes for a quick and responsive scrolling (so if I understand your
suggestions correctly, 1 and 2 are taken care of, since they pertained to
scrolling only).

But the zooming is still slow since wxPython (or PIL) still has to scale
the image. After clicking the zoom button 3 times, the image size goes from
512x512 to 4096x4096. The last zoom step takes about 2 seconds. However,
clicking the zoom one more time hangs the program for about 20 seconds and
then prints the following traceback:

My system: (Python2.2.2, wxPython2.3.4.2, Win2000).

Did the image get too big? Is this a bug in wxPython? The code that
produced it is below.

Bob

1024 1024
2048 2048
4096 4096
8192 8192
Traceback (most recent call last):
   File "SpotlightMain.py", line 255, in OnZoomIn
     self.iPanel.Zoom(2.0)
   File "SpotlightMain.py", line 91, in Zoom
     self.display2()
   File "SpotlightMain.py", line 98, in display2
     dc.DrawBitmap(self.bitmap, 0,0)
   File "D:\Python22\lib\site-packages\wxPython\gdi.py", line 784, in
DrawBitmap
     val = apply(gdic.wxDC_DrawBitmap,(self,) + _args, _kwargs)
wxPython.wxc.wxPyAssertionError: C++ assertion "wxAssertFailure" failed in
e:\pr
ojects\wx\src\msw\dc.cpp(907): invalid bitmap in wxDC::DrawBitmap

NOTE: The parameter "scale" is 2.0 when zooming in.

     def Zoom(self, scale):
         h = self.image.GetHeight()
         w = self.image.GetWidth()
         newWidth = int(round(float(w) * scale))
         newHeight = int(round(float(h) * scale))
         print newWidth, newHeight

         self.image.Rescale(newWidth, newHeight)
         #self.manageScrollbars(newWidth, newHeight, scale)
         self.SetScrollbars(10, 10, newWidth/10, newHeight/10)
         self.display2()

     def display2(self):
         if self.image:
             dc = wxClientDC(self)
             self.PrepareDC(dc)
             self.bitmap = self.image.ConvertToBitmap()
             dc.DrawBitmap(self.bitmap, 0,0)

     def OnPaint(self, event):
         dc = wxPaintDC(self)
         self.PrepareDC(dc)
         if self.image:
             dc.DrawBitmap(self.bitmap, 0,0)

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org