Christopher Barker wrote:
Steven Sproat wrote:
So, I have Tool (containing blank methods/default attributes),
extended by OverlayShape (since all my shapes are drawn on overlays,
has common methods here),
hmm -- interesting. How is the performance for that? I tried something
similar in the early days of FloatCanvas, and it was painfully slow.
Are you doing 1000s of shapes?
It's up to the user - they draw as many shapes as they wish. I've got
some test save files with ~300 shapes and it performs well.
I only overlay shapes when they're being drawn *by* the user, for redraw
operations, I pass a False value to my draw methods, which just blits to
the DC with no overlay.
The performance is good to say the least, on my dual-core, 4 years old
system I see no slowdown on GTK/XP, and it even runs well on my father's
7 year old XP box. The issues I've found is with a huge canvas - this
code seems a little slow
def get_dc(self):
cdc = wx.ClientDC(self)
self.PrepareDC(cdc)
return wx.BufferedDC(cdc, self.buffer, wx.BUFFER_VIRTUAL_AREA)
the PrepareDC statement seems to be at fault, but without that all my
painting's x/y coordinates are not calculated correctly.
creating 10x Image instances (around 150kb png each)
how big are these images? png is compressed, so there's no way to tell
from there. A wxImage stores either RGB or RGBA uncompressed, so that
would be: 3 (or 4) bytes per pixel.
spread over 10 tabs
used over 50MB!
which is 5 MB per image, which would be about a 1000x1000 image. Is
that what you're dealing with?
Yes. However, loading 10x tabs with only Pens/Rectangles drawn, the
memory use was around 44MB, which is the increase from each tab's
canvas' bitmap buffer. The more images I load, the worse things become.
My images contain references to a wx.Bitmap of the image, as well as
a wx.Image. The image is used to apply transformations to the bitmap,
such as rotation/scaling. The process is like this
-> create a copy of the original wx.Image
-> apply scaling to that
-> now use wx.BitmapFromImage to draw to the screen.
Do you need to keep a reference to the Bitmap, too? I don't in
FloatCanvas, I just keep the wx.Image around, and re-generate the
Bitmap on the fly to draw it. IT works OK with a single 10,000 by
10,000 image, or lots of little ones, but I've never tried to use lots
of large ones.
I could try this - as you mention below, only one tab is visible at a
time, so converting shouldn't be too much of a problem. There probably
shouldn't be many "lots of large ones" as it would be difficult for the
user to manage, say 3 1000x1000 images on my canvas (with no zoom,
they'd need a huge screen!)
If I did it the 2nd way there would be problems - for example,
scaling the image by 50%, and then scaling it back to the default
size would lose quality,
Exactly, I think that option is off the table, and wouldn't really
save you much anyway -- a wxBitmap isn't any smaller than a wxImage
(ussualy, anyway)
But, this is taking up lots of memory, and I'm not sure on how to
work around this. Any ideas? I imagine that creating the Bitmap (by
loading it) per draw operation would be too performance-intensive,
especially as my save format reads in images from a zip archive
Right. load from file at each draw would be painful.
First: 50MB really isnt that much these days -- is this really a problem?
Second: make sure you're not keeping more around that you really need
-- i.e. both a wxImage and a wxBitmap.
Otherwise:
A) You could do some sort of cache system - it would keep the n most
recently used Images in memory, and then load other ones as needed.
Depending on your use patterns, this could work fine. it sounds like
you have stuff displayed on various tabs, so your users can't be
working with all of them at once.
B) What kind of images are these? If they are much smaller as PNGs
than in memory, that could be for two reasons: they compress well,
and/or they are palleted images, so only one byte per pixel, instead
of 3or4. I don't know of any library that stores images in a
compressed format, but if they are palleted images, you could store
them as PIL images, and only convert to RBG or RGBA on the fly. (or
use numpy for that). That may be too slow, but it would save memory,
and be faster than going to disk.
C) It might also be possible to store the compressed image in memory
-- processors are very fast compared to disk these days. wxImage may
be able to load from memory now, so you could store it in memory as a
PNG file. If not, take a look at the python zip module and/or the
numpy savez format.
-Chris
No, 50MB is not much. but as an example, my program allows PDFs to be
"loaded", which really just converts each page to an image, and then
loads in the image. With a 22-page PDF (on linux), my app grew from
40MB to 184MB. That's a round a 5x increase!
Opening 22 tabs with nothing drawn took RAM usage up to 60MB, it's just
the images are *adding a lot*. I do keep both a Bitmap (to blit) and an
Image (the "original" Image, to rotate/scale as mentioned) but I can't
see any other way. The bitmap represents the image after any
scale/roation operation has been applied to it, so I can't just keep one
Image
A) This sounds good, 5 Images can use around, say, 40MB so that's not
too much of an overhead to store for the entire application. I'm just
wondering how much this "swapping" image caches would effect changing
from one tab to another, currently it's very fast, but maybe
regenerating/loading the cache per tab switch may be costly.
B) I have no idea, to be honest. I let the user load in all the image
types wx supports - bmps, tiffs, jpgs, pcx. My PDF converted PNGs can
vary in size; up to around 600KB. perhaps I'll be better off with JPGs,
here.
C) I'll take a look at how much ram this saves.
Thanks for your suggestions, Chris, much appreciated!