1 /*
2 * xvsunras.c - load routine for 'sun rasterfile' format pictures
3 *
4 * LoadSunRas(fname, numcols) - loads a PM pic, does 24to8 code if nec.
5 * WriteSunRas(fp, pic, w, h, r,g,b, numcols, style)
6 * WriteRaw(fp, pic, w, h, r,g,b, numcols, style)
7 *
8 * This file written by Dave Heath (heath@cs.jhu.edu)
9 * fixBGR() added by Ken Rossman (ken@shibuya.cc.columbia.edu)
10 */
11
12
13 #include "xv.h"
14
15 /* info on sun rasterfiles taken from rasterfile(5) man page */
16
17 #define RAS_MAGIC 0x59a66a95
18
19 struct rasterfile {
20 int ras_magic;
21 int ras_width;
22 int ras_height;
23 int ras_depth;
24 int ras_length;
25 int ras_type;
26 int ras_maptype;
27 int ras_maplength;
28 };
29
30 #define RT_OLD 0 /* Raw pixrect image in 68000 byte order */
31 #define RT_STANDARD 1 /* Raw pixrect image in 68000 byte order */
32 #define RT_BYTE_ENCODED 2 /* Run-length compression of bytes */
33 #define RT_FORMAT_RGB 3 /* XRGB or RGB instead of XBGR or BGR */
34
35 #define RMT_RAW 2
36 #define RMT_NONE 0
37 #define RMT_EQUAL_RGB 1
38
39 #define RAS_RLE 0x80
40
41
42 static int sunRasError PARM((const char *, const char *));
43 static int rle_read PARM((byte *, int, int, FILE *, int));
44 static void sunRas1to8 PARM((byte *, byte *, int));
45 static void sunRas8to1 PARM((byte *, byte *, int, int));
46 static int read_sun_long PARM((int *, FILE *));
47 static int write_sun_long PARM((int, FILE *));
48 static void fixBGR PARM((unsigned char *, int, int));
49
50
51 /*******************************************/
LoadSunRas(fname,pinfo)52 int LoadSunRas(fname, pinfo)
53 char *fname;
54 PICINFO *pinfo;
55 {
56 FILE *fp;
57 int linesize,lsize,csize,isize,i,w,h,d,npixels,nbytes;
58 byte *image, *line;
59 struct rasterfile sunheader;
60 const char *bname;
61
62 bname = BaseName(fname);
63
64 /* read in the Sun Rasterfile picture */
65 fp = xv_fopen(fname,"r");
66 if (!fp) return( sunRasError(bname, "unable to open file") );
67
68 read_sun_long (&sunheader.ras_magic , fp);
69 read_sun_long (&sunheader.ras_width , fp);
70 read_sun_long (&sunheader.ras_height , fp);
71 read_sun_long (&sunheader.ras_depth , fp);
72 read_sun_long (&sunheader.ras_length , fp);
73 read_sun_long (&sunheader.ras_type , fp);
74 read_sun_long (&sunheader.ras_maptype , fp);
75 read_sun_long (&sunheader.ras_maplength, fp);
76
77 if (sunheader.ras_magic != RAS_MAGIC) {
78 fclose(fp);
79 return( sunRasError(bname, "not a Sun rasterfile") );
80 }
81
82
83 /* make sure that the input picture can be dealt with */
84 if (sunheader.ras_depth != 1 &&
85 sunheader.ras_depth != 8 &&
86 sunheader.ras_depth != 24 &&
87 sunheader.ras_depth != 32) {
88 fprintf (stderr, "Sun rasterfile image has depth %d\n",
89 sunheader.ras_depth);
90 fprintf (stderr, "Depths supported are 1, 8, 24, and 32\n");
91 fclose(fp);
92 return 0;
93 }
94
95
96 if (sunheader.ras_type != RT_OLD &&
97 sunheader.ras_type != RT_STANDARD &&
98 sunheader.ras_type != RT_BYTE_ENCODED &&
99 sunheader.ras_type != RT_FORMAT_RGB) {
100 fprintf (stderr, "Sun rasterfile of unsupported type %d\n",
101 sunheader.ras_type);
102 fclose(fp);
103 return 0;
104 }
105
106
107 if (sunheader.ras_maptype != RMT_RAW &&
108 sunheader.ras_maptype != RMT_NONE &&
109 sunheader.ras_maptype != RMT_EQUAL_RGB) {
110 fprintf (stderr, "Sun rasterfile colormap of unsupported type %d\n",
111 sunheader.ras_maptype);
112 fclose(fp);
113 return 0;
114 }
115
116 w = sunheader.ras_width;
117 h = sunheader.ras_height;
118 d = sunheader.ras_depth; /* 1, 8, 24, or 32 (above) */
119 npixels = w * h;
120 if (w <= 0 || h <= 0 || npixels/w != h) {
121 fprintf (stderr, "Sun rasterfile image has invalid dimensions (%dx%d)\n",
122 w, h);
123 fclose(fp);
124 return 0;
125 }
126 if (d == 1)
127 nbytes = npixels/8; /* should round up here, but used only for printf */
128 else {
129 nbytes = npixels * (d/8);
130 /*
131 [nbytes (isize) used only in printfs; don't really care about overflows]
132 if (nbytes/npixels != (d/8)) {
133 fprintf (stderr, "Sun rasterfile has invalid dimensions (%dx%dx%d)\n",
134 w, h, d);
135 fclose(fp);
136 return 0;
137 }
138 */
139 }
140 isize = sunheader.ras_length ? sunheader.ras_length : nbytes;
141 csize = (sunheader.ras_maptype == RMT_NONE) ? 0 : sunheader.ras_maplength;
142
143
144 /* length of the output (xv-format) image */
145 lsize = npixels;
146 if (d == 24 || d == 32) {
147 lsize *= 3;
148 if (lsize/3 != npixels) {
149 fprintf (stderr, "Sun rasterfile has invalid dimensions (%dx%dx%d)\n",
150 w, h, d);
151 fclose(fp);
152 return 0;
153 }
154 }
155
156
157 linesize = w * d;
158 if (linesize/w != d || linesize + 15 < linesize) {
159 fprintf (stderr, "Sun rasterfile has invalid dimensions (%dx%dx%d)\n",
160 w, h, d);
161 fclose(fp);
162 return 0;
163 }
164 if (linesize % 16) linesize += (16 - (linesize % 16));
165 linesize /= 8;
166
167 if (DEBUG) {
168 fprintf(stderr,"%s: LoadSunRas() - loading a %dx%d pic, %d planes\n",
169 cmd, w, h, d);
170 fprintf (stderr,
171 "type %d, maptype %d, isize %d, csize %d, lsize %d, linesize %d\n",
172 sunheader.ras_type, sunheader.ras_maptype,
173 isize, csize, lsize, linesize);
174 }
175
176
177 /* read in the colormap, if any */
178 if (sunheader.ras_maptype == RMT_EQUAL_RGB && csize) {
179 fread (pinfo->r, (size_t) 1, (size_t) sunheader.ras_maplength/3, fp);
180 fread (pinfo->g, (size_t) 1, (size_t) sunheader.ras_maplength/3, fp);
181 fread (pinfo->b, (size_t) 1, (size_t) sunheader.ras_maplength/3, fp);
182 }
183
184 else if (sunheader.ras_maptype == RMT_RAW && csize) {
185 /* we don't know how to handle raw colormap, ignore */
186 fseek (fp, (long) csize, 1);
187 }
188
189 else { /* no colormap, make one up */
190 if (sunheader.ras_depth == 1) {
191 pinfo->r[0] = pinfo->g[0] = pinfo->b[0] = 0;
192 pinfo->r[1] = pinfo->g[1] = pinfo->b[1] = 255;
193 }
194
195 else if (sunheader.ras_depth == 8) {
196 for (i = 0; i < 256; i++)
197 pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i;
198 }
199 }
200
201
202 /* allocate memory for picture and read it in */
203 /* note we may slightly overallocate here (if image is padded) */
204 image = (byte *) malloc ((size_t) lsize);
205 line = (byte *) malloc ((size_t) linesize);
206 if (image == NULL || line == NULL)
207 FatalError("Can't allocate memory for image\n");
208
209
210 for (i = 0; i < h; i++) {
211 if ((i&0x1f) == 0) WaitCursor();
212 if (sunheader.ras_type == RT_BYTE_ENCODED) {
213 if (rle_read (line, 1, linesize, fp, (i==0)) != linesize) break;
214 }
215
216 else {
217 if (fread (line, (size_t) 1, (size_t) linesize, fp) != linesize) {
218 free(image); free(line); fclose(fp);
219 return (sunRasError (bname, "file read error"));
220 }
221 }
222
223 switch (d) {
224 case 1: sunRas1to8 (image + w * i, line, w);
225 break;
226 case 8: xvbcopy((char *) line, (char *) image + w * i, (size_t) w);
227 break;
228 case 24: xvbcopy((char *) line, (char *) image + w * i * 3, (size_t) w*3);
229 break;
230
231 case 32:
232 {
233 int k;
234 byte *ip, *op;
235 ip = line;
236 op = (byte *) (image + w * i * 3);
237 for (k = 0; k<w; k++) {
238 ip++; /* skip 'alpha' */
239 *op++ = *ip++; /* red */
240 *op++ = *ip++; /* green */
241 *op++ = *ip++; /* blue */
242 }
243 }
244 }
245 }
246
247 free(line);
248
249 if (DEBUG) fprintf(stderr,"Sun ras: image loaded!\n");
250
251
252
253 if (d == 24 || d == 32) {
254 if (sunheader.ras_type != RT_FORMAT_RGB) fixBGR(image,w,h);
255 pinfo->type = PIC24;
256 }
257 else pinfo->type = PIC8;
258
259 pinfo->pic = image;
260 pinfo->w = w;
261 pinfo->h = h;
262 pinfo->normw = pinfo->w; pinfo->normh = pinfo->h;
263 pinfo->frmType = F_SUNRAS;
264 pinfo->colType = (d==1) ? F_BWDITHER : F_FULLCOLOR;
265 sprintf(pinfo->fullInfo, "Sun %s rasterfile. (%d plane%s) (%ld bytes)",
266 sunheader.ras_type == RT_BYTE_ENCODED ? "rle" : "standard",
267 d, d == 1 ? "" : "s",
268 (long) (sizeof(struct rasterfile) + csize + isize));
269
270 sprintf(pinfo->shrtInfo, "%dx%d Sun Rasterfile.",w,h);
271 pinfo->comment = (char *) NULL;
272
273 fclose(fp);
274 return 1;
275 }
276
277
278 /*****************************/
rle_read(ptr,size,nitems,fp,init)279 static int rle_read (ptr, size, nitems, fp, init)
280 byte *ptr;
281 int size, nitems,init;
282 FILE *fp;
283 {
284 static int count, ch;
285 int readbytes, c, read;
286
287 if (init) { count = ch = 0; }
288
289 readbytes = size * nitems;
290 for (read = 0; read < readbytes; read++) {
291 if (count) {
292 *ptr++ = (byte) ch;
293 count--;
294 }
295
296 else {
297 c = getc(fp);
298 if (c == EOF) break;
299
300 if (c == RAS_RLE) { /* 0x80 */
301 count = getc(fp);
302 if (count == EOF) break;
303
304 if (count < 0) count &= 0xff;
305 if (count == 0) *ptr++ = c;
306 else {
307 if ((ch = getc(fp)) == EOF) break;
308 *ptr++ = ch;
309 }
310 }
311 else *ptr++ = c;
312 }
313 }
314
315 return (read/size);
316 }
317
318
319 /*****************************/
sunRasError(fname,st)320 static int sunRasError(fname, st)
321 const char *fname, *st;
322 {
323 SetISTR(ISTR_WARNING,"%s: %s", fname, st);
324 return 0;
325 }
326
327
328 /************************************************/
sunRas1to8(dest,src,len)329 static void sunRas1to8 (dest, src, len)
330 byte *dest, *src;
331 int len;
332 {
333 int i, b;
334 int c = 0;
335
336 for (i = 0, b = -1; i < len; i++) {
337 if (b < 0) {
338 b = 7;
339 c = ~*src++;
340 }
341 *dest++ = ((c >> (b--)) & 1);
342 }
343 }
344
345
346
sunRas8to1(dest,src,len,flip)347 static void sunRas8to1 (dest, src, len, flip)
348 byte *dest, *src;
349 int len, flip;
350 {
351 int i, b;
352 int c;
353
354 for (c = b = i = 0; i < len; i++) {
355 c <<= 1;
356 c |= (*src++ ? 1 : 0);
357 if (b++ == 7) {
358 if (flip) c = ~c;
359 *dest++ = (byte) (c & 0xff);
360 b = c = 0;
361 }
362 }
363 if (b) {
364 if (flip) c = ~c;
365 *dest = (byte) ((c<<(8-b)) & 0xff);
366 }
367 }
368
369
370
371
372 /*******************************************/
WriteSunRas(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,userle)373 int WriteSunRas(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,userle)
374 FILE *fp;
375 byte *pic;
376 int ptype,w,h;
377 byte *rmap, *gmap, *bmap;
378 int numcols, colorstyle, userle;
379 {
380 /* writes a sun rasterfile to the already open stream
381 writes either 24-bit, 8-bit or 1-bit
382 currently will not write rle files
383
384 if PIC24 and F_GREYSCALE, writes an 8-bit grayscale image
385
386 biggest problem w/ rle file: should we compute
387 image size first (nicer) or go back and write it
388 in when we are done (kludgy)?
389 */
390
391 struct rasterfile sunheader;
392 int linesize, i, color, d, y, flipbw;
393 byte *line, *graypic, graymap[256], *sp, *dp;
394
395 graypic = NULL;
396 flipbw = 0;
397
398 /* special case: if PIC24 and writing GREYSCALE, write 8-bit file */
399 if (ptype == PIC24 && colorstyle == F_GREYSCALE) {
400 int npixels = w * h;
401 if (w <= 0 || h <= 0 || npixels/w != h) {
402 SetISTR(ISTR_WARNING, "Image is too large (%dx%d)", w, h);
403 return (2);
404 }
405 graypic = (byte *) malloc((size_t) npixels);
406 if (!graypic) FatalError("unable to malloc in WriteSunRas()");
407
408 for (i=0,sp=pic,dp=graypic; i<npixels; i++,sp+=3,dp++) {
409 *dp = MONO(sp[0],sp[1],sp[2]);
410 }
411
412 for (i=0; i<256; i++) graymap[i] = i;
413 rmap = gmap = bmap = graymap;
414 numcols = 256;
415 ptype = PIC8;
416 pic = graypic;
417 }
418
419
420 if (ptype==PIC24) {
421 d = 24;
422 linesize = w * 3;
423 if (linesize/w != 3) {
424 SetISTR(ISTR_WARNING, "Image is too wide (%d)", w);
425 if (graypic) free(graypic);
426 return (2);
427 }
428 } else if (colorstyle != F_BWDITHER) {
429 d = 8;
430 linesize = w;
431 } else {
432 d = 1;
433 linesize = w;
434 if (linesize % 8) linesize += (8 - linesize % 8);
435 linesize /= 8;
436 }
437
438
439
440 if (linesize % 2) linesize++;
441 if (linesize == 0) {
442 SetISTR(ISTR_WARNING, "Image is too wide (%d)", w);
443 if (graypic) free(graypic);
444 return (2);
445 }
446 line = (byte *) malloc((size_t) linesize);
447 if (!line) {
448 SetISTR(ISTR_WARNING, "Can't allocate memory for save!\n");
449 if (graypic) free(graypic);
450 return (1);
451 }
452
453 if (DEBUG)
454 fprintf (stderr,
455 "WriteSunRas: d %d, linesize %d numcols %d\n",
456 d, linesize, numcols);
457
458 if (d==1) {
459 /* set flipbw if color#0 is black */
460 flipbw = (MONO(rmap[0],gmap[0],bmap[0]) < MONO(rmap[1],gmap[1],bmap[1]));
461 }
462
463 /* set up the header */
464 sunheader.ras_magic = RAS_MAGIC;
465 sunheader.ras_width = w;
466 sunheader.ras_height = h;
467 sunheader.ras_depth = d;
468 sunheader.ras_length = linesize * h;
469 sunheader.ras_type = RT_STANDARD;
470 sunheader.ras_maptype = (d==1 || d==24) ? RMT_NONE : RMT_EQUAL_RGB;
471 sunheader.ras_maplength = (d==1 || d==24) ? 0 : 3 * numcols;
472
473 write_sun_long (sunheader.ras_magic , fp);
474 write_sun_long (sunheader.ras_width , fp);
475 write_sun_long (sunheader.ras_height , fp);
476 write_sun_long (sunheader.ras_depth , fp);
477 write_sun_long (sunheader.ras_length , fp);
478 write_sun_long (sunheader.ras_type , fp);
479 write_sun_long (sunheader.ras_maptype , fp);
480 write_sun_long (sunheader.ras_maplength, fp);
481
482 /* write the colormap */
483 if (d == 8) {
484 if (colorstyle == 1) /* grayscale */
485 for (color=0; color<3; color++)
486 for (i=0; i<numcols; i++)
487 putc (MONO(rmap[i],gmap[i],bmap[i]), fp);
488 else {
489 fwrite (rmap, sizeof(byte), (size_t) numcols, fp);
490 fwrite (gmap, sizeof(byte), (size_t) numcols, fp);
491 fwrite (bmap, sizeof(byte), (size_t) numcols, fp);
492 }
493 }
494
495
496 /* write the image */
497 line[linesize-1] = 0;
498 for (y = 0; y < h; y++) {
499 if ((y&0x1f) == 0) WaitCursor();
500
501 if (d == 24) {
502 byte *lptr, *pix;
503
504 for (i=0,lptr=line,pix=pic+y*w*3; i<w; i++,pix+=3) {
505 *lptr++ = pix[2]; /* write date out in BGR order */
506 *lptr++ = pix[1];
507 *lptr++ = pix[0];
508 }
509 }
510
511 else if (d == 8)
512 xvbcopy((char *) pic + y * w, (char *) line, (size_t) w);
513
514 else /* d == 1 */
515 sunRas8to1 (line, pic + y * w, w, flipbw);
516
517 if (fwrite (line, (size_t) 1, (size_t) linesize, fp) != linesize) {
518 SetISTR(ISTR_WARNING, "Write failed during save!\n");
519 if (graypic) free(graypic);
520 free(line);
521 return (2);
522 }
523 }
524
525 free (line);
526 if (graypic) free(graypic);
527 return (0);
528 }
529
530
531 /* reads a 4-byte int in Sun byteorder
532 returns 0 for success, EOF for failure */
read_sun_long(l,fp)533 static int read_sun_long (l, fp)
534 int *l;
535 FILE *fp;
536 {
537 int c0, c1, c2, c3;
538
539 c0 = fgetc(fp);
540 c1 = fgetc(fp);
541 c2 = fgetc(fp);
542 c3 = fgetc(fp);
543
544 *l = (((u_long) c0 & 0xff) << 24) |
545 (((u_long) c1 & 0xff) << 16) |
546 (((u_long) c2 & 0xff) << 8) |
547 (((u_long) c3 & 0xff));
548
549 if (ferror(fp) || feof(fp)) return EOF;
550
551 return 0;
552 }
553
554
555 /* write a long word in sun byte-order
556 returns 0 for success, EOF for failure
557 */
write_sun_long(l,fp)558 static int write_sun_long (l, fp)
559 int l;
560 FILE *fp;
561 {
562 char c;
563
564 c = ((l >> 24) & 0xff);
565 if (putc (c, fp) == EOF) return (EOF);
566 c = ((l >> 16) & 0xff);
567 if (putc (c, fp) == EOF) return (EOF);
568 c = ((l >> 8) & 0xff);
569 if (putc (c, fp) == EOF) return (EOF);
570 c = (l & 0xff);
571 if (putc (c, fp) == EOF) return (EOF);
572 return (0);
573 }
574
575
576
577
578 /* kr3 - fix up BGR order SUN 24-bit rasters to be RGB order */
fixBGR(img,w,h)579 static void fixBGR(img,w,h)
580 unsigned char *img;
581 int w,h;
582 {
583 int i,npixels;
584 unsigned char tmp;
585
586 npixels = w*h;
587 for (i=0; i<npixels; i++) {
588 tmp = img[0]; /* swap red and blue channels */
589 img[0] = img[2];
590 img[2] = tmp;
591 img += 3; /* bump to next pixel */
592 }
593 }
594
595