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