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 3297 2015-12-14 20:30:04Z arthurcnorman $ *
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