Line data Source code
1 : /* Copyright (C) 2000-2012 by George Williams */
2 : /* 2013jan30..feb5, additional fixes and error checks done, Jose Da Silva */
3 : /*
4 : * Redistribution and use in source and binary forms, with or without
5 : * modification, are permitted provided that the following conditions are met:
6 :
7 : * Redistributions of source code must retain the above copyright notice, this
8 : * list of conditions and the following disclaimer.
9 :
10 : * Redistributions in binary form must reproduce the above copyright notice,
11 : * this list of conditions and the following disclaimer in the documentation
12 : * and/or other materials provided with the distribution.
13 :
14 : * The name of the author may not be used to endorse or promote products
15 : * derived from this software without specific prior written permission.
16 :
17 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : */
28 : #include "gimage.h"
29 :
30 : typedef struct _SunRaster {
31 : long MagicNumber; /* Magic (identification) number */
32 : long Width; /* Width of image in pixels */
33 : long Height; /* Height of image in pixels */
34 : long Depth; /* Number of bits per pixel */
35 : long Length; /* Size of image data in bytes */
36 : long Type; /* Type of raster file */
37 : long ColorMapType; /* Type of color map */
38 : long ColorMapLength; /* Size of the color map in bytes */
39 : } SUNRASTER;
40 :
41 : #define SUN_RAS_MAGIC 0x59a66a95
42 : #define LITTLE_ENDIAN_MAGIC 0x956aa659 /* if we read this value, must byte swap */
43 :
44 : enum types { TypeOld, TypeStandard, TypeByteEncoded, TypeRGB, TypeTIFF, TypeIFF };
45 : enum cluts { ClutNone, ClutRGB, ClutRaw };
46 :
47 0 : static int getlong(FILE *fp, long *value) {
48 : /* Get Big-Endian long (32bit int) value. Return 0 if okay, -1 if error */
49 : int ch1, ch2, ch3, ch4;
50 :
51 0 : if ( (ch1=fgetc(fp))<0 || (ch2=fgetc(fp))<0 || \
52 0 : (ch3=fgetc(fp))<0 || (ch4=fgetc(fp))<0 ) {
53 0 : *value=0;
54 0 : return( -1 );
55 : }
56 0 : *value=(long)( (ch1<<24)|(ch2<<16)|(ch3<<8)|ch4 );
57 0 : return( 0 );
58 : }
59 :
60 0 : static int getrasheader(SUNRASTER *head, FILE *fp) {
61 : /* Get Header info. Return 0 if read input file okay, -1 if read error */
62 0 : if ( getlong(fp,&head->MagicNumber) || \
63 0 : (head->MagicNumber!=SUN_RAS_MAGIC && head->MagicNumber!=LITTLE_ENDIAN_MAGIC) || \
64 0 : getlong(fp,&head->Width) || \
65 0 : getlong(fp,&head->Height) || \
66 0 : getlong(fp,&head->Depth) || \
67 0 : getlong(fp,&head->Length) || \
68 0 : getlong(fp,&head->Type) || \
69 0 : getlong(fp,&head->ColorMapType) || \
70 0 : getlong(fp,&head->ColorMapLength) )
71 0 : return( -1 );
72 :
73 : /* Check if header information okay (only try Big-Endian for now). */
74 0 : if ( head->MagicNumber!=SUN_RAS_MAGIC || \
75 0 : head->Type<0 || head->Type>TypeRGB || \
76 0 : (head->ColorMapType!=ClutNone && head->ColorMapType!=ClutRGB) || \
77 0 : (head->Depth!=1 && head->Depth!=8 && head->Depth!=24 && head->Depth!=32) || \
78 0 : (head->Depth>=24 && head->ColorMapType!=ClutNone) || \
79 0 : head->ColorMapLength>3*256 )
80 0 : return( -1 );
81 :
82 0 : return( 0 );
83 : }
84 :
85 0 : static GImage *ReadRasBitmap(GImage *ret,int width, int height, FILE *fp ) {
86 0 : struct _GImage *base = ret->u.image;
87 : int i,j,len;
88 : unsigned char *pt, *buf;
89 :
90 0 : len = ((width+15)/16)*2; /* pad out to 16 bits */
91 0 : if ( (buf=(unsigned char *) malloc(len*sizeof(unsigned char)))==NULL ) {
92 0 : NoMoreMemMessage();
93 0 : GImageDestroy(ret);
94 0 : return( NULL );
95 : }
96 :
97 0 : for ( i=0; i<height; ++i ) {
98 0 : if ( fread(buf,len,1,fp)<1 ) {
99 0 : free(buf);
100 0 : GImageDestroy(ret);
101 0 : return( NULL );
102 : }
103 0 : pt = (unsigned char *) (base->data + i*base->bytes_per_line);
104 0 : for ( j=0; j<(width+7)>>3; ++j )
105 0 : pt[j]=256-buf[j];
106 : }
107 0 : free(buf);
108 0 : return( ret );
109 : }
110 :
111 0 : static GImage *ReadRas8Bit(GImage *ret,int width, int height, FILE *fp ) {
112 0 : struct _GImage *base = ret->u.image;
113 : int i;
114 :
115 0 : for ( i=0; i<height; ++i ) {
116 0 : if ( fread((base->data + i*base->bytes_per_line),width,1,fp)<1 ) {
117 0 : goto errorReadRas8Bit;
118 : }
119 0 : if ( width&1 ) /* pad out to 16 bits */
120 0 : if ( fgetc(fp)<0 )
121 0 : goto errorReadRas8Bit;
122 : }
123 0 : return( ret );
124 :
125 : errorReadRas8Bit:
126 0 : GImageDestroy(ret);
127 0 : return( NULL );
128 : }
129 :
130 0 : static GImage *ReadRas24Bit(GImage *ret,int width, int height, FILE *fp ) {
131 0 : struct _GImage *base = ret->u.image;
132 0 : int ch1,ch2,ch3=0;
133 : int i;
134 : long *ipt,*end;
135 :
136 0 : for ( i=0; i<height; ++i ) {
137 0 : for ( ipt = (long *) (base->data + i*base->bytes_per_line), end = ipt+width; ipt<end; ) {
138 0 : if ( (ch1=fgetc(fp))<0 || (ch2=fgetc(fp))<0 || (ch3=fgetc(fp))<0 )
139 : goto errorReadRas24Bit;
140 0 : *ipt++ = COLOR_CREATE(ch3,ch2,ch1);
141 : }
142 0 : if ( width&1 ) /* pad out to 16 bits */
143 0 : if ( fgetc(fp)<0 )
144 0 : goto errorReadRas24Bit;
145 : }
146 0 : return( ret );
147 :
148 : errorReadRas24Bit:
149 0 : GImageDestroy(ret);
150 0 : return( NULL );
151 : }
152 :
153 0 : static GImage *ReadRas32Bit(GImage *ret,int width, int height, FILE *fp ) {
154 0 : struct _GImage *base = ret->u.image;
155 0 : int ch1,ch2,ch3=0;
156 : int i;
157 : long *ipt, *end;
158 :
159 0 : for ( i=0; i<height; ++i )
160 0 : for ( ipt = (long *) (base->data + i*base->bytes_per_line), end = ipt+width; ipt<end; ) {
161 0 : fgetc(fp); /* pad byte */
162 0 : ch1 = fgetc(fp); ch2 = fgetc(fp); ch3 = fgetc(fp);
163 0 : *ipt++ = COLOR_CREATE(ch3,ch2,ch1);
164 : }
165 0 : if ( ch3==EOF ) {
166 0 : GImageDestroy(ret);
167 0 : ret = NULL;
168 : }
169 0 : return ret;
170 : }
171 :
172 0 : static GImage *ReadRas24RBit(GImage *ret,int width, int height, FILE *fp ) {
173 0 : struct _GImage *base = ret->u.image;
174 0 : int ch1,ch2,ch3=0;
175 : int i;
176 : long *ipt,*end;
177 :
178 0 : for ( i=0; i<height; ++i ) {
179 0 : for ( ipt = (long *) (base->data + i*base->bytes_per_line), end = ipt+width; ipt<end; ) {
180 0 : if ( (ch1=fgetc(fp))<0 || (ch2=fgetc(fp))<0 || (ch3=fgetc(fp))<0 )
181 : goto errorReadRas24RBit;
182 0 : *ipt++ = COLOR_CREATE(ch1,ch2,ch3);
183 : }
184 0 : if ( width&1 ) /* pad out to 16 bits */
185 0 : if ( fgetc(fp)<0 )
186 0 : goto errorReadRas24RBit;
187 : }
188 0 : return( ret );
189 :
190 : errorReadRas24RBit:
191 0 : GImageDestroy(ret);
192 0 : return( NULL );
193 : }
194 :
195 0 : static GImage *ReadRas32RBit(GImage *ret,int width, int height, FILE *fp ) {
196 0 : struct _GImage *base = ret->u.image;
197 0 : int ch1,ch2,ch3=0;
198 : int i;
199 : long *ipt, *end;
200 :
201 0 : for ( i=0; i<height; ++i )
202 0 : for ( ipt = (long *) (base->data + i*base->bytes_per_line), end = ipt+width; ipt<end; ) {
203 0 : fgetc(fp); /* pad byte */
204 0 : ch1 = fgetc(fp); ch2 = fgetc(fp); ch3 = fgetc(fp);
205 0 : *ipt++ = COLOR_CREATE(ch1,ch2,ch3);
206 : }
207 0 : if ( ch3==EOF ) {
208 0 : GImageDestroy(ret);
209 0 : ret = NULL;
210 : }
211 0 : return ret;
212 : }
213 :
214 0 : static GImage *ReadRle8Bit(GImage *ret,int width, int height, FILE *fp ) {
215 : /* TODO: Make this an input filter that goes in front of other routines */
216 : /* above so that in can be re-used by the different converters above. */
217 0 : struct _GImage *base = ret->u.image;
218 0 : int x,y,cnt,val = 0;
219 0 : unsigned char *pt = NULL;
220 :
221 0 : x=0; y=0; cnt=0;
222 : while ( 1 ) {
223 0 : while ( cnt && x ) {
224 0 : --cnt; if ( --x || (width&1)-1 ) * pt++ = val;
225 : }
226 0 : if ( x==0 ) {
227 0 : pt = (unsigned char *) (base->data + y*base->bytes_per_line);
228 0 : if ( ++y>height )
229 0 : return( ret );
230 0 : x=((width+1)>>1)<<1;
231 : }
232 0 : if ( cnt==0 ) {
233 0 : if ( (val=fgetc(fp))<0 ) goto errorReadRle8Bit;
234 0 : cnt++;
235 0 : if ( val==0x80 ) {
236 0 : if ( (cnt=fgetc(fp))<0 ) goto errorReadRle8Bit;
237 0 : if ( cnt++!=0 )
238 : /* prepare to go insert 'val', 'cnt' times */
239 0 : if ( (val=fgetc(fp))<0 ) goto errorReadRle8Bit;
240 : }
241 : }
242 0 : }
243 :
244 : errorReadRle8Bit:
245 0 : GImageDestroy(ret);
246 0 : return( NULL );
247 : }
248 :
249 0 : GImage *GImageReadRas(char *filename) {
250 : /* Import a *.ras image (or *.im{1,8,24,32}), else return NULL if error */
251 : FILE *fp; /* source file */
252 : struct _SunRaster header;
253 0 : GImage *ret = NULL;
254 : struct _GImage *base;
255 :
256 0 : if ( (fp=fopen(filename,"rb"))==NULL ) {
257 0 : fprintf(stderr,"Can't open \"%s\"\n", filename);
258 0 : return( NULL );
259 : }
260 :
261 0 : if ( getrasheader(&header,fp) )
262 0 : goto errorGImageReadRas;
263 :
264 : /* Create memory to hold image, exit with NULL if not enough memory */
265 0 : if ( (header.Depth==1 && \
266 0 : (ret=GImageCreate(it_bitmap,header.Width,header.Height))==NULL) || \
267 0 : (header.Depth!=1 && \
268 0 : (ret=GImageCreate(header.Depth==24?it_true:it_index,header.Width,header.Height))==NULL) ) {
269 0 : fclose(fp);
270 0 : return( NULL );
271 : }
272 :
273 : /* Convert *.ras ColorMap to one that FF can use */
274 0 : base = ret->u.image;
275 0 : if ( header.ColorMapLength!=0 && base->clut!=NULL ) {
276 : unsigned char clutb[3*256]; int i,n;
277 0 : if ( fread(clutb,header.ColorMapLength,1,fp)<1 )
278 0 : goto errorGImageReadRas;
279 : // if ( header.ColorMapType==ClutRaw ) {
280 : // n = header.ColorMapLength;
281 : // base->clut->clut_len = n;
282 : // for ( i=0; i<n; ++i )
283 : // base->clut->clut[i] = clutb[i];
284 : // } else {
285 0 : n = header.ColorMapLength/3;
286 0 : base->clut->clut_len = n;
287 0 : for ( i=0; i<n; ++i )
288 0 : base->clut->clut[i] = COLOR_CREATE(clutb[i],clutb[i+n],clutb[i+2*n]);
289 : // }
290 : }
291 :
292 0 : if ( header.Type==TypeOld || header.Type==TypeStandard ) { /* Synonymous */
293 0 : if ( header.Depth==1 )
294 0 : ret = ReadRasBitmap(ret,header.Width,header.Height,fp);
295 0 : else if ( header.Depth==8 )
296 0 : ret = ReadRas8Bit(ret,header.Width,header.Height,fp);
297 0 : else if ( header.Depth==24 )
298 0 : ret = ReadRas24Bit(ret,header.Width,header.Height,fp);
299 : else
300 0 : ret = ReadRas32Bit(ret,header.Width,header.Height,fp);
301 0 : } else if ( header.Type==TypeRGB ) {
302 : /* I think this type is the same as standard except rgb not bgr */
303 0 : if ( header.Depth==1 )
304 0 : ret = ReadRasBitmap(ret,header.Width,header.Height,fp);
305 0 : else if ( header.Depth==8 )
306 0 : ret = ReadRas8Bit(ret,header.Width,header.Height,fp);
307 0 : else if ( header.Depth==24 )
308 0 : ret = ReadRas24RBit(ret,header.Width,header.Height,fp);
309 : else
310 0 : ret = ReadRas32RBit(ret,header.Width,header.Height,fp);
311 0 : } else if ( header.Type==TypeByteEncoded ) {
312 0 : if ( header.Depth==8 )
313 0 : ret = ReadRle8Bit(ret,header.Width,header.Height,fp);
314 : else {
315 : /* Don't bother with most rle formats */
316 : /* TODO: if someone wants to do this - accept more formats */
317 0 : fprintf(stderr,"Unsupported input file type\n");
318 0 : goto errorGImageReadRas;
319 : }
320 : } else {
321 : /* Don't bother with other formats */
322 : /* TODO: if someone wants to do this - accept more formats */
323 0 : fprintf(stderr,"Unsupported input file type\n");
324 0 : goto errorGImageReadRas;
325 : }
326 0 : if ( ret!=NULL ) {
327 : /* All okay if reached here, return converted image */
328 0 : fclose(fp);
329 0 : return( ret );
330 : }
331 :
332 : errorGImageReadRas:
333 0 : fprintf(stderr,"Bad input file \"%s\"\n",filename );
334 0 : GImageDestroy(ret);
335 0 : fclose(fp);
336 0 : return( NULL );
337 : }
|