1 /********************************************************************************
2 *                                                                               *
3 *                          P P M   I n p u t / O u t p u t                      *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 2003,2005 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or                 *
9 * modify it under the terms of the GNU Lesser General Public                    *
10 * License as published by the Free Software Foundation; either                  *
11 * version 2.1 of the License, or (at your option) any later version.            *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU             *
16 * Lesser General Public License for more details.                               *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public              *
19 * License along with this library; if not, write to the Free Software           *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.    *
21 *********************************************************************************
22 * $Id: fxppmio.cpp,v 1.10 2005/01/16 16:06:07 fox Exp $                          *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "FXHash.h"
28 #include "FXStream.h"
29 
30 
31 
32 /*
33   Notes:
34   - Definitely a 'no-frills' format.
35   - Certainly not optimized for speed; but it works.
36   - No support for values greater than 255.
37 */
38 
39 using namespace FX;
40 
41 /*******************************************************************************/
42 
43 namespace FX {
44 
45 
46 extern FXAPI FXbool fxcheckPPM(FXStream& store);
47 extern FXAPI FXbool fxloadPPM(FXStream& store,FXColor*& data,FXint& width,FXint& height);
48 extern FXAPI FXbool fxsavePPM(FXStream& store,const FXColor *data,FXint width,FXint height);
49 
50 
51 // Read one integer
getint(FXStream & store)52 static FXint getint(FXStream& store){
53   register FXint num=0;
54   FXuchar c;
55   while(!store.eof()){
56     store >> c;
57     if('0'<=c && c<='9') break;
58     if(c=='#'){
59       while(!store.eof()){
60         store >> c;
61         if(c=='\n') break;
62         }
63       }
64     }
65   while(!store.eof()){
66     num=num*10+c-'0';
67     store >> c;
68     if(c<'0' || c>'9') break;
69     }
70   return num;
71   }
72 
73 
74 // Check if stream contains a PPM
fxcheckPPM(FXStream & store)75 FXbool fxcheckPPM(FXStream& store){
76   FXuchar signature[2];
77   store.load(signature,2);
78   store.position(-2,FXFromCurrent);
79   return signature[0]=='P' && '1'<=signature[1] && signature[1]<='6';
80   }
81 
82 
83 // Load image from stream
fxloadPPM(FXStream & store,FXColor * & data,FXint & width,FXint & height)84 FXbool fxloadPPM(FXStream& store,FXColor*& data,FXint& width,FXint& height){
85   register FXint npixels,i,j,maxvalue=1;
86   register FXuchar *pp;
87   FXuchar magic,format,byte,r,g,b;
88 
89   // Null out
90   data=NULL;
91   width=0;
92   height=0;
93 
94   // Check magic byte
95   store >> magic;
96   if(magic!='P') return FALSE;
97 
98   // Check format
99   // "P1" = ascii bitmap, "P2" = ascii greymap, "P3" = ascii pixmap,
100   // "P4" = raw bitmap, "P5" = raw greymap, "P6" = raw pixmap
101   store >> format;
102   if(format<'1' || format>'6') return FALSE;
103 
104   // Get size
105   width=getint(store);
106   height=getint(store);
107   if(width<1 || height<1) return FALSE;
108   npixels=width*height;
109 
110   // Get maximum value
111   if(format!='1' && format!='4'){
112     maxvalue=getint(store);
113     if(maxvalue<=0 || maxvalue>=256) return FALSE;
114     }
115 
116   FXTRACE((1,"fxloadPPM: width=%d height=%d type=%c \n",width,height,format));
117 
118   // Allocate buffer
119   if(!FXCALLOC(&data,FXColor,npixels)) return FALSE;
120 
121   // Read it
122   pp=(FXuchar*)data;
123   switch(format){
124     case '1':   // ascii bitmap
125       for(i=0; i<height; i++){
126         for(j=0; j<width; j++,byte<<=1,pp+=4){
127           if((j&7)==0){ byte=getint(store); }
128           g=(byte&0x80)?255:0;
129           pp[0]=g;
130           pp[1]=g;
131           pp[2]=g;
132           pp[3]=255;
133           }
134         }
135       break;
136     case '2':   // ascii greymap
137       for(i=0; i<height; i++){
138         for(j=0; j<width; j++,pp+=4){
139           g=getint(store);
140           pp[0]=g;
141           pp[1]=g;
142           pp[2]=g;
143           pp[3]=255;
144           }
145         }
146       break;
147     case '3':   // ascii pixmap
148       for(i=0; i<height; i++){
149         for(j=0; j<width; j++,pp+=4){
150           r=getint(store);
151           g=getint(store);
152           b=getint(store);
153           pp[0]=r;
154           pp[1]=g;
155           pp[2]=b;
156           pp[3]=255;
157           }
158         }
159       break;
160     case '4':   // binary bitmap
161       for(i=0; i<height; i++){
162         for(j=0; j<width; j++,byte<<=1,pp+=4){
163           if((j&7)==0){ store >> byte; }
164           g=(byte&0x80)?255:0;
165           pp[0]=g;
166           pp[1]=g;
167           pp[2]=g;
168           pp[3]=255;
169           }
170         }
171       break;
172     case '5':   // binary greymap
173       for(i=0; i<height; i++){
174         for(j=0; j<width; j++,pp+=4){
175           store >> g;
176           pp[0]=g;
177           pp[1]=g;
178           pp[2]=g;
179           pp[3]=255;
180           }
181         }
182       break;
183     case '6':   // binary pixmap
184       for(i=0; i<height; i++){
185         for(j=0; j<width; j++,pp+=4){
186           store >> r;
187           store >> g;
188           store >> b;
189           pp[0]=r;
190           pp[1]=g;
191           pp[2]=b;
192           pp[3]=255;
193           }
194         }
195       break;
196     }
197 
198   return TRUE;
199   }
200 
201 
202 /*******************************************************************************/
203 
204 
205 // Save a bmp file to a stream
fxsavePPM(FXStream & store,const FXColor * data,FXint width,FXint height)206 FXbool fxsavePPM(FXStream& store,const FXColor *data,FXint width,FXint height){
207   register const FXuchar *pp=(const FXuchar*)data;
208   register FXint i,j,nsize;
209   FXchar size[20];
210 
211   // Must make sense
212   if(!pp || width<=0 || height<=0) return FALSE;
213 
214   // Save header
215   store.save("P6\n",3);
216   nsize=sprintf(size,"%d %d\n",width,height);
217   store.save(size,nsize);
218   store.save("255\n",4);
219 
220   // 24-bit/pixel
221   for(i=0; i<height; i++){
222     for(j=0; j<width; j++){
223       store << *pp++;
224       store << *pp++;
225       store << *pp++;
226       pp++;
227       }
228     }
229   return TRUE;
230   }
231 
232 }
233