- Tour the Icon Resource Format
- Accessing .ICO Files with the Ico Library
- Viewing Windows Icons with IcoViewer
- Conclusion
Accessing .ICO Files with the Ico Library
When I began designing a Java library to access Windows icon resources from .ICO files, I decided to keep the library small. The resulting Ico library consists of only two classes: Ico and BadIcoResException. Furthermore, the Ico class presents a concise API consisting of four constructors and three non-constructor methods:
- public Ico(File file) reads and parses the Windows icon resource identified by its File argument. This constructor throws IOException for a file I/O problem; BadIcoResException is thrown if the constructor cannot parse the resource.
- public Ico(InputStream is) reads and parses the Windows icon resource identified by its InputStream argument. This constructor throws the same exceptions as the previous constructor.
- public Ico(String filename) reads and parses the Windows icon resource identified by its String argument. This constructor throws the same exceptions as the previous constructors.
- public Ico(URL url) reads and parses the Windows icon resource identified by its URL argument. This constructor throws the same exceptions as the previous constructors.
- public BufferedImage getImage(int index) returns a BufferedImage containing the icon image located at the (zero-based) index position in the directory.
- public int getNumColors(int index) returns the maximum number of colors supported by the icon image located at the (zero-based) index position in the directory.
- public int getNumImages() returns the number of icon images in the resource. This value is obtained from the header’s count field (shown earlier in Figure 1).
Ico’s constructors give you flexibility in specifying the source of a Windows icon resource: file (via a File or String object), stream, or URL. Regardless of which constructor is invoked, the constructor ultimately invokes a private method to read the resource’s contents from an input stream into a byte array:
private byte [] icoimage = new byte [0]; // new byte [0] facilitates read() // ... private void read (InputStream is) throws IOException { int bytesToRead; while ((bytesToRead = is.available ()) != 0) { byte [] icoimage2 = new byte [icoimage.length+bytesToRead]; System.arraycopy (icoimage, 0, icoimage2, 0, icoimage.length); is.read (icoimage2, icoimage.length, bytesToRead); icoimage = icoimage2; } }
After reading the entire resource into the icoimage byte array, a constructor parses this array’s contents (via another private method), extracting icon images into separate BufferedImage objects—each BufferedImage is created with the BufferedImage.TYPE_INT_ARGB constant so that it contains an eight-bit alpha channel.
Each constructor recognizes only 2-color, 16-color, 256-color, or 32-bit color icon images while parsing the Windows icon resource. If it encounters an icon image with a different number of colors, the constructor ignores the image without throwing an exception. In this situation, the associated BufferedImage contains a transparent image.
Unlike the 1-based index implied by Figure 1, the getImage() and getNumColors() methods accept a zero-based index. If the index is less than zero, or if it’s greater than or equal to the value returned by the getNumImages() method, each method throws an IllegalArgumentException.
The Ico and BadIcoResException classes belong to the ca.mb.javajeff.ico package. This package corresponds to an equivalent directory path (in this article’s code archive) containing Ico.java and BadIcoResException.java. You can compile these source files with a Java SE 6 compiler, a J2SE 5.x compiler, and probably a compiler from an earlier Java release.