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