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