001    /*
002     * Copyright 2002-2004 the original author or authors.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.springframework.richclient.image;
017    
018    import java.awt.Image;
019    import java.awt.Toolkit;
020    import java.awt.image.ImageObserver;
021    import java.io.File;
022    import java.io.IOException;
023    import java.io.InputStream;
024    import java.net.URL;
025    
026    import org.springframework.core.io.AbstractResource;
027    import org.springframework.core.io.Resource;
028    import org.springframework.util.Assert;
029    import org.springframework.util.FileCopyUtils;
030    
031    /**
032     * A resource decorator that represents an underlying graphical AWT image, such
033     * as a GIF, JPEG, or PNG.
034     * 
035     * @author Keith Donald
036     */
037    public class AwtImageResource extends AbstractResource implements ImageObserver {
038        private Resource wrappedResource;
039    
040        private boolean imageLoaded;
041    
042        private boolean imageError;
043    
044        public static final String RESOURCE_PREFIX = "image:";
045    
046        /**
047         * Constructs a AwtImageResource for the following io.core.Resource. This
048         * assumes the wrapped resource actually points to a underlying image.
049         * 
050         * @param resource
051         *            The wrapped resource.
052         * @throws IllegalArgumentException,
053         *             if the resource is invalid.
054         */
055        public AwtImageResource(Resource resource) {
056            Assert.notNull(resource);
057            if (resource instanceof AwtImageResource) {
058                throw new IllegalArgumentException("Wrapping another AwtImageResource instance is illegal.");
059            }
060            this.wrappedResource = resource;
061        }
062    
063        public String getDescription() {
064            return wrappedResource.getDescription();
065        }
066    
067        public Resource createRelative(String relativePath) throws IOException {
068            return wrappedResource.createRelative(relativePath);
069        }
070    
071        public boolean exists() {
072            return wrappedResource.exists();
073        }
074    
075        public boolean isOpen() {
076            return wrappedResource.isOpen();
077        }
078    
079        public URL getURL() throws IOException {
080            return wrappedResource.getURL();
081        }
082    
083        public File getFile() throws IOException {
084            return wrappedResource.getFile();
085        }
086    
087        public String getFilename() throws IllegalStateException {
088            return wrappedResource.getFilename();
089        }
090    
091        public InputStream getInputStream() throws IOException {
092            return wrappedResource.getInputStream();
093        }
094    
095        /**
096         * Loads the image from the underlying <code>core.io.Resource.</code>
097         * 
098         * This method does not cache. Calling it successively will result in a new
099         * image being loaded each time.
100         * 
101         * @throws java.io.IOException
102         *             If an error occurred while reading from the resource input
103         *             stream.
104         */
105        public Image getImage() throws IOException {
106            return loadImage(getInputStream());
107        }
108    
109        /**
110         * Load an image from the underlying resource's input stream. Constructs a
111         * new <code>Image</code> object from the data read from the input stream
112         * on each call.
113         * <p>
114         * This method loads the image fully into memory. This improves UI
115         * responsiveness when the image is needed by the GUI event-dispatching
116         * thread.
117         * 
118         * @param stream
119         *            The input stream.
120         * @return The resulting <code>Image</code> object.
121         * @throws java.io.IOException
122         *             If an error occurred while reading from the stream.
123         */
124        private synchronized Image loadImage(InputStream stream) throws IOException {
125            Toolkit toolkit = Toolkit.getDefaultToolkit();
126            byte data[] = FileCopyUtils.copyToByteArray(stream);
127    
128            Image image = toolkit.createImage(data);
129            imageLoaded = false;
130            imageError = false;
131            // fully loads the image into memory
132            toolkit.prepareImage(image, -1, -1, this);
133            while (!imageLoaded && !imageError) {
134                try {
135                    wait();
136                }
137                catch (InterruptedException ex) {
138                }
139            }
140            if (imageError) {
141                throw new IOException("Error preparing image from resource.");
142            }
143            return image;
144        }
145    
146        public synchronized boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) {
147            if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) {
148                imageLoaded = true;
149                notifyAll();
150            }
151            else {
152                if ((infoflags & ERROR) != 0) {
153                    imageError = true;
154                    notifyAll();
155                }
156            }
157            return true;
158        }
159    
160        public boolean equals(Object o) {
161            if (!(o instanceof AwtImageResource)) {
162                return false;
163            }
164            AwtImageResource r = (AwtImageResource)o;
165            return wrappedResource.equals(r.wrappedResource);
166        }
167    
168        public int hashCode() {
169            return wrappedResource.hashCode();
170        }
171    }