4 * SGI image file format library routines for CUPS.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1993-2005 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
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/".
15 * This file is subject to the Apple OS-Developed Software exception.
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.
34 #include "image-sgi.h"
41 static int getlong(FILE *);
42 static int getshort(FILE *);
43 static int putlong(long, FILE *);
44 static int putshort(unsigned short, FILE *);
45 static int read_rle8(FILE *, unsigned short *, int);
46 static int read_rle16(FILE *, unsigned short *, int);
47 static int write_rle8(FILE *, unsigned short *, int);
48 static int write_rle16(FILE *, unsigned short *, int);
52 * 'sgiClose()' - Close an SGI image file.
55 int /* O - 0 on success, -1 on error */
56 sgiClose(sgi_t *sgip) /* I - SGI image */
58 int i; /* Return status */
59 long *offset; /* Looping var for offset table */
65 if (sgip->mode == SGI_WRITE && sgip->comp != SGI_COMP_NONE)
68 * Write the scanline offset table to the file...
71 fseek(sgip->file, 512, SEEK_SET);
73 for (i = sgip->ysize * sgip->zsize, offset = sgip->table[0];
76 if (putlong(offset[0], sgip->file) < 0)
79 for (i = sgip->ysize * sgip->zsize, offset = sgip->length[0];
82 if (putlong(offset[0], sgip->file) < 0)
86 if (sgip->table != NULL)
92 if (sgip->length != NULL)
94 free(sgip->length[0]);
98 if (sgip->comp == SGI_COMP_ARLE)
101 i = fclose(sgip->file);
109 * 'sgiGetRow()' - Get a row of image data from a file.
112 int /* O - 0 on success, -1 on error */
113 sgiGetRow(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 */
118 int x; /* X coordinate */
119 long offset; /* File offset */
124 y < 0 || y >= sgip->ysize ||
125 z < 0 || z >= sgip->zsize)
132 * Seek to the image row - optimize buffering by only seeking if
136 offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp;
137 if (offset != ftell(sgip->file))
138 fseek(sgip->file, offset, SEEK_SET);
142 for (x = sgip->xsize; x > 0; x --, row ++)
143 *row = getc(sgip->file);
147 for (x = sgip->xsize; x > 0; x --, row ++)
148 *row = getshort(sgip->file);
153 offset = sgip->table[z][y];
154 if (offset != ftell(sgip->file))
155 fseek(sgip->file, offset, SEEK_SET);
158 return (read_rle8(sgip->file, row, sgip->xsize));
160 return (read_rle16(sgip->file, row, sgip->xsize));
168 * 'sgiOpen()' - Open an SGI image file for reading or writing.
171 sgi_t * /* O - New image */
172 sgiOpen(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 */
180 sgi_t *sgip; /* New SGI image file */
181 FILE *file; /* Image file pointer */
184 if (mode == SGI_READ)
185 file = fopen(filename, "rb");
187 file = fopen(filename, "wb+");
192 if ((sgip = sgiOpenFile(file, mode, comp, bpp, xsize, ysize, zsize)) == NULL)
200 * 'sgiOpenFile()' - Open an SGI image file for reading or writing.
203 sgi_t * /* O - New image */
204 sgiOpenFile(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 */
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 */
218 if ((sgip = calloc(sizeof(sgi_t), 1)) == NULL)
226 sgip->mode = SGI_READ;
228 magic = getshort(sgip->file);
229 if (magic != SGI_MAGIC)
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 */
247 * This file is compressed; read the scanline tables...
250 fseek(sgip->file, 512, SEEK_SET);
252 if ((sgip->table = calloc(sgip->zsize, sizeof(long *))) == NULL)
258 if ((sgip->table[0] = calloc(sgip->ysize * sgip->zsize,
259 sizeof(long))) == NULL)
266 for (i = 1; i < sgip->zsize; i ++)
267 sgip->table[i] = sgip->table[0] + i * sgip->ysize;
269 for (i = 0; i < sgip->zsize; i ++)
270 for (j = 0; j < sgip->ysize; j ++)
271 sgip->table[i][j] = getlong(sgip->file);
279 bpp < 1 || bpp > 2 ||
280 comp < SGI_COMP_NONE || comp > SGI_COMP_ARLE)
286 sgip->mode = SGI_WRITE;
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);
297 putlong(0, sgip->file); /* Minimum pixel */
298 putlong(255, sgip->file); /* Maximum pixel */
302 putlong(-32768, sgip->file); /* Minimum pixel */
303 putlong(32767, sgip->file); /* Maximum pixel */
305 putlong(0, sgip->file); /* Reserved */
307 memset(name, 0, sizeof(name));
308 fwrite(name, sizeof(name), 1, sgip->file);
310 for (i = 0; i < 102; i ++)
311 putlong(0, sgip->file);
315 case SGI_COMP_NONE : /* No compression */
317 * This file is uncompressed. To avoid problems with sparse files,
318 * we need to write blank pixels for the entire image...
323 for (i = xsize * ysize * zsize; i > 0; i --)
328 for (i = xsize * ysize * zsize; i > 0; i --)
329 putshort(0, sgip->file);
333 case SGI_COMP_ARLE : /* Aggressive RLE */
334 sgip->arle_row = calloc(xsize, sizeof(unsigned short));
335 sgip->arle_offset = 0;
337 case SGI_COMP_RLE : /* Run-Length Encoding */
339 * This file is compressed; write the (blank) scanline tables...
342 for (i = 2 * ysize * zsize; i > 0; i --)
343 putlong(0, sgip->file);
345 sgip->firstrow = ftell(sgip->file);
346 sgip->nextrow = ftell(sgip->file);
347 if ((sgip->table = calloc(sgip->zsize, sizeof(long *))) == NULL)
353 if ((sgip->table[0] = calloc(sgip->ysize * sgip->zsize,
354 sizeof(long))) == NULL)
361 for (i = 1; i < sgip->zsize; i ++)
362 sgip->table[i] = sgip->table[0] + i * sgip->ysize;
364 if ((sgip->length = calloc(sgip->zsize, sizeof(long *))) == NULL)
371 if ((sgip->length[0] = calloc(sgip->ysize * sgip->zsize,
372 sizeof(long))) == NULL)
380 for (i = 1; i < sgip->zsize; i ++)
381 sgip->length[i] = sgip->length[0] + i * sgip->ysize;
396 * 'sgiPutRow()' - Put a row of image data to a file.
399 int /* O - 0 on success, -1 on error */
400 sgiPutRow(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 */
405 int x; /* X coordinate */
406 long offset; /* File offset */
411 y < 0 || y >= sgip->ysize ||
412 z < 0 || z >= sgip->zsize)
419 * Seek to the image row - optimize buffering by only seeking if
423 offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp;
424 if (offset != ftell(sgip->file))
425 fseek(sgip->file, offset, SEEK_SET);
429 for (x = sgip->xsize; x > 0; x --, row ++)
430 putc(*row, sgip->file);
434 for (x = sgip->xsize; x > 0; x --, row ++)
435 putshort(*row, sgip->file);
440 if (sgip->table[z][y] != 0)
444 * First check the last row written...
447 if (sgip->arle_offset > 0)
449 for (x = 0; x < sgip->xsize; x ++)
450 if (row[x] != sgip->arle_row[x])
453 if (x == sgip->xsize)
455 sgip->table[z][y] = sgip->arle_offset;
456 sgip->length[z][y] = sgip->arle_length;
462 * If that didn't match, search all the previous rows...
465 fseek(sgip->file, sgip->firstrow, SEEK_SET);
471 sgip->arle_offset = ftell(sgip->file);
472 if ((sgip->arle_length = read_rle8(sgip->file, sgip->arle_row, sgip->xsize)) < 0)
478 if (memcmp(row, sgip->arle_row, sgip->xsize * sizeof(unsigned short)) == 0)
489 sgip->arle_offset = ftell(sgip->file);
490 if ((sgip->arle_length = read_rle16(sgip->file, sgip->arle_row, sgip->xsize)) < 0)
496 if (memcmp(row, sgip->arle_row, sgip->xsize * sizeof(unsigned short)) == 0)
504 if (x == sgip->xsize)
506 sgip->table[z][y] = sgip->arle_offset;
507 sgip->length[z][y] = sgip->arle_length;
511 fseek(sgip->file, 0, SEEK_END); /* Clear EOF */
514 if (sgip->table[z][y] != 0)
517 offset = sgip->table[z][y] = sgip->nextrow;
519 if (offset != ftell(sgip->file))
520 fseek(sgip->file, offset, SEEK_SET);
523 x = write_rle8(sgip->file, row, sgip->xsize);
525 x = write_rle16(sgip->file, row, sgip->xsize);
527 if (sgip->comp == SGI_COMP_ARLE)
529 sgip->arle_offset = offset;
530 sgip->arle_length = x;
531 memcpy(sgip->arle_row, row, sgip->xsize * sizeof(unsigned short));
534 sgip->nextrow = ftell(sgip->file);
535 sgip->length[z][y] = x;
545 * 'getlong()' - Get a 32-bit big-endian integer.
548 static int /* O - Long value */
549 getlong(FILE *fp) /* I - File to read from */
551 unsigned char b[4]; /* Bytes from file */
555 return ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
560 * 'getshort()' - Get a 16-bit big-endian integer.
563 static int /* O - Short value */
564 getshort(FILE *fp) /* I - File to read from */
566 unsigned char b[2]; /* Bytes from file */
570 return ((b[0] << 8) | b[1]);
575 * 'putlong()' - Put a 32-bit big-endian integer.
578 static int /* O - 0 on success, -1 on error */
579 putlong(long n, /* I - Long to write */
580 FILE *fp) /* I - File to write to */
582 if (putc(n >> 24, fp) == EOF)
584 if (putc(n >> 16, fp) == EOF)
586 if (putc(n >> 8, fp) == EOF)
588 if (putc(n, fp) == EOF)
596 * 'putshort()' - Put a 16-bit big-endian integer.
599 static int /* O - 0 on success, -1 on error */
600 putshort(unsigned short n, /* I - Short to write */
601 FILE *fp) /* I - File to write to */
603 if (putc(n >> 8, fp) == EOF)
605 if (putc(n, fp) == EOF)
613 * 'read_rle8()' - Read 8-bit RLE data.
616 static int /* O - Value on success, -1 on error */
617 read_rle8(FILE *fp, /* I - File to read from */
618 unsigned short *row, /* O - Data */
619 int xsize) /* I - Width of data in pixels */
621 int i, /* Looping var */
622 ch, /* Current character */
623 count, /* RLE count */
624 length; /* Number of bytes read... */
631 if ((ch = getc(fp)) == EOF)
641 for (i = 0; i < count; i ++, row ++, xsize --, length ++)
649 for (i = 0; i < count && xsize > 0; i ++, row ++, xsize --)
654 return (xsize > 0 ? -1 : length);
659 * 'read_rle16()' - Read 16-bit RLE data.
662 static int /* O - Value on success, -1 on error */
663 read_rle16(FILE *fp, /* I - File to read from */
664 unsigned short *row, /* O - Data */
665 int xsize) /* I - Width of data in pixels */
667 int i, /* Looping var */
668 ch, /* Current character */
669 count, /* RLE count */
670 length; /* Number of bytes read... */
677 if ((ch = getshort(fp)) == EOF)
687 for (i = 0; i < count; i ++, row ++, xsize --, length ++)
695 for (i = 0; i < count && xsize > 0; i ++, row ++, xsize --)
700 return (xsize > 0 ? -1 : length * 2);
705 * 'write_rle8()' - Write 8-bit RLE data.
708 static int /* O - Length on success, -1 on error */
709 write_rle8(FILE *fp, /* I - File to write to */
710 unsigned short *row, /* I - Data */
711 int xsize) /* I - Width of data in pixels */
713 int length, /* Length in bytes */
714 count, /* Number of repeating pixels */
716 x; /* Current column */
717 unsigned short *start, /* Start of current sequence */
718 repeat; /* Repeated pixel */
721 for (x = xsize, length = 0; x > 0;)
727 while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
739 i = count > 126 ? 126 : count;
742 if (putc(128 | i, fp) == EOF)
748 if (putc(*start, fp) == EOF)
765 while (x > 0 && *row == repeat)
774 i = count > 126 ? 126 : count;
777 if (putc(i, fp) == EOF)
781 if (putc(repeat, fp) == EOF)
789 if (putc(0, fp) == EOF)
797 * 'write_rle16()' - Write 16-bit RLE data.
800 static int /* O - Length in words */
801 write_rle16(FILE *fp, /* I - File to write to */
802 unsigned short *row, /* I - Data */
803 int xsize) /* I - Width of data in pixels */
805 int length, /* Length in words */
806 count, /* Number of repeating pixels */
808 x; /* Current column */
809 unsigned short *start, /* Start of current sequence */
810 repeat; /* Repeated pixel */
813 for (x = xsize, length = 0; x > 0;)
819 while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
831 i = count > 126 ? 126 : count;
834 if (putshort(128 | i, fp) == EOF)
840 if (putshort(*start, fp) == EOF)
857 while (x > 0 && *row == repeat)
866 i = count > 126 ? 126 : count;
869 if (putshort(i, fp) == EOF)
873 if (putshort(repeat, fp) == EOF)
881 if (putshort(0, fp) == EOF)