001/* An actor that converts an AWTImage to a base-64 encoded String.
002
003 @Copyright (c) 2003-2018 The Regents of the University of California.
004 All rights reserved.
005
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the
009 above copyright notice and the following two paragraphs appear in all
010 copies of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION 2
026 COPYRIGHTENDKEY
027 */
028package ptolemy.actor.lib.conversions;
029
030import java.awt.Graphics2D;
031import java.awt.Image;
032import java.awt.image.BufferedImage;
033import java.awt.image.RenderedImage;
034import java.io.ByteArrayOutputStream;
035import java.io.IOException;
036import java.io.OutputStream;
037import java.nio.charset.StandardCharsets;
038import java.util.Base64;
039
040import javax.imageio.ImageIO;
041
042import ptolemy.data.AWTImageToken;
043import ptolemy.data.StringToken;
044import ptolemy.data.expr.StringParameter;
045import ptolemy.data.type.BaseType;
046import ptolemy.kernel.CompositeEntity;
047import ptolemy.kernel.util.IllegalActionException;
048import ptolemy.kernel.util.NameDuplicationException;
049
050///////////////////////////////////////////////////////////////////
051//// ImageToBase64
052
053/**
054 Convert an AWT Image to a base-64 String.
055
056 @author Marten Lohstroh
057 @version $Id$
058 @since Ptolemy II 11.0
059 @Pt.ProposedRating Red (liuj)
060 @Pt.AcceptedRating Red (liuj)
061 */
062public class ImageToString extends Converter {
063
064    /** Construct an actor with the given container and name.
065     *  @param container The container.
066     *  @param name The name of this actor.
067     *  @exception IllegalActionException If the actor cannot be contained
068     *   by the proposed container.
069     *  @exception NameDuplicationException If the container already has an
070     *   actor with this name.
071     */
072    public ImageToString(CompositeEntity container, String name)
073            throws IllegalActionException, NameDuplicationException {
074        super(container, name);
075
076        // Set the type of the input port.
077        input.setTypeEquals(BaseType.GENERAL); // FIXME: No image type available...
078        input.setMultiport(false);
079        // Set the type of the output port.
080        output.setTypeEquals(BaseType.STRING);
081        output.setMultiport(false);
082
083        compression = new StringParameter(this, "compression");
084        compression.setExpression("png");
085    }
086
087    ///////////////////////////////////////////////////////////////////
088    ////                     ports and parameters                  ////
089
090    /** Parameter that determines the encoding of the image ('gif',
091     * 'png', 'jpg').
092     */
093    public StringParameter compression;
094
095    ///////////////////////////////////////////////////////////////////
096    ////                         public methods                    ////
097
098    /**
099     *  @exception IllegalActionException If the conversion fails.
100     */
101    @Override
102    public void fire() throws IllegalActionException {
103        super.fire();
104        final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
105        Object inputValue = input.get(0);
106        if (!(inputValue instanceof AWTImageToken)) {
107            throw new IllegalActionException(this,
108                    "The input value \"" + inputValue
109                            + "\" is not an AWTImageToken, " + "it is a "
110                            + inputValue.getClass());
111        } else {
112            RenderedImage image = getRenderedImage(
113                    ((AWTImageToken) inputValue).getValue());
114            try {
115                OutputStream encodedStream = Base64.getUrlEncoder()
116                        .wrap(outputStream);
117                ImageIO.write(image, "png", encodedStream); // FIXME: Use parameter instead.
118                encodedStream.close(); // Important, flushes the output buffer.
119                StringToken result = new StringToken(outputStream
120                        .toString(StandardCharsets.US_ASCII.name()));
121                output.send(0, result);
122            } catch (final IOException ioe) {
123                throw new IllegalActionException(this, ioe,
124                        "Unable to convert image to base-64 string.");
125            }
126        }
127    }
128
129    /** Return false if the input port has no token, otherwise return
130     *  what the superclass returns (presumably true).
131     *  @exception IllegalActionException If there is no director.
132     */
133    @Override
134    public boolean prefire() throws IllegalActionException {
135        if (!input.hasToken(0)) {
136            return false;
137        }
138
139        return super.prefire();
140    }
141
142    ///////////////////////////////////////////////////////////////////
143    ////                         private members                   ////
144
145    /** Convert an AWT Image object to a BufferedImage.
146     *  @param in An AWT Image object.
147     *  @return a BufferedImage.
148     */
149    private BufferedImage getRenderedImage(Image in) {
150        BufferedImage out = new BufferedImage(in.getWidth(null),
151                in.getHeight(null), BufferedImage.TYPE_INT_RGB);
152        Graphics2D g2 = out.createGraphics();
153        g2.drawImage(in, 0, 0, null);
154        g2.dispose();
155        return out;
156    }
157
158}