diff --git a/src/java/com/threerings/cast/bundle/BundledComponentRepository.java b/src/java/com/threerings/cast/bundle/BundledComponentRepository.java index 623a099f8..8addb6455 100644 --- a/src/java/com/threerings/cast/bundle/BundledComponentRepository.java +++ b/src/java/com/threerings/cast/bundle/BundledComponentRepository.java @@ -1,10 +1,9 @@ // -// $Id: BundledComponentRepository.java,v 1.3 2001/11/30 02:34:57 mdb Exp $ +// $Id: BundledComponentRepository.java,v 1.4 2001/12/07 01:33:29 mdb Exp $ package com.threerings.cast.bundle; import java.awt.Image; -import java.awt.image.BufferedImage; import java.io.File; import java.io.FileNotFoundException; @@ -196,7 +195,7 @@ public class BundledComponentRepository } // documentation inherited - public BufferedImage loadImage (String path) + public Image loadImage (String path) throws IOException { // obtain the image data from our resource bundle diff --git a/src/java/com/threerings/media/image/ImageIOLoader.java b/src/java/com/threerings/media/image/ImageIOLoader.java new file mode 100644 index 000000000..99290d9e2 --- /dev/null +++ b/src/java/com/threerings/media/image/ImageIOLoader.java @@ -0,0 +1,31 @@ +// +// $Id: ImageIOLoader.java,v 1.1 2001/12/07 01:33:29 mdb Exp $ + +package com.threerings.media; + +import java.awt.Image; +import java.io.IOException; +import java.io.InputStream; + +import javax.imageio.ImageIO; + +/** + * Loads images using the ImageIO services provided by J2SE + * 1.4 (and, presumably, above). + */ +public class ImageIOLoader +{ + // documentation inherited + public Image loadImage (InputStream source) + throws IOException + { + // this seems to choke when decoding the compressed image data + // which may mean it's a JDK bug or something, but I'd like to see + // it resolved so that the image manager will work on applets + // + // ImageInputStream iis = new MemoryCacheImageInputStream(source); + // return ImageIO.read(iis); + + return ImageIO.read(source); + } +} diff --git a/src/java/com/threerings/media/image/ImageLoader.java b/src/java/com/threerings/media/image/ImageLoader.java new file mode 100644 index 000000000..146a597b3 --- /dev/null +++ b/src/java/com/threerings/media/image/ImageLoader.java @@ -0,0 +1,24 @@ +// +// $Id: ImageLoader.java,v 1.1 2001/12/07 01:33:29 mdb Exp $ + +package com.threerings.media; + +import java.awt.Image; +import java.io.IOException; +import java.io.InputStream; + +/** + * In order to take advantage of the new J2SE 1.4 image loading facilites + * (in the form of ImageIO and friends), while preserving the + * ability to operate on J2SE 1.3 and previous, we have the image loader + * interface. It allows us to attempt to load the ImageIO based loader and + * fall back if the class is not available. + */ +public interface ImageLoader +{ + /** + * Load up the image from the supplied input stream. + */ + public Image loadImage (InputStream source) + throws IOException; +} diff --git a/src/java/com/threerings/media/image/ImageManager.java b/src/java/com/threerings/media/image/ImageManager.java index ea098f27f..8271a8768 100644 --- a/src/java/com/threerings/media/image/ImageManager.java +++ b/src/java/com/threerings/media/image/ImageManager.java @@ -1,12 +1,14 @@ // -// $Id: ImageManager.java,v 1.8 2001/11/30 02:33:34 mdb Exp $ +// $Id: ImageManager.java,v 1.9 2001/12/07 01:33:29 mdb Exp $ package com.threerings.media; +import java.awt.Component; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; +import java.awt.Image; import java.awt.Transparency; import java.awt.image.BufferedImage; @@ -17,7 +19,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.NoSuchElementException; -import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.stream.ImageInputStream; @@ -33,9 +34,13 @@ public class ImageManager { /** * Construct an image manager with the specified {@link - * ResourceManager} from which it will obtain its data. + * ResourceManager} from which it will obtain its data. A non-null + * context must be provided if there is any expectation + * that the image manager will not be able to load images via the + * ImageIO services and will have to fallback to Toolkit-style + * loading. */ - public ImageManager (ResourceManager rmgr) + public ImageManager (ResourceManager rmgr, Component context) { _rmgr = rmgr; @@ -44,16 +49,25 @@ public class ImageManager GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice gdev = genv.getDefaultScreenDevice(); _gconf = gdev.getDefaultConfiguration(); + + // try to figure out which image loader we'll be using + try { + _loader = (ImageLoader)Class.forName(IMAGEIO_LOADER).newInstance(); + } catch (Exception e) { + Log.info("Unable to use ImageIO to load images. " + + "Falling back to Toolkit."); + _loader = new ToolkitLoader(context); + } } /** * Loads the image via the resource manager using the specified path * and caches it for faster retrieval henceforth. */ - public BufferedImage getImage (String path) + public Image getImage (String path) throws IOException { - BufferedImage img = (BufferedImage)_imgs.get(path); + Image img = (Image)_imgs.get(path); if (img != null) { // Log.info("Retrieved image from cache [path=" + path + "]."); return img; @@ -70,19 +84,12 @@ public class ImageManager * environment and decodes the image data from the specified source * image into that target image. The resulting image is not cached. */ - public BufferedImage createImage (InputStream source) + public Image createImage (InputStream source) throws IOException { - // this seems to choke when decoding the compressed image data - // which may mean it's a JDK bug or something, but I'd like to see - // it resolved so that the image manager will work on applets - // - // ImageInputStream iis = new MemoryCacheImageInputStream(source); - // BufferedImage src = ImageIO.read(iis); - - BufferedImage src = ImageIO.read(source); - int swidth = src.getWidth(); - int sheight = src.getHeight(); + Image src = _loader.loadImage(source); + int swidth = src.getWidth(null); + int sheight = src.getHeight(null); // now convert the image to a format optimized for display BufferedImage dest = _gconf.createCompatibleImage( @@ -98,9 +105,19 @@ public class ImageManager * by default. */ protected ResourceManager _rmgr; + /** The image loader via which we convert an input stream into an + * image. */ + protected ImageLoader _loader; + /** A cache of loaded images. */ protected HashMap _imgs = new HashMap(); /** The graphics configuration of our default display device. */ protected GraphicsConfiguration _gconf; + + /** The classname of the ImageIO-based image loader which we attempt + * to use but fallback from if we're not running a JVM that has + * ImageIO support. */ + protected static final String IMAGEIO_LOADER = + "com.threerings.media.ImageIOLoader"; } diff --git a/src/java/com/threerings/media/image/ImageUtil.java b/src/java/com/threerings/media/image/ImageUtil.java new file mode 100644 index 000000000..5a8d98930 --- /dev/null +++ b/src/java/com/threerings/media/image/ImageUtil.java @@ -0,0 +1,40 @@ +// +// $Id: ImageUtil.java,v 1.1 2001/12/07 01:33:29 mdb Exp $ + +package com.threerings.media; + +import java.awt.Image; +import java.awt.Graphics; +import java.awt.image.BufferedImage; + +/** + * Image related utility functions. + */ +public class ImageUtil +{ + /** + * Extracts a subimage from the supplied image with the specified + * dimensions. If the supplied image is an instance of {@link + * BufferedImage}, then the subimage will simply reference the main + * image. If it is not, the subimage will be created and the data will + * be rendered into the newly created image. + * + * @return the desired subimage. + */ + public static Image getSubimage ( + Image source, int x, int y, int width, int height) + { + if (source instanceof BufferedImage) { + return ((BufferedImage)source).getSubimage(x, y, width, height); + + } else { + BufferedImage target = + new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics g = target.getGraphics(); + g.drawImage(source, 0, 0, width, height, + x, y, x+width, y+height, null); + g.dispose(); + return target; + } + } +} diff --git a/src/java/com/threerings/media/image/ToolkitLoader.java b/src/java/com/threerings/media/image/ToolkitLoader.java new file mode 100644 index 000000000..850a9fb04 --- /dev/null +++ b/src/java/com/threerings/media/image/ToolkitLoader.java @@ -0,0 +1,74 @@ +// +// $Id: ToolkitLoader.java,v 1.1 2001/12/07 01:33:29 mdb Exp $ + +package com.threerings.media; + +import java.awt.Component; +import java.awt.Image; +import java.awt.MediaTracker; +import java.awt.Toolkit; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.util.StreamUtils; + +/** + * Loads images using the default AWT toolkit (for compatibility with + * pre-1.4 JVMs). + */ +public class ToolkitLoader implements ImageLoader +{ + public ToolkitLoader (Component context) + { + // do something more informative than NPE if we're misconfigured + if (context == null) { + String errmsg = "Toolkit image loader constructed without a " + + "context via which we can create a MediaTracker. If the " + + "image manager may fall back to using the Toolkit image " + + "loader (like it just did), then you have to provide a " + + "component instance for it at construct time. Thanks and " + + "have a nice day."; + throw new RuntimeException(errmsg); + } + + _toolkit = context.getToolkit(); + _tracker = new MediaTracker(context); + } + + // documentation inherited + public Image loadImage (InputStream source) + throws IOException + { + byte[] data = StreamUtils.streamAsBytes(source, READ_BUFFER_SIZE); + Image image = _toolkit.createImage(data); + + // we now have to wait for the image to finish decoding (this all + // apparently happens on another thread. yay!) + _tracker.addImage(image, 0); + + // if something goes horribly awry, we don't want to go into an + // infinite loop, so we bound the number of times we'll allow + // ourselves to be interrupted and loop + boolean done = false; + for (int i = 0; (i < 1000) && !done; i++) { + try { + _tracker.waitForAll(); + done = true; + } catch (InterruptedException e) { + // loop back around + } + } + + return image; + } + + /** Our AWT toolkit which we use to create images. */ + protected Toolkit _toolkit; + + /** Used to wait for images to load. */ + protected MediaTracker _tracker; + + /** The size of the read buffer used to load the image data. */ + protected static final int READ_BUFFER_SIZE = 4096; +} diff --git a/src/java/com/threerings/media/tile/ImageProvider.java b/src/java/com/threerings/media/tile/ImageProvider.java index cf68d1377..c772ef5ef 100644 --- a/src/java/com/threerings/media/tile/ImageProvider.java +++ b/src/java/com/threerings/media/tile/ImageProvider.java @@ -1,9 +1,9 @@ // -// $Id: ImageProvider.java,v 1.1 2001/11/18 04:09:21 mdb Exp $ +// $Id: ImageProvider.java,v 1.2 2001/12/07 01:33:29 mdb Exp $ package com.threerings.media.tile; -import java.awt.image.BufferedImage; +import java.awt.Image; import java.io.IOException; /** @@ -21,6 +21,6 @@ public interface ImageProvider * @exception IOException thrown if an error occurs loading the image * data. */ - public BufferedImage loadImage (String path) + public Image loadImage (String path) throws IOException; } diff --git a/src/java/com/threerings/media/tile/SwissArmyTileSet.java b/src/java/com/threerings/media/tile/SwissArmyTileSet.java index 1485f906b..1f5455c7e 100644 --- a/src/java/com/threerings/media/tile/SwissArmyTileSet.java +++ b/src/java/com/threerings/media/tile/SwissArmyTileSet.java @@ -1,12 +1,11 @@ // -// $Id: SwissArmyTileSet.java,v 1.4 2001/11/29 21:57:31 mdb Exp $ +// $Id: SwissArmyTileSet.java,v 1.5 2001/12/07 01:33:29 mdb Exp $ package com.threerings.media.tile; import java.awt.Image; import java.awt.Point; import java.awt.Dimension; -import java.awt.image.BufferedImage; import java.io.IOException; import java.io.ObjectInputStream; @@ -14,7 +13,7 @@ import java.io.ObjectInputStream; import com.samskivert.util.StringUtil; import com.threerings.media.Log; -import com.threerings.media.ImageManager; +import com.threerings.media.ImageUtil; /** * The swiss army tileset supports a diverse variety of tiles in the @@ -131,7 +130,7 @@ public class SwissArmyTileSet extends TileSet // documentation inherited protected Image extractTileImage (int tileIndex) { - BufferedImage tsimg = getTilesetImage(); + Image tsimg = getTilesetImage(); if (tsimg == null) { return null; } @@ -160,7 +159,8 @@ public class SwissArmyTileSet extends TileSet // ", tx=" + tx + ", ty=" + ty + "]."); // crop the tile-sized image chunk from the full image - return tsimg.getSubimage(tx, ty, _widths[ridx], _heights[ridx]); + return ImageUtil.getSubimage( + tsimg, tx, ty, _widths[ridx], _heights[ridx]); } private void readObject (ObjectInputStream in) diff --git a/src/java/com/threerings/media/tile/TileManager.java b/src/java/com/threerings/media/tile/TileManager.java index 4225c5d16..01bc96e7d 100644 --- a/src/java/com/threerings/media/tile/TileManager.java +++ b/src/java/com/threerings/media/tile/TileManager.java @@ -1,9 +1,9 @@ // -// $Id: TileManager.java,v 1.22 2001/11/30 02:34:57 mdb Exp $ +// $Id: TileManager.java,v 1.23 2001/12/07 01:33:29 mdb Exp $ package com.threerings.media.tile; -import java.awt.image.BufferedImage; +import java.awt.Image; import java.io.IOException; import com.samskivert.io.PersistenceException; @@ -136,7 +136,7 @@ public class TileManager implements ImageProvider } // documentation inherited - public BufferedImage loadImage (String path) + public Image loadImage (String path) throws IOException { // load up the image data from the resource manager diff --git a/src/java/com/threerings/media/tile/TileSet.java b/src/java/com/threerings/media/tile/TileSet.java index fb817927c..05225c9f4 100644 --- a/src/java/com/threerings/media/tile/TileSet.java +++ b/src/java/com/threerings/media/tile/TileSet.java @@ -1,5 +1,5 @@ // -// $Id: TileSet.java,v 1.22 2001/11/27 08:40:34 mdb Exp $ +// $Id: TileSet.java,v 1.23 2001/12/07 01:33:29 mdb Exp $ package com.threerings.media.tile; @@ -227,7 +227,7 @@ public abstract class TileSet * @return the tileset image or null if an error occurred loading the * image. */ - protected BufferedImage getTilesetImage () + protected Image getTilesetImage () { // return it straight away if it's already loaded if (_tilesetImg != null) { @@ -281,5 +281,5 @@ public abstract class TileSet /** The image containing all tile images for this set. This is private * because it should be accessed via {@link #getTilesetImage} even by * derived classes. */ - private transient BufferedImage _tilesetImg; + private transient Image _tilesetImg; } diff --git a/src/java/com/threerings/media/tile/UniformTileSet.java b/src/java/com/threerings/media/tile/UniformTileSet.java index 53b6115fd..32b3c7926 100644 --- a/src/java/com/threerings/media/tile/UniformTileSet.java +++ b/src/java/com/threerings/media/tile/UniformTileSet.java @@ -1,13 +1,12 @@ // -// $Id: UniformTileSet.java,v 1.4 2001/11/29 21:57:31 mdb Exp $ +// $Id: UniformTileSet.java,v 1.5 2001/12/07 01:33:29 mdb Exp $ package com.threerings.media.tile; import java.awt.Image; -import java.awt.image.BufferedImage; import com.threerings.media.Log; -import com.threerings.media.ImageManager; +import com.threerings.media.ImageUtil; /** * A uniform tileset is one that is composed of tiles that are all the @@ -68,7 +67,7 @@ public class UniformTileSet extends TileSet // documentation inherited protected Image extractTileImage (int tileId) { - BufferedImage tsimg = getTilesetImage(); + Image tsimg = getTilesetImage(); if (tsimg == null) { return null; } @@ -79,7 +78,8 @@ public class UniformTileSet extends TileSet int col = tileId % tilesPerRow; // crop the tile-sized image chunk from the full image - return tsimg.getSubimage(_width*col, _height*row, _width, _height); + return ImageUtil.getSubimage( + tsimg, _width*col, _height*row, _width, _height); } // documentation inherited diff --git a/src/java/com/threerings/media/tile/bundle/TileSetBundle.java b/src/java/com/threerings/media/tile/bundle/TileSetBundle.java index 2e1c9423e..3546b053c 100644 --- a/src/java/com/threerings/media/tile/bundle/TileSetBundle.java +++ b/src/java/com/threerings/media/tile/bundle/TileSetBundle.java @@ -1,9 +1,9 @@ // -// $Id: TileSetBundle.java,v 1.4 2001/11/30 02:34:57 mdb Exp $ +// $Id: TileSetBundle.java,v 1.5 2001/12/07 01:33:29 mdb Exp $ package com.threerings.media.tile.bundle; -import java.awt.image.BufferedImage; +import java.awt.Image; import java.io.FileNotFoundException; import java.io.IOException; @@ -73,7 +73,7 @@ public class TileSetBundle } // documentation inherited - public BufferedImage loadImage (String path) + public Image loadImage (String path) throws IOException { // obtain the image data from our jarfile diff --git a/src/java/com/threerings/media/tile/bundle/tools/DumpBundle.java b/src/java/com/threerings/media/tile/bundle/tools/DumpBundle.java index d965cfec5..f0f207507 100644 --- a/src/java/com/threerings/media/tile/bundle/tools/DumpBundle.java +++ b/src/java/com/threerings/media/tile/bundle/tools/DumpBundle.java @@ -1,5 +1,5 @@ // -// $Id: DumpBundle.java,v 1.3 2001/11/30 02:34:58 mdb Exp $ +// $Id: DumpBundle.java,v 1.4 2001/12/07 01:33:29 mdb Exp $ package com.threerings.media.tools.tile.bundle; @@ -34,7 +34,7 @@ public class DumpBundle // create a resource and image manager in case they want to dump // the tiles ResourceManager rmgr = new ResourceManager(null, "rsrc"); - ImageManager imgr = new ImageManager(rmgr); + ImageManager imgr = new ImageManager(rmgr, null); for (int i = 0; i < args.length; i++) { // oh the hackery diff --git a/tests/src/java/com/threerings/cast/builder/TestApp.java b/tests/src/java/com/threerings/cast/builder/TestApp.java index 76165e4af..938ec72f3 100644 --- a/tests/src/java/com/threerings/cast/builder/TestApp.java +++ b/tests/src/java/com/threerings/cast/builder/TestApp.java @@ -1,5 +1,5 @@ // -// $Id: TestApp.java,v 1.9 2001/11/30 02:35:37 mdb Exp $ +// $Id: TestApp.java,v 1.10 2001/12/07 01:33:29 mdb Exp $ package com.threerings.cast.builder; @@ -34,7 +34,7 @@ public class TestApp MisoUtil.bindProperties(_config); ResourceManager rmgr = new ResourceManager(null, "rsrc"); - ImageManager imgr = new ImageManager(rmgr); + ImageManager imgr = new ImageManager(rmgr, _frame); ComponentRepository crepo = new BundledComponentRepository(rmgr, imgr, "components"); diff --git a/tests/src/java/com/threerings/cast/bundle/BundledComponentRepositoryTest.java b/tests/src/java/com/threerings/cast/bundle/BundledComponentRepositoryTest.java index d390475d5..52a8a6ead 100644 --- a/tests/src/java/com/threerings/cast/bundle/BundledComponentRepositoryTest.java +++ b/tests/src/java/com/threerings/cast/bundle/BundledComponentRepositoryTest.java @@ -1,5 +1,5 @@ // -// $Id: BundledComponentRepositoryTest.java,v 1.3 2001/11/30 02:35:37 mdb Exp $ +// $Id: BundledComponentRepositoryTest.java,v 1.4 2001/12/07 01:33:29 mdb Exp $ package com.threerings.cast.bundle; @@ -23,7 +23,7 @@ public class BundledComponentRepositoryTest extends TestCase { try { ResourceManager rmgr = new ResourceManager(null, "rsrc"); - ImageManager imgr = new ImageManager(rmgr); + ImageManager imgr = new ImageManager(rmgr, null); BundledComponentRepository repo = new BundledComponentRepository(rmgr, imgr, "components"); diff --git a/tests/src/java/com/threerings/media/tile/bundle/BundledTileSetRepositoryTest.java b/tests/src/java/com/threerings/media/tile/bundle/BundledTileSetRepositoryTest.java index 8ac23a2f0..3ba7fca41 100644 --- a/tests/src/java/com/threerings/media/tile/bundle/BundledTileSetRepositoryTest.java +++ b/tests/src/java/com/threerings/media/tile/bundle/BundledTileSetRepositoryTest.java @@ -1,5 +1,5 @@ // -// $Id: BundledTileSetRepositoryTest.java,v 1.3 2001/11/30 02:35:37 mdb Exp $ +// $Id: BundledTileSetRepositoryTest.java,v 1.4 2001/12/07 01:33:29 mdb Exp $ package com.threerings.media.tile.bundle; @@ -21,7 +21,7 @@ public class BundledTileSetRepositoryTest extends TestCase { try { ResourceManager rmgr = new ResourceManager(null, "rsrc"); - ImageManager imgr = new ImageManager(rmgr); + ImageManager imgr = new ImageManager(rmgr, null); BundledTileSetRepository repo = new BundledTileSetRepository(rmgr, imgr, "tilesets"); Iterator sets = repo.enumerateTileSets(); diff --git a/tests/src/java/com/threerings/miso/viewer/ViewerApp.java b/tests/src/java/com/threerings/miso/viewer/ViewerApp.java index 93208b57e..81f279c2f 100644 --- a/tests/src/java/com/threerings/miso/viewer/ViewerApp.java +++ b/tests/src/java/com/threerings/miso/viewer/ViewerApp.java @@ -1,5 +1,5 @@ // -// $Id: ViewerApp.java,v 1.19 2001/11/30 02:35:37 mdb Exp $ +// $Id: ViewerApp.java,v 1.20 2001/12/07 01:33:29 mdb Exp $ package com.threerings.miso.viewer; @@ -42,10 +42,14 @@ public class ViewerApp System.exit(-1); } + // create and size the main application frame + _frame = new ViewerFrame(); + _frame.setSize(WIDTH, HEIGHT); + // we don't need to configure anything _config = new Config(); ResourceManager rmgr = new ResourceManager(null, "rsrc"); - ImageManager imgr = new ImageManager(rmgr); + ImageManager imgr = new ImageManager(rmgr, _frame); _tilemgr = new TileManager(imgr); _tilemgr.setTileSetRepository( new BundledTileSetRepository(rmgr, imgr, "tilesets")); @@ -62,10 +66,6 @@ public class ViewerApp new BundledComponentRepository(rmgr, imgr, "components"); CharacterManager charmgr = new CharacterManager(crepo); - // create and size the main application frame - _frame = new ViewerFrame(); - _frame.setSize(WIDTH, HEIGHT); - // create our scene view panel _panel = new ViewerSceneViewPanel(ctx, spritemgr, charmgr, crepo); _frame.setPanel(_panel);