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