/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