Path: blob/master/src/java.desktop/share/classes/javax/swing/ImageIcon.java
41153 views
/*1* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.swing;2627import java.awt.Component;28import java.awt.Graphics;29import java.awt.IllegalComponentStateException;30import java.awt.Image;31import java.awt.MediaTracker;32import java.awt.Toolkit;33import java.awt.image.ColorModel;34import java.awt.image.ImageObserver;35import java.awt.image.MemoryImageSource;36import java.awt.image.PixelGrabber;37import java.beans.BeanProperty;38import java.beans.ConstructorProperties;39import java.beans.Transient;40import java.io.IOException;41import java.io.ObjectInputStream;42import java.io.ObjectOutputStream;43import java.io.Serial;44import java.io.Serializable;45import java.net.URL;46import java.security.AccessControlContext;47import java.security.AccessController;48import java.security.PrivilegedAction;49import java.security.ProtectionDomain;50import java.util.Locale;5152import javax.accessibility.Accessible;53import javax.accessibility.AccessibleContext;54import javax.accessibility.AccessibleIcon;55import javax.accessibility.AccessibleRole;56import javax.accessibility.AccessibleState;57import javax.accessibility.AccessibleStateSet;5859import sun.awt.AWTAccessor;60import sun.awt.AppContext;6162/**63* An implementation of the Icon interface that paints Icons64* from Images. Images that are created from a URL, filename or byte array65* are preloaded using MediaTracker to monitor the loaded state66* of the image.67*68* <p>69* For further information and examples of using image icons, see70* <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/icon.html">How to Use Icons</a>71* in <em>The Java Tutorial.</em>72*73* <p>74* <strong>Warning:</strong>75* Serialized objects of this class will not be compatible with76* future Swing releases. The current serialization support is77* appropriate for short term storage or RMI between applications running78* the same version of Swing. As of 1.4, support for long term storage79* of all JavaBeans80* has been added to the <code>java.beans</code> package.81* Please see {@link java.beans.XMLEncoder}.82*83* @author Jeff Dinkins84* @author Lynn Monsanto85* @since 1.286*/87@SuppressWarnings({"removal","serial"}) // Same-version serialization only88public class ImageIcon implements Icon, Serializable, Accessible {89/* Keep references to the filename and location so that90* alternate persistence schemes have the option to archive91* images symbolically rather than including the image data92* in the archive.93*/94private transient String filename;95private transient URL location;9697transient Image image;98transient int loadStatus = 0;99ImageObserver imageObserver;100String description = null;101102/**103* Do not use this shared component, which is used to track image loading.104* It is left for backward compatibility only.105* @deprecated since 1.8106*/107@Deprecated108protected static final Component component;109110/**111* Do not use this shared media tracker, which is used to load images.112* It is left for backward compatibility only.113* @deprecated since 1.8114*/115@Deprecated116protected static final MediaTracker tracker;117118static {119component = AccessController.doPrivileged(new PrivilegedAction<Component>() {120public Component run() {121try {122final Component component = createNoPermsComponent();123124// 6482575 - clear the appContext field so as not to leak it125AWTAccessor.getComponentAccessor().126setAppContext(component, null);127128return component;129} catch (Throwable e) {130// We don't care about component.131// So don't prevent class initialisation.132e.printStackTrace();133return null;134}135}136});137tracker = new MediaTracker(component);138}139140private static Component createNoPermsComponent() {141// 7020198 - set acc field to no permissions and no subject142// Note, will have appContext set.143return AccessController.doPrivileged(144new PrivilegedAction<Component>() {145public Component run() {146return new Component() {147};148}149},150new AccessControlContext(new ProtectionDomain[]{151new ProtectionDomain(null, null)152})153);154}155156/**157* Id used in loading images from MediaTracker.158*/159private static int mediaTrackerID;160161private static final Object TRACKER_KEY = new StringBuilder("TRACKER_KEY");162163int width = -1;164int height = -1;165166/**167* Creates an ImageIcon from the specified file. The image will168* be preloaded by using MediaTracker to monitor the loading state169* of the image.170* @param filename the name of the file containing the image171* @param description a brief textual description of the image172* @see #ImageIcon(String)173*/174public ImageIcon(String filename, String description) {175image = Toolkit.getDefaultToolkit().getImage(filename);176if (image == null) {177return;178}179this.filename = filename;180this.description = description;181loadImage(image);182}183184/**185* Creates an ImageIcon from the specified file. The image will186* be preloaded by using MediaTracker to monitor the loading state187* of the image. The specified String can be a file name or a188* file path. When specifying a path, use the Internet-standard189* forward-slash ("/") as a separator.190* (The string is converted to an URL, so the forward-slash works191* on all systems.)192* For example, specify:193* <pre>194* new ImageIcon("images/myImage.gif") </pre>195* The description is initialized to the <code>filename</code> string.196*197* @param filename a String specifying a filename or path198* @see #getDescription199*/200@ConstructorProperties({"description"})201public ImageIcon (String filename) {202this(filename, filename);203}204205/**206* Creates an ImageIcon from the specified URL. The image will207* be preloaded by using MediaTracker to monitor the loaded state208* of the image.209* @param location the URL for the image210* @param description a brief textual description of the image211* @see #ImageIcon(String)212*/213public ImageIcon(URL location, String description) {214image = Toolkit.getDefaultToolkit().getImage(location);215if (image == null) {216return;217}218this.location = location;219this.description = description;220loadImage(image);221}222223/**224* Creates an ImageIcon from the specified URL. The image will225* be preloaded by using MediaTracker to monitor the loaded state226* of the image.227* The icon's description is initialized to be228* a string representation of the URL.229* @param location the URL for the image230* @see #getDescription231*/232public ImageIcon (URL location) {233this(location, location.toExternalForm());234}235236/**237* Creates an ImageIcon from the image.238* @param image the image239* @param description a brief textual description of the image240*/241public ImageIcon(Image image, String description) {242this(image);243this.description = description;244}245246/**247* Creates an ImageIcon from an image object.248* If the image has a "comment" property that is a string,249* then the string is used as the description of this icon.250* @param image the image251* @see #getDescription252* @see java.awt.Image#getProperty253*/254public ImageIcon (Image image) {255this.image = image;256Object o = image.getProperty("comment", imageObserver);257if (o instanceof String) {258description = (String) o;259}260loadImage(image);261}262263/**264* Creates an ImageIcon from an array of bytes which were265* read from an image file containing a supported image format,266* such as GIF, JPEG, or (as of 1.3) PNG.267* Normally this array is created268* by reading an image using Class.getResourceAsStream(), but269* the byte array may also be statically stored in a class.270*271* @param imageData an array of pixels in an image format supported272* by the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG273* @param description a brief textual description of the image274* @see java.awt.Toolkit#createImage275*/276public ImageIcon (byte[] imageData, String description) {277this.image = Toolkit.getDefaultToolkit().createImage(imageData);278if (image == null) {279return;280}281this.description = description;282loadImage(image);283}284285/**286* Creates an ImageIcon from an array of bytes which were287* read from an image file containing a supported image format,288* such as GIF, JPEG, or (as of 1.3) PNG.289* Normally this array is created290* by reading an image using Class.getResourceAsStream(), but291* the byte array may also be statically stored in a class.292* If the resulting image has a "comment" property that is a string,293* then the string is used as the description of this icon.294*295* @param imageData an array of pixels in an image format supported by296* the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG297* @see java.awt.Toolkit#createImage298* @see #getDescription299* @see java.awt.Image#getProperty300*/301public ImageIcon (byte[] imageData) {302this.image = Toolkit.getDefaultToolkit().createImage(imageData);303if (image == null) {304return;305}306Object o = image.getProperty("comment", imageObserver);307if (o instanceof String) {308description = (String) o;309}310loadImage(image);311}312313/**314* Creates an uninitialized image icon.315*/316public ImageIcon() {317}318319/**320* Loads the image, returning only when the image is loaded.321* @param image the image322*/323protected void loadImage(Image image) {324MediaTracker mTracker = getTracker();325synchronized(mTracker) {326int id = getNextID();327328mTracker.addImage(image, id);329try {330mTracker.waitForID(id, 0);331} catch (InterruptedException e) {332System.out.println("INTERRUPTED while loading Image");333}334loadStatus = mTracker.statusID(id, false);335mTracker.removeImage(image, id);336337width = image.getWidth(imageObserver);338height = image.getHeight(imageObserver);339}340}341342/**343* Returns an ID to use with the MediaTracker in loading an image.344*/345private int getNextID() {346synchronized(getTracker()) {347return ++mediaTrackerID;348}349}350351/**352* Returns the MediaTracker for the current AppContext, creating a new353* MediaTracker if necessary.354*/355private MediaTracker getTracker() {356Object trackerObj;357AppContext ac = AppContext.getAppContext();358// Opt: Only synchronize if trackerObj comes back null?359// If null, synchronize, re-check for null, and put new tracker360synchronized(ac) {361trackerObj = ac.get(TRACKER_KEY);362if (trackerObj == null) {363Component comp = new Component() {};364trackerObj = new MediaTracker(comp);365ac.put(TRACKER_KEY, trackerObj);366}367}368return (MediaTracker) trackerObj;369}370371/**372* Returns the status of the image loading operation.373* @return the loading status as defined by java.awt.MediaTracker374* @see java.awt.MediaTracker#ABORTED375* @see java.awt.MediaTracker#ERRORED376* @see java.awt.MediaTracker#COMPLETE377*/378public int getImageLoadStatus() {379return loadStatus;380}381382/**383* Returns this icon's <code>Image</code>.384* @return the <code>Image</code> object for this <code>ImageIcon</code>385*/386@Transient387public Image getImage() {388return image;389}390391/**392* Sets the image displayed by this icon.393* @param image the image394*/395public void setImage(Image image) {396this.image = image;397loadImage(image);398}399400/**401* Gets the description of the image. This is meant to be a brief402* textual description of the object. For example, it might be403* presented to a blind user to give an indication of the purpose404* of the image.405* The description may be null.406*407* @return a brief textual description of the image408*/409public String getDescription() {410return description;411}412413/**414* Sets the description of the image. This is meant to be a brief415* textual description of the object. For example, it might be416* presented to a blind user to give an indication of the purpose417* of the image.418* @param description a brief textual description of the image419*/420public void setDescription(String description) {421this.description = description;422}423424/**425* Paints the icon.426* The top-left corner of the icon is drawn at427* the point (<code>x</code>, <code>y</code>)428* in the coordinate space of the graphics context <code>g</code>.429* If this icon has no image observer,430* this method uses the <code>c</code> component431* as the observer.432*433* @param c the component to be used as the observer434* if this icon has no image observer435* @param g the graphics context436* @param x the X coordinate of the icon's top-left corner437* @param y the Y coordinate of the icon's top-left corner438*/439public synchronized void paintIcon(Component c, Graphics g, int x, int y) {440if(imageObserver == null) {441g.drawImage(image, x, y, c);442} else {443g.drawImage(image, x, y, imageObserver);444}445}446447/**448* Gets the width of the icon.449*450* @return the width in pixels of this icon451*/452public int getIconWidth() {453return width;454}455456/**457* Gets the height of the icon.458*459* @return the height in pixels of this icon460*/461public int getIconHeight() {462return height;463}464465/**466* Sets the image observer for the image. Set this467* property if the ImageIcon contains an animated GIF, so468* the observer is notified to update its display.469* For example:470* <pre>471* icon = new ImageIcon(...)472* button.setIcon(icon);473* icon.setImageObserver(button);474* </pre>475*476* @param observer the image observer477*/478public void setImageObserver(ImageObserver observer) {479imageObserver = observer;480}481482/**483* Returns the image observer for the image.484*485* @return the image observer, which may be null486*/487@Transient488public ImageObserver getImageObserver() {489return imageObserver;490}491492/**493* Returns a string representation of this image.494*495* @return a string representing this image496*/497public String toString() {498if (description != null) {499return description;500}501return super.toString();502}503504@Serial505private void readObject(ObjectInputStream s)506throws ClassNotFoundException, IOException507{508ObjectInputStream.GetField f = s.readFields();509510imageObserver = (ImageObserver) f.get("imageObserver", null);511description = (String) f.get("description", null);512width = f.get("width", -1);513height = f.get("height", -1);514accessibleContext = (AccessibleImageIcon) f.get("accessibleContext", null);515516int w = s.readInt();517int h = s.readInt();518int[] pixels = (int[])(s.readObject());519520if (pixels == null && (w != -1 || h != -1)) {521throw new IllegalStateException("Inconsistent width and height"522+ " for null image [" + w + ", " + h + "]");523}524525if (pixels != null && (w < 0 || h < 0)) {526throw new IllegalStateException("Inconsistent width and height"527+ " for image [" + w + ", " + h + "]");528}529530if (w != getIconWidth() || h != getIconHeight()) {531throw new IllegalStateException("Inconsistent width and height"532+ " for image [" + w + ", " + h + "]");533}534535if (pixels != null) {536Toolkit tk = Toolkit.getDefaultToolkit();537ColorModel cm = ColorModel.getRGBdefault();538image = tk.createImage(new MemoryImageSource(w, h, cm, pixels, 0, w));539loadImage(image);540}541}542543544@Serial545private void writeObject(ObjectOutputStream s)546throws IOException547{548s.defaultWriteObject();549550int w = getIconWidth();551int h = getIconHeight();552int[] pixels = image != null? new int[w * h] : null;553554if (image != null) {555try {556PixelGrabber pg = new PixelGrabber(image, 0, 0, w, h, pixels, 0, w);557pg.grabPixels();558if ((pg.getStatus() & ImageObserver.ABORT) != 0) {559throw new IOException("failed to load image contents");560}561}562catch (InterruptedException e) {563throw new IOException("image load interrupted");564}565}566567s.writeInt(w);568s.writeInt(h);569s.writeObject(pixels);570}571572/**573* --- Accessibility Support ---574*/575576private AccessibleImageIcon accessibleContext = null;577578/**579* Gets the AccessibleContext associated with this ImageIcon.580* For image icons, the AccessibleContext takes the form of an581* AccessibleImageIcon.582* A new AccessibleImageIcon instance is created if necessary.583*584* @return an AccessibleImageIcon that serves as the585* AccessibleContext of this ImageIcon586* @since 1.3587*/588@BeanProperty(expert = true, description589= "The AccessibleContext associated with this ImageIcon.")590public AccessibleContext getAccessibleContext() {591if (accessibleContext == null) {592accessibleContext = new AccessibleImageIcon();593}594return accessibleContext;595}596597/**598* This class implements accessibility support for the599* <code>ImageIcon</code> class. It provides an implementation of the600* Java Accessibility API appropriate to image icon user-interface601* elements.602* <p>603* <strong>Warning:</strong>604* Serialized objects of this class will not be compatible with605* future Swing releases. The current serialization support is606* appropriate for short term storage or RMI between applications running607* the same version of Swing. As of 1.4, support for long term storage608* of all JavaBeans609* has been added to the <code>java.beans</code> package.610* Please see {@link java.beans.XMLEncoder}.611* @since 1.3612*/613@SuppressWarnings("serial") // Same-version serialization only614protected class AccessibleImageIcon extends AccessibleContext615implements AccessibleIcon, Serializable {616617/**618* Constructs an {@code AccessibleImageIcon}.619*/620protected AccessibleImageIcon() {}621622/*623* AccessibleContest implementation -----------------624*/625626/**627* Gets the role of this object.628*629* @return an instance of AccessibleRole describing the role of the630* object631* @see AccessibleRole632*/633public AccessibleRole getAccessibleRole() {634return AccessibleRole.ICON;635}636637/**638* Gets the state of this object.639*640* @return an instance of AccessibleStateSet containing the current641* state set of the object642* @see AccessibleState643*/644public AccessibleStateSet getAccessibleStateSet() {645return null;646}647648/**649* Gets the Accessible parent of this object. If the parent of this650* object implements Accessible, this method should simply return651* getParent().652*653* @return the Accessible parent of this object -- can be null if this654* object does not have an Accessible parent655*/656public Accessible getAccessibleParent() {657return null;658}659660/**661* Gets the index of this object in its accessible parent.662*663* @return the index of this object in its parent; -1 if this664* object does not have an accessible parent.665* @see #getAccessibleParent666*/667public int getAccessibleIndexInParent() {668return -1;669}670671/**672* Returns the number of accessible children in the object. If all673* of the children of this object implement Accessible, than this674* method should return the number of children of this object.675*676* @return the number of accessible children in the object.677*/678public int getAccessibleChildrenCount() {679return 0;680}681682/**683* Returns the nth Accessible child of the object.684*685* @param i zero-based index of child686* @return the nth Accessible child of the object687*/688public Accessible getAccessibleChild(int i) {689return null;690}691692/**693* Returns the locale of this object.694*695* @return the locale of this object696*/697public Locale getLocale() throws IllegalComponentStateException {698return null;699}700701/*702* AccessibleIcon implementation -----------------703*/704705/**706* Gets the description of the icon. This is meant to be a brief707* textual description of the object. For example, it might be708* presented to a blind user to give an indication of the purpose709* of the icon.710*711* @return the description of the icon712*/713public String getAccessibleIconDescription() {714return ImageIcon.this.getDescription();715}716717/**718* Sets the description of the icon. This is meant to be a brief719* textual description of the object. For example, it might be720* presented to a blind user to give an indication of the purpose721* of the icon.722*723* @param description the description of the icon724*/725public void setAccessibleIconDescription(String description) {726ImageIcon.this.setDescription(description);727}728729/**730* Gets the height of the icon.731*732* @return the height of the icon733*/734public int getAccessibleIconHeight() {735return ImageIcon.this.height;736}737738/**739* Gets the width of the icon.740*741* @return the width of the icon742*/743public int getAccessibleIconWidth() {744return ImageIcon.this.width;745}746747@Serial748private void readObject(ObjectInputStream s)749throws ClassNotFoundException, IOException750{751s.defaultReadObject();752}753754@Serial755private void writeObject(ObjectOutputStream s)756throws IOException757{758s.defaultWriteObject();759}760} // AccessibleImageIcon761}762763764