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