Normally when I run into problems like this I try to remember to not get focused too much on one aspect of it. I've come to realize that there was an inherent 'requirement defect' in my initial design, I was putting too much responsbility on one object. This library should essentially have:
1. An object that can paint an image of a generic type.
2. An object that can paint shapes and text over an image.
3. An object that can overlay an image over another image.
4. A JComponent that can display an image, shapes, text and an overlay.
5. A component usable in Swing that can display an image with shapes, text and an overlay in a scroll pane and provides a method of zooming (scaling) the image.
Of course it should also be done in a way that makes those objects as reusable as possible for adding new functionality or creating new GUI components. So what I really need at the lowest level is simply an object that, given a Graphics context and a Component, can paint an image of a generic type. ImageLabel did far more than that and even ImageRenderer is assigned too much responsibility because it provided scaling. I've revised ImageRenderer to thus:
Even the width and height methods are probably above and beyond what it should be responsible for. The problem is most of the components won't know what kind of image it actually is but will need to know how big it is. I could always wrap the image in some kind of interface, but that seems like it's going through too much trouble over such a minor issue. The only two objects that should *care* about the specific type is the ImageRenderer and the class that creates the ImageRenderer. Basically, once that ImageRenderer is created I want my library to not give a rats behind what kind of image it is or how it's being painted, just that it can be painted properly when passed a Graphics and Component. So this seems pretty okay to me, but I'm kind of confused on where to go from there.
I need some way to provide scaling. I'm wrestling with whether or not this should be an object that is passed an ImageRenderer, or if it should be an ImageRenderer itself that provides the additional functionality. However, in typing this I just realized that it must be an ImageRenderer itself otherwise it will have no idea how to perform the scaling. How do you scale an image if you have no idea what kind of image it is? So I guess it'll be something like:
But then I need to draw on top of the image, however I don't think that requires any knowledge of how the image itself is drawn. I just realized, typing this, that it doesn't need to know anything at all. If I just pass it a Graphics and a Component and tell it what it should be drawing then it doesn't matter what it's drawing over does it? Heck, I guess I could then use that outside of anything to do with images, just drawing period.
A painter is something that paints...something! Right? Then make an interface for each requirement:
Repeat for Shapes and overlays. Although now that I think about it an overlay is really just another ImageRenderer that has transparency painting over the top of the first one. Looking at the Painter interface is there any reason I can't just make ImageRenderer an "ImagePainter" and extend Painter? I'm not sure how to handle the "OverlayPainter" though.
From those interfaces it seems I could create GUI components that delegate painting to those interfaces. With composition I could create more complex components comprised of a few of those components and so on. Plus, I don't see any reason I couldn't reuse something like an ImageRenderer(Painter) if I wanted to paint the same image in two different places.
Ernest:
I have to strongly disagree with the suggestion. From the documentation an Icon is:
A small fixed size picture, typically used to decorate components.
I don't intend this to be small nor fixed size. While I suppose you could, I also don't really intend this to be used as an Icon in a JButton, JLabel, or anywhere you would normally use an Icon. Thank you for the suggestion though, sorry if this post (or the entire thread) is rather convoluted. I'm pretty good at writing good objects, designing an architecture, framework, library, etc. is definitely one of my weaker points so i'm kind of stumbling through this trying to get it right and looking for input.