10 /* values for the storage field */
11 #define SGI_STORAGE_VERBATIM 0
12 #define SGI_STORAGE_RLE 1
14 /* values for the colormap field */
15 #define SGI_COLORMAP_NORMAL 0
16 #define SGI_COLORMAP_DITHERED 1
17 #define SGI_COLORMAP_SCREEN 2
18 #define SGI_COLORMAP_COLORMAP 3
20 /* we add that little bit to avoid rounding issues */
21 #define SampleFTo16(num) ((int)((num) * 65535.0 + 0.01))
24 unsigned short imagic;
25 unsigned char storagetype;
27 unsigned short dimensions;
28 unsigned short xsize, ysize, zsize;
29 unsigned int pixmin, pixmax;
31 unsigned int colormap;
35 read_rgb_8_verbatim(i_img *im, io_glue *ig, rgb_header const *hdr);
37 read_rgb_8_rle(i_img *im, io_glue *ig, rgb_header const *hdr);
39 read_rgb_16_verbatim(i_img *im, io_glue *ig, rgb_header const *hdr);
41 read_rgb_16_rle(i_img *im, io_glue *ig, rgb_header const *hdr);
43 write_sgi_header(i_img *img, io_glue *ig, int *rle, int *bpc2);
45 write_sgi_8_rle(i_img *img, io_glue *ig);
47 write_sgi_8_verb(i_img *img, io_glue *ig);
49 write_sgi_16_rle(i_img *img, io_glue *ig);
51 write_sgi_16_verb(i_img *img, io_glue *ig);
53 #define Sample16ToF(num) ((num) / 65535.0)
56 #define STRING(x) _STRING(x)
61 rgb.c - implements reading and writing sgi image files, uses io layer.
65 io_glue *ig = io_new_fd( fd );
66 i_img *im = i_readrgb_wiol(ig, 0); // disallow partial reads
68 io_glue *ig = io_new_fd( fd );
69 return_code = i_writergb_wiol(im, ig);
73 imsgi.c implements the basic functions to read and write portable SGI
74 files. It uses the iolayer and needs either a seekable source or an
75 entire memory mapped buffer.
77 =head1 FUNCTION REFERENCE
79 Some of these functions are internal.
87 =item rgb_header_unpack(header, headbuf)
89 Unpacks the header structure into from buffer and stores
90 in the header structure.
92 header - header structure
93 headbuf - buffer to unpack from
101 rgb_header_unpack(rgb_header *header, const unsigned char *headbuf) {
102 header->imagic = (headbuf[0]<<8) + headbuf[1];
103 header->storagetype = headbuf[2];
104 header->BPC = headbuf[3];
105 header->dimensions = (headbuf[4]<<8) + headbuf[5];
106 header->xsize = (headbuf[6]<<8) + headbuf[7];
107 header->ysize = (headbuf[8]<<8) + headbuf[9];
108 header->zsize = (headbuf[10]<<8) + headbuf[11];
109 header->pixmin = (headbuf[12]<<24) + (headbuf[13]<<16)+(headbuf[14]<<8)+headbuf[15];
110 header->pixmax = (headbuf[16]<<24) + (headbuf[17]<<16)+(headbuf[18]<<8)+headbuf[19];
111 memcpy(header->name,headbuf+24,80);
112 header->name[79] = '\0';
113 header->colormap = (headbuf[104]<<24) + (headbuf[105]<<16)+(headbuf[106]<<8)+headbuf[107];
116 /* don't make this a macro */
118 store_16(unsigned char *buf, unsigned short value) {
120 buf[1] = value & 0xFF;
124 store_32(unsigned char *buf, unsigned long value) {
125 buf[0] = value >> 24;
126 buf[1] = (value >> 16) & 0xFF;
127 buf[2] = (value >> 8) & 0xFF;
128 buf[3] = value & 0xFF;
132 =item rgb_header_pack(header, headbuf)
134 Packs header structure into buffer for writing.
136 header - header structure
137 headbuf - buffer to pack into
144 rgb_header_pack(const rgb_header *header, unsigned char headbuf[512]) {
145 memset(headbuf, 0, 512);
146 store_16(headbuf, header->imagic);
147 headbuf[2] = header->storagetype;
148 headbuf[3] = header->BPC;
149 store_16(headbuf+4, header->dimensions);
150 store_16(headbuf+6, header->xsize);
151 store_16(headbuf+8, header->ysize);
152 store_16(headbuf+10, header->zsize);
153 store_32(headbuf+12, header->pixmin);
154 store_32(headbuf+16, header->pixmax);
155 memccpy(headbuf+24, header->name, '\0', 80);
156 store_32(headbuf+104, header->colormap);
160 =item i_readsgi_wiol(ig, partial)
162 Read in an image from the iolayer data source and return the image structure to it.
163 Returns NULL on error.
166 length - maximum length to read from data source, before closing it -1
173 i_readsgi_wiol(io_glue *ig, int partial) {
175 int width, height, channels;
177 unsigned char headbuf[512];
179 mm_log((1,"i_readsgi(ig %p, partial %d)\n", ig, partial));
182 if (ig->readcb(ig, headbuf, 512) != 512) {
183 i_push_error(errno, "SGI image: could not read header");
187 rgb_header_unpack(&header, headbuf);
189 if (header.imagic != SGI_MAGIC) {
190 i_push_error(0, "SGI image: invalid magic number");
194 mm_log((1,"imagic: %d\n", header.imagic));
195 mm_log((1,"storagetype: %d\n", header.storagetype));
196 mm_log((1,"BPC: %d\n", header.BPC));
197 mm_log((1,"dimensions: %d\n", header.dimensions));
198 mm_log((1,"xsize: %d\n", header.xsize));
199 mm_log((1,"ysize: %d\n", header.ysize));
200 mm_log((1,"zsize: %d\n", header.zsize));
201 mm_log((1,"min: %d\n", header.pixmin));
202 mm_log((1,"max: %d\n", header.pixmax));
203 mm_log((1,"name [skipped]\n"));
204 mm_log((1,"colormap: %d\n", header.colormap));
206 if (header.colormap != SGI_COLORMAP_NORMAL) {
207 i_push_errorf(0, "SGI image: invalid value for colormap (%d)", header.colormap);
211 if (header.BPC != 1 && header.BPC != 2) {
212 i_push_errorf(0, "SGI image: invalid value for BPC (%d)", header.BPC);
216 if (header.storagetype != SGI_STORAGE_VERBATIM
217 && header.storagetype != SGI_STORAGE_RLE) {
218 i_push_error(0, "SGI image: invalid storage type field");
222 if (header.pixmin >= header.pixmax) {
223 i_push_error(0, "SGI image: invalid pixmin >= pixmax");
227 width = header.xsize;
228 height = header.ysize;
229 channels = header.zsize;
231 switch (header.dimensions) {
242 /* fall through and use all of the dimensions */
246 i_push_error(0, "SGI image: invalid dimension field");
250 if (!i_int_check_image_file_limits(width, height, channels, header.BPC)) {
251 mm_log((1, "i_readsgi_wiol: image size exceeds limits\n"));
255 if (header.BPC == 1) {
256 img = i_img_8_new(width, height, channels);
260 switch (header.storagetype) {
261 case SGI_STORAGE_VERBATIM:
262 img = read_rgb_8_verbatim(img, ig, &header);
265 case SGI_STORAGE_RLE:
266 img = read_rgb_8_rle(img, ig, &header);
274 img = i_img_16_new(width, height, channels);
278 switch (header.storagetype) {
279 case SGI_STORAGE_VERBATIM:
280 img = read_rgb_16_verbatim(img, ig, &header);
283 case SGI_STORAGE_RLE:
284 img = read_rgb_16_rle(img, ig, &header);
296 i_tags_set(&img->tags, "i_comment", header.name, -1);
297 i_tags_setn(&img->tags, "sgi_pixmin", header.pixmin);
298 i_tags_setn(&img->tags, "sgi_pixmax", header.pixmax);
299 i_tags_setn(&img->tags, "sgi_bpc", header.BPC);
300 i_tags_setn(&img->tags, "sgi_rle", header.storagetype == SGI_STORAGE_RLE);
301 i_tags_set(&img->tags, "i_format", "sgi", -1);
306 if (img) i_img_destroy(img);
311 =item i_writergb_wiol(img, ig)
313 Writes an image in targa format. Returns 0 on error.
322 i_writesgi_wiol(io_glue *ig, i_img *img) {
328 if (!write_sgi_header(img, ig, &rle, &bpc2))
331 mm_log((1, "format rle %d bpc2 %d\n", rle, bpc2));
335 return write_sgi_16_rle(img, ig);
337 return write_sgi_16_verb(img, ig);
341 return write_sgi_8_rle(img, ig);
343 return write_sgi_8_verb(img, ig);
348 read_rgb_8_verbatim(i_img *img, io_glue *ig, rgb_header const *header) {
350 unsigned char *databuf;
353 i_img_dim width = i_img_get_width(img);
354 i_img_dim height = i_img_get_height(img);
355 int channels = i_img_getchannels(img);
356 int pixmin = header->pixmin;
357 int pixmax = header->pixmax;
358 int outmax = pixmax - pixmin;
360 linebuf = mymalloc(width * sizeof(i_color)); /* checked 31Jul07 TonyC */
361 databuf = mymalloc(width); /* checked 31Jul07 TonyC */
363 savemask = i_img_getmask(img);
365 for(c = 0; c < channels; c++) {
366 i_img_setmask(img, 1<<c);
367 for(y = 0; y < height; y++) {
370 if (ig->readcb(ig, databuf, width) != width) {
371 i_push_error(0, "SGI image: cannot read image data");
378 if (pixmin == 0 && pixmax == 255) {
379 for(x = 0; x < img->xsize; x++)
380 linebuf[x].channel[c] = databuf[x];
383 for(x = 0; x < img->xsize; x++) {
384 int sample = databuf[x];
387 else if (sample > pixmax)
392 linebuf[x].channel[c] = sample * 255 / outmax;
396 i_plin(img, 0, width, height-1-y, linebuf);
399 i_img_setmask(img, savemask);
408 read_rle_tables(io_glue *ig, i_img *img,
409 unsigned long **pstart_tab, unsigned long **plength_tab,
410 unsigned long *pmax_length) {
411 i_img_dim height = i_img_get_height(img);
412 int channels = i_img_getchannels(img);
413 unsigned char *databuf;
414 unsigned long *start_tab, *length_tab;
415 unsigned long max_length = 0;
417 size_t databuf_size = (size_t)height * channels * 4;
418 size_t tab_size = (size_t)height * channels * sizeof(unsigned long);
420 /* assumption: that the lengths are in bytes rather than in pixels */
421 if (databuf_size / height / channels != 4
422 || tab_size / height / channels != sizeof(unsigned long)) {
423 i_push_error(0, "SGI image: integer overflow calculating allocation size");
426 databuf = mymalloc(height * channels * 4); /* checked 31Jul07 TonyC */
427 start_tab = mymalloc(height*channels*sizeof(unsigned long));
428 length_tab = mymalloc(height*channels*sizeof(unsigned long));
430 /* Read offset table */
431 if (ig->readcb(ig, databuf, height * channels * 4) != height * channels * 4) {
432 i_push_error(0, "SGI image: short read reading RLE start table");
436 for(i = 0; i < height * channels; i++)
437 start_tab[i] = (databuf[i*4] << 24) | (databuf[i*4+1] << 16) |
438 (databuf[i*4+2] << 8) | (databuf[i*4+3]);
441 /* Read length table */
442 if (ig->readcb(ig, databuf, height*channels*4) != height*channels*4) {
443 i_push_error(0, "SGI image: short read reading RLE length table");
447 for(i=0; i < height * channels; i++) {
448 length_tab[i] = (databuf[i*4] << 24) + (databuf[i*4+1] << 16)+
449 (databuf[i*4+2] << 8) + (databuf[i*4+3]);
450 if (length_tab[i] > max_length)
451 max_length = length_tab[i];
454 mm_log((3, "Offset/length table:\n"));
455 for(i=0; i < height * channels; i++)
456 mm_log((3, "%d: %d/%d\n", i, start_tab[i], length_tab[i]));
458 *pstart_tab = start_tab;
459 *plength_tab = length_tab;
460 *pmax_length = max_length;
475 read_rgb_8_rle(i_img *img, io_glue *ig, rgb_header const *header) {
476 i_color *linebuf = NULL;
477 unsigned char *databuf = NULL;
478 unsigned long *start_tab, *length_tab;
479 unsigned long max_length;
480 i_img_dim width = i_img_get_width(img);
481 i_img_dim height = i_img_get_height(img);
482 int channels = i_img_getchannels(img);
485 int pixmin = header->pixmin;
486 int pixmax = header->pixmax;
487 int outmax = pixmax - pixmin;
489 if (!read_rle_tables(ig, img,
490 &start_tab, &length_tab, &max_length)) {
495 mm_log((1, "maxlen for an rle buffer: %d\n", max_length));
497 if (max_length > (img->xsize + 1) * 2) {
498 i_push_errorf(0, "SGI image: ridiculous RLE line length %lu", max_length);
502 linebuf = mymalloc(width*sizeof(i_color)); /* checked 31Jul07 TonyC */
503 databuf = mymalloc(max_length); /* checked 31Jul07 TonyC */
505 for(y = 0; y < img->ysize; y++) {
506 for(c = 0; c < channels; c++) {
507 int ci = height * c + y;
508 int datalen = length_tab[ci];
511 int data_left = datalen;
512 int pixels_left = width;
515 if (ig->seekcb(ig, start_tab[ci], SEEK_SET) != start_tab[ci]) {
516 i_push_error(0, "SGI image: cannot seek to RLE data");
519 if (ig->readcb(ig, databuf, datalen) != datalen) {
520 i_push_error(0, "SGI image: cannot read RLE data");
528 int count = code & 0x7f;
536 if (count > pixels_left) {
537 i_push_error(0, "SGI image: literal run overflows scanline");
540 if (count > data_left) {
541 i_push_error(0, "SGI image: literal run consumes more data than available");
545 pixels_left -= count;
547 if (pixmin == 0 && pixmax == 255) {
548 while (count-- > 0) {
549 outp->channel[c] = *inp++;
554 while (count-- > 0) {
558 else if (sample > pixmax)
562 outp->channel[c] = sample * 255 / outmax;
569 if (count > pixels_left) {
570 i_push_error(0, "SGI image: RLE run overflows scanline");
571 mm_log((2, "RLE run overflows scanline (y %d chan %d offset %ld len %ld)\n", y, c, start_tab[ci], length_tab[ci]));
575 i_push_error(0, "SGI image: RLE run has no data for pixel");
579 if (pixmin != 0 || pixmax != 255) {
582 else if (sample > pixmax)
586 sample = sample * 255 / outmax;
589 pixels_left -= count;
590 while (count-- > 0) {
591 outp->channel[c] = sample;
596 /* must have a full scanline */
598 i_push_error(0, "SGI image: incomplete RLE scanline");
601 /* must have used all of the data */
603 i_push_errorf(0, "SGI image: unused RLE data");
607 i_plin(img, 0, width, height-1-y, linebuf);
629 read_rgb_16_verbatim(i_img *img, io_glue *ig, rgb_header const *header) {
631 unsigned char *databuf;
634 i_img_dim width = i_img_get_width(img);
635 i_img_dim height = i_img_get_height(img);
636 int channels = i_img_getchannels(img);
637 int pixmin = header->pixmin;
638 int pixmax = header->pixmax;
639 int outmax = pixmax - pixmin;
641 linebuf = mymalloc(width * sizeof(i_fcolor)); /* checked 31Jul07 TonyC */
642 databuf = mymalloc(width * 2); /* checked 31Jul07 TonyC */
644 savemask = i_img_getmask(img);
646 for(c = 0; c < channels; c++) {
647 i_img_setmask(img, 1<<c);
648 for(y = 0; y < height; y++) {
651 if (ig->readcb(ig, databuf, width*2) != width*2) {
652 i_push_error(0, "SGI image: cannot read image data");
659 if (pixmin == 0 && pixmax == 65535) {
660 for(x = 0; x < img->xsize; x++)
661 linebuf[x].channel[c] = (databuf[x*2] * 256 + databuf[x*2+1]) / 65535.0;
664 for(x = 0; x < img->xsize; x++) {
665 int sample = databuf[x*2] * 256 + databuf[x*2+1];
668 else if (sample > pixmax)
673 linebuf[x].channel[c] = (double)sample / outmax;
677 i_plinf(img, 0, width, height-1-y, linebuf);
680 i_img_setmask(img, savemask);
689 read_rgb_16_rle(i_img *img, io_glue *ig, rgb_header const *header) {
690 i_fcolor *linebuf = NULL;
691 unsigned char *databuf = NULL;
692 unsigned long *start_tab, *length_tab;
693 unsigned long max_length;
694 i_img_dim width = i_img_get_width(img);
695 i_img_dim height = i_img_get_height(img);
696 int channels = i_img_getchannels(img);
699 int pixmin = header->pixmin;
700 int pixmax = header->pixmax;
701 int outmax = pixmax - pixmin;
703 if (!read_rle_tables(ig, img,
704 &start_tab, &length_tab, &max_length)) {
709 mm_log((1, "maxlen for an rle buffer: %lu\n", max_length));
711 if (max_length > (img->xsize * 2 + 1) * 2) {
712 i_push_errorf(0, "SGI image: ridiculous RLE line length %lu", max_length);
716 linebuf = mymalloc(width*sizeof(i_fcolor)); /* checked 31Jul07 TonyC */
717 databuf = mymalloc(max_length); /* checked 31Jul07 TonyC */
719 for(y = 0; y < img->ysize; y++) {
720 for(c = 0; c < channels; c++) {
721 int ci = height * c + y;
722 int datalen = length_tab[ci];
725 int data_left = datalen;
726 int pixels_left = width;
730 i_push_error(0, "SGI image: invalid RLE length value for BPC=2");
733 if (ig->seekcb(ig, start_tab[ci], SEEK_SET) != start_tab[ci]) {
734 i_push_error(0, "SGI image: cannot seek to RLE data");
737 if (ig->readcb(ig, databuf, datalen) != datalen) {
738 i_push_error(0, "SGI image: cannot read RLE data");
744 while (data_left > 0) {
745 int code = inp[0] * 256 + inp[1];
746 int count = code & 0x7f;
755 if (count > pixels_left) {
756 i_push_error(0, "SGI image: literal run overflows scanline");
759 if (count > data_left) {
760 i_push_error(0, "SGI image: literal run consumes more data than available");
764 pixels_left -= count;
765 data_left -= count * 2;
766 if (pixmin == 0 && pixmax == 65535) {
767 while (count-- > 0) {
768 outp->channel[c] = (inp[0] * 256 + inp[1]) / 65535.0;
774 while (count-- > 0) {
775 int sample = inp[0] * 256 + inp[1];
778 else if (sample > pixmax)
782 outp->channel[c] = (double)sample / outmax;
791 if (count > pixels_left) {
792 i_push_error(0, "SGI image: RLE run overflows scanline");
796 i_push_error(0, "SGI image: RLE run has no data for pixel");
799 sample = inp[0] * 256 + inp[1];
802 if (pixmin != 0 || pixmax != 65535) {
805 else if (sample > pixmax)
809 fsample = (double)sample / outmax;
812 fsample = (double)sample / 65535.0;
814 pixels_left -= count;
815 while (count-- > 0) {
816 outp->channel[c] = fsample;
821 /* must have a full scanline */
823 i_push_error(0, "SGI image: incomplete RLE scanline");
826 /* must have used all of the data */
828 i_push_errorf(0, "SGI image: unused RLE data");
832 i_plinf(img, 0, width, height-1-y, linebuf);
854 write_sgi_header(i_img *img, io_glue *ig, int *rle, int *bpc2) {
856 unsigned char headbuf[512] = { 0 };
858 header.imagic = SGI_MAGIC;
859 if (!i_tags_get_int(&img->tags, "sgi_rle", 0, rle))
861 header.storagetype = *rle ? SGI_STORAGE_RLE : SGI_STORAGE_VERBATIM;
863 header.colormap = SGI_COLORMAP_NORMAL;
864 *bpc2 = img->bits > 8;
867 header.pixmax = 65535;
873 if (img->channels == 1) {
874 header.dimensions = 2;
877 header.dimensions = 3;
879 header.xsize = img->xsize;
880 header.ysize = img->ysize;
881 header.zsize = img->channels;
882 memset(header.name, 0, sizeof(header.name));
883 i_tags_get_string(&img->tags, "i_comment", 0,
884 header.name, sizeof(header.name));
886 rgb_header_pack(&header, headbuf);
888 if (i_io_write(ig, headbuf, sizeof(headbuf)) != sizeof(headbuf)) {
889 i_push_error(0, "SGI image: cannot write header");
897 write_sgi_8_verb(i_img *img, io_glue *ig) {
899 i_img_dim width = img->xsize;
903 linebuf = mymalloc(width); /* checked 31Jul07 TonyC */
904 for (c = 0; c < img->channels; ++c) {
905 for (y = img->ysize - 1; y >= 0; --y) {
906 i_gsamp(img, 0, width, y, linebuf, &c, 1);
907 if (ig->writecb(ig, linebuf, width) != width) {
908 i_push_error(errno, "SGI image: error writing image data");
920 write_sgi_8_rle(i_img *img, io_glue *ig) {
922 unsigned char *comp_buf;
923 i_img_dim width = img->xsize;
926 unsigned char *offsets;
927 unsigned char *lengths;
929 size_t offsets_size = (size_t)4 * img->ysize * img->channels * 2;
930 unsigned long start_offset = 512 + offsets_size;
931 unsigned long current_offset = start_offset;
937 if (offsets_size / 2 / 4 / img->channels != img->ysize) {
938 i_push_error(0, "SGI image: integer overflow calculating allocation size");
942 linebuf = mymalloc(width); /* checked 31Jul07 TonyC */
943 comp_buf = mymalloc((width + 1) * 2); /* checked 31Jul07 TonyC */
944 offsets = mymalloc(offsets_size);
945 memset(offsets, 0, offsets_size);
946 if (i_io_write(ig, offsets, offsets_size) != offsets_size) {
947 i_push_error(errno, "SGI image: error writing offsets/lengths");
950 lengths = offsets + img->ysize * img->channels * 4;
951 for (c = 0; c < img->channels; ++c) {
952 for (y = img->ysize - 1; y >= 0; --y) {
953 i_gsamp(img, 0, width, y, linebuf, &c, 1);
958 unsigned char *run_start = inp;
960 /* first try for an RLE run */
962 while (in_left - run_length >= 2 && inp[0] == inp[1] && run_length < 127) {
966 if (in_left - run_length == 1 && inp[0] == inp[1] && run_length < 127) {
970 if (run_length > 2) {
971 *outp++ = run_length;
974 in_left -= run_length;
979 /* scan for a literal run */
982 while (in_left - run_length > 1 && (inp[0] != inp[1] || inp[1] != inp[2]) && run_length < 127) {
988 /* fill out the run if 2 or less samples left and there's space */
989 if (in_left - run_length <= 2
991 run_length = in_left;
993 in_left -= run_length;
994 *outp++ = run_length | 0x80;
995 while (run_length--) {
996 *outp++ = *run_start++;
1001 comp_size = outp - comp_buf;
1002 store_32(offsets + offset_pos, current_offset);
1003 store_32(lengths + offset_pos, comp_size);
1005 current_offset += comp_size;
1006 if (ig->writecb(ig, comp_buf, comp_size) != comp_size) {
1007 i_push_error(errno, "SGI image: error writing RLE data");
1013 /* seek back to store the offsets and lengths */
1014 if (i_io_seek(ig, 512, SEEK_SET) != 512) {
1015 i_push_error(errno, "SGI image: cannot seek to RLE table");
1019 if (i_io_write(ig, offsets, offsets_size) != offsets_size) {
1020 i_push_error(errno, "SGI image: cannot write final RLE table");
1038 write_sgi_16_verb(i_img *img, io_glue *ig) {
1039 i_fsample_t *linebuf;
1040 unsigned char *encbuf;
1041 unsigned char *outp;
1042 i_img_dim width = img->xsize;
1047 linebuf = mymalloc(width * sizeof(i_fsample_t)); /* checked 31Jul07 TonyC */
1048 encbuf = mymalloc(width * 2); /* checked 31Jul07 TonyC */
1049 for (c = 0; c < img->channels; ++c) {
1050 for (y = img->ysize - 1; y >= 0; --y) {
1051 i_gsampf(img, 0, width, y, linebuf, &c, 1);
1052 for (x = 0, outp = encbuf; x < width; ++x, outp+=2) {
1053 unsigned short samp16 = SampleFTo16(linebuf[x]);
1054 store_16(outp, samp16);
1056 if (ig->writecb(ig, encbuf, width * 2) != width * 2) {
1057 i_push_error(errno, "SGI image: error writing image data");
1071 write_sgi_16_rle(i_img *img, io_glue *ig) {
1072 i_fsample_t *sampbuf;
1073 unsigned short *linebuf;
1074 unsigned char *comp_buf;
1075 i_img_dim width = img->xsize;
1078 unsigned char *offsets;
1079 unsigned char *lengths;
1081 size_t offsets_size = (size_t)4 * img->ysize * img->channels * 2;
1082 unsigned long start_offset = 512 + offsets_size;
1083 unsigned long current_offset = start_offset;
1085 unsigned char *outp;
1086 unsigned short *inp;
1090 if (offsets_size / 4 / 2 / img->channels != img->ysize) {
1091 i_push_error(0, "SGI image: integer overflow calculating allocation size");
1095 sampbuf = mymalloc(width * sizeof(i_fsample_t)); /* checked 31Jul07 TonyC */
1096 linebuf = mymalloc(width * sizeof(unsigned short)); /* checked 31Jul07 TonyC */
1097 comp_buf = mymalloc((width + 1) * 2 * 2); /* checked 31Jul07 TonyC */
1098 offsets = mymalloc(offsets_size);
1099 memset(offsets, 0, offsets_size);
1100 if (i_io_write(ig, offsets, offsets_size) != offsets_size) {
1101 i_push_error(errno, "SGI image: error writing offsets/lengths");
1104 lengths = offsets + img->ysize * img->channels * 4;
1105 for (c = 0; c < img->channels; ++c) {
1106 for (y = img->ysize - 1; y >= 0; --y) {
1107 i_gsampf(img, 0, width, y, sampbuf, &c, 1);
1108 for (x = 0; x < width; ++x)
1109 linebuf[x] = (unsigned short)(SampleFTo16(sampbuf[x]));
1114 unsigned short *run_start = inp;
1116 /* first try for an RLE run */
1118 while (in_left - run_length >= 2 && inp[0] == inp[1] && run_length < 127) {
1122 if (in_left - run_length == 1 && inp[0] == inp[1] && run_length < 127) {
1126 if (run_length > 2) {
1127 store_16(outp, run_length);
1128 store_16(outp+2, inp[0]);
1131 in_left -= run_length;
1136 /* scan for a literal run */
1139 while (in_left - run_length > 1 && (inp[0] != inp[1] || inp[1] != inp[2]) && run_length < 127) {
1145 /* fill out the run if 2 or less samples left and there's space */
1146 if (in_left - run_length <= 2
1147 && in_left <= 127) {
1148 run_length = in_left;
1150 in_left -= run_length;
1151 store_16(outp, run_length | 0x80);
1153 while (run_length--) {
1154 store_16(outp, *run_start++);
1161 comp_size = outp - comp_buf;
1162 store_32(offsets + offset_pos, current_offset);
1163 store_32(lengths + offset_pos, comp_size);
1165 current_offset += comp_size;
1166 if (ig->writecb(ig, comp_buf, comp_size) != comp_size) {
1167 i_push_error(errno, "SGI image: error writing RLE data");
1173 /* seek back to store the offsets and lengths */
1174 if (i_io_seek(ig, 512, SEEK_SET) != 512) {
1175 i_push_error(errno, "SGI image: cannot seek to RLE table");
1179 if (i_io_write(ig, offsets, offsets_size) != offsets_size) {
1180 i_push_error(errno, "SGI image: cannot write final RLE table");