]> git.ipfire.org Git - thirdparty/cups.git/blame - filter/image-sgilib.c
Import CUPS 1.4svn-r7226.
[thirdparty/cups.git] / filter / image-sgilib.c
CommitLineData
ef416fc2 1/*
bc44d920 2 * "$Id: image-sgilib.c 6649 2007-07-11 21:46:42Z mike $"
ef416fc2 3 *
4 * SGI image file format library routines for the Common UNIX Printing
5 * System (CUPS).
6 *
91c84a35 7 * Copyright 2007-2008 by Apple Inc.
ef416fc2 8 * Copyright 1993-2005 by Easy Software Products.
9 *
10 * These coded instructions, statements, and computer programs are the
bc44d920 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/".
ef416fc2 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
42static int getlong(FILE *);
43static int getshort(FILE *);
44static int putlong(long, FILE *);
45static int putshort(unsigned short, FILE *);
46static int read_rle8(FILE *, unsigned short *, int);
47static int read_rle16(FILE *, unsigned short *, int);
48static int write_rle8(FILE *, unsigned short *, int);
49static int write_rle16(FILE *, unsigned short *, int);
50
51
52/*
53 * 'sgiClose()' - Close an SGI image file.
54 */
55
56int /* O - 0 on success, -1 on error */
57sgiClose(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
113int /* O - 0 on success, -1 on error */
114sgiGetRow(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
172sgi_t * /* O - New image */
173sgiOpen(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
204sgi_t * /* O - New image */
205sgiOpenFile(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
91c84a35
MS
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
ef416fc2 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);
91c84a35
MS
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
ef416fc2 362 for (i = 1; i < sgip->zsize; i ++)
363 sgip->table[i] = sgip->table[0] + i * sgip->ysize;
91c84a35
MS
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
ef416fc2 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
400int /* O - 0 on success, -1 on error */
401sgiPutRow(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
549static int /* O - Long value */
550getlong(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
564static int /* O - Short value */
565getshort(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
579static int /* O - 0 on success, -1 on error */
580putlong(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
600static int /* O - 0 on success, -1 on error */
601putshort(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
617static int /* O - Value on success, -1 on error */
618read_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 *row = getc(fp);
644 }
645 else
646 {
647 ch = getc(fp);
648 length ++;
649 for (i = 0; i < count; i ++, row ++, xsize --)
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 ++)
688 *row = getshort(fp);
689 }
690 else
691 {
692 ch = getshort(fp);
693 length ++;
694 for (i = 0; i < count; i ++, row ++, xsize --)
695 *row = ch;
696 }
697 }
698
699 return (xsize > 0 ? -1 : length * 2);
700}
701
702
703/*
704 * 'write_rle8()' - Write 8-bit RLE data.
705 */
706
707static int /* O - Length on success, -1 on error */
708write_rle8(FILE *fp, /* I - File to write to */
709 unsigned short *row, /* I - Data */
710 int xsize) /* I - Width of data in pixels */
711{
712 int length, /* Length in bytes */
713 count, /* Number of repeating pixels */
714 i, /* Looping var */
715 x; /* Current column */
716 unsigned short *start, /* Start of current sequence */
717 repeat; /* Repeated pixel */
718
719
720 for (x = xsize, length = 0; x > 0;)
721 {
722 start = row;
723 row += 2;
724 x -= 2;
725
726 while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
727 {
728 row ++;
729 x --;
730 }
731
732 row -= 2;
733 x += 2;
734
735 count = row - start;
736 while (count > 0)
737 {
738 i = count > 126 ? 126 : count;
739 count -= i;
740
741 if (putc(128 | i, fp) == EOF)
742 return (-1);
743 length ++;
744
745 while (i > 0)
746 {
747 if (putc(*start, fp) == EOF)
748 return (-1);
749 start ++;
750 i --;
751 length ++;
752 }
753 }
754
755 if (x <= 0)
756 break;
757
758 start = row;
759 repeat = row[0];
760
761 row ++;
762 x --;
763
764 while (x > 0 && *row == repeat)
765 {
766 row ++;
767 x --;
768 }
769
770 count = row - start;
771 while (count > 0)
772 {
773 i = count > 126 ? 126 : count;
774 count -= i;
775
776 if (putc(i, fp) == EOF)
777 return (-1);
778 length ++;
779
780 if (putc(repeat, fp) == EOF)
781 return (-1);
782 length ++;
783 }
784 }
785
786 length ++;
787
788 if (putc(0, fp) == EOF)
789 return (-1);
790 else
791 return (length);
792}
793
794
795/*
796 * 'write_rle16()' - Write 16-bit RLE data.
797 */
798
799static int /* O - Length in words */
800write_rle16(FILE *fp, /* I - File to write to */
801 unsigned short *row, /* I - Data */
802 int xsize) /* I - Width of data in pixels */
803{
804 int length, /* Length in words */
805 count, /* Number of repeating pixels */
806 i, /* Looping var */
807 x; /* Current column */
808 unsigned short *start, /* Start of current sequence */
809 repeat; /* Repeated pixel */
810
811
812 for (x = xsize, length = 0; x > 0;)
813 {
814 start = row;
815 row += 2;
816 x -= 2;
817
818 while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
819 {
820 row ++;
821 x --;
822 }
823
824 row -= 2;
825 x += 2;
826
827 count = row - start;
828 while (count > 0)
829 {
830 i = count > 126 ? 126 : count;
831 count -= i;
832
833 if (putshort(128 | i, fp) == EOF)
834 return (-1);
835 length ++;
836
837 while (i > 0)
838 {
839 if (putshort(*start, fp) == EOF)
840 return (-1);
841 start ++;
842 i --;
843 length ++;
844 }
845 }
846
847 if (x <= 0)
848 break;
849
850 start = row;
851 repeat = row[0];
852
853 row ++;
854 x --;
855
856 while (x > 0 && *row == repeat)
857 {
858 row ++;
859 x --;
860 }
861
862 count = row - start;
863 while (count > 0)
864 {
865 i = count > 126 ? 126 : count;
866 count -= i;
867
868 if (putshort(i, fp) == EOF)
869 return (-1);
870 length ++;
871
872 if (putshort(repeat, fp) == EOF)
873 return (-1);
874 length ++;
875 }
876 }
877
878 length ++;
879
880 if (putshort(0, fp) == EOF)
881 return (-1);
882 else
883 return (2 * length);
884}
885
886
887/*
bc44d920 888 * End of "$Id: image-sgilib.c 6649 2007-07-11 21:46:42Z mike $".
ef416fc2 889 */