1 /*
2 * SGI image file format library routines.
3 *
4 * Copyright 1997-1998 Michael Sweet (mike@easysw.com)
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 3 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 *
19 * Contents:
20 *
21 * sgiClose() - Close an SGI image file.
22 * sgiGetRow() - Get a row of image data from a file.
23 * sgiOpen() - Open an SGI image file for reading or writing.
24 * sgiOpenFile() - Open an SGI image file for reading or writing.
25 * sgiPutRow() - Put a row of image data to a file.
26 * getlong() - Get a 32-bit big-endian integer.
27 * getshort() - Get a 16-bit big-endian integer.
28 * putlong() - Put a 32-bit big-endian integer.
29 * putshort() - Put a 16-bit big-endian integer.
30 * read_rle8() - Read 8-bit RLE data.
31 * read_rle16() - Read 16-bit RLE data.
32 * write_rle8() - Write 8-bit RLE data.
33 * write_rle16() - Write 16-bit RLE data.
34 *
35 * Revision History:
36 *
37 * $Log$
38 * Revision 1.9 2005/03/04 13:23:31 neo
39 * 2005-03-04 Sven Neumann <sven@gimp.org>
40 *
41 * * plug-ins/FractalExplorer
42 * * plug-ins/Lighting
43 * * plug-ins/bmp
44 * * plug-ins/dbbrowser
45 * * plug-ins/faxg3
46 * * plug-ins/fits
47 * * plug-ins/flame
48 * * plug-ins/gfig
49 * * plug-ins/gflare
50 * * plug-ins/gfli
51 * * plug-ins/gimpressionist
52 * * plug-ins/ifscompose
53 * * plug-ins/jpeg
54 * * plug-ins/maze
55 * * plug-ins/pagecurl
56 * * plug-ins/print
57 * * plug-ins/rcm
58 * * plug-ins/script-fu
59 * * plug-ins/sel2path
60 * * plug-ins/sgi
61 * * plug-ins/twain
62 * * plug-ins/winicon
63 * * plug-ins/xjt: ported to gstdio, removed unnecessary includes,
64 * minor fixes to filename handling here and there.
65 *
66 * Revision 1.8 2003/04/07 11:59:33 neo
67 * 2003-04-07 Sven Neumann <sven@gimp.org>
68 *
69 * * plug-ins/sgi/sgi.h
70 * * plug-ins/sgi/sgilib.c: applied a patch from marek@aki.cz that
71 * adds support for reading SGI files in little-endian format. Fixes
72 * bug #106610.
73 *
74 * Revision 1.7 1998/06/06 23:22:21 yosh
75 * * adding Lighting plugin
76 *
77 * * updated despeckle, png, sgi, and sharpen
78 *
79 * -Yosh
80 *
81 * Revision 1.5 1998/04/23 17:40:49 mike
82 * Updated to support 16-bit <unsigned> image data.
83 *
84 * Revision 1.4 1998/02/05 17:10:58 mike
85 * Added sgiOpenFile() function for opening an existing file pointer.
86 *
87 * Revision 1.3 1997/07/02 16:40:16 mike
88 * sgiOpen() wasn't opening files with "rb" or "wb+". This caused problems
89 * on PCs running Windows/DOS...
90 *
91 * Revision 1.2 1997/06/18 00:55:28 mike
92 * Updated to hold length table when writing.
93 * Updated to hold current length when doing ARLE.
94 * Wasn't writing length table on close.
95 * Wasn't saving new line into arle_row when necessary.
96 *
97 * Revision 1.1 1997/06/15 03:37:19 mike
98 * Initial revision
99 */
100
101 #include "config.h"
102
103 #include <stdlib.h>
104 #include <string.h>
105
106 #include <glib.h>
107 #include <glib/gstdio.h>
108
109 #include "sgi-lib.h"
110
111
112 /*
113 * Local functions...
114 */
115
116 static int getlong(sgi_t*);
117 static int getshort(sgi_t*);
118 static int putlong(long, sgi_t*);
119 static int putshort(unsigned short, sgi_t*);
120 static int read_rle8(sgi_t*, unsigned short *, int);
121 static int read_rle16(sgi_t*, unsigned short *, int);
122 static int write_rle8(sgi_t*, unsigned short *, int);
123 static int write_rle16(sgi_t*, unsigned short *, int);
124
125
126 /*
127 * 'sgiClose()' - Close an SGI image file.
128 */
129
130 int
sgiClose(sgi_t * sgip)131 sgiClose(sgi_t *sgip) /* I - SGI image */
132 {
133 int i; /* Return status */
134 long *offset; /* Looping var for offset table */
135
136
137 if (sgip == NULL)
138 return (-1);
139
140 if (sgip->mode == SGI_WRITE && sgip->comp != SGI_COMP_NONE)
141 {
142 /*
143 * Write the scanline offset table to the file...
144 */
145
146 fseek(sgip->file, 512, SEEK_SET);
147
148 for (i = sgip->ysize * sgip->zsize, offset = sgip->table[0];
149 i > 0;
150 i --, offset ++)
151 if (putlong(offset[0], sgip) < 0)
152 return (-1);
153
154 for (i = sgip->ysize * sgip->zsize, offset = sgip->length[0];
155 i > 0;
156 i --, offset ++)
157 if (putlong(offset[0], sgip) < 0)
158 return (-1);
159 };
160
161 if (sgip->table != NULL)
162 {
163 free(sgip->table[0]);
164 free(sgip->table);
165 };
166
167 if (sgip->length != NULL)
168 {
169 free(sgip->length[0]);
170 free(sgip->length);
171 };
172
173 if (sgip->comp == SGI_COMP_ARLE)
174 free(sgip->arle_row);
175
176 i = fclose(sgip->file);
177 free(sgip);
178
179 return (i);
180 }
181
182
183 /*
184 * 'sgiGetRow()' - Get a row of image data from a file.
185 */
186
187 int
sgiGetRow(sgi_t * sgip,unsigned short * row,int y,int z)188 sgiGetRow(sgi_t *sgip, /* I - SGI image */
189 unsigned short *row, /* O - Row to read */
190 int y, /* I - Line to read */
191 int z) /* I - Channel to read */
192 {
193 int x; /* X coordinate */
194 long offset; /* File offset */
195
196
197 if (sgip == NULL ||
198 row == NULL ||
199 y < 0 || y >= sgip->ysize ||
200 z < 0 || z >= sgip->zsize)
201 return (-1);
202
203 switch (sgip->comp)
204 {
205 case SGI_COMP_NONE :
206 /*
207 * Seek to the image row - optimize buffering by only seeking if
208 * necessary...
209 */
210
211 offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp;
212 if (offset != ftell(sgip->file))
213 fseek(sgip->file, offset, SEEK_SET);
214
215 if (sgip->bpp == 1)
216 {
217 for (x = sgip->xsize; x > 0; x --, row ++)
218 *row = getc(sgip->file);
219 }
220 else
221 {
222 for (x = sgip->xsize; x > 0; x --, row ++)
223 *row = getshort(sgip);
224 };
225 break;
226
227 case SGI_COMP_RLE :
228 offset = sgip->table[z][y];
229 if (offset != ftell(sgip->file))
230 fseek(sgip->file, offset, SEEK_SET);
231
232 if (sgip->bpp == 1)
233 return (read_rle8(sgip, row, sgip->xsize));
234 else
235 return (read_rle16(sgip, row, sgip->xsize));
236 break;
237 };
238
239 return (0);
240 }
241
242
243 /*
244 * 'sgiOpen()' - Open an SGI image file for reading or writing.
245 */
246
247 sgi_t *
sgiOpen(const char * filename,int mode,int comp,int bpp,int xsize,int ysize,int zsize)248 sgiOpen(const char *filename, /* I - File to open */
249 int mode, /* I - Open mode (SGI_READ or SGI_WRITE) */
250 int comp, /* I - Type of compression */
251 int bpp, /* I - Bytes per pixel */
252 int xsize, /* I - Width of image in pixels */
253 int ysize, /* I - Height of image in pixels */
254 int zsize) /* I - Number of channels */
255 {
256 sgi_t *sgip; /* New SGI image file */
257 FILE *file; /* Image file pointer */
258
259
260 if (mode == SGI_READ)
261 file = g_fopen(filename, "rb");
262 else
263 file = g_fopen(filename, "w+b");
264
265 if (file == NULL)
266 return (NULL);
267
268 if ((sgip = sgiOpenFile(file, mode, comp, bpp, xsize, ysize, zsize)) == NULL)
269 fclose(file);
270
271 return (sgip);
272 }
273
274
275 /*
276 * 'sgiOpenFile()' - Open an SGI image file for reading or writing.
277 */
278
279 sgi_t *
sgiOpenFile(FILE * file,int mode,int comp,int bpp,int xsize,int ysize,int zsize)280 sgiOpenFile(FILE *file, /* I - File to open */
281 int mode, /* I - Open mode (SGI_READ or SGI_WRITE) */
282 int comp, /* I - Type of compression */
283 int bpp, /* I - Bytes per pixel */
284 int xsize, /* I - Width of image in pixels */
285 int ysize, /* I - Height of image in pixels */
286 int zsize) /* I - Number of channels */
287 {
288 int i, j; /* Looping var */
289 char name[80]; /* Name of file in image header */
290 short magic; /* Magic number */
291 sgi_t *sgip; /* New image pointer */
292
293
294 if ((sgip = calloc(sizeof(sgi_t), 1)) == NULL)
295 return (NULL);
296
297 sgip->file = file;
298 sgip->swapBytes = 0;
299
300 switch (mode)
301 {
302 case SGI_READ :
303 sgip->mode = SGI_READ;
304
305 magic = getshort(sgip);
306 if (magic != SGI_MAGIC)
307 {
308 /* try little endian format */
309 magic = ((magic >> 8) & 0x00ff) | ((magic << 8) & 0xff00);
310 if(magic != SGI_MAGIC) {
311 free(sgip);
312 return (NULL);
313 } else {
314 sgip->swapBytes = 1;
315 }
316 }
317
318 sgip->comp = getc(sgip->file);
319 sgip->bpp = getc(sgip->file);
320 getshort(sgip); /* Dimensions */
321 sgip->xsize = getshort(sgip);
322 sgip->ysize = getshort(sgip);
323 sgip->zsize = getshort(sgip);
324 getlong(sgip); /* Minimum pixel */
325 getlong(sgip); /* Maximum pixel */
326
327 if (sgip->comp)
328 {
329 /*
330 * This file is compressed; read the scanline tables...
331 */
332
333 fseek(sgip->file, 512, SEEK_SET);
334
335 sgip->table = calloc(sgip->zsize, sizeof(long *));
336 if (sgip->table == NULL)
337 {
338 free(sgip);
339 return (NULL);
340 }
341 sgip->table[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long));
342 if (sgip->table[0] == NULL)
343 {
344 free(sgip->table);
345 free(sgip);
346 return (NULL);
347 }
348 for (i = 1; i < sgip->zsize; i ++)
349 sgip->table[i] = sgip->table[0] + i * sgip->ysize;
350
351 for (i = 0; i < sgip->zsize; i ++)
352 for (j = 0; j < sgip->ysize; j ++)
353 sgip->table[i][j] = getlong(sgip);
354 };
355 break;
356
357 case SGI_WRITE :
358 if (xsize < 1 ||
359 ysize < 1 ||
360 zsize < 1 ||
361 bpp < 1 || bpp > 2 ||
362 comp < SGI_COMP_NONE || comp > SGI_COMP_ARLE)
363 {
364 free(sgip);
365 return (NULL);
366 };
367
368 sgip->mode = SGI_WRITE;
369
370 putshort(SGI_MAGIC, sgip);
371 putc((sgip->comp = comp) != 0, sgip->file);
372 putc(sgip->bpp = bpp, sgip->file);
373 putshort(3, sgip); /* Dimensions */
374 putshort(sgip->xsize = xsize, sgip);
375 putshort(sgip->ysize = ysize, sgip);
376 putshort(sgip->zsize = zsize, sgip);
377 if (bpp == 1)
378 {
379 putlong(0, sgip); /* Minimum pixel */
380 putlong(255, sgip); /* Maximum pixel */
381 }
382 else
383 {
384 putlong(-32768, sgip); /* Minimum pixel */
385 putlong(32767, sgip); /* Maximum pixel */
386 };
387 putlong(0, sgip); /* Reserved */
388
389 memset(name, 0, sizeof(name));
390 fwrite(name, sizeof(name), 1, sgip->file);
391
392 for (i = 0; i < 102; i ++)
393 putlong(0, sgip);
394
395 switch (comp)
396 {
397 case SGI_COMP_NONE : /* No compression */
398 /*
399 * This file is uncompressed. To avoid problems with sparse files,
400 * we need to write blank pixels for the entire image...
401 */
402
403 if (bpp == 1)
404 {
405 for (i = xsize * ysize * zsize; i > 0; i --)
406 putc(0, sgip->file);
407 }
408 else
409 {
410 for (i = xsize * ysize * zsize; i > 0; i --)
411 putshort(0, sgip);
412 };
413 break;
414
415 case SGI_COMP_ARLE : /* Aggressive RLE */
416 sgip->arle_row = (unsigned short *)calloc(xsize, sizeof(unsigned short));
417 if (sgip->arle_row == NULL)
418 {
419 free(sgip);
420 return (NULL);
421 }
422 sgip->arle_offset = 0;
423
424 case SGI_COMP_RLE : /* Run-Length Encoding */
425 /*
426 * This file is compressed; write the (blank) scanline tables...
427 */
428
429 for (i = 2 * ysize * zsize; i > 0; i --)
430 putlong(0, sgip);
431
432 sgip->firstrow = ftell(sgip->file);
433 sgip->nextrow = ftell(sgip->file);
434 sgip->table = calloc(sgip->zsize, sizeof(long *));
435 if (sgip->table == NULL)
436 {
437 free(sgip->arle_row);
438 free(sgip);
439 return (NULL);
440 }
441 sgip->table[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long));
442 if (sgip->table[0] == NULL)
443 {
444 free(sgip->table);
445 free(sgip->arle_row);
446 free(sgip);
447 return (NULL);
448 }
449 for (i = 1; i < sgip->zsize; i ++)
450 sgip->table[i] = sgip->table[0] + i * sgip->ysize;
451 sgip->length = calloc(sgip->zsize, sizeof(long *));
452 sgip->length[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long));
453 for (i = 1; i < sgip->zsize; i ++)
454 sgip->length[i] = sgip->length[0] + i * sgip->ysize;
455 break;
456 };
457 break;
458
459 default :
460 free(sgip);
461 return (NULL);
462 };
463
464 return (sgip);
465 }
466
467
468 /*
469 * 'sgiPutRow()' - Put a row of image data to a file.
470 */
471
472 int
sgiPutRow(sgi_t * sgip,unsigned short * row,int y,int z)473 sgiPutRow(sgi_t *sgip, /* I - SGI image */
474 unsigned short *row, /* I - Row to write */
475 int y, /* I - Line to write */
476 int z) /* I - Channel to write */
477 {
478 int x; /* X coordinate */
479 long offset; /* File offset */
480
481
482 if (sgip == NULL ||
483 row == NULL ||
484 y < 0 || y >= sgip->ysize ||
485 z < 0 || z >= sgip->zsize)
486 return (-1);
487
488 switch (sgip->comp)
489 {
490 case SGI_COMP_NONE :
491 /*
492 * Seek to the image row - optimize buffering by only seeking if
493 * necessary...
494 */
495
496 offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp;
497 if (offset != ftell(sgip->file))
498 fseek(sgip->file, offset, SEEK_SET);
499
500 if (sgip->bpp == 1)
501 {
502 for (x = sgip->xsize; x > 0; x --, row ++)
503 putc(*row, sgip->file);
504 }
505 else
506 {
507 for (x = sgip->xsize; x > 0; x --, row ++)
508 putshort(*row, sgip);
509 };
510 break;
511
512 case SGI_COMP_ARLE :
513 if (sgip->table[z][y] != 0)
514 return (-1);
515
516 /*
517 * First check the last row written...
518 */
519
520 if (sgip->arle_offset > 0)
521 {
522 for (x = 0; x < sgip->xsize; x ++)
523 if (row[x] != sgip->arle_row[x])
524 break;
525
526 if (x == sgip->xsize)
527 {
528 sgip->table[z][y] = sgip->arle_offset;
529 sgip->length[z][y] = sgip->arle_length;
530 return (0);
531 };
532 };
533
534 /*
535 * If that didn't match, search all the previous rows...
536 */
537
538 fseek(sgip->file, sgip->firstrow, SEEK_SET);
539
540 if (sgip->bpp == 1)
541 {
542 do
543 {
544 sgip->arle_offset = ftell(sgip->file);
545 if ((sgip->arle_length = read_rle8(sgip, sgip->arle_row, sgip->xsize)) < 0)
546 {
547 x = 0;
548 break;
549 };
550
551 for (x = 0; x < sgip->xsize; x ++)
552 if (row[x] != sgip->arle_row[x])
553 break;
554 }
555 while (x < sgip->xsize);
556 }
557 else
558 {
559 do
560 {
561 sgip->arle_offset = ftell(sgip->file);
562 if ((sgip->arle_length = read_rle16(sgip, sgip->arle_row, sgip->xsize)) < 0)
563 {
564 x = 0;
565 break;
566 };
567
568 for (x = 0; x < sgip->xsize; x ++)
569 if (row[x] != sgip->arle_row[x])
570 break;
571 }
572 while (x < sgip->xsize);
573 };
574
575 if (x == sgip->xsize)
576 {
577 sgip->table[z][y] = sgip->arle_offset;
578 sgip->length[z][y] = sgip->arle_length;
579 return (0);
580 }
581 else
582 fseek(sgip->file, 0, SEEK_END); /* Clear EOF */
583
584 case SGI_COMP_RLE :
585 if (sgip->table[z][y] != 0)
586 return (-1);
587
588 offset = sgip->table[z][y] = sgip->nextrow;
589
590 if (offset != ftell(sgip->file))
591 fseek(sgip->file, offset, SEEK_SET);
592
593 if (sgip->bpp == 1)
594 x = write_rle8(sgip, row, sgip->xsize);
595 else
596 x = write_rle16(sgip, row, sgip->xsize);
597
598 if (sgip->comp == SGI_COMP_ARLE)
599 {
600 sgip->arle_offset = offset;
601 sgip->arle_length = x;
602 memcpy(sgip->arle_row, row, sgip->xsize * sizeof(short));
603 };
604
605 sgip->nextrow = ftell(sgip->file);
606 sgip->length[z][y] = x;
607
608 return (x);
609 };
610
611 return (0);
612 }
613
614
615 /*
616 * 'getlong()' - Get a 32-bit big-endian integer.
617 */
618
619 static int
getlong(sgi_t * sgip)620 getlong(sgi_t *sgip) /* I - SGI image to read from */
621 {
622 unsigned char b[4];
623
624
625 fread(b, 4, 1, sgip->file);
626 if(sgip->swapBytes)
627 return ((b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0]);
628 else
629 return ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
630 }
631
632
633 /*
634 * 'getshort()' - Get a 16-bit big-endian integer.
635 */
636
637 static int
getshort(sgi_t * sgip)638 getshort(sgi_t *sgip) /* I - SGI image to read from */
639 {
640 unsigned char b[2];
641
642
643 fread(b, 2, 1, sgip->file);
644 if(sgip->swapBytes)
645 return ((b[1] << 8) | b[0]);
646 else
647 return ((b[0] << 8) | b[1]);
648 }
649
650
651 /*
652 * 'putlong()' - Put a 32-bit big-endian integer.
653 */
654
655 static int
putlong(long n,sgi_t * sgip)656 putlong(long n, /* I - Long to write */
657 sgi_t *sgip) /* I - File to write to */
658 {
659 if (putc(n >> 24, sgip->file) == EOF)
660 return (EOF);
661 if (putc(n >> 16, sgip->file) == EOF)
662 return (EOF);
663 if (putc(n >> 8, sgip->file) == EOF)
664 return (EOF);
665 if (putc(n, sgip->file) == EOF)
666 return (EOF);
667 else
668 return (0);
669 }
670
671
672 /*
673 * 'putshort()' - Put a 16-bit big-endian integer.
674 */
675
676 static int
putshort(unsigned short n,sgi_t * sgip)677 putshort(unsigned short n, /* I - Short to write */
678 sgi_t *sgip) /* I - File to write to */
679 {
680 if (putc(n >> 8, sgip->file) == EOF)
681 return (EOF);
682 if (putc(n, sgip->file) == EOF)
683 return (EOF);
684 else
685 return (0);
686 }
687
688
689 /*
690 * 'read_rle8()' - Read 8-bit RLE data.
691 */
692
693 static int
read_rle8(sgi_t * sgip,unsigned short * row,int xsize)694 read_rle8(sgi_t *sgip, /* I - SGI image to read from */
695 unsigned short *row, /* O - Data */
696 int xsize) /* I - Width of data in pixels */
697 {
698 int i, /* Looping var */
699 ch, /* Current character */
700 count, /* RLE count */
701 length; /* Number of bytes read... */
702
703
704 length = 0;
705
706 while (xsize > 0)
707 {
708 if ((ch = getc(sgip->file)) == EOF)
709 return (-1);
710 length ++;
711
712 count = MIN (ch & 127, xsize);
713 if (count == 0)
714 break;
715
716 if (ch & 128)
717 {
718 for (i = 0; i < count; i ++, row ++, xsize --, length ++)
719 *row = getc(sgip->file);
720 }
721 else
722 {
723 ch = getc(sgip->file);
724 length ++;
725 for (i = 0; i < count; i ++, row ++, xsize --)
726 *row = ch;
727 };
728 };
729
730 return (xsize > 0 ? -1 : length);
731 }
732
733
734 /*
735 * 'read_rle16()' - Read 16-bit RLE data.
736 */
737
738 static int
read_rle16(sgi_t * sgip,unsigned short * row,int xsize)739 read_rle16(sgi_t *sgip, /* I - SGI image to read from */
740 unsigned short *row, /* O - Data */
741 int xsize)/* I - Width of data in pixels */
742 {
743 int i, /* Looping var */
744 ch, /* Current character */
745 count, /* RLE count */
746 length; /* Number of bytes read... */
747
748
749 length = 0;
750
751 while (xsize > 0)
752 {
753 if ((ch = getshort(sgip)) == EOF)
754 return (-1);
755 length ++;
756
757 count = MIN (ch & 127, xsize);
758 if (count == 0)
759 break;
760
761 if (ch & 128)
762 {
763 for (i = 0; i < count; i ++, row ++, xsize --, length ++)
764 *row = getshort(sgip);
765 }
766 else
767 {
768 ch = getshort(sgip);
769 length ++;
770 for (i = 0; i < count; i ++, row ++, xsize --)
771 *row = ch;
772 };
773 };
774
775 return (xsize > 0 ? -1 : length * 2);
776 }
777
778
779 /*
780 * 'write_rle8()' - Write 8-bit RLE data.
781 */
782
783 static int
write_rle8(sgi_t * sgip,unsigned short * row,int xsize)784 write_rle8(sgi_t *sgip, /* I - SGI image to write to */
785 unsigned short *row, /* I - Data */
786 int xsize)/* I - Width of data in pixels */
787 {
788 int length, /* Length of output line */
789 count, /* Number of repeated/non-repeated pixels */
790 i, /* Looping var */
791 x; /* Looping var */
792 unsigned short *start, /* Start of sequence */
793 repeat; /* Repeated pixel */
794
795
796 for (x = xsize, length = 0; x > 0;)
797 {
798 start = row;
799 row += 2;
800 x -= 2;
801
802 while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
803 {
804 row ++;
805 x --;
806 };
807
808 row -= 2;
809 x += 2;
810
811 count = row - start;
812 while (count > 0)
813 {
814 i = count > 126 ? 126 : count;
815 count -= i;
816
817 if (putc(128 | i, sgip->file) == EOF)
818 return (-1);
819 length ++;
820
821 while (i > 0)
822 {
823 if (putc(*start, sgip->file) == EOF)
824 return (-1);
825 start ++;
826 i --;
827 length ++;
828 };
829 };
830
831 if (x <= 0)
832 break;
833
834 start = row;
835 repeat = row[0];
836
837 row ++;
838 x --;
839
840 while (x > 0 && *row == repeat)
841 {
842 row ++;
843 x --;
844 };
845
846 count = row - start;
847 while (count > 0)
848 {
849 i = count > 126 ? 126 : count;
850 count -= i;
851
852 if (putc(i, sgip->file) == EOF)
853 return (-1);
854 length ++;
855
856 if (putc(repeat, sgip->file) == EOF)
857 return (-1);
858 length ++;
859 };
860 };
861
862 length ++;
863
864 if (putc(0, sgip->file) == EOF)
865 return (-1);
866 else
867 return (length);
868 }
869
870
871 /*
872 * 'write_rle16()' - Write 16-bit RLE data.
873 */
874
875 static int
write_rle16(sgi_t * sgip,unsigned short * row,int xsize)876 write_rle16(sgi_t *sgip, /* I - SGI image to write to */
877 unsigned short *row,/* I - Data */
878 int xsize)/* I - Width of data in pixels */
879 {
880 int length, /* Length of output line */
881 count, /* Number of repeated/non-repeated pixels */
882 i, /* Looping var */
883 x; /* Looping var */
884 unsigned short *start, /* Start of sequence */
885 repeat; /* Repeated pixel */
886
887
888 for (x = xsize, length = 0; x > 0;)
889 {
890 start = row;
891 row += 2;
892 x -= 2;
893
894 while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
895 {
896 row ++;
897 x --;
898 };
899
900 row -= 2;
901 x += 2;
902
903 count = row - start;
904 while (count > 0)
905 {
906 i = count > 126 ? 126 : count;
907 count -= i;
908
909 if (putshort(128 | i, sgip) == EOF)
910 return (-1);
911 length ++;
912
913 while (i > 0)
914 {
915 if (putshort(*start, sgip) == EOF)
916 return (-1);
917 start ++;
918 i --;
919 length ++;
920 };
921 };
922
923 if (x <= 0)
924 break;
925
926 start = row;
927 repeat = row[0];
928
929 row ++;
930 x --;
931
932 while (x > 0 && *row == repeat)
933 {
934 row ++;
935 x --;
936 };
937
938 count = row - start;
939 while (count > 0)
940 {
941 i = count > 126 ? 126 : count;
942 count -= i;
943
944 if (putshort(i, sgip) == EOF)
945 return (-1);
946 length ++;
947
948 if (putshort(repeat, sgip) == EOF)
949 return (-1);
950 length ++;
951 };
952 };
953
954 length ++;
955
956 if (putshort(0, sgip) == EOF)
957 return (-1);
958 else
959 return (2 * length);
960 }
961