1 /*
2 * xvrle.c - load routine for rle (Utah Raster Toolkit) format pictures
3 *
4 * LoadRLE(fname, numcols) - loads an RLE file
5 */
6
7 #include "copyright.h"
8
9 #include "xv.h"
10
11
12 /* Definitions needed to parse RLE format */
13 /* snarfed from rle_code.h, part of the Utah Raster Toolkit */
14 #define LONG_OP 0x40
15 #define RSkipLinesOp 1
16 #define RSetColorOp 2
17 #define RSkipPixelsOp 3
18 #define RByteDataOp 5
19 #define RRunDataOp 6
20 #define REOFOp 7
21
22 #define H_CLEARFIRST 0x1 /* clear framebuffer flag */
23 #define H_NO_BACKGROUND 0x2 /* if set, no bg color supplied */
24 #define H_ALPHA 0x4 /* if set, alpha channel (-1) present */
25 #define H_COMMENT 0x8 /* if set, comments present */
26
27
28 #define GETINT(fp) (c=getc(fp), c1=getc(fp), (c1<<8) + c )
29
30 static void read_rle PARM((FILE *, byte *, int, int, int, int));
31 static int rleError PARM((const char *, const char *));
32
33
34
35 /*******************************************/
LoadRLE(fname,pinfo)36 int LoadRLE(fname, pinfo)
37 char *fname;
38 PICINFO *pinfo;
39 /*******************************************/
40 {
41 FILE *fp;
42 int c, c1, i, j, k;
43 byte bgcol[256];
44 byte maps[3][256];
45 int xpos, ypos, w, h, flags, ncolors, pixelbits, ncmap, cmaplen;
46 int cmtlen;
47 byte *img;
48 long filesize;
49 const char *bname;
50 const char *errstr;
51
52 pinfo->type = PIC8;
53 pinfo->pic = (byte *) NULL;
54 pinfo->comment = (char *) NULL;
55
56 bname = BaseName(fname);
57
58 /* open the stream */
59 fp = xv_fopen(fname,"r");
60 if (!fp) return (rleError(bname, "unable to open file"));
61
62
63 /* figure out the file size */
64 fseek(fp, 0L, 2);
65 filesize = ftell(fp);
66 fseek(fp, 0L, 0);
67
68
69 /* read the magic number */
70 c = getc(fp); c1 = getc(fp);
71 if ((c != 0x52) || (c1 != 0xcc))
72 return(rleError(bname, "unrecognized magic number"));
73
74
75 xpos = GETINT(fp); /* read rest of header info */
76 ypos = GETINT(fp);
77 w = GETINT(fp);
78 h = GETINT(fp);
79 flags = getc(fp);
80 ncolors = getc(fp);
81 pixelbits = getc(fp);
82 ncmap = getc(fp);
83 c = getc(fp);
84 cmaplen = (1L << c);
85
86 if (DEBUG) {
87 fprintf(stderr,"RLE: %dx%d image at %d,%d\n", w, h, xpos, ypos);
88 fprintf(stderr,"flags: 0x%02x (%s%s%s%s)\n",
89 flags,
90 (flags & H_CLEARFIRST) ? "CLEARFIRST " : "",
91 (flags & H_NO_BACKGROUND) ? "NO_BG " : "",
92 (flags & H_ALPHA) ? "ALPHA " : "",
93 (flags & H_COMMENT) ? "COMMENT" : "");
94
95 fprintf(stderr, "%d bands, %d pixelbits, %d cmap bands, %d cmap entries\n",
96 ncolors, pixelbits, ncmap, cmaplen);
97 }
98
99 if (!(flags & H_NO_BACKGROUND)) {
100 if (DEBUG) fprintf(stderr, "background value: ");
101 for (i=0; i<ncolors; i++) {
102 bgcol[i] = getc(fp);
103 if (DEBUG) fprintf(stderr, "0x%02x ", bgcol[i]);
104 }
105 if (DEBUG) fprintf(stderr,"\n");
106 }
107 else {
108 getc(fp); /* skip filler byte */
109 }
110
111 if ((ncolors % 2) == 0) getc(fp); /* get on a word boundary */
112
113 /* read colormap(s) */
114 for (i=0; i<ncmap; i++) {
115 for (j = 0; j<cmaplen; j++) {
116 k = GETINT(fp);
117 if (i<3) maps[i][j] = k>>8;
118 }
119 }
120
121 if (DEBUG) {
122 if (ncmap) {
123 fprintf(stderr, "Colormap:\n");
124 for (i=0; i<cmaplen; i++) {
125 fprintf(stderr,"(");
126 for (j=0; (j<ncmap && j<3); j++) {
127 fprintf(stderr, "%02x ", maps[j][i]);
128 }
129 fprintf(stderr,") ");
130 }
131 fprintf(stderr,"\n\n");
132 }
133 else fprintf(stderr,"No colormap\n");
134 }
135
136
137 /* read (skip over, actually) the comments, if any */
138 if (flags & H_COMMENT) {
139 cmtlen = GETINT(fp);
140 if (cmtlen) {
141 pinfo->comment = (char *) malloc((size_t) (cmtlen + 1));
142
143 if (DEBUG) fprintf(stderr,"Comment: (%d bytes) '", cmtlen);
144 for (i=0; i<cmtlen; i++) {
145 c = getc(fp);
146 if (c==EOF) break;
147 if (pinfo->comment) {
148 if (c == '\0') c = '\n'; /* translate NUL to NL */
149 pinfo->comment[i] = (char) c;
150 }
151 if (DEBUG) fprintf(stderr,"%c",c);
152 }
153 if (pinfo->comment) pinfo->comment[i] = '\0';
154
155 if (cmtlen % 2) getc(fp); /* get on a word boundary */
156 if (DEBUG) fprintf(stderr,"'\n\n");
157 }
158 }
159
160
161 if (ferror(fp) || feof(fp)) {
162 fclose(fp);
163 if (pinfo->comment) free(pinfo->comment); pinfo->comment = (char *) NULL;
164 return rleError(bname, "EOF reached in RLE header.\n");
165 }
166
167
168 /*
169 * Acceptable cases:
170 * ncolors = 1, 3, or >3 (extra planes ignored)
171 * pixelbits = 8
172 * ncmap = 0 (interpreted as TrueColor/TrueGray)
173 * 1 (TrueColor/TrueGray with a gamma curve)
174 * 3 | ncolors (TrueColor with three gamma curves, or
175 * PseudoColor if ncolors==1)
176 */
177
178 errstr = NULL;
179 if (ncolors == 0 || ncolors == 2)
180 errstr = "Unsupt. # of channels in RLE file.\n";
181
182 if (pixelbits != 8)
183 errstr = "Only 8-bit pixels supported in RLE files.\n";
184
185 if (ncmap==0 || ncmap==1 || ncmap == 3 || ncmap == ncolors) { /* ok */ }
186 else errstr = "Invalid # of colormap channels in RLE file.\n";
187
188 if (w<1 || h<1)
189 errstr = "Bogus size in RLE header.\n";
190
191
192 if (errstr) {
193 fclose(fp);
194 if (pinfo->comment) free(pinfo->comment); pinfo->comment = (char *) NULL;
195 return rleError(bname, errstr);
196 }
197
198
199 /* allocate image memory */
200 if (ncolors == 1) img = (byte *) calloc((size_t) w * h, (size_t) 1);
201 else img = (byte *) calloc((size_t) w * h * 3, (size_t) 1);
202 if (!img) {
203 fclose(fp);
204 if (pinfo->comment) free(pinfo->comment); pinfo->comment = (char *) NULL;
205 return rleError(bname, "unable to allocate image data.\n");
206 }
207
208
209 /* set background, if necessary */
210 if ((flags & H_CLEARFIRST) && !(flags & H_NO_BACKGROUND)) {
211 byte *ip;
212 if (ncolors == 1) {
213 for (i=0, ip=img; i<w*h; i++, ip++) *ip = bgcol[0];
214 }
215 else {
216 for (i=0, ip=img; i<w*h; i++)
217 for (j=0; j<3; j++, ip++) *ip = bgcol[j];
218 }
219 }
220
221
222 read_rle(fp, img, w, h, ncolors, ncmap);
223
224 if (ferror(fp) || feof(fp)) /* just a warning */
225 rleError(bname, "RLE file appears to be truncated.");
226
227 fclose(fp);
228
229
230 /* apply gamma curve(s) to image (if grayscale or truecolor) */
231 if (ncmap) {
232 byte *ip;
233 int imagelen, cmask;
234 imagelen = (ncolors==1) ? w*h : w*h*3;
235 cmask = (cmaplen-1);
236
237 if (ncmap == 1) { /* single gamma curve */
238 for (i=0, ip=img; i<imagelen; i++, ip++) *ip = maps[0][*ip & cmask];
239 }
240
241 else if (ncmap >= 3 && ncolors >=3) { /* one curve per band */
242 for (i=0, ip=img; i<w*h; i++) {
243 *ip = maps[0][*ip & cmask]; ip++;
244 *ip = maps[1][*ip & cmask]; ip++;
245 *ip = maps[2][*ip & cmask]; ip++;
246 }
247 }
248 }
249
250
251 /* finally, convert into XV internal format */
252
253 pinfo->pic = img;
254 pinfo->w = w;
255 pinfo->h = h;
256 pinfo->normw = pinfo->w; pinfo->normh = pinfo->h;
257 pinfo->frmType = -1; /* no default format to save in */
258
259 if (ncolors == 1) { /* grayscale or PseudoColor */
260 pinfo->type = PIC8;
261 if (ncmap == 0 || ncmap == 1) { /* grey, or grey with gamma curve */
262 pinfo->colType = F_GREYSCALE;
263 sprintf(pinfo->fullInfo, "Greyscale RLE. (%ld bytes)", filesize);
264 for (i=0; i<256; i++)
265 pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i;
266 }
267 else {
268 pinfo->colType = F_FULLCOLOR;
269 sprintf(pinfo->fullInfo, "PseudoColor RLE. (%ld bytes)", filesize);
270 for (i=0; i<256; i++) {
271 pinfo->r[i] = maps[0][i];
272 pinfo->g[i] = maps[1][i];
273 pinfo->b[i] = maps[2][i];
274 }
275 }
276
277 sprintf(pinfo->shrtInfo, "%dx%d RLE.",w, h);
278 }
279
280 else { /* true color */
281 pinfo->type = PIC24;
282 pinfo->colType = F_FULLCOLOR;
283 sprintf(pinfo->fullInfo, "TrueColor RLE. (%ld bytes)", filesize);
284 sprintf(pinfo->shrtInfo, "%dx%d RLE.", w, h);
285 }
286
287 return 1;
288 }
289
290
291 /*******************************************/
read_rle(fp,img,w,h,ncolors,ncmap)292 static void read_rle(fp, img, w, h, ncolors, ncmap)
293 FILE *fp;
294 byte *img;
295 int w, h, ncolors, ncmap;
296 {
297 int posx, posy, plane, bperpix, i, pixval, skipcalls;
298 int opcode, operand, done, c, c1;
299 byte *ip;
300
301 posx = posy = plane = done = skipcalls = 0;
302 if (ncolors == 1) bperpix = 1;
303 else bperpix = 3;
304
305
306 while (!done && (opcode=getc(fp)) != EOF) {
307 switch (opcode & 0x3f) {
308 case RSkipLinesOp:
309 if (opcode & LONG_OP) { getc(fp); operand = GETINT(fp); }
310 else operand = getc(fp);
311 posx = 0;
312 posy += operand;
313 skipcalls++;
314 if ((skipcalls & 0x7f)==0) WaitCursor();
315 break;
316
317
318 case RSetColorOp:
319 operand = getc(fp);
320 plane = operand;
321 posx = 0;
322 break;
323
324
325 case RSkipPixelsOp:
326 if (opcode & LONG_OP) { getc(fp); operand = GETINT(fp); }
327 else operand = getc(fp);
328
329 posx += operand;
330 break;
331
332
333 case RByteDataOp:
334 if (opcode & LONG_OP) { getc(fp); operand = GETINT(fp); }
335 else operand = getc(fp);
336
337 ip = img + ((h-posy-1) * w*bperpix) + posx*bperpix + plane;
338 operand++;
339
340 for (i=0; i<operand; i++, ip+=bperpix) {
341 c = getc(fp);
342 if (plane<ncolors && posy<h && (posx+i < w)) *ip = c;
343 }
344
345 if (operand & 1) getc(fp); /* word boundary */
346 posx += operand;
347 break;
348
349
350 case RRunDataOp:
351 if (opcode & LONG_OP) { getc(fp); operand = GETINT(fp); }
352 else operand = getc(fp);
353
354 pixval = getc(fp); getc(fp);
355 operand++;
356
357 ip = img + ((h-posy-1) * w*bperpix) + posx*bperpix + plane;
358
359 for (i=0; i<operand; i++, ip+=bperpix) {
360 if (plane<ncolors && posy<h && (posx+i < w)) *ip = pixval;
361 }
362
363 /* if (operand & 1) getc(fp); */ /* word boundary */
364 posx += operand;
365 break;
366
367 case REOFOp:
368 done = 1;
369 break;
370 }
371 }
372 }
373
374
375 /*******************************************/
rleError(fname,st)376 static int rleError(fname,st)
377 const char *fname, *st;
378 {
379 SetISTR(ISTR_WARNING,"%s: %s", fname, st);
380 return 0;
381 }
382
383