I’ve made an important change to the way that the Image class is used…
(I’ve been wanting to do this for years, but finally decided it was a good time when I hit a problem that I just couldn’t solve cleanly with the current Image class…)
Previously, you’d create an Image object, keep a pointer to it, and delete it when you’d finished. This was fine, but there were all sorts of places in the code where images were shared or passed around, and the responsibility for owning and deleting them was very confusing. This provided lots of opportunities for dangling pointers, leaks, or unnecessary copying of images, as well as making it a PITA to make sure you were using them safely by using ScopedPointers and other tricks.
I’ve now changed the design, so that an Image is a lightweight object with value semantics, which internally points to a shared, reference-counted object that actually holds the data. That means that instead of keeping a pointer to an image, you just pass them around by value, and when they go out of scope, their image data gets released automatically. Being ref-counted makes it easy to share the same image data between separate tasks.
This has lots of benefits: it makes your code cleaner, safer, less prone to leaks, and it’s impossible to get a dangling pointer to an image. The ImageCache class is now much simpler, and you don’t have to worry about releasing the objects that it gives you. Likewise when you use the ImageFormat classes to create an image, you don’t need to worry about deleting it.
So code like this:
Image* im = ImageCache::getFromFile (f);
g.drawImage (im, x, y)
ImageCache::release (im);[/code]
becomes:
[code]g.drawImage (ImageCache::getFromFile (f), x, y);
The changes also mean that you can use images in places that you previously couldn’t, e.g. Array.
Since the Image copy constructor now simply creates a reference to a shared image rather than actually duplicating the image, I’ve added a new method Image::duplicateIfShared(). This will internally duplicate an image if there is are any other references to it, so that if you’ve been given an image but don’t know whether it’s in use elsewhere, calling this method will make sure that you’re drawing onto your own private copy, and not onto a shared image.
The changes will, of course, break some code. Although most of the Image class member functions are the same, all the Juce functions that used to take or return an Image* now use a const Image& instead… Updating is really straightforward though, and in every place that I’ve had to change my code for this, the result has been much cleaner and more concise than it was before.
An image can also now be ‘null’, if you just create it with the default constructor. So where you’d previously have written:
Image* im = ImageFileFormat::loadFrom (f);
if (im != 0)
{
doSomething (im);
delete im;
}
You’d now write
Image im = ImageFileFormat::loadFrom (f);
if (im.isValid())
doSomething (im);
I’ve updated the (old) Jucer to generate code that’s compatible with the new class - let me know if you have any problems with that.
I think the only pitfall that you might need to watch out for would be if you’ve used the Image copy constructor anywhere to deliberately create a copy, and if it’s important to your code that the image actually gets duplicated, then you’d need to make sure you add a call to duplicateIfShared().