1. /*
  2. * @(#)ImageIcon.java 1.53 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.awt.*;
  9. import java.awt.image.*;
  10. import java.net.URL;
  11. import java.io.Serializable;
  12. import java.io.ObjectOutputStream;
  13. import java.io.ObjectInputStream;
  14. import java.io.IOException;
  15. import java.util.Locale;
  16. import javax.accessibility.*;
  17. /**
  18. * An implementation of the Icon interface that paints Icons
  19. * from Images. Images that are created from a URL, filename or byte array
  20. * are preloaded using MediaTracker to monitor the loaded state
  21. * of the image.
  22. *
  23. * <p>
  24. * For further information and examples of using image icons, see
  25. * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/icon.html">How to Use Icons</a>
  26. * in <em>The Java Tutorial.</em>
  27. *
  28. * <p>
  29. * <strong>Warning:</strong>
  30. * Serialized objects of this class will not be compatible with
  31. * future Swing releases. The current serialization support is
  32. * appropriate for short term storage or RMI between applications running
  33. * the same version of Swing. As of 1.4, support for long term storage
  34. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  35. * has been added to the <code>java.beans</code> package.
  36. * Please see {@link java.beans.XMLEncoder}.
  37. *
  38. * @version 1.53 12/19/03
  39. * @author Jeff Dinkins
  40. * @author Lynn Monsanto
  41. */
  42. public class ImageIcon implements Icon, Serializable, Accessible {
  43. /* Keep references to the filename and location so that
  44. * alternate persistence schemes have the option to archive
  45. * images symbolically rather than including the image data
  46. * in the archive.
  47. */
  48. transient private String filename;
  49. transient private URL location;
  50. transient Image image;
  51. transient int loadStatus = 0;
  52. ImageObserver imageObserver;
  53. String description = null;
  54. protected final static Component component = new Component() {};
  55. protected final static MediaTracker tracker = new MediaTracker(component);
  56. /**
  57. * Id used in loading images from MediaTracker.
  58. */
  59. private static int mediaTrackerID;
  60. int width = -1;
  61. int height = -1;
  62. /**
  63. * Creates an ImageIcon from the specified file. The image will
  64. * be preloaded by using MediaTracker to monitor the loading state
  65. * of the image.
  66. * @param filename the name of the file containing the image
  67. * @param description a brief textual description of the image
  68. * @see #ImageIcon(String)
  69. */
  70. public ImageIcon(String filename, String description) {
  71. image = Toolkit.getDefaultToolkit().getImage(filename);
  72. if (image == null) {
  73. return;
  74. }
  75. this.filename = filename;
  76. this.description = description;
  77. loadImage(image);
  78. }
  79. /**
  80. * Creates an ImageIcon from the specified file. The image will
  81. * be preloaded by using MediaTracker to monitor the loading state
  82. * of the image. The specified String can be a file name or a
  83. * file path. When specifying a path, use the Internet-standard
  84. * forward-slash ("/") as a separator.
  85. * (The string is converted to an URL, so the forward-slash works
  86. * on all systems.)
  87. * For example, specify:
  88. * <pre>
  89. * new ImageIcon("images/myImage.gif") </pre>
  90. * The description is initialized to the <code>filename</code> string.
  91. *
  92. * @param filename a String specifying a filename or path
  93. * @see #getDescription
  94. */
  95. public ImageIcon (String filename) {
  96. this(filename, filename);
  97. }
  98. /**
  99. * Creates an ImageIcon from the specified URL. The image will
  100. * be preloaded by using MediaTracker to monitor the loaded state
  101. * of the image.
  102. * @param location the URL for the image
  103. * @param description a brief textual description of the image
  104. * @see #ImageIcon(String)
  105. */
  106. public ImageIcon(URL location, String description) {
  107. image = Toolkit.getDefaultToolkit().getImage(location);
  108. if (image == null) {
  109. return;
  110. }
  111. this.location = location;
  112. this.description = description;
  113. loadImage(image);
  114. }
  115. /**
  116. * Creates an ImageIcon from the specified URL. The image will
  117. * be preloaded by using MediaTracker to monitor the loaded state
  118. * of the image.
  119. * The icon's description is initialized to be
  120. * a string representation of the URL.
  121. * @param location the URL for the image
  122. * @see #getDescription
  123. */
  124. public ImageIcon (URL location) {
  125. this(location, location.toExternalForm());
  126. }
  127. /**
  128. * Creates an ImageIcon from the image.
  129. * @param image the image
  130. * @param description a brief textual description of the image
  131. */
  132. public ImageIcon(Image image, String description) {
  133. this(image);
  134. this.description = description;
  135. }
  136. /**
  137. * Creates an ImageIcon from an image object.
  138. * If the image has a "comment" property that is a string,
  139. * then the string is used as the description of this icon.
  140. * @param image the image
  141. * @see #getDescription
  142. * @see java.awt.Image#getProperty
  143. */
  144. public ImageIcon (Image image) {
  145. this.image = image;
  146. Object o = image.getProperty("comment", imageObserver);
  147. if (o instanceof String) {
  148. description = (String) o;
  149. }
  150. loadImage(image);
  151. }
  152. /**
  153. * Creates an ImageIcon from an array of bytes which were
  154. * read from an image file containing a supported image format,
  155. * such as GIF, JPEG, or (as of 1.3) PNG.
  156. * Normally this array is created
  157. * by reading an image using Class.getResourceAsStream(), but
  158. * the byte array may also be statically stored in a class.
  159. *
  160. * @param imageData an array of pixels in an image format supported
  161. * by the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG
  162. * @param description a brief textual description of the image
  163. * @see java.awt.Toolkit#createImage
  164. */
  165. public ImageIcon (byte[] imageData, String description) {
  166. this.image = Toolkit.getDefaultToolkit().createImage(imageData);
  167. if (image == null) {
  168. return;
  169. }
  170. this.description = description;
  171. loadImage(image);
  172. }
  173. /**
  174. * Creates an ImageIcon from an array of bytes which were
  175. * read from an image file containing a supported image format,
  176. * such as GIF, JPEG, or (as of 1.3) PNG.
  177. * Normally this array is created
  178. * by reading an image using Class.getResourceAsStream(), but
  179. * the byte array may also be statically stored in a class.
  180. * If the resulting image has a "comment" property that is a string,
  181. * then the string is used as the description of this icon.
  182. *
  183. * @param imageData an array of pixels in an image format supported by
  184. * the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG
  185. * @see java.awt.Toolkit#createImage
  186. * @see #getDescription
  187. * @see java.awt.Image#getProperty
  188. */
  189. public ImageIcon (byte[] imageData) {
  190. this.image = Toolkit.getDefaultToolkit().createImage(imageData);
  191. if (image == null) {
  192. return;
  193. }
  194. Object o = image.getProperty("comment", imageObserver);
  195. if (o instanceof String) {
  196. description = (String) o;
  197. }
  198. loadImage(image);
  199. }
  200. /**
  201. * Creates an uninitialized image icon.
  202. */
  203. public ImageIcon() {
  204. }
  205. /**
  206. * Loads the image, returning only when the image is loaded.
  207. * @param image the image
  208. */
  209. protected void loadImage(Image image) {
  210. synchronized(tracker) {
  211. int id = getNextID();
  212. tracker.addImage(image, id);
  213. try {
  214. tracker.waitForID(id, 0);
  215. } catch (InterruptedException e) {
  216. System.out.println("INTERRUPTED while loading Image");
  217. }
  218. loadStatus = tracker.statusID(id, false);
  219. tracker.removeImage(image, id);
  220. width = image.getWidth(imageObserver);
  221. height = image.getHeight(imageObserver);
  222. }
  223. }
  224. /**
  225. * Returns an ID to use with the MediaTracker in loading an image.
  226. */
  227. private int getNextID() {
  228. synchronized(tracker) {
  229. return ++mediaTrackerID;
  230. }
  231. }
  232. /**
  233. * Returns the status of the image loading operation.
  234. * @return the loading status as defined by java.awt.MediaTracker
  235. * @see java.awt.MediaTracker#ABORTED
  236. * @see java.awt.MediaTracker#ERRORED
  237. * @see java.awt.MediaTracker#COMPLETE
  238. */
  239. public int getImageLoadStatus() {
  240. return loadStatus;
  241. }
  242. /**
  243. * Returns this icon's <code>Image</code>.
  244. * @return the <code>Image</code> object for this <code>ImageIcon</code>
  245. */
  246. public Image getImage() {
  247. return image;
  248. }
  249. /**
  250. * Sets the image displayed by this icon.
  251. * @param image the image
  252. */
  253. public void setImage(Image image) {
  254. this.image = image;
  255. loadImage(image);
  256. }
  257. /**
  258. * Gets the description of the image. This is meant to be a brief
  259. * textual description of the object. For example, it might be
  260. * presented to a blind user to give an indication of the purpose
  261. * of the image.
  262. * The description may be null.
  263. *
  264. * @return a brief textual description of the image
  265. */
  266. public String getDescription() {
  267. return description;
  268. }
  269. /**
  270. * Sets the description of the image. This is meant to be a brief
  271. * textual description of the object. For example, it might be
  272. * presented to a blind user to give an indication of the purpose
  273. * of the image.
  274. * @param description a brief textual description of the image
  275. */
  276. public void setDescription(String description) {
  277. this.description = description;
  278. }
  279. /**
  280. * Paints the icon.
  281. * The top-left corner of the icon is drawn at
  282. * the point (<code>x</code>, <code>y</code>)
  283. * in the coordinate space of the graphics context <code>g</code>.
  284. * If this icon has no image observer,
  285. * this method uses the <code>c</code> component
  286. * as the observer.
  287. *
  288. * @param c the component to be used as the observer
  289. * if this icon has no image observer
  290. * @param g the graphics context
  291. * @param x the X coordinate of the icon's top-left corner
  292. * @param y the Y coordinate of the icon's top-left corner
  293. */
  294. public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
  295. if(imageObserver == null) {
  296. g.drawImage(image, x, y, c);
  297. } else {
  298. g.drawImage(image, x, y, imageObserver);
  299. }
  300. }
  301. /**
  302. * Gets the width of the icon.
  303. *
  304. * @return the width in pixels of this icon
  305. */
  306. public int getIconWidth() {
  307. return width;
  308. }
  309. /**
  310. * Gets the height of the icon.
  311. *
  312. * @return the height in pixels of this icon
  313. */
  314. public int getIconHeight() {
  315. return height;
  316. }
  317. /**
  318. * Sets the image observer for the image. Set this
  319. * property if the ImageIcon contains an animated GIF, so
  320. * the observer is notified to update its display.
  321. * For example:
  322. * <pre>
  323. * icon = new ImageIcon(...)
  324. * button.setIcon(icon);
  325. * icon.setImageObserver(button);
  326. * </pre>
  327. *
  328. * @param observer the image observer
  329. */
  330. public void setImageObserver(ImageObserver observer) {
  331. imageObserver = observer;
  332. }
  333. /**
  334. * Returns the image observer for the image.
  335. *
  336. * @return the image observer, which may be null
  337. */
  338. public ImageObserver getImageObserver() {
  339. return imageObserver;
  340. }
  341. /**
  342. * Returns a string representation of this image.
  343. *
  344. * @return a string representing this image
  345. */
  346. public String toString() {
  347. if (description != null) {
  348. return description;
  349. }
  350. return super.toString();
  351. }
  352. private void readObject(ObjectInputStream s)
  353. throws ClassNotFoundException, IOException
  354. {
  355. s.defaultReadObject();
  356. int w = s.readInt();
  357. int h = s.readInt();
  358. int[] pixels = (int[])(s.readObject());
  359. if (pixels != null) {
  360. Toolkit tk = Toolkit.getDefaultToolkit();
  361. ColorModel cm = ColorModel.getRGBdefault();
  362. image = tk.createImage(new MemoryImageSource(w, h, cm, pixels, 0, w));
  363. loadImage(image);
  364. }
  365. }
  366. private void writeObject(ObjectOutputStream s)
  367. throws IOException
  368. {
  369. s.defaultWriteObject();
  370. int w = getIconWidth();
  371. int h = getIconHeight();
  372. int[] pixels = image != null? new int[w * h] : null;
  373. if (image != null) {
  374. try {
  375. PixelGrabber pg = new PixelGrabber(image, 0, 0, w, h, pixels, 0, w);
  376. pg.grabPixels();
  377. if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
  378. throw new IOException("failed to load image contents");
  379. }
  380. }
  381. catch (InterruptedException e) {
  382. throw new IOException("image load interrupted");
  383. }
  384. }
  385. s.writeInt(w);
  386. s.writeInt(h);
  387. s.writeObject(pixels);
  388. }
  389. /**
  390. * --- Accessibility Support ---
  391. */
  392. private AccessibleImageIcon accessibleContext = null;
  393. /**
  394. * Gets the AccessibleContext associated with this ImageIcon.
  395. * For image icons, the AccessibleContext takes the form of an
  396. * AccessibleImageIcon.
  397. * A new AccessibleImageIcon instance is created if necessary.
  398. *
  399. * @return an AccessibleImageIcon that serves as the
  400. * AccessibleContext of this ImageIcon
  401. * @beaninfo
  402. * expert: true
  403. * description: The AccessibleContext associated with this ImageIcon.
  404. */
  405. public AccessibleContext getAccessibleContext() {
  406. if (accessibleContext == null) {
  407. accessibleContext = new AccessibleImageIcon();
  408. }
  409. return accessibleContext;
  410. }
  411. /**
  412. * This class implements accessibility support for the
  413. * <code>ImageIcon</code> class. It provides an implementation of the
  414. * Java Accessibility API appropriate to image icon user-interface
  415. * elements.
  416. * <p>
  417. * <strong>Warning:</strong>
  418. * Serialized objects of this class will not be compatible with
  419. * future Swing releases. The current serialization support is
  420. * appropriate for short term storage or RMI between applications running
  421. * the same version of Swing. As of 1.4, support for long term storage
  422. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  423. * has been added to the <code>java.beans</code> package.
  424. * Please see {@link java.beans.XMLEncoder}.
  425. */
  426. protected class AccessibleImageIcon extends AccessibleContext
  427. implements AccessibleIcon, Serializable {
  428. /*
  429. * AccessibleContest implementation -----------------
  430. */
  431. /**
  432. * Gets the role of this object.
  433. *
  434. * @return an instance of AccessibleRole describing the role of the
  435. * object
  436. * @see AccessibleRole
  437. */
  438. public AccessibleRole getAccessibleRole() {
  439. return AccessibleRole.ICON;
  440. }
  441. /**
  442. * Gets the state of this object.
  443. *
  444. * @return an instance of AccessibleStateSet containing the current
  445. * state set of the object
  446. * @see AccessibleState
  447. */
  448. public AccessibleStateSet getAccessibleStateSet() {
  449. return null;
  450. }
  451. /**
  452. * Gets the Accessible parent of this object. If the parent of this
  453. * object implements Accessible, this method should simply return
  454. * getParent().
  455. *
  456. * @return the Accessible parent of this object -- can be null if this
  457. * object does not have an Accessible parent
  458. */
  459. public Accessible getAccessibleParent() {
  460. return null;
  461. }
  462. /**
  463. * Gets the index of this object in its accessible parent.
  464. *
  465. * @return the index of this object in its parent; -1 if this
  466. * object does not have an accessible parent.
  467. * @see #getAccessibleParent
  468. */
  469. public int getAccessibleIndexInParent() {
  470. return -1;
  471. }
  472. /**
  473. * Returns the number of accessible children in the object. If all
  474. * of the children of this object implement Accessible, than this
  475. * method should return the number of children of this object.
  476. *
  477. * @return the number of accessible children in the object.
  478. */
  479. public int getAccessibleChildrenCount() {
  480. return 0;
  481. }
  482. /**
  483. * Returns the nth Accessible child of the object.
  484. *
  485. * @param i zero-based index of child
  486. * @return the nth Accessible child of the object
  487. */
  488. public Accessible getAccessibleChild(int i) {
  489. return null;
  490. }
  491. /**
  492. * Returns the locale of this object.
  493. *
  494. * @return the locale of this object
  495. */
  496. public Locale getLocale() throws IllegalComponentStateException {
  497. return null;
  498. }
  499. /*
  500. * AccessibleIcon implementation -----------------
  501. */
  502. /**
  503. * Gets the description of the icon. This is meant to be a brief
  504. * textual description of the object. For example, it might be
  505. * presented to a blind user to give an indication of the purpose
  506. * of the icon.
  507. *
  508. * @return the description of the icon
  509. */
  510. public String getAccessibleIconDescription() {
  511. return ImageIcon.this.getDescription();
  512. }
  513. /**
  514. * Sets the description of the icon. This is meant to be a brief
  515. * textual description of the object. For example, it might be
  516. * presented to a blind user to give an indication of the purpose
  517. * of the icon.
  518. *
  519. * @param description the description of the icon
  520. */
  521. public void setAccessibleIconDescription(String description) {
  522. ImageIcon.this.setDescription(description);
  523. }
  524. /**
  525. * Gets the height of the icon.
  526. *
  527. * @return the height of the icon
  528. */
  529. public int getAccessibleIconHeight() {
  530. return ImageIcon.this.height;
  531. }
  532. /**
  533. * Gets the width of the icon.
  534. *
  535. * @return the width of the icon
  536. */
  537. public int getAccessibleIconWidth() {
  538. return ImageIcon.this.width;
  539. }
  540. private void readObject(ObjectInputStream s)
  541. throws ClassNotFoundException, IOException
  542. {
  543. s.defaultReadObject();
  544. }
  545. private void writeObject(ObjectOutputStream s)
  546. throws IOException
  547. {
  548. s.defaultWriteObject();
  549. }
  550. } // AccessibleImageIcon
  551. }