/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