]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/image-sgilib.c
13045ab5776717ced21491f61ff8134eccf7f2f4
[thirdparty/cups.git] / filter / image-sgilib.c
1 /*
2 * "$Id: image-sgilib.c 7221 2008-01-16 22:20:08Z mike $"
3 *
4 * SGI image file format library routines for the Common UNIX Printing
5 * System (CUPS).
6 *
7 * Copyright 2007-2008 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 if ((sgip->table = calloc(sgip->zsize, sizeof(long *))) == NULL)
254 {
255 free(sgip);
256 return (NULL);
257 }
258
259 if ((sgip->table[0] = calloc(sgip->ysize * sgip->zsize,
260 sizeof(long))) == NULL)
261 {
262 free(sgip->table);
263 free(sgip);
264 return (NULL);
265 }
266
267 for (i = 1; i < sgip->zsize; i ++)
268 sgip->table[i] = sgip->table[0] + i * sgip->ysize;
269
270 for (i = 0; i < sgip->zsize; i ++)
271 for (j = 0; j < sgip->ysize; j ++)
272 sgip->table[i][j] = getlong(sgip->file);
273 }
274 break;
275
276 case SGI_WRITE :
277 if (xsize < 1 ||
278 ysize < 1 ||
279 zsize < 1 ||
280 bpp < 1 || bpp > 2 ||
281 comp < SGI_COMP_NONE || comp > SGI_COMP_ARLE)
282 {
283 free(sgip);
284 return (NULL);
285 }
286
287 sgip->mode = SGI_WRITE;
288
289 putshort(SGI_MAGIC, sgip->file);
290 putc((sgip->comp = comp) != 0, sgip->file);
291 putc(sgip->bpp = bpp, sgip->file);
292 putshort(3, sgip->file); /* Dimensions */
293 putshort(sgip->xsize = xsize, sgip->file);
294 putshort(sgip->ysize = ysize, sgip->file);
295 putshort(sgip->zsize = zsize, sgip->file);
296 if (bpp == 1)
297 {
298 putlong(0, sgip->file); /* Minimum pixel */
299 putlong(255, sgip->file); /* Maximum pixel */
300 }
301 else
302 {
303 putlong(-32768, sgip->file); /* Minimum pixel */
304 putlong(32767, sgip->file); /* Maximum pixel */
305 }
306 putlong(0, sgip->file); /* Reserved */
307
308 memset(name, 0, sizeof(name));
309 fwrite(name, sizeof(name), 1, sgip->file);
310
311 for (i = 0; i < 102; i ++)
312 putlong(0, sgip->file);
313
314 switch (comp)
315 {
316 case SGI_COMP_NONE : /* No compression */
317 /*
318 * This file is uncompressed. To avoid problems with sparse files,
319 * we need to write blank pixels for the entire image...
320 */
321
322 if (bpp == 1)
323 {
324 for (i = xsize * ysize * zsize; i > 0; i --)
325 putc(0, sgip->file);
326 }
327 else
328 {
329 for (i = xsize * ysize * zsize; i > 0; i --)
330 putshort(0, sgip->file);
331 }
332 break;
333
334 case SGI_COMP_ARLE : /* Aggressive RLE */
335 sgip->arle_row = calloc(xsize, sizeof(unsigned short));
336 sgip->arle_offset = 0;
337
338 case SGI_COMP_RLE : /* Run-Length Encoding */
339 /*
340 * This file is compressed; write the (blank) scanline tables...
341 */
342
343 for (i = 2 * ysize * zsize; i > 0; i --)
344 putlong(0, sgip->file);
345
346 sgip->firstrow = ftell(sgip->file);
347 sgip->nextrow = ftell(sgip->file);
348 if ((sgip->table = calloc(sgip->zsize, sizeof(long *))) == NULL)
349 {
350 free(sgip);
351 return (NULL);
352 }
353
354 if ((sgip->table[0] = calloc(sgip->ysize * sgip->zsize,
355 sizeof(long))) == NULL)
356 {
357 free(sgip->table);
358 free(sgip);
359 return (NULL);
360 }
361
362 for (i = 1; i < sgip->zsize; i ++)
363 sgip->table[i] = sgip->table[0] + i * sgip->ysize;
364
365 if ((sgip->length = calloc(sgip->zsize, sizeof(long *))) == NULL)
366 {
367 free(sgip->table);
368 free(sgip);
369 return (NULL);
370 }
371
372 if ((sgip->length[0] = calloc(sgip->ysize * sgip->zsize,
373 sizeof(long))) == NULL)
374 {
375 free(sgip->length);
376 free(sgip->table);
377 free(sgip);
378 return (NULL);
379 }
380
381 for (i = 1; i < sgip->zsize; i ++)
382 sgip->length[i] = sgip->length[0] + i * sgip->ysize;
383 break;
384 }
385 break;
386
387 default :
388 free(sgip);
389 return (NULL);
390 }
391
392 return (sgip);
393 }
394
395
396 /*
397 * 'sgiPutRow()' - Put a row of image data to a file.
398 */
399
400 int /* O - 0 on success, -1 on error */
401 sgiPutRow(sgi_t *sgip, /* I - SGI image */
402 unsigned short *row, /* I - Row to write */
403 int y, /* I - Line to write */
404 int z) /* I - Channel to write */
405 {
406 int x; /* X coordinate */
407 long offset; /* File offset */
408
409
410 if (sgip == NULL ||
411 row == NULL ||
412 y < 0 || y >= sgip->ysize ||
413 z < 0 || z >= sgip->zsize)
414 return (-1);
415
416 switch (sgip->comp)
417 {
418 case SGI_COMP_NONE :
419 /*
420 * Seek to the image row - optimize buffering by only seeking if
421 * necessary...
422 */
423
424 offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp;
425 if (offset != ftell(sgip->file))
426 fseek(sgip->file, offset, SEEK_SET);
427
428 if (sgip->bpp == 1)
429 {
430 for (x = sgip->xsize; x > 0; x --, row ++)
431 putc(*row, sgip->file);
432 }
433 else
434 {
435 for (x = sgip->xsize; x > 0; x --, row ++)
436 putshort(*row, sgip->file);
437 }
438 break;
439
440 case SGI_COMP_ARLE :
441 if (sgip->table[z][y] != 0)
442 return (-1);
443
444 /*
445 * First check the last row written...
446 */
447
448 if (sgip->arle_offset > 0)
449 {
450 for (x = 0; x < sgip->xsize; x ++)
451 if (row[x] != sgip->arle_row[x])
452 break;
453
454 if (x == sgip->xsize)
455 {
456 sgip->table[z][y] = sgip->arle_offset;
457 sgip->length[z][y] = sgip->arle_length;
458 return (0);
459 }
460 }
461
462 /*
463 * If that didn't match, search all the previous rows...
464 */
465
466 fseek(sgip->file, sgip->firstrow, SEEK_SET);
467
468 if (sgip->bpp == 1)
469 {
470 for (;;)
471 {
472 sgip->arle_offset = ftell(sgip->file);
473 if ((sgip->arle_length = read_rle8(sgip->file, sgip->arle_row, sgip->xsize)) < 0)
474 {
475 x = 0;
476 break;
477 }
478
479 if (memcmp(row, sgip->arle_row, sgip->xsize * sizeof(unsigned short)) == 0)
480 {
481 x = sgip->xsize;
482 break;
483 }
484 }
485 }
486 else
487 {
488 for (;;)
489 {
490 sgip->arle_offset = ftell(sgip->file);
491 if ((sgip->arle_length = read_rle16(sgip->file, sgip->arle_row, sgip->xsize)) < 0)
492 {
493 x = 0;
494 break;
495 }
496
497 if (memcmp(row, sgip->arle_row, sgip->xsize * sizeof(unsigned short)) == 0)
498 {
499 x = sgip->xsize;
500 break;
501 }
502 }
503 }
504
505 if (x == sgip->xsize)
506 {
507 sgip->table[z][y] = sgip->arle_offset;
508 sgip->length[z][y] = sgip->arle_length;
509 return (0);
510 }
511 else
512 fseek(sgip->file, 0, SEEK_END); /* Clear EOF */
513
514 case SGI_COMP_RLE :
515 if (sgip->table[z][y] != 0)
516 return (-1);
517
518 offset = sgip->table[z][y] = sgip->nextrow;
519
520 if (offset != ftell(sgip->file))
521 fseek(sgip->file, offset, SEEK_SET);
522
523 if (sgip->bpp == 1)
524 x = write_rle8(sgip->file, row, sgip->xsize);
525 else
526 x = write_rle16(sgip->file, row, sgip->xsize);
527
528 if (sgip->comp == SGI_COMP_ARLE)
529 {
530 sgip->arle_offset = offset;
531 sgip->arle_length = x;
532 memcpy(sgip->arle_row, row, sgip->xsize * sizeof(unsigned short));
533 }
534
535 sgip->nextrow = ftell(sgip->file);
536 sgip->length[z][y] = x;
537
538 return (x);
539 }
540
541 return (0);
542 }
543
544
545 /*
546 * 'getlong()' - Get a 32-bit big-endian integer.
547 */
548
549 static int /* O - Long value */
550 getlong(FILE *fp) /* I - File to read from */
551 {
552 unsigned char b[4]; /* Bytes from file */
553
554
555 fread(b, 4, 1, fp);
556 return ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
557 }
558
559
560 /*
561 * 'getshort()' - Get a 16-bit big-endian integer.
562 */
563
564 static int /* O - Short value */
565 getshort(FILE *fp) /* I - File to read from */
566 {
567 unsigned char b[2]; /* Bytes from file */
568
569
570 fread(b, 2, 1, fp);
571 return ((b[0] << 8) | b[1]);
572 }
573
574
575 /*
576 * 'putlong()' - Put a 32-bit big-endian integer.
577 */
578
579 static int /* O - 0 on success, -1 on error */
580 putlong(long n, /* I - Long to write */
581 FILE *fp) /* I - File to write to */
582 {
583 if (putc(n >> 24, fp) == EOF)
584 return (EOF);
585 if (putc(n >> 16, fp) == EOF)
586 return (EOF);
587 if (putc(n >> 8, fp) == EOF)
588 return (EOF);
589 if (putc(n, fp) == EOF)
590 return (EOF);
591 else
592 return (0);
593 }
594
595
596 /*
597 * 'putshort()' - Put a 16-bit big-endian integer.
598 */
599
600 static int /* O - 0 on success, -1 on error */
601 putshort(unsigned short n, /* I - Short to write */
602 FILE *fp) /* I - File to write to */
603 {
604 if (putc(n >> 8, fp) == EOF)
605 return (EOF);
606 if (putc(n, fp) == EOF)
607 return (EOF);
608 else
609 return (0);
610 }
611
612
613 /*
614 * 'read_rle8()' - Read 8-bit RLE data.
615 */
616
617 static int /* O - Value on success, -1 on error */
618 read_rle8(FILE *fp, /* I - File to read from */
619 unsigned short *row, /* O - Data */
620 int xsize) /* I - Width of data in pixels */
621 {
622 int i, /* Looping var */
623 ch, /* Current character */
624 count, /* RLE count */
625 length; /* Number of bytes read... */
626
627
628 length = 0;
629
630 while (xsize > 0)
631 {
632 if ((ch = getc(fp)) == EOF)
633 return (-1);
634 length ++;
635
636 count = ch & 127;
637 if (count == 0)
638 break;
639
640 if (ch & 128)
641 {
642 for (i = 0; i < count; i ++, row ++, xsize --, length ++)
643 if (xsize > 0)
644 *row = getc(fp);
645 }
646 else
647 {
648 ch = getc(fp);
649 length ++;
650 for (i = 0; i < count && xsize > 0; i ++, row ++, xsize --)
651 *row = ch;
652 }
653 }
654
655 return (xsize > 0 ? -1 : length);
656 }
657
658
659 /*
660 * 'read_rle16()' - Read 16-bit RLE data.
661 */
662
663 static int /* O - Value on success, -1 on error */
664 read_rle16(FILE *fp, /* I - File to read from */
665 unsigned short *row, /* O - Data */
666 int xsize) /* I - Width of data in pixels */
667 {
668 int i, /* Looping var */
669 ch, /* Current character */
670 count, /* RLE count */
671 length; /* Number of bytes read... */
672
673
674 length = 0;
675
676 while (xsize > 0)
677 {
678 if ((ch = getshort(fp)) == EOF)
679 return (-1);
680 length ++;
681
682 count = ch & 127;
683 if (count == 0)
684 break;
685
686 if (ch & 128)
687 {
688 for (i = 0; i < count; i ++, row ++, xsize --, length ++)
689 if (xsize > 0)
690 *row = getshort(fp);
691 }
692 else
693 {
694 ch = getshort(fp);
695 length ++;
696 for (i = 0; i < count && xsize > 0; i ++, row ++, xsize --)
697 *row = ch;
698 }
699 }
700
701 return (xsize > 0 ? -1 : length * 2);
702 }
703
704
705 /*
706 * 'write_rle8()' - Write 8-bit RLE data.
707 */
708
709 static int /* O - Length on success, -1 on error */
710 write_rle8(FILE *fp, /* I - File to write to */
711 unsigned short *row, /* I - Data */
712 int xsize) /* I - Width of data in pixels */
713 {
714 int length, /* Length in bytes */
715 count, /* Number of repeating pixels */
716 i, /* Looping var */
717 x; /* Current column */
718 unsigned short *start, /* Start of current sequence */
719 repeat; /* Repeated pixel */
720
721
722 for (x = xsize, length = 0; x > 0;)
723 {
724 start = row;
725 row += 2;
726 x -= 2;
727
728 while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
729 {
730 row ++;
731 x --;
732 }
733
734 row -= 2;
735 x += 2;
736
737 count = row - start;
738 while (count > 0)
739 {
740 i = count > 126 ? 126 : count;
741 count -= i;
742
743 if (putc(128 | i, fp) == EOF)
744 return (-1);
745 length ++;
746
747 while (i > 0)
748 {
749 if (putc(*start, fp) == EOF)
750 return (-1);
751 start ++;
752 i --;
753 length ++;
754 }
755 }
756
757 if (x <= 0)
758 break;
759
760 start = row;
761 repeat = row[0];
762
763 row ++;
764 x --;
765
766 while (x > 0 && *row == repeat)
767 {
768 row ++;
769 x --;
770 }
771
772 count = row - start;
773 while (count > 0)
774 {
775 i = count > 126 ? 126 : count;
776 count -= i;
777
778 if (putc(i, fp) == EOF)
779 return (-1);
780 length ++;
781
782 if (putc(repeat, fp) == EOF)
783 return (-1);
784 length ++;
785 }
786 }
787
788 length ++;
789
790 if (putc(0, fp) == EOF)
791 return (-1);
792 else
793 return (length);
794 }
795
796
797 /*
798 * 'write_rle16()' - Write 16-bit RLE data.
799 */
800
801 static int /* O - Length in words */
802 write_rle16(FILE *fp, /* I - File to write to */
803 unsigned short *row, /* I - Data */
804 int xsize) /* I - Width of data in pixels */
805 {
806 int length, /* Length in words */
807 count, /* Number of repeating pixels */
808 i, /* Looping var */
809 x; /* Current column */
810 unsigned short *start, /* Start of current sequence */
811 repeat; /* Repeated pixel */
812
813
814 for (x = xsize, length = 0; x > 0;)
815 {
816 start = row;
817 row += 2;
818 x -= 2;
819
820 while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
821 {
822 row ++;
823 x --;
824 }
825
826 row -= 2;
827 x += 2;
828
829 count = row - start;
830 while (count > 0)
831 {
832 i = count > 126 ? 126 : count;
833 count -= i;
834
835 if (putshort(128 | i, fp) == EOF)
836 return (-1);
837 length ++;
838
839 while (i > 0)
840 {
841 if (putshort(*start, fp) == EOF)
842 return (-1);
843 start ++;
844 i --;
845 length ++;
846 }
847 }
848
849 if (x <= 0)
850 break;
851
852 start = row;
853 repeat = row[0];
854
855 row ++;
856 x --;
857
858 while (x > 0 && *row == repeat)
859 {
860 row ++;
861 x --;
862 }
863
864 count = row - start;
865 while (count > 0)
866 {
867 i = count > 126 ? 126 : count;
868 count -= i;
869
870 if (putshort(i, fp) == EOF)
871 return (-1);
872 length ++;
873
874 if (putshort(repeat, fp) == EOF)
875 return (-1);
876 length ++;
877 }
878 }
879
880 length ++;
881
882 if (putshort(0, fp) == EOF)
883 return (-1);
884 else
885 return (2 * length);
886 }
887
888
889 /*
890 * End of "$Id: image-sgilib.c 7221 2008-01-16 22:20:08Z mike $".
891 */