1 /*
2 * This software is copyrighted as noted below. It may be freely copied,
3 * modified, and redistributed, provided that the copyright notice is
4 * preserved on all copies.
5 *
6 * There is no warranty or other guarantee of fitness for this software,
7 * it is provided solely "as is". Bug reports or fixes may be sent
8 * to the author, who may or may not act on them as he desires.
9 *
10 * You may not include this software in a program or other software product
11 * without supplying the source, or without informing the end-user that the
12 * source is available for no extra charge.
13 *
14 * If you modify this software, you should include a notice giving the
15 * name of the person performing the modification, the date of modification,
16 * and the reason for such modification.
17 */
18 /*
19 * aliastorle.c - Convert Alias "pix" format to Utah's rle images
20 *
21 * Author: Raul Rivero
22 * Mathematics Dept.
23 * University of Oviedo
24 * Date: Fri Dec 27 1991
25 * Copyright (c) 1991, Raul Rivero
26 *
27 */
28 #ifndef lint
29 static char rcs_id[] = "$Header: /l/spencer/src/urt/cnv/RCS/aliastorle.c,v 3.0.1.1 1992/04/29 20:01:12 spencer Exp $";
30 #endif
31 /*
32 aliastorle() Tag the file.
33 */
34
35 #include <stdio.h>
36 #include <math.h>
37 #include "rle.h"
38
39 #define byte unsigned char
40 #define Fread(p, s, n, f) if ( fread(p, s, n, f) != n ) error(3)
41 #define Fwrite(p, s, n, f) if ( fwrite(p, s, n, f) != n ) error(4)
42 #define VPRINTF if (verbose) fprintf
43
44 /*
45 * Alias header.
46 */
47 typedef struct {
48 short xsize, ysize;
49 short xinit, yinit;
50 short depth;
51 } alias_hdr;
52
53 /*
54 * I use a intermediate format ( a simple bitmap ) with
55 * this format ...
56 */
57 typedef struct {
58 int xsize, ysize; /* sizes */
59 int depth; /* # of colors */
60 int colors; /* # of colors */
61 byte *r, *g, *b; /* components or bitmap (planes < 8) */
62 byte *cmap; /* cmap if planes < 8 */
63 } bitmap_hdr;
64
65 /*
66 * Prototypes ( only what is necesary ).
67 */
68 #ifdef USE_PROTOTYPES
69 static char *Malloc(long int);
70 static char *read_file(FILE *, int *);
71 static long filelen(FILE *);
72 static int read_alias(FILE *, bitmap_hdr *);
73 static void write_rle(FILE *, bitmap_hdr *);
74 static void read_alias_header(FILE *, alias_hdr *);
75 static void create_alias_cmap(bitmap_hdr *);
76 static void uncode_alias24(byte *, byte *, byte *, byte *, byte *);
77 static void uncode_alias(byte *, byte *, byte *);
78 static int read_line_alias24(FILE *, byte *, byte *, byte *, int);
79 static int read_line_alias(FILE *, byte *, int);
80 static void error( int );
81 #else
82 static char *Malloc();
83 static char *read_file();
84 static long filelen();
85 static int read_alias();
86 static void write_rle(), read_alias_header();
87 static void create_alias_cmap(), uncode_alias24(), uncode_alias();
88 static int read_line_alias24(), read_line_alias();
89 static void error();
90 #endif
91
92
93 /*
94 * The flag for verbose.
95 */
96 int verbose= 0;
97 /*
98 * RLE file header (put here so can be initialized with cmd and file names).
99 */
100 rle_hdr the_hdr;
101
102 /*****************************************************************
103 * TAG( main )
104 *
105 * Usage: aliastorle [-v] [-o outfile] [infile]
106 *
107 * Inputs:
108 * -v: Verbose switch.
109 * infile: Input Alias pix file. Stdin used if not
110 * specified.
111 * Outputs:
112 * outfile: Output a RLE file. Stdout used if not
113 * specified.
114 * Assumptions:
115 * [None]
116 * Algorithm:
117 * [None]
118 */
119
120 int
main(argc,argv)121 main( argc, argv )
122 int argc;
123 char **argv;
124 {
125 char *inname = NULL;
126 char *outname = NULL;
127 FILE *infile;
128 FILE *outfile;
129 int oflag = 0;
130 bitmap_hdr bitmap;
131
132 the_hdr = *rle_hdr_init( (rle_hdr *)NULL );
133 /*
134 * Get options
135 */
136 if ( !scanargs( argc, argv, "% v%- o%-outfile!s infile%s",
137 &verbose, &oflag, &outname, &inname ))
138 exit( 1 );
139
140 /* An input file name ? */
141 rle_names( &the_hdr, cmd_name( argv ), inname, 0 );
142 infile= rle_open_f(the_hdr.cmd, inname, "r");
143
144
145 /*
146 * Translate Alias "pix" format into my bitmap.
147 */
148 read_alias(infile, &bitmap);
149 rle_close_f(infile); /* We finish with this file */
150
151 /*
152 * We have a bitmap with the image, so we open the
153 * new rle file and write it.
154 */
155 outfile = rle_open_f(cmd_name(argv), outname, "w");
156 write_rle(outfile, &bitmap);
157 fclose(outfile); /* it is not necesary, but ... */
158
159 exit(0);
160 }
161
162 static int
read_alias(handle,image)163 read_alias(handle, image)
164 FILE *handle;
165 bitmap_hdr *image;
166 {
167 register int i;
168 alias_hdr header;
169 int total_size;
170 register int xsize;
171 byte *end;
172 byte *r, *g = 0, *b = 0;
173 int can_read_all;
174 byte *buffer = 0, *ptr = 0;
175 int filesize;
176 int allplanes = 0;
177 int error;
178 int cmapsize;
179
180 /*
181 * Alias "pix" is a bad format to read line per line. If every
182 * triplet is different to its next, then we read 2 bytes, 2 bytes ...
183 * ... and read a file of 1 Mb. with this form ... hmmmmmm !!!
184 * This is necesary if we are reading from stdin, but if we have
185 * a file, we'll read the file into memory ( one access to disk ).
186 */
187 can_read_all = (handle != stdin); /* a regular file ? */
188 VPRINTF(stderr, "Reading Alias from %s\n",
189 (can_read_all ? "file" : "stdin"));
190
191 if (can_read_all) {
192 /*
193 * We are using a regular file ( not a pipe ), so we can
194 * read it into memory.
195 */
196 ptr= buffer= (byte *) read_file(handle, &filesize);
197 VPRINTF(stderr, "File size: %d\n", filesize);
198 /* Copy the header */
199 bcopy(ptr, &header, sizeof(alias_hdr));
200 ptr += sizeof(alias_hdr); /* skip the header */
201 }else {
202 /*
203 * We are using stdin so ...
204 */
205 /* We need the header of Alias pix */
206 VPRINTF(stderr, "Reading Alias header\n");
207 read_alias_header(handle, &header);
208 }
209
210 /* Size in pixels */
211 total_size = header.xsize * header.ysize;
212
213 /* Fill our header */
214 image->xsize = header.xsize;
215 image->ysize = header.ysize;
216 image->depth = header.depth;
217 image->colors = 1 << image->depth;
218 allplanes = ( image->depth > 8 ); /* an image with 24 planes ? */
219 VPRINTF(stderr, "Image size: %dx%d\n", image->xsize, image->ysize);
220 VPRINTF(stderr, "Depth: %d\n", image->depth);
221
222 /* Get some memory */
223 if ( allplanes ) {
224 /*
225 * We have a image with 24 planes, so we need three buffers to
226 * store it.
227 */
228 r= image->r = (byte *) Malloc(total_size);
229 g= image->g = (byte *) Malloc(total_size);
230 b= image->b = (byte *) Malloc(total_size);
231 }else {
232 /*
233 * The image has less than 256 colors, so we use one plane,
234 * for the bitmap, and the cmap.
235 */
236 r= image->r = (byte *) Malloc(total_size);
237 cmapsize= image->colors * 3; /* size in bytes */
238 image->cmap = (byte *) Malloc(cmapsize);
239 /* Creating the cmap from file */
240 VPRINTF(stderr, "Creating cmap\n");
241 create_alias_cmap(image);
242 }
243
244 /*
245 * We are ready to uncompress Alias file.
246 */
247 VPRINTF(stderr, "Uncompressing Alias file\n");
248 if (can_read_all) {
249 /*
250 * We have the file into memory so we uncode it directly.
251 */
252 end = r + total_size; /* the end of main buffer */
253 if ( allplanes )
254 uncode_alias24(ptr, r, g, b, end);
255 else uncode_alias(ptr, r, end);
256 /*
257 * We have read the file and uncompressed, so we can
258 * free the memory ( and exit ).
259 */
260 free(buffer);
261 }else {
262 /*
263 * We'll read each line from Alias file ( stdin ) until we
264 * fill our buffers or we get an error.
265 */
266 xsize = image->xsize;
267 for (i= 0; i< image->ysize; i++) {
268 /*
269 * Read and decode the Alias raster information, two cases:
270 * with planes > 8 => a triplet (RGB), else a index.
271 */
272 if ( allplanes ) {
273 /* An image with 24 planes */
274 error= read_line_alias24(handle, r, b, g, xsize);
275 }else {
276 /* An image with indexes to cmap */
277 error= read_line_alias(handle, r, xsize);
278 }
279 if (error) {
280 /* An error, so we exit */
281 fprintf(stderr, "Error while reading line %d\n", i);
282 return 1;
283 }else {
284 /* A line has been read, so we increment theirs pointers */
285 r += xsize;
286 if ( allplanes ) {
287 g += xsize;
288 b += xsize;
289 }
290 }
291 }
292 } /* end of reading from stdin */
293
294 /* Finish with no problems */
295 return 0;
296 }
297
298 static void
read_alias_header(handle,header)299 read_alias_header(handle, header)
300 FILE *handle;
301 alias_hdr *header;
302 {
303 /* Read the header */
304 Fread(header, sizeof(alias_hdr), 1, handle);
305
306 /* Check some things */
307 if ( header->xsize < 1 || header -> xsize > 2560 ||
308 header->ysize < 1 || header -> ysize > 2560 )
309 error(5);
310 if ( header->depth > 24 || header->depth < 1 )
311 error(5);
312 }
313
314 static int
read_line_alias24(handle,r,g,b,size)315 read_line_alias24(handle, r, g, b, size)
316 FILE *handle;
317 byte *r, *g, *b;
318 register int size;
319 {
320 register int i;
321 register int count = 0;
322 byte *end;
323 byte buffer[4];
324
325 end = r + size;
326 while (count < size) {
327 /*
328 * Alias code format: <repeat>BGR => 4 bytes.
329 */
330 if ( !fread(buffer, 4, 1, handle) ) /* read next buffer */
331 return 1; /* hey !, an EOF here ?. Hmmmm, this is an error ! */
332
333 count += buffer[0]; /* # of repetitions */
334 /* repeat 'buffer[0]' times these triplet */
335 for (i= 0; i< buffer[0]; i++) {
336 *r++ = buffer[3];
337 *g++ = buffer[1];
338 *b++ = buffer[2];
339 }
340 if ( r > end )
341 error(6); /* uncompress more bytes than size */
342 }
343
344 /* No problems */
345 return 0;
346 }
347
348 static int
read_line_alias(handle,r,size)349 read_line_alias(handle, r, size)
350 FILE *handle;
351 byte *r;
352 register int size;
353 {
354 register int i;
355 register int count = 0;
356 byte *end;
357 byte buffer[2];
358
359 end = r + size;
360 while (count < size) {
361 /*
362 * Alias code format: <repeat><index> => 2 bytes.
363 */
364 if ( !fread(buffer, 2, 1, handle) ) /* read next buffer */
365 return 1; /* hey !, an EOF here ?. Hmmmm, this is an error ! */
366
367 count += buffer[0]; /* # of repetitions */
368 /* repeat 'buffer[0]' times these index */
369 for (i= 0; i< buffer[0]; i++) {
370 *r++ = buffer[1];
371 }
372 if ( r > end )
373 error(6); /* uncompress more bytes than size */
374 }
375
376 /* No problems */
377 return 0;
378 }
379
380 static void
create_alias_cmap(image)381 create_alias_cmap(image)
382 bitmap_hdr *image;
383 {
384 register int i;
385 byte *ptr;
386
387 /*
388 * Alias 8 bits files are b&w, so ...
389 */
390 ptr = (byte *) image->cmap;
391 for (i= 0; i< image->colors; i++) {
392 *ptr++ = i;
393 *ptr++ = i;
394 *ptr++ = i;
395 }
396 }
397
398 static void
bitmapcmap_to_rlecmap(bitmap,rle)399 bitmapcmap_to_rlecmap(bitmap, rle)
400 bitmap_hdr *bitmap;
401 rle_hdr *rle;
402 {
403 register int i;
404 rle_map *rch, *gch, *bch;
405 byte *ptr;
406
407 /* Allocate memory */
408 rle->cmap= (rle_map *) Malloc(bitmap->colors * 3 * sizeof(rle_map));
409
410 /*
411 * We'll use 3 ptrs, first to R channel, second to G channel, ...
412 */
413 ptr = bitmap->cmap;
414 rch = rle->cmap;
415 gch = &(rle->cmap[bitmap->colors]);
416 bch = &(rle->cmap[2 * bitmap->colors]);
417 for (i= 0; i< bitmap->colors; i++) {
418 *rch++ = (*ptr++ << 8);
419 *gch++ = (*ptr++ << 8);
420 *bch++ = (*ptr++ << 8);
421 }
422 }
423
424 static void
uncode_alias24(ptr,rbuf,gbuf,bbuf,end)425 uncode_alias24(ptr, rbuf, gbuf, bbuf, end)
426 byte *ptr;
427 byte *rbuf, *gbuf, *bbuf;
428 byte *end;
429 {
430 register int i;
431 byte r, g, b;
432
433 while ( rbuf < end ) { /* while not end of buffer */
434 if ( (i= *ptr++) > 1 ) { /* how mary repetitions ? */
435 b= *ptr++;
436 g= *ptr++;
437 r= *ptr++;
438 while( i-- ) { /* copy these triplet 'i' times */
439 *rbuf++ = r;
440 *gbuf++ = g;
441 *bbuf++ = b;
442 }
443 }else { /* else, copy these triplet */
444 *bbuf++ = *ptr++;
445 *gbuf++ = *ptr++;
446 *rbuf++ = *ptr++;
447 }
448 }
449 }
450
451 static void
uncode_alias(ptr,rbuf,end)452 uncode_alias(ptr, rbuf, end)
453 byte *ptr;
454 byte *rbuf;
455 byte *end;
456 {
457 register int i;
458 byte r;
459
460 while ( rbuf < end ) { /* while not end of buffer */
461 if ( (i= *ptr++) > 1 ) { /* how mary repetitions ? */
462 r= *ptr++;
463 while( i-- ) { /* copy these index 'i' times */
464 *rbuf++ = r;
465 }
466 }else { /* else, copy these index */
467 *rbuf++ = *ptr++;
468 }
469 }
470 }
471
472 static void
write_rle(handle,image)473 write_rle(handle, image)
474 FILE *handle;
475 bitmap_hdr *image;
476 {
477 register int i, j;
478 rle_pixel **row;
479 byte *r;
480 int offset_last;
481
482 VPRINTF(stderr, "Writing RLE file\n");
483 /*
484 * Fill the rle header with our ( little ) information.
485 */
486 the_hdr.rle_file = handle;
487 the_hdr.xmin = 0;
488 the_hdr.ymin = 0;
489 the_hdr.xmax = image->xsize - 1;
490 the_hdr.ymax = image->ysize - 1;
491 if (image->depth > 8) {
492 the_hdr.ncolors = 3; /* 24 planes */
493 the_hdr.ncmap = 0;
494 }else {
495 the_hdr.ncolors = 1;
496 the_hdr.ncmap = 3;
497 the_hdr.cmaplen = image->depth;
498 /* Convert our cmap to rle cmap */
499 bitmapcmap_to_rlecmap(image, &the_hdr);
500 }
501 the_hdr.alpha = 0; /* we don't use alpha channels */
502
503 /* Write the header */
504 rle_put_setup(&the_hdr);
505
506 /*
507 * RLE write raster lines in reverse order, so we'll put
508 * pointers to the last line.
509 */
510 offset_last = image->xsize * image->ysize - image->xsize;
511
512 VPRINTF(stderr, "Compressing RLE lines\n");
513 if (image->depth > 8) {
514 /*
515 * 24 planes, rle_putrow functions use a buffer which contains
516 * a line, so we need do it.
517 */
518 /* Allocate some memory */
519 row = (rle_pixel **)Malloc( 3 * sizeof(rle_pixel *) );
520 if ( row == 0 )
521 error(2);
522
523 /* Pointers to last line */
524 row[0] = image->r + offset_last;
525 row[1] = image->g + offset_last;
526 row[2] = image->b + offset_last;
527
528 /* Write each line */
529 for (i= 0; i< image->ysize; i++) {
530 rle_putrow(row, image->xsize, &the_hdr);
531 /*
532 * Back up to the previous line.
533 */
534 for ( j = 0; j < 3; j++ )
535 row[0] -= image->xsize;
536 }
537 /* free rle row buffer */
538 free(row);
539
540 }else {
541 /*
542 * A image with cmap.
543 */
544 /* if a simple plane => stored on R component */
545 r = image->r + offset_last;
546 for (i= 0; i< image->ysize; i++) {
547 rle_putrow(&r, image->xsize, &the_hdr);
548 r -= image->xsize;
549 }
550 }
551
552 /*
553 * Put an EOF into the RLE file ( and THE END ! )
554 */
555 rle_puteof(&the_hdr);
556 }
557
558 static void
error(code)559 error(code)
560 int code;
561 {
562 fprintf(stderr, "%s: ", the_hdr.cmd);
563 switch (code) {
564 case 0:
565 break;
566 case 1: fprintf(stderr, "Cannot open file\n");
567 break;
568 case 2: fprintf(stderr, "Out of memory\n");
569 break;
570 case 3: fprintf(stderr, "Error while reading input file\n");
571 break;
572 case 4: fprintf(stderr, "Error while writing output file\n");
573 break;
574 case 5: fprintf(stderr, "Input file is not an Alias pix\n");
575 break;
576 case 6: fprintf(stderr, "File corrupt ( uncompress too bytes )\n");
577 break;
578 case 99: fprintf(stderr, "Not ready\n");
579 break;
580 default: fprintf(stderr, "Unknow error code (%d)\n", code);
581 break;
582 }
583 exit(1);
584 }
585
586 /*
587 * My standard functions.
588 */
589
Malloc(size)590 static char *Malloc(size)
591 long int size;
592 {
593 char *ptr;
594
595 if ((ptr = (char *) malloc(size)) == NULL)
596 error(2);
597
598 /*
599 * Usually compilers fill buffers with zeros,
600 * but ...
601 */
602 bzero( ptr, size );
603 return ptr;
604 }
605
606
read_file(handle,bytes)607 static char *read_file(handle, bytes)
608 FILE *handle;
609 int *bytes;
610 {
611 char *buffer;
612
613 /* Get size of file and allocate memory */
614 *bytes= (int) filelen(handle);
615 if ( *bytes > 0 ) /* Ok, it's a regular file. */
616 {
617 buffer= (char *) Malloc(*bytes);
618
619 /* Read it */
620 Fread(buffer, (int) (*bytes), 1, handle);
621 }
622 else /* Oops! It's a pipe. */
623 {
624 int n = 0, bufsize = 0;
625 /* Read in chunks of BUFSIZ. */
626 buffer = Malloc( BUFSIZ );
627 while ( (n = fread( buffer + bufsize, 1, BUFSIZ, handle )) == BUFSIZ )
628 {
629 bufsize += BUFSIZ;
630 buffer = realloc( buffer, bufsize + BUFSIZ );
631 RLE_CHECK_ALLOC( the_hdr.cmd, buffer, "input image" );
632 }
633 if ( n >= 0 )
634 n += bufsize;
635 else
636 n = bufsize;
637 }
638
639 /* Return the buffer */
640 return buffer;
641 }
642
filelen(handle)643 static long filelen(handle)
644 FILE *handle;
645 {
646 long current_pos;
647 long len;
648
649 /* Save current position */
650 current_pos= ftell(handle);
651
652 /* Get len of file */
653 fseek(handle, 0, 2);
654 len= ftell(handle);
655
656 /* Restore position */
657 fseek(handle, current_pos, 0);
658
659 return len;
660 }
661
662
663