Color Management, Stage 2: Switch color pipeline to use OpenColorIO
[blender.git] / source / blender / imbuf / intern / iris.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/imbuf/intern/iris.c
29  *  \ingroup imbuf
30  */
31
32
33 #include <string.h>
34
35 #include "BLI_fileops.h"
36
37 #include "MEM_guardedalloc.h"
38
39 #include "imbuf.h"
40 #include "IMB_imbuf_types.h"
41 #include "IMB_imbuf.h"
42 #include "IMB_allocimbuf.h"
43 #include "IMB_filetype.h"
44
45 #include "IMB_colormanagement.h"
46 #include "IMB_colormanagement_intern.h"
47
48 typedef struct {
49         unsigned short  imagic;      /* stuff saved on disk . . */
50         unsigned short  type;
51         unsigned short  dim;
52         unsigned short  xsize;
53         unsigned short  ysize;
54         unsigned short  zsize;
55         unsigned int    min;
56         unsigned int    max;
57         unsigned int    wastebytes;
58         char name[80];
59         unsigned int    colormap;
60
61         int file;               /* stuff used in core only */
62         unsigned short  flags;
63         short           dorev;
64         short           x;
65         short           y;
66         short           z;
67         short           cnt;
68         unsigned short *ptr;
69         unsigned short *base;
70         unsigned short *tmpbuf;
71         unsigned int    offset;
72         unsigned int    rleend;        /* for rle images */
73         unsigned int   *rowstart;  /* for rle images */
74         int            *rowsize;   /* for rle images */
75 } IMAGE;
76
77 #define RINTLUM (79)
78 #define GINTLUM (156)
79 #define BINTLUM (21)
80
81 #define ILUM(r, g, b)   ((int)(RINTLUM * (r) + GINTLUM * (g) + BINTLUM * (b)) >> 8)
82
83 #define OFFSET_R    0   /* this is byte order dependent */
84 #define OFFSET_G    1
85 #define OFFSET_B    2
86 #define OFFSET_A    3
87
88 #define CHANOFFSET(z)   (3 - (z)) /* this is byte order dependent */
89
90 #define TYPEMASK        0xff00
91 #define BPPMASK         0x00ff
92 #define ITYPE_VERBATIM      0x0000
93 #define ITYPE_RLE       0x0100
94 #define ISRLE(type)     (((type) & 0xff00) == ITYPE_RLE)
95 #define ISVERBATIM(type)    (((type) & 0xff00) == ITYPE_VERBATIM)
96 #define BPP(type)       ((type) & BPPMASK)
97 #define RLE(bpp)        (ITYPE_RLE | (bpp))
98 #define VERBATIM(bpp)       (ITYPE_VERBATIM | (bpp))
99 #define IBUFSIZE(pixels)    ((pixels + (pixels >> 6)) << 2)
100 #define RLE_NOP         0x00
101
102 /* funcs */
103 static void readheader(FILE *inf, IMAGE *image);
104 static int writeheader(FILE *outf, IMAGE *image);
105
106 static unsigned short getshort(FILE *inf);
107 static unsigned int getlong(FILE *inf);
108 static void putshort(FILE *outf, unsigned short val);
109 static int putlong(FILE *outf, unsigned int val);
110 static int writetab(FILE *outf, unsigned int *tab, int len);
111 static void readtab(FILE *inf, unsigned int *tab, int len);
112
113 static void expandrow(unsigned char *optr, unsigned char *iptr, int z);
114 static void expandrow2(float *optr, unsigned char *iptr, int z);
115 static void interleaverow(unsigned char *lptr, unsigned char *cptr, int z, int n);
116 static void interleaverow2(float *lptr, unsigned char *cptr, int z, int n);
117 static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cnt);
118 static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n);
119
120 /*
121  *      byte order independent read/write of shorts and ints.
122  *
123  */
124
125 static uchar *file_data;
126 static int file_offset;
127
128 static unsigned short getshort(FILE *inf)
129 {
130         unsigned char *buf;
131         (void)inf; /* unused */
132
133         buf = file_data + file_offset;
134         file_offset += 2;
135         
136         return (buf[0] << 8) + (buf[1] << 0);
137 }
138
139 static unsigned int getlong(FILE *inf)
140 {
141         unsigned char *buf;
142         (void)inf; /* unused */
143         
144         buf = file_data + file_offset;
145         file_offset += 4;
146         
147         return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3] << 0);
148 }
149
150 static void putshort(FILE *outf, unsigned short val)
151 {
152         unsigned char buf[2];
153
154         buf[0] = (val >> 8);
155         buf[1] = (val >> 0);
156         fwrite(buf, 2, 1, outf);
157 }
158
159 static int putlong(FILE *outf, unsigned int val)
160 {
161         unsigned char buf[4];
162
163         buf[0] = (val >> 24);
164         buf[1] = (val >> 16);
165         buf[2] = (val >> 8);
166         buf[3] = (val >> 0);
167         return fwrite(buf, 4, 1, outf);
168 }
169
170 static void readheader(FILE *inf, IMAGE *image)
171 {
172         memset(image, 0, sizeof(IMAGE));
173         image->imagic = getshort(inf);
174         image->type = getshort(inf);
175         image->dim = getshort(inf);
176         image->xsize = getshort(inf);
177         image->ysize = getshort(inf);
178         image->zsize = getshort(inf);
179 }
180
181 static int writeheader(FILE *outf, IMAGE *image)
182 {
183         IMAGE t = {0};
184
185         fwrite(&t, sizeof(IMAGE), 1, outf);
186         fseek(outf, 0, SEEK_SET);
187         putshort(outf, image->imagic);
188         putshort(outf, image->type);
189         putshort(outf, image->dim);
190         putshort(outf, image->xsize);
191         putshort(outf, image->ysize);
192         putshort(outf, image->zsize);
193         putlong(outf, image->min);
194         putlong(outf, image->max);
195         putlong(outf, 0);
196         return fwrite("no name", 8, 1, outf);
197 }
198
199 static int writetab(FILE *outf, unsigned int *tab, int len)
200 {
201         int r = 0;
202
203         while (len) {
204                 r = putlong(outf, *tab++);
205                 len -= 4;
206         }
207         return r;
208 }
209
210 static void readtab(FILE *inf, unsigned int *tab, int len)
211 {
212         while (len) {
213                 *tab++ = getlong(inf);
214                 len -= 4;
215         }
216 }
217
218 static void test_endian_zbuf(struct ImBuf *ibuf)
219 {
220         int len;
221         int *zval;
222         
223         if (BIG_LONG(1) == 1) return;
224         if (ibuf->zbuf == NULL) return;
225         
226         len = ibuf->x * ibuf->y;
227         zval = ibuf->zbuf;
228         
229         while (len--) {
230                 zval[0] = BIG_LONG(zval[0]);
231                 zval++;
232         }
233 }
234
235 /* from misc_util: flip the bytes from x  */
236 #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1])
237
238 /* this one is only def-ed once, strangely... */
239 #define GSS(x) (((uchar *)(x))[1] << 8 | ((uchar *)(x))[0])
240
241 int imb_is_a_iris(unsigned char *mem)
242 {
243         return ((GS(mem) == IMAGIC) || (GSS(mem) == IMAGIC));
244 }
245
246 /*
247  *      longimagedata - 
248  *              read in a B/W RGB or RGBA iris image file and return a 
249  *      pointer to an array of ints.
250  *
251  */
252
253 struct ImBuf *imb_loadiris(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
254 {
255         unsigned int *base, *lptr = NULL;
256         float *fbase, *fptr = NULL;
257         unsigned int *zbase, *zptr;
258         unsigned char *rledat;
259         unsigned int *starttab, *lengthtab;
260         FILE *inf = NULL;
261         IMAGE image;
262         int x, y, z, tablen;
263         int xsize, ysize, zsize;
264         int bpp, rle, cur, badorder;
265         ImBuf *ibuf;
266
267         (void)size; /* unused */
268         
269         if (!imb_is_a_iris(mem)) return NULL;
270
271         /* OCIO_TODO: only tested with 1 byte per pixel, not sure how to test with other settings */
272         colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
273
274         /*printf("new iris\n");*/
275         
276         file_data = mem;
277         file_offset = 0;
278         
279         readheader(inf, &image);
280         if (image.imagic != IMAGIC) {
281                 fprintf(stderr, "longimagedata: bad magic number in image file\n");
282                 return(NULL);
283         }
284         
285         rle = ISRLE(image.type);
286         bpp = BPP(image.type);
287         if (bpp != 1 && bpp != 2) {
288                 fprintf(stderr, "longimagedata: image must have 1 or 2 byte per pix chan\n");
289                 return(NULL);
290         }
291         
292         xsize = image.xsize;
293         ysize = image.ysize;
294         zsize = image.zsize;
295         
296         if (flags & IB_test) {
297                 ibuf = IMB_allocImBuf(image.xsize, image.ysize, 8 * image.zsize, 0);
298                 if (ibuf) ibuf->ftype = IMAGIC;
299                 return(ibuf);
300         }
301         
302         if (rle) {
303                 
304                 tablen = ysize * zsize * sizeof(int);
305                 starttab = (unsigned int *)MEM_mallocN(tablen, "iris starttab");
306                 lengthtab = (unsigned int *)MEM_mallocN(tablen, "iris endtab");
307                 file_offset = 512;
308                 
309                 readtab(inf, starttab, tablen);
310                 readtab(inf, lengthtab, tablen);
311         
312                 /* check data order */
313                 cur = 0;
314                 badorder = 0;
315                 for (y = 0; y < ysize; y++) {
316                         for (z = 0; z < zsize; z++) {
317                                 if (starttab[y + z * ysize] < cur) {
318                                         badorder = 1;
319                                         break;
320                                 }
321                                 cur = starttab[y + z * ysize];
322                         }
323                         if (badorder)
324                                 break;
325                 }
326         
327                 if (bpp == 1) {
328                         
329                         ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect);
330                         if (ibuf->planes > 32) ibuf->planes = 32;
331                         base = ibuf->rect;
332                         zbase = (unsigned int *)ibuf->zbuf;
333                         
334                         if (badorder) {
335                                 for (z = 0; z < zsize; z++) {
336                                         lptr = base;
337                                         for (y = 0; y < ysize; y++) {
338                                                 file_offset = starttab[y + z * ysize];
339                                                 
340                                                 rledat = file_data + file_offset;
341                                                 file_offset += lengthtab[y + z * ysize];
342                                                 
343                                                 expandrow((uchar *)lptr, rledat, 3 - z);
344                                                 lptr += xsize;
345                                         }
346                                 }
347                         }
348                         else {
349                                 lptr = base;
350                                 zptr = zbase;
351                                 for (y = 0; y < ysize; y++) {
352                                 
353                                         for (z = 0; z < zsize; z++) {
354                                                 
355                                                 file_offset = starttab[y + z * ysize];
356
357                                                 rledat = file_data + file_offset;
358                                                 file_offset += lengthtab[y + z * ysize];
359                                                 
360                                                 if (z < 4) expandrow((uchar *)lptr, rledat, 3 - z);
361                                                 else if (z < 8) expandrow((uchar *)zptr, rledat, 7 - z);
362                                         }
363                                         lptr += xsize;
364                                         zptr += xsize;
365                                 }
366                         }
367                         
368
369                 }
370                 else {  /* bpp == 2 */
371                         
372                         ibuf = IMB_allocImBuf(xsize, ysize, 32, (flags & IB_rect) | IB_rectfloat);
373                         
374                         fbase = ibuf->rect_float;
375                         
376                         if (badorder) {
377                                 for (z = 0; z < zsize; z++) {
378                                         fptr = fbase;
379                                         for (y = 0; y < ysize; y++) {
380                                                 file_offset = starttab[y + z * ysize];
381                                                 
382                                                 rledat = file_data + file_offset;
383                                                 file_offset += lengthtab[y + z * ysize];
384                                                 
385                                                 expandrow2(fptr, rledat, 3 - z);
386                                                 fptr += xsize * 4;
387                                         }
388                                 }
389                         }
390                         else {
391                                 fptr = fbase;
392
393                                 for (y = 0; y < ysize; y++) {
394                                 
395                                         for (z = 0; z < zsize; z++) {
396                                                 
397                                                 file_offset = starttab[y + z * ysize];
398
399                                                 rledat = file_data + file_offset;
400                                                 file_offset += lengthtab[y + z * ysize];
401                                                 
402                                                 expandrow2(fptr, rledat, 3 - z);
403                                                 
404                                         }
405                                         fptr += xsize * 4;
406                                 }
407                         }
408                 }
409                 
410                 MEM_freeN(starttab);
411                 MEM_freeN(lengthtab);   
412
413         }
414         else {
415                 if (bpp == 1) {
416                         
417                         ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect);
418                         if (ibuf->planes > 32) ibuf->planes = 32;
419
420                         base = ibuf->rect;
421                         zbase = (unsigned int *)ibuf->zbuf;
422                         
423                         file_offset = 512;
424                         rledat = file_data + file_offset;
425                         
426                         for (z = 0; z < zsize; z++) {
427                                 
428                                 if (z < 4) lptr = base;
429                                 else if (z < 8) lptr = zbase;
430                                 
431                                 for (y = 0; y < ysize; y++) {
432
433                                         interleaverow((uchar *)lptr, rledat, 3 - z, xsize);
434                                         rledat += xsize;
435                                         
436                                         lptr += xsize;
437                                 }
438                         }
439                         
440                 }
441                 else {  /* bpp == 2 */
442                         
443                         ibuf = IMB_allocImBuf(xsize, ysize, 32, (flags & IB_rect) | IB_rectfloat);
444
445                         fbase = ibuf->rect_float;
446
447                         file_offset = 512;
448                         rledat = file_data + file_offset;
449                         
450                         for (z = 0; z < zsize; z++) {
451                                 
452                                 fptr = fbase;
453                                 
454                                 for (y = 0; y < ysize; y++) {
455
456                                         interleaverow2(fptr, rledat, 3 - z, xsize);
457                                         rledat += xsize * 2;
458                                         
459                                         fptr += xsize * 4;
460                                 }
461                         }
462                         
463                 }
464         }
465         
466         
467         if (bpp == 1) {
468                 uchar *rect;
469                 
470                 if (image.zsize == 1) {
471                         rect = (uchar *) ibuf->rect;
472                         for (x = ibuf->x * ibuf->y; x > 0; x--) {
473                                 rect[0] = 255;
474                                 rect[1] = rect[2] = rect[3];
475                                 rect += 4;
476                         }
477                 }
478                 else if (image.zsize == 2) {
479                         /* grayscale with alpha */
480                         rect = (uchar *) ibuf->rect;
481                         for (x = ibuf->x * ibuf->y; x > 0; x--) {
482                                 rect[0] = rect[2];
483                                 rect[1] = rect[2] = rect[3];
484                                 rect += 4;
485                         }
486                 }
487                 else if (image.zsize == 3) {
488                         /* add alpha */
489                         rect = (uchar *) ibuf->rect;
490                         for (x = ibuf->x * ibuf->y; x > 0; x--) {
491                                 rect[0] = 255;
492                                 rect += 4;
493                         }
494                 }
495                 
496         }
497         else {  /* bpp == 2 */
498                 
499                 if (image.zsize == 1) {
500                         fbase = ibuf->rect_float;
501                         for (x = ibuf->x * ibuf->y; x > 0; x--) {
502                                 fbase[0] = 1;
503                                 fbase[1] = fbase[2] = fbase[3];
504                                 fbase += 4;
505                         }
506                 }
507                 else if (image.zsize == 2) {
508                         /* grayscale with alpha */
509                         fbase = ibuf->rect_float;
510                         for (x = ibuf->x * ibuf->y; x > 0; x--) {
511                                 fbase[0] = fbase[2];
512                                 fbase[1] = fbase[2] = fbase[3];
513                                 fbase += 4;
514                         }
515                 }
516                 else if (image.zsize == 3) {
517                         /* add alpha */
518                         fbase = ibuf->rect_float;
519                         for (x = ibuf->x * ibuf->y; x > 0; x--) {
520                                 fbase[0] = 1;
521                                 fbase += 4;
522                         }
523                 }
524                 
525                 if (flags & IB_rect) {
526                         IMB_rect_from_float(ibuf);
527                 }
528                 
529         }
530
531         ibuf->ftype = IMAGIC;
532
533         test_endian_zbuf(ibuf);
534
535         if (ibuf->rect) {
536                 IMB_convert_rgba_to_abgr(ibuf);
537         }
538
539         return(ibuf);
540 }
541
542 /* static utility functions for longimagedata */
543
544 static void interleaverow(unsigned char *lptr, unsigned char *cptr, int z, int n)
545 {
546         lptr += z;
547         while (n--) {
548                 *lptr = *cptr++;
549                 lptr += 4;
550         }
551 }
552
553 static void interleaverow2(float *lptr, unsigned char *cptr, int z, int n)
554 {
555         lptr += z;
556         while (n--) {
557                 *lptr = ((cptr[0] << 8) | (cptr[1] << 0)) / (float)0xFFFF;
558                 cptr += 2;
559                 lptr += 4;
560         }
561 }
562
563 static void expandrow2(float *optr, unsigned char *iptr, int z)
564 {
565         unsigned short pixel, count;
566         float pixel_f;
567
568         optr += z;
569         while (1) {
570                 pixel = (iptr[0] << 8) | (iptr[1] << 0);
571                 iptr += 2;
572                 
573                 if (!(count = (pixel & 0x7f)) )
574                         return;
575                 if (pixel & 0x80) {
576                         while (count >= 8) {
577                                 optr[0 * 4] = ((iptr[0] << 8) | (iptr[1] << 0)) / (float)0xFFFF;
578                                 optr[1 * 4] = ((iptr[2] << 8) | (iptr[3] << 0)) / (float)0xFFFF;
579                                 optr[2 * 4] = ((iptr[4] << 8) | (iptr[5] << 0)) / (float)0xFFFF;
580                                 optr[3 * 4] = ((iptr[6] << 8) | (iptr[7] << 0)) / (float)0xFFFF;
581                                 optr[4 * 4] = ((iptr[8] << 8) | (iptr[9] << 0)) / (float)0xFFFF;
582                                 optr[5 * 4] = ((iptr[10] << 8) | (iptr[11] << 0)) / (float)0xFFFF;
583                                 optr[6 * 4] = ((iptr[12] << 8) | (iptr[13] << 0)) / (float)0xFFFF;
584                                 optr[7 * 4] = ((iptr[14] << 8) | (iptr[15] << 0)) / (float)0xFFFF;
585                                 optr += 8 * 4;
586                                 iptr += 8 * 2;
587                                 count -= 8;
588                         }
589                         while (count--) {
590                                 *optr = ((iptr[0] << 8) | (iptr[1] << 0)) / (float)0xFFFF;
591                                 iptr += 2;
592                                 optr += 4;
593                         }
594                 }
595                 else {
596                         pixel_f = ((iptr[0] << 8) | (iptr[1] << 0)) / (float)0xFFFF;
597                         iptr += 2;
598
599                         while (count >= 8) {
600                                 optr[0 * 4] = pixel_f;
601                                 optr[1 * 4] = pixel_f;
602                                 optr[2 * 4] = pixel_f;
603                                 optr[3 * 4] = pixel_f;
604                                 optr[4 * 4] = pixel_f;
605                                 optr[5 * 4] = pixel_f;
606                                 optr[6 * 4] = pixel_f;
607                                 optr[7 * 4] = pixel_f;
608                                 optr += 8 * 4;
609                                 count -= 8;
610                         }
611                         while (count--) {
612                                 *optr = pixel_f;
613                                 optr += 4;
614                         }
615                 }
616         }       
617 }
618
619 static void expandrow(unsigned char *optr, unsigned char *iptr, int z)
620 {
621         unsigned char pixel, count;
622
623         optr += z;
624         while (1) {
625                 pixel = *iptr++;
626                 if (!(count = (pixel & 0x7f)) )
627                         return;
628                 if (pixel & 0x80) {
629                         while (count >= 8) {
630                                 optr[0 * 4] = iptr[0];
631                                 optr[1 * 4] = iptr[1];
632                                 optr[2 * 4] = iptr[2];
633                                 optr[3 * 4] = iptr[3];
634                                 optr[4 * 4] = iptr[4];
635                                 optr[5 * 4] = iptr[5];
636                                 optr[6 * 4] = iptr[6];
637                                 optr[7 * 4] = iptr[7];
638                                 optr += 8 * 4;
639                                 iptr += 8;
640                                 count -= 8;
641                         }
642                         while (count--) {
643                                 *optr = *iptr++;
644                                 optr += 4;
645                         }
646                 }
647                 else {
648                         pixel = *iptr++;
649                         while (count >= 8) {
650                                 optr[0 * 4] = pixel;
651                                 optr[1 * 4] = pixel;
652                                 optr[2 * 4] = pixel;
653                                 optr[3 * 4] = pixel;
654                                 optr[4 * 4] = pixel;
655                                 optr[5 * 4] = pixel;
656                                 optr[6 * 4] = pixel;
657                                 optr[7 * 4] = pixel;
658                                 optr += 8 * 4;
659                                 count -= 8;
660                         }
661                         while (count--) {
662                                 *optr = pixel;
663                                 optr += 4;
664                         }
665                 }
666         }
667 }
668
669 /*
670  *      output_iris -
671  *              copy an array of ints to an iris image file.  Each int
672  *      represents one pixel.  xsize and ysize specify the dimensions of
673  *      the pixel array.  zsize specifies what kind of image file to
674  *      write out.  if zsize is 1, the luminance of the pixels are
675  *      calculated, and a sinlge channel black and white image is saved.
676  *      If zsize is 3, an RGB image file is saved.  If zsize is 4, an
677  *      RGBA image file is saved.
678  *
679  *  Added: zbuf write
680  */
681
682 static int output_iris(unsigned int *lptr, int xsize, int ysize, int zsize, const char *name, int *zptr)
683 {
684         FILE *outf;
685         IMAGE *image;
686         int tablen, y, z, pos, len = 0;
687         unsigned int *starttab, *lengthtab;
688         unsigned char *rlebuf;
689         unsigned int *lumbuf;
690         int rlebuflen, goodwrite;
691
692         goodwrite = 1;
693         outf = BLI_fopen(name, "wb");
694         if (!outf) return 0;
695
696         tablen = ysize * zsize * sizeof(int);
697
698         image = (IMAGE *)MEM_mallocN(sizeof(IMAGE), "iris image");
699         starttab = (unsigned int *)MEM_mallocN(tablen, "iris starttab");
700         lengthtab = (unsigned int *)MEM_mallocN(tablen, "iris lengthtab");
701         rlebuflen = 1.05 * xsize + 10;
702         rlebuf = (unsigned char *)MEM_mallocN(rlebuflen, "iris rlebuf");
703         lumbuf = (unsigned int *)MEM_mallocN(xsize * sizeof(int), "iris lumbuf");
704
705         memset(image, 0, sizeof(IMAGE));
706         image->imagic = IMAGIC;
707         image->type = RLE(1);
708         if (zsize > 1)
709                 image->dim = 3;
710         else
711                 image->dim = 2;
712         image->xsize = xsize;
713         image->ysize = ysize;
714         image->zsize = zsize;
715         image->min = 0;
716         image->max = 255;
717         goodwrite *= writeheader(outf, image);
718         fseek(outf, 512 + 2 * tablen, SEEK_SET);
719         pos = 512 + 2 * tablen;
720         
721         for (y = 0; y < ysize; y++) {
722                 for (z = 0; z < zsize; z++) {
723                         
724                         if (zsize == 1) {
725                                 lumrow((uchar *)lptr, (uchar *)lumbuf, xsize);
726                                 len = compressrow((uchar *)lumbuf, rlebuf, CHANOFFSET(z), xsize);
727                         }
728                         else {
729                                 if (z < 4) {
730                                         len = compressrow((uchar *)lptr, rlebuf, CHANOFFSET(z), xsize);
731                                 }
732                                 else if (z < 8 && zptr) {
733                                         len = compressrow((uchar *)zptr, rlebuf, CHANOFFSET(z - 4), xsize);
734                                 }
735                         }
736                         if (len > rlebuflen) {
737                                 fprintf(stderr, "output_iris: rlebuf is too small - bad poop\n");
738                                 exit(1);
739                         }
740                         goodwrite *= fwrite(rlebuf, len, 1, outf);
741                         starttab[y + z * ysize] = pos;
742                         lengthtab[y + z * ysize] = len;
743                         pos += len;
744                 }
745                 lptr += xsize;
746                 if (zptr) zptr += xsize;
747         }
748
749         fseek(outf, 512, SEEK_SET);
750         goodwrite *= writetab(outf, starttab, tablen);
751         goodwrite *= writetab(outf, lengthtab, tablen);
752         MEM_freeN(image);
753         MEM_freeN(starttab);
754         MEM_freeN(lengthtab);
755         MEM_freeN(rlebuf);
756         MEM_freeN(lumbuf);
757         fclose(outf);
758         if (goodwrite)
759                 return 1;
760         else {
761                 fprintf(stderr, "output_iris: not enough space for image!!\n");
762                 return 0;
763         }
764 }
765
766 /* static utility functions for output_iris */
767
768 static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n)
769 {
770         lumptr += CHANOFFSET(0);
771         while (n--) {
772                 *lumptr = ILUM(rgbptr[OFFSET_R], rgbptr[OFFSET_G], rgbptr[OFFSET_B]);
773                 lumptr += 4;
774                 rgbptr += 4;
775         }
776 }
777
778 static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cnt)
779 {
780         unsigned char *iptr, *ibufend, *sptr, *optr;
781         short todo, cc;
782         int count;
783
784         lbuf += z;
785         iptr = lbuf;
786         ibufend = iptr + cnt * 4;
787         optr = rlebuf;
788
789         while (iptr < ibufend) {
790                 sptr = iptr;
791                 iptr += 8;
792                 while ((iptr < ibufend) && ((iptr[-8] != iptr[-4]) || (iptr[-4] != iptr[0])))
793                         iptr += 4;
794                 iptr -= 8;
795                 count = (iptr - sptr) / 4;
796                 while (count) {
797                         todo = count > 126 ? 126 : count;
798                         count -= todo;
799                         *optr++ = 0x80 | todo;
800                         while (todo > 8) {
801                                 optr[0] = sptr[0 * 4];
802                                 optr[1] = sptr[1 * 4];
803                                 optr[2] = sptr[2 * 4];
804                                 optr[3] = sptr[3 * 4];
805                                 optr[4] = sptr[4 * 4];
806                                 optr[5] = sptr[5 * 4];
807                                 optr[6] = sptr[6 * 4];
808                                 optr[7] = sptr[7 * 4];
809
810                                 optr += 8;
811                                 sptr += 8 * 4;
812                                 todo -= 8;
813                         }
814                         while (todo--) {
815                                 *optr++ = *sptr;
816                                 sptr += 4;
817                         }
818                 }
819                 sptr = iptr;
820                 cc = *iptr;
821                 iptr += 4;
822                 while ( (iptr < ibufend) && (*iptr == cc) )
823                         iptr += 4;
824                 count = (iptr - sptr) / 4;
825                 while (count) {
826                         todo = count > 126 ? 126 : count;
827                         count -= todo;
828                         *optr++ = todo;
829                         *optr++ = cc;
830                 }
831         }
832         *optr++ = 0;
833         return optr - (unsigned char *)rlebuf;
834 }
835
836 int imb_saveiris(struct ImBuf *ibuf, const char *name, int flags)
837 {
838         short zsize;
839         int ret;
840
841         zsize = (ibuf->planes + 7) >> 3;
842         if (flags & IB_zbuf &&  ibuf->zbuf != NULL) zsize = 8;
843         
844         IMB_convert_rgba_to_abgr(ibuf);
845         test_endian_zbuf(ibuf);
846
847         ret = output_iris(ibuf->rect, ibuf->x, ibuf->y, zsize, name, ibuf->zbuf);
848
849         /* restore! Quite clumsy, 2 times a switch... maybe better a malloc ? */
850         IMB_convert_rgba_to_abgr(ibuf);
851         test_endian_zbuf(ibuf);
852
853         return(ret);
854 }
855