001/* An actor that reads an image from a FileParameter and outputs
002 an AWTImageToken.
003
004 @Copyright (c) 2001-2017 The Regents of the University of California.
005 All rights reserved.
006
007 Permission is hereby granted, without written agreement and without
008 license or royalty fees, to use, copy, modify, and distribute this
009 software and its documentation for any purpose, provided that the
010 above copyright notice and the following two paragraphs appear in all
011 copies of this software.
012
013 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
014 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
015 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
016 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
017 SUCH DAMAGE.
018
019 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
020 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
021 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
022 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
023 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
024 ENHANCEMENTS, OR MODIFICATIONS.
025
026 PT_COPYRIGHT_VERSION 2
027 COPYRIGHTENDKEY
028 */
029package ptolemy.actor.lib.image;
030
031import java.awt.Image;
032import java.io.IOException;
033import java.net.URL;
034
035import javax.imageio.ImageIO;
036
037import ptolemy.actor.lib.Source;
038import ptolemy.data.AWTImageToken;
039import ptolemy.data.expr.FileParameter;
040import ptolemy.data.type.BaseType;
041import ptolemy.kernel.CompositeEntity;
042import ptolemy.kernel.util.Attribute;
043import ptolemy.kernel.util.IllegalActionException;
044import ptolemy.kernel.util.NameDuplicationException;
045import ptolemy.util.FileUtilities;
046
047///////////////////////////////////////////////////////////////////
048//// ImageReader
049
050/**
051 <p>This actor reads an Image from a FileParameter, and outputs it as an
052 AWTImageToken.</p>
053
054 <p>FIXME: It would be nice if we could read images from stdin.</p>
055
056 @see FileParameter
057 @see AWTImageToken
058 @author  Christopher Hylands
059 @version $Id$
060 @since Ptolemy II 3.0
061 @Pt.ProposedRating Red (cxh)
062 @Pt.AcceptedRating Red (cxh)
063 */
064public class ImageReader extends Source {
065    // We don't extend ptolemy.actor.lib.Reader because we are not
066    // reading in data by columns.  Probably this class and
067    // ptolemy.actor.lib.Reader should extend a common base class?
068
069    /** Construct an actor with the given container and name.
070     *  @param container The container.
071     *  @param name The name of this actor.
072     *  @exception IllegalActionException If the actor cannot be contained
073     *   by the proposed container.
074     *  @exception NameDuplicationException If the container already has an
075     *   actor with this name.
076     */
077    public ImageReader(CompositeEntity container, String name)
078            throws IllegalActionException, NameDuplicationException {
079        super(container, name);
080
081        // Set the type of the output port.
082        //output.setMultiport(true);
083        output.setTypeEquals(BaseType.OBJECT);
084
085        fileOrURL = new FileParameter(this, "fileOrURL");
086    }
087
088    ///////////////////////////////////////////////////////////////////
089    ////                     ports and parameters                  ////
090
091    /** The file name or URL from which to read.  This is a string with
092     *  any form accepted by File Attribute.
093     *  @see FileParameter
094     */
095    public FileParameter fileOrURL;
096
097    ///////////////////////////////////////////////////////////////////
098    ////                         public methods                    ////
099
100    /** If the specified attribute is <i>URL</i>, then close
101     *  the current file (if there is one) and open the new one.
102     *  @param attribute The attribute that has changed.
103     *  @exception IllegalActionException If the specified attribute
104     *   is <i>URL</i> and the file cannot be opened.
105     */
106    @Override
107    public void attributeChanged(Attribute attribute)
108            throws IllegalActionException {
109        if (attribute == fileOrURL) {
110            // Would it be worth checking to see if the URL exists and
111            // is readable?
112            _url = fileOrURL.asURL();
113        }
114
115        super.attributeChanged(attribute);
116    }
117
118    /** Output the data read in the prefire.
119     *  @exception IllegalActionException If there's no director.
120     */
121    @Override
122    public void fire() throws IllegalActionException {
123        super.fire();
124        output.broadcast(new AWTImageToken(_image));
125    }
126
127    /** Open the file at the URL, and set the width of the output.
128     */
129    @Override
130    public void initialize() throws IllegalActionException {
131        super.initialize();
132        attributeChanged(fileOrURL);
133    }
134
135    /** Read in an image.
136     *  @exception IllegalActionException If an IO error occurs.
137     */
138    @Override
139    public boolean prefire() throws IllegalActionException {
140        if (!super.prefire()) {
141            return false;
142        }
143        if (_url == null) {
144            throw new IllegalActionException("sourceURL was null");
145        }
146
147        try {
148            _image = ImageIO.read(FileUtilities.followRedirects(_url));
149        } catch (IOException e) {
150            throw new IllegalActionException(this, e, "Failed to read image.");
151        }
152
153        // Coverity Scan: ImageIO.read() can return null.
154        if (_image != null && _image.getWidth(null) == -1
155                && _image.getHeight(null) == -1) {
156            throw new IllegalActionException(this,
157                    "Image size is -1 x -1.  Failed to open '" + _url + "'");
158        }
159
160        return super.prefire();
161    }
162
163    // Image that is read in.
164    private Image _image;
165
166    // The URL of the file.
167    private URL _url;
168}