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
24package simp;
25
26import java.awt.image.BufferedImage;
27import java.io.IOException;
28import java.util.ArrayList;
29import java.util.Iterator;
30import javax.imageio.IIOException;
31import javax.imageio.ImageReadParam;
32import javax.imageio.ImageReader;
33import javax.imageio.ImageTypeSpecifier;
34import javax.imageio.metadata.IIOMetadata;
35import javax.imageio.spi.ImageReaderSpi;
36import 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  */
46public 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
53    public SIMPImageReader(ImageReaderSpi originatingProvider) {
54       super(originatingProvider);
55    }
56
57    public void setInput(Object input,
58                         boolean seekForwardOnly,
59                         boolean ignoreMetadata) {
60        super.setInput(input, seekForwardOnly, ignoreMetadata);
61        stream = (ImageInputStream) input;
62    }
63
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
89    public int getWidth(int imageIndex) throws IOException {
90        checkState(imageIndex);
91        return width;
92    }
93
94    public int getHeight(int imageIndex) throws IOException {
95        checkState(imageIndex);
96        return height;
97    }
98
99     public int getNumImages(boolean allowSearch) throws IOException {
100        checkState(0);
101        return 1;
102    }
103
104     public IIOMetadata getStreamMetadata() throws IOException {
105        return null;
106     }
107
108     public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
109        checkState(imageIndex);
110        return metadata;
111    }
112
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
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