1 /********************************************************************************
2 *                                                                               *
3 *                    I R I S   R G B   I n p u t / O u t p u t                  *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 2002,2006 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: fxrgbio.cpp,v 1.28 2006/03/18 04:57:03 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   - Need to implement RLE compression some time.
35   - Bad data may core reader.
36 */
37 
38 using namespace FX;
39 
40 /*******************************************************************************/
41 
42 namespace FX {
43 
44 
45 extern FXAPI bool fxcheckRGB(FXStream& store);
46 extern FXAPI bool fxloadRGB(FXStream& store,FXColor*& data,FXint& width,FXint& height);
47 extern FXAPI bool fxsaveRGB(FXStream& store,const FXColor *data,FXint width,FXint height);
48 
49 
50 // RLE decompress
expandrow(FXuchar * optr,FXuchar * iptr)51 static void expandrow(FXuchar* optr,FXuchar *iptr){   // FIXME bad data could blow past array!!
52   unsigned char pixel, count;
53   while(1){
54     pixel=*iptr++;
55     count=pixel&0x7f;
56     if(count==0) return;
57     if(pixel&0x80){   // Literal bytes
58       while(count--){
59 	*optr=*iptr++;
60 	optr+=4;
61         }
62       }
63     else{             // Repeated bytes
64       pixel=*iptr++;
65       while(count--){
66 	*optr=pixel;
67 	optr+=4;
68         }
69       }
70     }
71   }
72 
73 
74 // Check if stream contains a RGB
fxcheckRGB(FXStream & store)75 bool fxcheckRGB(FXStream& store){
76   FXuchar signature[2];
77   store.load(signature,2);
78   store.position(-2,FXFromCurrent);
79   return signature[0]==0x01 && signature[1]==0xDA;
80   }
81 
82 
83 // Load image from stream
fxloadRGB(FXStream & store,FXColor * & data,FXint & width,FXint & height)84 bool fxloadRGB(FXStream& store,FXColor*& data,FXint& width,FXint& height){
85   FXint i,j,c,tablen,sub,t,total;
86   FXuchar temp[4096],*array,storage,bpc,swap;
87   FXuint *starttab,*lengthtab;
88   FXushort magic,dimension,nchannels,w,h;
89   FXlong base,start;
90 
91   // Null out
92   data=NULL;
93   width=0;
94   height=0;
95 
96   // Remember swap state
97   swap=store.swapBytes();
98   store.setBigEndian(TRUE);
99 
100   // Where the image format starts
101   base=store.position();
102 
103   // Load header
104   store >> magic;       // MAGIC (2)
105   store >> storage;     // STORAGE (1)
106   store >> bpc;         // BPC (1)
107   store >> dimension;   // DIMENSION (2)
108   store >> w;           // XSIZE (2)
109   store >> h;           // YSIZE (2)
110   store >> nchannels;   // ZSIZE (2)
111 
112   FXTRACE((50,"fxloadRGB: magic=%d width=%d height=%d nchannels=%d dimension=%d storage=%d bpc=%d\n",magic,w,h,nchannels,dimension,storage,bpc));
113 
114   // Check magic number and other parameters
115   if(magic==474 && nchannels==3 && bpc==1 && w>0 && h>0){
116 
117     // Make room for image
118     if(FXMALLOC(&data,FXColor,w*h)){
119 
120       // Clear
121       memset(data,0xff,sizeof(FXColor)*w*h);
122 
123       // Skip stuff
124       store.position(500,FXFromCurrent);
125 
126       // RLE compressed
127       if(storage){
128         tablen=h*3;
129 
130         // Allocate line tables
131         if(FXMALLOC(&starttab,FXuint,tablen*2)){
132           lengthtab=&starttab[tablen];
133 
134           // Read line tables
135           store.load(starttab,tablen);
136           store.load(lengthtab,tablen);
137 
138           // Where the RLE chunks start
139           start=store.position();
140 
141           // Substract this amount to get offset from chunk start
142           sub=start-base;
143 
144           total=0;
145 
146           // Fix up the line table & figure space for RLE chunks
147           // Intelligent RGB writers (not ours ;-)) may re-use RLE
148           // chunks for more than 1 line...
149           for(i=0; i<tablen; i++){
150             starttab[i]-=sub;
151             t=starttab[i]+lengthtab[i];
152             if(t>total) total=t;
153             }
154 
155           // Make room for the compressed lines
156           if(FXMALLOC(&array,FXuchar,total)){
157 
158             // Load all RLE chunks
159             store.load(array,total);
160             for(c=0; c<3; c++){
161               for(j=h-1; j>=0; j--){
162                 expandrow(((FXuchar*)(data+j*w))+c,&array[starttab[h-1-j+c*h]]);
163                 }
164               }
165 
166             // Free RLE chunks
167             FXFREE(&array);
168             }
169 
170           // Free line tables
171           FXFREE(&starttab);
172           }
173         }
174 
175       // NON compressed
176       else{
177         for(c=0; c<3; c++){
178           for(j=h-1; j>=0; j--){
179             store.load(temp,w);
180             for(i=0; i<w; i++) ((FXuchar*)(data+j*w+i))[c]=temp[i];
181             }
182           }
183         }
184 
185       // Set width and height
186       width=w;
187       height=h;
188 
189       // Reset swap status
190       store.swapBytes(swap);
191       return TRUE;
192       }
193     }
194 
195   // Reset swap status
196   store.swapBytes(swap);
197   return false;
198   }
199 
200 
201 /*******************************************************************************/
202 
203 
204 // Save a bmp file to a stream
fxsaveRGB(FXStream & store,const FXColor * data,FXint width,FXint height)205 bool fxsaveRGB(FXStream& store,const FXColor *data,FXint width,FXint height){
206   const FXushort dimension=3;
207   const FXushort nchannels=3;
208   const FXushort magic=474;
209   const FXuint maxpix=255;
210   const FXuint minpix=0;
211   const FXuint dummy=0;
212   const FXuchar storage=0;
213   const FXuchar bpc=1;
214   FXuchar temp[4096],swap;
215   FXushort w=width;
216   FXushort h=height;
217   FXint i,j,c;
218 
219   // Must make sense
220   if(data && 0<width && 0<height){
221 
222     // Remember swap state
223     swap=store.swapBytes();
224     store.setBigEndian(TRUE);
225 
226     // Save header
227     store << magic;             // MAGIC (2)
228     store << storage;           // STORAGE (1)
229     store << bpc;               // BPC (1)
230     store << dimension;         // DIMENSION (2)
231     store << w;                 // XSIZE (2)
232     store << h;                 // YSIZE (2)
233     store << nchannels;         // ZSIZE (2)
234     store << minpix;            // PIXMIN (4)
235     store << maxpix;            // PIXMAX (4)
236     store << dummy;             // DUMMY (4)
237     memset(temp,0,80);          // Clean it
238     memcpy(temp,"IRIS RGB",8);  // Write name
239     store.save(temp,80);        // IMAGENAME (80)
240     store << dummy;             // COLORMAP (4)
241     memset(temp,0,404);         // Clean it
242     store.save(temp,404);       // DUMMY (404)
243 
244     // Write pixels
245     for(c=0; c<3; c++){
246       for(j=height-1; j>=0; j--){
247         for(i=0; i<width; i++) temp[i]=((FXuchar*)(data+j*width+i))[c];
248         store.save(temp,width);
249         }
250       }
251 
252     // Reset swap status
253     store.swapBytes(swap);
254     return true;
255     }
256   return false;
257   }
258 
259 }
260