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