Load cups into easysw/current.
[thirdparty/cups.git] / filter / image-sgilib.c
1 /*
2  * "$Id: image-sgilib.c 4741 2005-10-02 04:25:52Z mike $"
3  *
4  *   SGI image file format library routines for the Common UNIX Printing
5  *   System (CUPS).
6  *
7  *   Copyright 1993-2005 by Easy Software Products.
8  *
9  *   These coded instructions, statements, and computer programs are the
10  *   property of Easy Software Products and are protected by Federal
11  *   copyright law.  Distribution and use rights are outlined in the file
12  *   "LICENSE.txt" which should have been included with this file.  If this
13  *   file is missing or damaged please contact Easy Software Products
14  *   at:
15  *
16  *       Attn: CUPS Licensing Information
17  *       Easy Software Products
18  *       44141 Airport View Drive, Suite 204
19  *       Hollywood, Maryland 20636 USA
20  *
21  *       Voice: (301) 373-9600
22  *       EMail: cups-info@cups.org
23  *         WWW: http://www.cups.org
24  *
25  *   This file is subject to the Apple OS-Developed Software exception.
26  *
27  * Contents:
28  *
29  *   sgiClose()    - Close an SGI image file.
30  *   sgiGetRow()   - Get a row of image data from a file.
31  *   sgiOpen()     - Open an SGI image file for reading or writing.
32  *   sgiOpenFile() - Open an SGI image file for reading or writing.
33  *   sgiPutRow()   - Put a row of image data to a file.
34  *   getlong()     - Get a 32-bit big-endian integer.
35  *   getshort()    - Get a 16-bit big-endian integer.
36  *   putlong()     - Put a 32-bit big-endian integer.
37  *   putshort()    - Put a 16-bit big-endian integer.
38  *   read_rle8()   - Read 8-bit RLE data.
39  *   read_rle16()  - Read 16-bit RLE data.
40  *   write_rle8()  - Write 8-bit RLE data.
41  *   write_rle16() - Write 16-bit RLE data.
42  */
43
44 #include "image-sgi.h"
45
46
47 /*
48  * Local functions...
49  */
50
51 static int      getlong(FILE *);
52 static int      getshort(FILE *);
53 static int      putlong(long, FILE *);
54 static int      putshort(unsigned short, FILE *);
55 static int      read_rle8(FILE *, unsigned short *, int);
56 static int      read_rle16(FILE *, unsigned short *, int);
57 static int      write_rle8(FILE *, unsigned short *, int);
58 static int      write_rle16(FILE *, unsigned short *, int);
59
60
61 /*
62  * 'sgiClose()' - Close an SGI image file.
63  */
64
65 int                                     /* O - 0 on success, -1 on error */
66 sgiClose(sgi_t *sgip)                   /* I - SGI image */
67 {
68   int   i;                              /* Return status */
69   long  *offset;                        /* Looping var for offset table */
70
71
72   if (sgip == NULL)
73     return (-1);
74
75   if (sgip->mode == SGI_WRITE && sgip->comp != SGI_COMP_NONE)
76   {
77    /*
78     * Write the scanline offset table to the file...
79     */
80
81     fseek(sgip->file, 512, SEEK_SET);
82
83     for (i = sgip->ysize * sgip->zsize, offset = sgip->table[0];
84          i > 0;
85          i --, offset ++)
86       if (putlong(offset[0], sgip->file) < 0)
87         return (-1);
88
89     for (i = sgip->ysize * sgip->zsize, offset = sgip->length[0];
90          i > 0;
91          i --, offset ++)
92       if (putlong(offset[0], sgip->file) < 0)
93         return (-1);
94   }
95
96   if (sgip->table != NULL)
97   {
98     free(sgip->table[0]);
99     free(sgip->table);
100   }
101
102   if (sgip->length != NULL)
103   {
104     free(sgip->length[0]);
105     free(sgip->length);
106   }
107
108   if (sgip->comp == SGI_COMP_ARLE)
109     free(sgip->arle_row);
110
111   i = fclose(sgip->file);
112   free(sgip);
113
114   return (i);
115 }
116
117
118 /*
119  * 'sgiGetRow()' - Get a row of image data from a file.
120  */
121
122 int                                     /* O - 0 on success, -1 on error */
123 sgiGetRow(sgi_t          *sgip,         /* I - SGI image */
124           unsigned short *row,          /* O - Row to read */
125           int            y,             /* I - Line to read */
126           int            z)             /* I - Channel to read */
127 {
128   int   x;                              /* X coordinate */
129   long  offset;                         /* File offset */
130
131
132   if (sgip == NULL ||
133       row == NULL ||
134       y < 0 || y >= sgip->ysize ||
135       z < 0 || z >= sgip->zsize)
136     return (-1);
137
138   switch (sgip->comp)
139   {
140     case SGI_COMP_NONE :
141        /*
142         * Seek to the image row - optimize buffering by only seeking if
143         * necessary...
144         */
145
146         offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp;
147         if (offset != ftell(sgip->file))
148           fseek(sgip->file, offset, SEEK_SET);
149
150         if (sgip->bpp == 1)
151         {
152           for (x = sgip->xsize; x > 0; x --, row ++)
153             *row = getc(sgip->file);
154         }
155         else
156         {
157           for (x = sgip->xsize; x > 0; x --, row ++)
158             *row = getshort(sgip->file);
159         }
160         break;
161
162     case SGI_COMP_RLE :
163         offset = sgip->table[z][y];
164         if (offset != ftell(sgip->file))
165           fseek(sgip->file, offset, SEEK_SET);
166
167         if (sgip->bpp == 1)
168           return (read_rle8(sgip->file, row, sgip->xsize));
169         else
170           return (read_rle16(sgip->file, row, sgip->xsize));
171   }
172
173   return (0);
174 }
175
176
177 /*
178  * 'sgiOpen()' - Open an SGI image file for reading or writing.
179  */
180
181 sgi_t *                                 /* O - New image */
182 sgiOpen(const char *filename,           /* I - File to open */
183         int        mode,                /* I - Open mode (SGI_READ or SGI_WRITE) */
184         int        comp,                /* I - Type of compression */
185         int        bpp,                 /* I - Bytes per pixel */
186         int        xsize,               /* I - Width of image in pixels */
187         int        ysize,               /* I - Height of image in pixels */
188         int        zsize)               /* I - Number of channels */
189 {
190   sgi_t *sgip;                          /* New SGI image file */
191   FILE  *file;                          /* Image file pointer */
192
193
194   if (mode == SGI_READ)
195     file = fopen(filename, "rb");
196   else
197     file = fopen(filename, "wb+");
198
199   if (file == NULL)
200     return (NULL);
201
202   if ((sgip = sgiOpenFile(file, mode, comp, bpp, xsize, ysize, zsize)) == NULL)
203     fclose(file);
204
205   return (sgip);
206 }
207
208
209 /*
210  * 'sgiOpenFile()' - Open an SGI image file for reading or writing.
211  */
212
213 sgi_t *                                 /* O - New image */
214 sgiOpenFile(FILE *file,                 /* I - File to open */
215             int  mode,                  /* I - Open mode (SGI_READ or SGI_WRITE) */
216             int  comp,                  /* I - Type of compression */
217             int  bpp,                   /* I - Bytes per pixel */
218             int  xsize,                 /* I - Width of image in pixels */
219             int  ysize,                 /* I - Height of image in pixels */
220             int  zsize)                 /* I - Number of channels */
221 {
222   int   i, j;                           /* Looping var */
223   char  name[80];                       /* Name of file in image header */
224   short magic;                          /* Magic number */
225   sgi_t *sgip;                          /* New image pointer */
226
227
228   if ((sgip = calloc(sizeof(sgi_t), 1)) == NULL)
229     return (NULL);
230
231   sgip->file = file;
232
233   switch (mode)
234   {
235     case SGI_READ :
236         sgip->mode = SGI_READ;
237
238         magic = getshort(sgip->file);
239         if (magic != SGI_MAGIC)
240         {
241           free(sgip);
242           return (NULL);
243         }
244
245         sgip->comp  = getc(sgip->file);
246         sgip->bpp   = getc(sgip->file);
247         getshort(sgip->file);           /* Dimensions */
248         sgip->xsize = getshort(sgip->file);
249         sgip->ysize = getshort(sgip->file);
250         sgip->zsize = getshort(sgip->file);
251         getlong(sgip->file);            /* Minimum pixel */
252         getlong(sgip->file);            /* Maximum pixel */
253
254         if (sgip->comp)
255         {
256          /*
257           * This file is compressed; read the scanline tables...
258           */
259
260           fseek(sgip->file, 512, SEEK_SET);
261
262           sgip->table    = calloc(sgip->zsize, sizeof(long *));
263           sgip->table[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long));
264           for (i = 1; i < sgip->zsize; i ++)
265             sgip->table[i] = sgip->table[0] + i * sgip->ysize;
266
267           for (i = 0; i < sgip->zsize; i ++)
268             for (j = 0; j < sgip->ysize; j ++)
269               sgip->table[i][j] = getlong(sgip->file);
270         }
271         break;
272
273     case SGI_WRITE :
274         if (xsize < 1 ||
275             ysize < 1 ||
276             zsize < 1 ||
277             bpp < 1 || bpp > 2 ||
278             comp < SGI_COMP_NONE || comp > SGI_COMP_ARLE)
279         {
280           free(sgip);
281           return (NULL);
282         }
283
284         sgip->mode = SGI_WRITE;
285
286         putshort(SGI_MAGIC, sgip->file);
287         putc((sgip->comp = comp) != 0, sgip->file);
288         putc(sgip->bpp = bpp, sgip->file);
289         putshort(3, sgip->file);                /* Dimensions */
290         putshort(sgip->xsize = xsize, sgip->file);
291         putshort(sgip->ysize = ysize, sgip->file);
292         putshort(sgip->zsize = zsize, sgip->file);
293         if (bpp == 1)
294         {
295           putlong(0, sgip->file);       /* Minimum pixel */
296           putlong(255, sgip->file);     /* Maximum pixel */
297         }
298         else
299         {
300           putlong(-32768, sgip->file);  /* Minimum pixel */
301           putlong(32767, sgip->file);   /* Maximum pixel */
302         }
303         putlong(0, sgip->file);         /* Reserved */
304
305         memset(name, 0, sizeof(name));
306         fwrite(name, sizeof(name), 1, sgip->file);
307
308         for (i = 0; i < 102; i ++)
309           putlong(0, sgip->file);
310
311         switch (comp)
312         {
313           case SGI_COMP_NONE : /* No compression */
314              /*
315               * This file is uncompressed.  To avoid problems with sparse files,
316               * we need to write blank pixels for the entire image...
317               */
318
319               if (bpp == 1)
320               {
321                 for (i = xsize * ysize * zsize; i > 0; i --)
322                   putc(0, sgip->file);
323               }
324               else
325               {
326                 for (i = xsize * ysize * zsize; i > 0; i --)
327                   putshort(0, sgip->file);
328               }
329               break;
330
331           case SGI_COMP_ARLE : /* Aggressive RLE */
332               sgip->arle_row    = calloc(xsize, sizeof(unsigned short));
333               sgip->arle_offset = 0;
334
335           case SGI_COMP_RLE : /* Run-Length Encoding */
336              /*
337               * This file is compressed; write the (blank) scanline tables...
338               */
339
340               for (i = 2 * ysize * zsize; i > 0; i --)
341                 putlong(0, sgip->file);
342
343               sgip->firstrow = ftell(sgip->file);
344               sgip->nextrow  = ftell(sgip->file);
345               sgip->table    = calloc(sgip->zsize, sizeof(long *));
346               sgip->table[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long));
347               for (i = 1; i < sgip->zsize; i ++)
348                 sgip->table[i] = sgip->table[0] + i * sgip->ysize;
349               sgip->length    = calloc(sgip->zsize, sizeof(long *));
350               sgip->length[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long));
351               for (i = 1; i < sgip->zsize; i ++)
352                 sgip->length[i] = sgip->length[0] + i * sgip->ysize;
353               break;
354         }
355         break;
356
357     default :
358         free(sgip);
359         return (NULL);
360   }
361
362   return (sgip);
363 }
364
365
366 /*
367  * 'sgiPutRow()' - Put a row of image data to a file.
368  */
369
370 int                                     /* O - 0 on success, -1 on error */
371 sgiPutRow(sgi_t          *sgip,         /* I - SGI image */
372           unsigned short *row,          /* I - Row to write */
373           int            y,             /* I - Line to write */
374           int            z)             /* I - Channel to write */
375 {
376   int   x;                              /* X coordinate */
377   long  offset;                         /* File offset */
378
379
380   if (sgip == NULL ||
381       row == NULL ||
382       y < 0 || y >= sgip->ysize ||
383       z < 0 || z >= sgip->zsize)
384     return (-1);
385
386   switch (sgip->comp)
387   {
388     case SGI_COMP_NONE :
389        /*
390         * Seek to the image row - optimize buffering by only seeking if
391         * necessary...
392         */
393
394         offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp;
395         if (offset != ftell(sgip->file))
396           fseek(sgip->file, offset, SEEK_SET);
397
398         if (sgip->bpp == 1)
399         {
400           for (x = sgip->xsize; x > 0; x --, row ++)
401             putc(*row, sgip->file);
402         }
403         else
404         {
405           for (x = sgip->xsize; x > 0; x --, row ++)
406             putshort(*row, sgip->file);
407         }
408         break;
409
410     case SGI_COMP_ARLE :
411         if (sgip->table[z][y] != 0)
412           return (-1);
413
414        /*
415         * First check the last row written...
416         */
417
418         if (sgip->arle_offset > 0)
419         {
420           for (x = 0; x < sgip->xsize; x ++)
421             if (row[x] != sgip->arle_row[x])
422               break;
423
424           if (x == sgip->xsize)
425           {
426             sgip->table[z][y]  = sgip->arle_offset;
427             sgip->length[z][y] = sgip->arle_length;
428             return (0);
429           }
430         }
431
432        /*
433         * If that didn't match, search all the previous rows...
434         */
435
436         fseek(sgip->file, sgip->firstrow, SEEK_SET);
437
438         if (sgip->bpp == 1)
439         {
440           for (;;)
441           {
442             sgip->arle_offset = ftell(sgip->file);
443             if ((sgip->arle_length = read_rle8(sgip->file, sgip->arle_row, sgip->xsize)) < 0)
444             {
445               x = 0;
446               break;
447             }
448
449             if (memcmp(row, sgip->arle_row, sgip->xsize * sizeof(unsigned short)) == 0)
450             {
451               x = sgip->xsize;
452               break;
453             }
454           }
455         }
456         else
457         {
458           for (;;)
459           {
460             sgip->arle_offset = ftell(sgip->file);
461             if ((sgip->arle_length = read_rle16(sgip->file, sgip->arle_row, sgip->xsize)) < 0)
462             {
463               x = 0;
464               break;
465             }
466
467             if (memcmp(row, sgip->arle_row, sgip->xsize * sizeof(unsigned short)) == 0)
468             {
469               x = sgip->xsize;
470               break;
471             }
472           }
473         }
474
475         if (x == sgip->xsize)
476         {
477           sgip->table[z][y]  = sgip->arle_offset;
478           sgip->length[z][y] = sgip->arle_length;
479           return (0);
480         }
481         else
482           fseek(sgip->file, 0, SEEK_END);       /* Clear EOF */
483
484     case SGI_COMP_RLE :
485         if (sgip->table[z][y] != 0)
486           return (-1);
487
488         offset = sgip->table[z][y] = sgip->nextrow;
489
490         if (offset != ftell(sgip->file))
491           fseek(sgip->file, offset, SEEK_SET);
492
493         if (sgip->bpp == 1)
494           x = write_rle8(sgip->file, row, sgip->xsize);
495         else
496           x = write_rle16(sgip->file, row, sgip->xsize);
497
498         if (sgip->comp == SGI_COMP_ARLE)
499         {
500           sgip->arle_offset = offset;
501           sgip->arle_length = x;
502           memcpy(sgip->arle_row, row, sgip->xsize * sizeof(unsigned short));
503         }
504
505         sgip->nextrow      = ftell(sgip->file);
506         sgip->length[z][y] = x;
507
508         return (x);
509   }
510
511   return (0);
512 }
513
514
515 /*
516  * 'getlong()' - Get a 32-bit big-endian integer.
517  */
518
519 static int                              /* O - Long value */
520 getlong(FILE *fp)                       /* I - File to read from */
521 {
522   unsigned char b[4];                   /* Bytes from file */
523
524
525   fread(b, 4, 1, fp);
526   return ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
527 }
528
529
530 /*
531  * 'getshort()' - Get a 16-bit big-endian integer.
532  */
533
534 static int                              /* O - Short value */
535 getshort(FILE *fp)                      /* I - File to read from */
536 {
537   unsigned char b[2];                   /* Bytes from file */
538
539
540   fread(b, 2, 1, fp);
541   return ((b[0] << 8) | b[1]);
542 }
543
544
545 /*
546  * 'putlong()' - Put a 32-bit big-endian integer.
547  */
548
549 static int                              /* O - 0 on success, -1 on error */
550 putlong(long n,                         /* I - Long to write */
551         FILE *fp)                       /* I - File to write to */
552 {
553   if (putc(n >> 24, fp) == EOF)
554     return (EOF);
555   if (putc(n >> 16, fp) == EOF)
556     return (EOF);
557   if (putc(n >> 8, fp) == EOF)
558     return (EOF);
559   if (putc(n, fp) == EOF)
560     return (EOF);
561   else
562     return (0);
563 }
564
565
566 /*
567  * 'putshort()' - Put a 16-bit big-endian integer.
568  */
569
570 static int                              /* O - 0 on success, -1 on error */
571 putshort(unsigned short n,              /* I - Short to write */
572          FILE           *fp)            /* I - File to write to */
573 {
574   if (putc(n >> 8, fp) == EOF)
575     return (EOF);
576   if (putc(n, fp) == EOF)
577     return (EOF);
578   else
579     return (0);
580 }
581
582
583 /*
584  * 'read_rle8()' - Read 8-bit RLE data.
585  */
586
587 static int                              /* O - Value on success, -1 on error */
588 read_rle8(FILE           *fp,           /* I - File to read from */
589           unsigned short *row,          /* O - Data */
590           int            xsize)         /* I - Width of data in pixels */
591 {
592   int   i,                              /* Looping var */
593         ch,                             /* Current character */
594         count,                          /* RLE count */
595         length;                         /* Number of bytes read... */
596
597
598   length = 0;
599
600   while (xsize > 0)
601   {
602     if ((ch = getc(fp)) == EOF)
603       return (-1);
604     length ++;
605
606     count = ch & 127;
607     if (count == 0)
608       break;
609
610     if (ch & 128)
611     {
612       for (i = 0; i < count; i ++, row ++, xsize --, length ++)
613         *row = getc(fp);
614     }
615     else
616     {
617       ch = getc(fp);
618       length ++;
619       for (i = 0; i < count; i ++, row ++, xsize --)
620         *row = ch;
621     }
622   }
623
624   return (xsize > 0 ? -1 : length);
625 }
626
627
628 /*
629  * 'read_rle16()' - Read 16-bit RLE data.
630  */
631
632 static int                              /* O - Value on success, -1 on error */
633 read_rle16(FILE           *fp,          /* I - File to read from */
634            unsigned short *row,         /* O - Data */
635            int            xsize)        /* I - Width of data in pixels */
636 {
637   int   i,                              /* Looping var */
638         ch,                             /* Current character */
639         count,                          /* RLE count */
640         length;                         /* Number of bytes read... */
641
642
643   length = 0;
644
645   while (xsize > 0)
646   {
647     if ((ch = getshort(fp)) == EOF)
648       return (-1);
649     length ++;
650
651     count = ch & 127;
652     if (count == 0)
653       break;
654
655     if (ch & 128)
656     {
657       for (i = 0; i < count; i ++, row ++, xsize --, length ++)
658         *row = getshort(fp);
659     }
660     else
661     {
662       ch = getshort(fp);
663       length ++;
664       for (i = 0; i < count; i ++, row ++, xsize --)
665         *row = ch;
666     }
667   }
668
669   return (xsize > 0 ? -1 : length * 2);
670 }
671
672
673 /*
674  * 'write_rle8()' - Write 8-bit RLE data.
675  */
676
677 static int                              /* O - Length on success, -1 on error */
678 write_rle8(FILE           *fp,          /* I - File to write to */
679            unsigned short *row,         /* I - Data */
680            int            xsize)        /* I - Width of data in pixels */
681 {
682   int                   length,         /* Length in bytes */
683                         count,          /* Number of repeating pixels */
684                         i,              /* Looping var */
685                         x;              /* Current column */
686   unsigned short        *start,         /* Start of current sequence */
687                         repeat;         /* Repeated pixel */
688
689
690   for (x = xsize, length = 0; x > 0;)
691   {
692     start = row;
693     row   += 2;
694     x     -= 2;
695
696     while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
697     {
698       row ++;
699       x --;
700     }
701
702     row -= 2;
703     x   += 2;
704
705     count = row - start;
706     while (count > 0)
707     {
708       i     = count > 126 ? 126 : count;
709       count -= i;
710
711       if (putc(128 | i, fp) == EOF)
712         return (-1);
713       length ++;
714
715       while (i > 0)
716       {
717         if (putc(*start, fp) == EOF)
718           return (-1);
719         start ++;
720         i --;
721         length ++;
722       }
723     }
724
725     if (x <= 0)
726       break;
727
728     start  = row;
729     repeat = row[0];
730
731     row ++;
732     x --;
733
734     while (x > 0 && *row == repeat)
735     {
736       row ++;
737       x --;
738     }
739
740     count = row - start;
741     while (count > 0)
742     {
743       i     = count > 126 ? 126 : count;
744       count -= i;
745
746       if (putc(i, fp) == EOF)
747         return (-1);
748       length ++;
749
750       if (putc(repeat, fp) == EOF)
751         return (-1);
752       length ++;
753     }
754   }
755
756   length ++;
757
758   if (putc(0, fp) == EOF)
759     return (-1);
760   else
761     return (length);
762 }
763
764
765 /*
766  * 'write_rle16()' - Write 16-bit RLE data.
767  */
768
769 static int                              /* O - Length in words */
770 write_rle16(FILE           *fp,         /* I - File to write to */
771             unsigned short *row,        /* I - Data */
772             int            xsize)       /* I - Width of data in pixels */
773 {
774   int                   length,         /* Length in words */
775                         count,          /* Number of repeating pixels */
776                         i,              /* Looping var */
777                         x;              /* Current column */
778   unsigned short        *start,         /* Start of current sequence */
779                         repeat;         /* Repeated pixel */
780
781
782   for (x = xsize, length = 0; x > 0;)
783   {
784     start = row;
785     row   += 2;
786     x     -= 2;
787
788     while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
789     {
790       row ++;
791       x --;
792     }
793
794     row -= 2;
795     x   += 2;
796
797     count = row - start;
798     while (count > 0)
799     {
800       i     = count > 126 ? 126 : count;
801       count -= i;
802
803       if (putshort(128 | i, fp) == EOF)
804         return (-1);
805       length ++;
806
807       while (i > 0)
808       {
809         if (putshort(*start, fp) == EOF)
810           return (-1);
811         start ++;
812         i --;
813         length ++;
814       }
815     }
816
817     if (x <= 0)
818       break;
819
820     start  = row;
821     repeat = row[0];
822
823     row ++;
824     x --;
825
826     while (x > 0 && *row == repeat)
827     {
828       row ++;
829       x --;
830     }
831
832     count = row - start;
833     while (count > 0)
834     {
835       i     = count > 126 ? 126 : count;
836       count -= i;
837
838       if (putshort(i, fp) == EOF)
839         return (-1);
840       length ++;
841
842       if (putshort(repeat, fp) == EOF)
843         return (-1);
844       length ++;
845     }
846   }
847
848   length ++;
849
850   if (putshort(0, fp) == EOF)
851     return (-1);
852   else
853     return (2 * length);
854 }
855
856
857 /*
858  * End of "$Id: image-sgilib.c 4741 2005-10-02 04:25:52Z mike $".
859  */