1 /**
2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package simp;
25 
26 import java.awt.image.BufferedImage;
27 import java.io.IOException;
28 import java.util.ArrayList;
29 import java.util.Iterator;
30 import javax.imageio.IIOException;
31 import javax.imageio.ImageReadParam;
32 import javax.imageio.ImageReader;
33 import javax.imageio.ImageTypeSpecifier;
34 import javax.imageio.metadata.IIOMetadata;
35 import javax.imageio.spi.ImageReaderSpi;
36 import javax.imageio.stream.ImageInputStream;
37 
38 /**
39   * A simple image format which has no compression and is a
40   * header with bytes 'SIMP', two signed bytes for width and height,
41   * and then unpadded 3 byte per pixel data representing RGB assumed
42   * to be in sRGB. The signed byte implies a maximum size of 127x127 pixels.
43   * Trailing data is ignored but there must be at least
44   * 3*width*height bytes of data following the simple 6 byte header.
45   */
46 public class SIMPImageReader extends ImageReader {
47 
48     private ImageInputStream stream = null;
49     private byte width = -1, height = -1;
50     SIMPMetadata metadata = null;
51     byte[] imageData = null;
52 
SIMPImageReader(ImageReaderSpi originatingProvider)53     public SIMPImageReader(ImageReaderSpi originatingProvider) {
54        super(originatingProvider);
55     }
56 
setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata)57     public void setInput(Object input,
58                          boolean seekForwardOnly,
59                          boolean ignoreMetadata) {
60         super.setInput(input, seekForwardOnly, ignoreMetadata);
61         stream = (ImageInputStream) input;
62     }
63 
checkState(int imageIndex)64     private void checkState(int imageIndex) throws IOException {
65         if (stream == null) {
66             throw new IllegalStateException("input not set.");
67         }
68         if (imageIndex != 0) {
69             throw new IndexOutOfBoundsException("index != 0");
70         }
71         if (width==-1) {
72             byte[] sig = new byte[4];
73             stream.reset();
74             stream.read(sig);
75             boolean ok = sig[0]=='S' && sig[1]=='I' &&
76                          sig[2]=='M' && sig[3]=='P';
77             if (!ok) {
78                 throw new IIOException("Not a SIMP image");
79             }
80             width = stream.readByte();
81             height = stream.readByte();
82         }
83         if (width <= 0 || height <= 0) {
84             throw new IOException("bad image size");
85         }
86         metadata = new SIMPMetadata(width, height);
87     }
88 
getWidth(int imageIndex)89     public int getWidth(int imageIndex) throws IOException {
90         checkState(imageIndex);
91         return width;
92     }
93 
getHeight(int imageIndex)94     public int getHeight(int imageIndex) throws IOException {
95         checkState(imageIndex);
96         return height;
97     }
98 
getNumImages(boolean allowSearch)99      public int getNumImages(boolean allowSearch) throws IOException {
100         checkState(0);
101         return 1;
102     }
103 
getStreamMetadata()104      public IIOMetadata getStreamMetadata() throws IOException {
105         return null;
106      }
107 
getImageMetadata(int imageIndex)108      public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
109         checkState(imageIndex);
110         return metadata;
111     }
112 
getImageTypes(int imageIndex)113     public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex)
114         throws IOException {
115 
116         checkState(imageIndex);
117         BufferedImage bi =
118             new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
119         ArrayList<ImageTypeSpecifier> list = new ArrayList<>(1);
120         list.add(new ImageTypeSpecifier(bi));
121         return list.iterator();
122     }
123 
read(int imageIndex, ImageReadParam param)124     public BufferedImage read(int imageIndex, ImageReadParam param)
125                             throws IOException {
126         checkState(imageIndex);
127         int len = 3*width*height;
128         byte[] imageData = new byte[len];
129         // The following is not efficient and is skipping all the
130         // progress updates, and ignoring the ImageReadParam, which
131         // it should not, but it is all we need for this test.
132         stream.readFully(imageData, 0, len);
133         BufferedImage bi =
134             new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
135         int off = 0;
136         for (int h=0;h<height;h++) {
137             int rgb = imageData[off]++ << 16 |
138                       imageData[off++] <<  8 | imageData[off++];
139             for (int w=0;w<width;w++) {
140                 bi.setRGB(w, h, rgb);
141             }
142         }
143         return bi;
144     }
145 }
146