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