/Users/lyon/j4p/src/ip/ppm/ReadPPM.java
|
1 /*
2 * @author Douglas A. Lyon
3 * @version Oct 12, 2002.10:53:37 AM
4 */
5 package ip.ppm;
6
7
8 import java.io.IOException;
9 import java.io.InputStream;
10
11
12 // PpmDecoder - read in a PPM image
13 //
14 // Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
15 //
16 // Redistribution and use in source and binary forms, with or without
17 // modification, are permitted provided that the following conditions
18 // are met:
19 // 1. Redistributions of source code must retain the above copyright
20 // notice, this list of conditions and the following disclaimer.
21 // 2. Redistributions in binary form must reproduce the above copyright
22 // notice, this list of conditions and the following disclaimer in the
23 // documentation and/or other materials provided with the distribution.
24 //
25 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
26 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
29 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 // SUCH DAMAGE.
36 //
37 // Visit the ACME Labs Java page for up-to-date versions of this and other
38 // fine Java utilities: http://www.acme.com/java/
39
40
41
42
43
44 /// Read in a PPM image.
45 // <P>
46 // <A HREF="/resources/classes/Acme/JPM/Decoders/PpmDecoder.java">Fetch the software.</A><BR>
47 // <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
48 // <P>
49 // @see Acme.JPM.Encoders.PpmEncoder
50
51 public class ReadPPM extends ImageDecoder {
52
53 /// Constructor.
54 // @param in The stream to read the bytes from.
55 public ReadPPM(InputStream in) {
56 super(in);
57 }
58
59
60 private int type;
61 private static final int PBM_ASCII = 1;
62 private static final int PGM_ASCII = 2;
63 private static final int PPM_ASCII = 3;
64 private static final int PBM_RAW = 4;
65 private static final int PGM_RAW = 5;
66 private static final int PPM_RAW = 6;
67
68 private int width = -1, height = -1;
69 private int maxval;
70
71 /// Subclasses implement this to read in enough of the image stream
72 // to figure out the width and height.
73 void readHeader(InputStream in) throws IOException {
74 char c1, c2;
75
76 c1 = (char) readByte(in);
77 c2 = (char) readByte(in);
78
79 if (c1 != 'P')
80 throw new IOException("not a PBM/PGM/PPM file");
81 switch (c2) {
82 case '1':
83 type = PBM_ASCII;
84 break;
85 case '2':
86 type = PGM_ASCII;
87 break;
88 case '3':
89 type = PPM_ASCII;
90 break;
91 case '4':
92 type = PBM_RAW;
93 break;
94 case '5':
95 type = PGM_RAW;
96 break;
97 case '6':
98 type = PPM_RAW;
99 break;
100 default:
101 throw new IOException("not a standard PBM/PGM/PPM file");
102 }
103 width = readInt(in);
104 height = readInt(in);
105 if (type != PBM_ASCII && type != PBM_RAW)
106 maxval = readInt(in);
107 }
108
109 /// Subclasses implement this to return the width, or -1 if not known.
110 int getWidth() {
111 return width;
112 }
113
114 /// Subclasses implement this to return the height, or -1 if not known.
115 int getHeight() {
116 return height;
117 }
118
119 /// Subclasses implement this to read pixel data into the rgbRow
120 // array, an int[width]. One int per pixel, no offsets or padding,
121 // RGBdefault (AARRGGBB) color model
122 void readRow(InputStream in, int row, int[] rgbRow) throws IOException {
123 int col, r, g, b;
124 int rgb = 0;
125 char c;
126
127 for (col = 0; col < width; ++col) {
128 switch (type) {
129 case PBM_ASCII:
130 c = readChar(in);
131 if (c == '1')
132 rgb = 0xff000000;
133 else if (c == '0')
134 rgb = 0xffffffff;
135 else
136 throw new IOException("illegal PBM bit");
137 break;
138 case PGM_ASCII:
139 g = readInt(in);
140 rgb = makeRgb(g, g, g);
141 break;
142 case PPM_ASCII:
143 r = readInt(in);
144 g = readInt(in);
145 b = readInt(in);
146 rgb = makeRgb(r, g, b);
147 break;
148 case PBM_RAW:
149 if (readBit(in))
150 rgb = 0xff000000;
151 else
152 rgb = 0xffffffff;
153 break;
154 case PGM_RAW:
155 g = readByte(in);
156 if (maxval != 255)
157 g = fixDepth(g);
158 rgb = makeRgb(g, g, g);
159 break;
160 case PPM_RAW:
161 r = readByte(in);
162 g = readByte(in);
163 b = readByte(in);
164 if (maxval != 255) {
165 r = fixDepth(r);
166 g = fixDepth(g);
167 b = fixDepth(b);
168 }
169 rgb = makeRgb(r, g, b);
170 break;
171 }
172 rgbRow[col] = rgb;
173 }
174 }
175
176 /// Utility routine to read a byte. Instead of returning -1 on
177 // EOF, it throws an exception.
178 private static int readByte(InputStream in) throws IOException {
179 int b = in.read();
180 if (b == -1)
181 throw new IOException();
182 return b;
183 }
184
185 private int bitshift = -1;
186 private int bits;
187
188 /// Utility routine to read a bit, packed eight to a byte, big-endian.
189 private boolean readBit(InputStream in) throws IOException {
190 if (bitshift == -1) {
191 bits = readByte(in);
192 bitshift = 7;
193 }
194 boolean bit = (((bits >> bitshift) & 1) != 0);
195 --bitshift;
196 return bit;
197 }
198
199 /// Utility routine to read a character, ignoring comments.
200 private static char readChar(InputStream in) throws IOException {
201 char c;
202
203 c = (char) readByte(in);
204 if (c == '#') {
205 do {
206 c = (char) readByte(in);
207 } while (c != '\n' && c != '\r');
208 }
209
210 return c;
211 }
212
213 /// Utility routine to read the first non-whitespace character.
214 private static char readNonwhiteChar(InputStream in) throws IOException {
215 char c;
216
217 do {
218 c = readChar(in);
219 } while (c == ' ' || c == '\t' || c == '\n' || c == '\r');
220
221 return c;
222 }
223
224 /// Utility routine to read an ASCII integer, ignoring comments.
225 private static int readInt(InputStream in) throws IOException {
226 char c;
227 int i;
228
229 c = readNonwhiteChar(in);
230 if (c < '0' || c > '9')
231 throw new IOException("junk in file where integer should be");
232
233 i = 0;
234 do {
235 i = i * 10 + c - '0';
236 c = readChar(in);
237 } while (c >= '0' && c <= '9');
238
239 return i;
240 }
241
242 /// Utility routine to rescale a pixel value from a non-eight-bit maxval.
243 private int fixDepth(int p) {
244 return (p * 255 + maxval / 2) / maxval;
245 }
246
247 /// Utility routine make an RGBdefault pixel from three color values.
248 private static int makeRgb(int r, int g, int b) {
249 return 0xff000000 | (r << 16) | (g << 8) | b;
250 }
251
252 }
253
254