001/* Image display component.
002
003 @Copyright (c) 1998-2015 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.media;
029
030import static java.awt.RenderingHints.KEY_ANTIALIASING;
031import static java.awt.RenderingHints.KEY_RENDERING;
032import static java.awt.RenderingHints.VALUE_ANTIALIAS_OFF;
033import static java.awt.RenderingHints.VALUE_RENDER_SPEED;
034
035import java.awt.Dimension;
036import java.awt.Graphics;
037import java.awt.Graphics2D;
038import java.awt.Image;
039import java.awt.image.ColorModel;
040import java.awt.image.MemoryImageSource;
041
042import javax.swing.JPanel;
043
044///////////////////////////////////////////////////////////////////
045//// Picture
046
047/** A component that displays an image.  The image can be updated
048 in real time to create videos.  It can be monochrome or color.
049 To use it, simply create it, populate it with pixels using one or more
050 of the set methods, and call displayImage().
051
052 @author Edward A. Lee
053 @version $Id$
054 @since Ptolemy II 0.2
055 @Pt.ProposedRating Red (eal)
056 @Pt.AcceptedRating Red (cxh)
057 */
058@SuppressWarnings("serial")
059public class Picture extends JPanel {
060    /** Create an image with the specified width and height, in pixels.
061     *  @param width The width in pixels.
062     *  @param height The height in pixels.
063     */
064    public Picture(int width, int height) {
065        _width = width;
066        _height = height;
067        _pixels = new int[_width * _height];
068        setSize(width, height);
069    }
070
071    /** Return the preferred size.
072     *  @return The size of the image.
073     */
074    @Override
075    public Dimension getPreferredSize() {
076        return new Dimension(_width, _height);
077    }
078
079    /** Return the minimum size.
080     *  @return The size of the image.
081     */
082    @Override
083    public Dimension getMinimumSize() {
084        return new Dimension(_width, _height);
085    }
086
087    /** Return the maximum size.
088     *  @return The size of the image.
089     */
090    @Override
091    public Dimension getMaximumSize() {
092        return new Dimension(_width, _height);
093    }
094
095    /** Notify this picture that its image has been changed and that it is
096     *  now OK to display the new image.
097     */
098    public void displayImage() {
099        if (_imageSource == null && _image == null) {
100            _imageSource = new MemoryImageSource(_width, _height,
101                    ColorModel.getRGBdefault(), _pixels, 0, _width);
102            _imageSource.setAnimated(true);
103            _image = createImage(_imageSource);
104        }
105
106        if (_imageSource != null) {
107            _imageSource.newPixels();
108        }
109    }
110
111    /** Paint this component.  If no pixels have been set, do nothing.
112     *  @param graphics The graphics context.
113     */
114    @Override
115    public synchronized void paint(Graphics graphics) {
116        if (_image != null) {
117            ((Graphics2D) graphics).setRenderingHint(KEY_ANTIALIASING,
118                    VALUE_ANTIALIAS_OFF);
119            ((Graphics2D) graphics).setRenderingHint(KEY_RENDERING,
120                    VALUE_RENDER_SPEED);
121            graphics.drawImage(_image, 0, 0, this);
122        }
123    }
124
125    /** Specify the java.awt.Image representation of the image.
126     *  @param image A java.awt.Image object
127     *  @exception IllegalArgumentException If the image size does not
128     */
129    public void setImage(Image image) throws IllegalArgumentException {
130        _image = image;
131    }
132
133    /** Specify the packed ARGB representation of the image.
134     *  Each pixel is a 32-bit integer where the top 8 bits give alpha
135     *  (the transparency), then next 8 bits give the red value,
136     *  the next 8 bits the green value, and the bottom 8 bits give
137     *  the blue value.  The pixels are assembled into a single
138     *  one-dimensional array that contains the first row followed by
139     *  the second row, etc.  So the size of the array is the product
140     *  of the width and the height of the image.  An element in the
141     *  array might be set using a statement like:
142     *  <pre>
143     *    pix[row*col] = (alpha &lt;&lt; 24) | (red &lt;&lt; 16) | (green &lt;&lt; 8) | blue;
144     *  </pre>
145     *
146     *  @param pixels The packed ARGB representation of the image.
147     *  @exception IllegalArgumentException If the image size does not
148     *   match.
149     */
150    public void setImage(int[] pixels) throws IllegalArgumentException {
151        if (pixels.length != _width * _height) {
152            throw new IllegalArgumentException(
153                    "setImage: Specified image size does not"
154                            + "match that of the component.");
155        }
156
157        _pixels = pixels;
158
159        if (_imageSource != null) {
160            _imageSource.newPixels(pixels, ColorModel.getRGBdefault(), 0,
161                    _width);
162        }
163    }
164
165    /** Set the specified pixel to the given monochrome value, which
166     *  should be in the range from zero (black) to 255 (white). If the
167     *  argument is outside this range, then either white or black will
168     *  be displayed, depending on the sign of the argument.
169     *  If the row and column are out of bounds, then the command
170     *  is ignored.
171     *
172     *  @param row The index of the row for the pixel.
173     *  @param col The index of the column for the pixel.
174     *  @param intensity The value of the pixel.
175     */
176    public void setPixel(int row, int col, int intensity) {
177        if (row < 0 || row >= _height || col < 0 || col >= _width) {
178            return;
179        }
180
181        if (intensity < 0) {
182            intensity = 0;
183        } else if (intensity > 255) {
184            intensity = 255;
185        }
186
187        // Alpha, red, green, blue, where alpha controls transparency.
188        _pixels[row * _width + col] = 255 << 24 | intensity << 16
189                | intensity << 8 | intensity;
190    }
191
192    /** Set the specified pixel to the given color value, where each color
193     *  argument should be in the range from zero (absent) to 255 (fully
194     *  saturated). If an argument is outside this range, then the nearest
195     *  extreme of the range will be displayed.
196     *  If the row and column are out of bounds, then the command
197     *  is ignored.
198     *
199     *  @param row The index of the row for the pixel.
200     *  @param col The index of the column for the pixel.
201     *  @param red The red value of the pixel.
202     *  @param green The green value of the pixel.
203     *  @param blue The blue value of the pixel.
204     */
205    public void setPixel(int row, int col, int red, int green, int blue) {
206        if (row < 0 || row >= _height || col < 0 || col >= _width) {
207            return;
208        }
209
210        if (red < 0) {
211            red = 0;
212        } else if (red > 255) {
213            red = 255;
214        }
215
216        if (green < 0) {
217            green = 0;
218        } else if (green > 255) {
219            green = 255;
220        }
221
222        if (blue < 0) {
223            blue = 0;
224        } else if (blue > 255) {
225            blue = 255;
226        }
227
228        // Alpha, red, green, blue, where alpha controls transparency.
229        _pixels[row * _width + col] = 255 << 24 | red << 16 | green << 8 | blue;
230    }
231
232    /** Override the base class to prevent blanking, which causes flashing
233     *  of the display.
234     *  @param graphics The graphics context.
235     */
236    @Override
237    public void update(Graphics graphics) {
238        paint(graphics);
239    }
240
241    ///////////////////////////////////////////////////////////////////
242    ////                         private variables                 ////
243    private int _width;
244
245    ///////////////////////////////////////////////////////////////////
246    ////                         private variables                 ////
247    private int _height;
248
249    private int[] _pixels;
250
251    private Image _image;
252
253    private MemoryImageSource _imageSource;
254}