Blender V4.5
format_iris.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
13
14#include <algorithm>
15#include <cstring>
16
17#include "BLI_fileops.h"
18#include "BLI_utildefines.h"
19
20#include "MEM_guardedalloc.h"
21
23#include "IMB_filetype.hh"
24#include "IMB_imbuf.hh"
25#include "IMB_imbuf_types.hh"
26
31#define IRIS_MAGIC 0732
32
52
53#define HEADER_SIZE 512
54
55BLI_STATIC_ASSERT(sizeof(IRIS_Header) == HEADER_SIZE, "Invalid header size");
56
57#define RINTLUM (79)
58#define GINTLUM (156)
59#define BINTLUM (21)
60
61#define ILUM(r, g, b) (int(RINTLUM * (r) + GINTLUM * (g) + BINTLUM * (b)) >> 8)
62
63#define OFFSET_R 0 /* this is byte order dependent */
64#define OFFSET_G 1
65#define OFFSET_B 2
66// #define OFFSET_A 3
67
68#define CHANOFFSET(z) (3 - (z)) /* this is byte order dependent */
69
70// #define TYPEMASK 0xff00
71#define BPPMASK 0x00ff
72// #define ITYPE_VERBATIM 0x0000 /* UNUSED */
73#define ITYPE_RLE 0x0100
74#define ISRLE(type) (((type) & 0xff00) == ITYPE_RLE)
75// #define ISVERBATIM(type) (((type) & 0xff00) == ITYPE_VERBATIM)
76#define BPP(type) ((type) & BPPMASK)
77#define RLE(bpp) (ITYPE_RLE | (bpp))
78// #define VERBATIM(bpp) (ITYPE_VERBATIM | (bpp)) /* UNUSED */
79// #define IBUFSIZE(pixels) ((pixels + (pixels >> 6)) << 2) /* UNUSED */
80// #define RLE_NOP 0x00
81
82/* local struct for mem access */
87
88#define MFILE_DATA(inf) ((void)0, ((inf)->_file_data + (inf)->_file_offset))
89#define MFILE_STEP(inf, step) \
90 { \
91 (inf)->_file_offset += step; \
92 } \
93 ((void)0)
94#define MFILE_SEEK(inf, pos) \
95 { \
96 (inf)->_file_offset = pos; \
97 } \
98 ((void)0)
99
100/* error flags */
101#define DIRTY_FLAG_EOF (1 << 0)
102#define DIRTY_FLAG_ENCODING (1 << 1)
103
104/* Functions. */
105static void readheader(MFileOffset *inf, IRIS_Header *image);
106static int writeheader(FILE *outf, const IRIS_Header *image);
107
108static ushort getshort(MFileOffset *inf);
109static uint getlong(MFileOffset *mofs);
110static void putshort(FILE *outf, ushort val);
111static int putlong(FILE *outf, uint val);
112static int writetab(FILE *outf, const uint *tab, int len);
113static void readtab(MFileOffset *inf, uint *tab, int len);
114
115static int expandrow(
116 uchar *optr, const uchar *optr_end, const uchar *iptr, const uchar *iptr_end, int z);
117static int expandrow2(
118 float *optr, const float *optr_end, const uchar *iptr, const uchar *iptr_end, int z);
119static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n);
120static void interleaverow2(float *lptr, const uchar *cptr, int z, int n);
121static int compressrow(const uchar *lbuf, uchar *rlebuf, int z, int row_len);
122static void lumrow(const uchar *rgbptr, uchar *lumptr, int n);
123
124/* -------------------------------------------------------------------- */
127
134static void imbuf_rgba_to_abgr(ImBuf *ibuf)
135{
136 size_t size;
137 uchar rt, *cp = ibuf->byte_buffer.data;
138
139 if (ibuf->byte_buffer.data) {
141
142 while (size-- > 0) {
143 rt = cp[0];
144 cp[0] = cp[3];
145 cp[3] = rt;
146 rt = cp[1];
147 cp[1] = cp[2];
148 cp[2] = rt;
149 cp += 4;
150 }
151 }
152}
153
155
156/*
157 * byte order independent read/write of shorts and ints.
158 */
159
161{
162 const uchar *buf;
163
164 buf = MFILE_DATA(inf);
165 MFILE_STEP(inf, 2);
166
167 return (ushort(buf[0]) << 8) + (ushort(buf[1]) << 0);
168}
169
171{
172 const uchar *buf;
173
174 buf = MFILE_DATA(mofs);
175 MFILE_STEP(mofs, 4);
176
177 return (uint(buf[0]) << 24) + (uint(buf[1]) << 16) + (uint(buf[2]) << 8) + (uint(buf[3]) << 0);
178}
179
180static void putshort(FILE *outf, ushort val)
181{
182 uchar buf[2];
183
184 buf[0] = (val >> 8);
185 buf[1] = (val >> 0);
186 fwrite(buf, 2, 1, outf);
187}
188
189static int putlong(FILE *outf, uint val)
190{
191 uchar buf[4];
192
193 buf[0] = (val >> 24);
194 buf[1] = (val >> 16);
195 buf[2] = (val >> 8);
196 buf[3] = (val >> 0);
197 return fwrite(buf, 4, 1, outf);
198}
199
200static void readheader(MFileOffset *inf, IRIS_Header *image)
201{
202 memset(image, 0, sizeof(IRIS_Header));
203 image->imagic = getshort(inf);
204 image->type = getshort(inf);
205 image->dim = getshort(inf);
206 image->xsize = getshort(inf);
207 image->ysize = getshort(inf);
208 image->zsize = getshort(inf);
209}
210
211static int writeheader(FILE *outf, const IRIS_Header *image)
212{
213 IRIS_Header t = {0};
214
215 fwrite(&t, sizeof(IRIS_Header), 1, outf);
216 fseek(outf, 0, SEEK_SET);
217 putshort(outf, image->imagic);
218 putshort(outf, image->type);
219 putshort(outf, image->dim);
220 putshort(outf, image->xsize);
221 putshort(outf, image->ysize);
222 putshort(outf, image->zsize);
223 putlong(outf, image->min);
224 putlong(outf, image->max);
225 putlong(outf, 0);
226 return fwrite("no name", 8, 1, outf);
227}
228
229static int writetab(FILE *outf, const uint *tab, int len)
230{
231 int r = 0;
232
233 while (len) {
234 r = putlong(outf, *tab++);
235 len -= 4;
236 }
237 return r;
238}
239
240static void readtab(MFileOffset *inf, uint *tab, int len)
241{
242 while (len) {
243 *tab++ = getlong(inf);
244 len -= 4;
245 }
246}
247
248/* From misc_util: flip the bytes from x. */
249#define GS(x) (((uchar *)(x))[0] << 8 | ((uchar *)(x))[1])
250
251bool imb_is_a_iris(const uchar *mem, size_t size)
252{
253 if (size < 2) {
254 return false;
255 }
256 return GS(mem) == IRIS_MAGIC;
257}
258
259ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, ImFileColorSpace & /*r_colorspace*/)
260{
261 uint *base, *lptr = nullptr;
262 float *fbase, *fptr = nullptr;
263 const uchar *rledat;
264 const uchar *mem_end = mem + size;
265 MFileOffset _inf_data = {mem, 0}, *inf = &_inf_data;
266 IRIS_Header image;
267 int bpp, rle, cur, badorder;
268 ImBuf *ibuf = nullptr;
269 uchar dirty_flag = 0;
270
271 if (!imb_is_a_iris(mem, size)) {
272 return nullptr;
273 }
274
275 /* Could be part of the magic check above,
276 * by convention this check only requests the size needed to read it's magic though. */
277 if (size < HEADER_SIZE) {
278 return nullptr;
279 }
280
281 readheader(inf, &image);
282 /* The call to `imb_is_a_iris` ensures this. */
283 BLI_assert(image.imagic == IRIS_MAGIC);
284
285 rle = ISRLE(image.type);
286 bpp = BPP(image.type);
287 if (!ELEM(bpp, 1, 2)) {
288 fprintf(stderr, "%s: image must have 1 or 2 byte per pix chan\n", __func__);
289 return nullptr;
290 }
291 if (uint(image.zsize) > 8) {
292 fprintf(stderr, "%s: channels over 8 not supported\n", __func__);
293 return nullptr;
294 }
295 if (image.xsize == 0 || image.ysize == 0 || image.zsize == 0) {
296 fprintf(stderr, "%s: zero size image found\n", __func__);
297 return nullptr;
298 }
299
300 const int xsize = image.xsize;
301 const int ysize = image.ysize;
302
303 const int zsize_file = image.zsize;
304 const int zsize_read = min_ii(image.zsize, 4);
305
306 if (flags & IB_test) {
307 ibuf = IMB_allocImBuf(image.xsize, image.ysize, 8 * image.zsize, 0);
308 if (ibuf) {
309 ibuf->ftype = IMB_FTYPE_IRIS;
310 }
311 return ibuf;
312 }
313
314 if (rle) {
315 size_t tablen = size_t(ysize) * size_t(zsize_file) * sizeof(int);
317
318 uint *starttab = MEM_malloc_arrayN<uint>(tablen, "iris starttab");
319 uint *lengthtab = MEM_malloc_arrayN<uint>(tablen, "iris endtab");
320
321#define MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(p) \
322 if (UNLIKELY((p) > mem_end)) { \
323 dirty_flag |= DIRTY_FLAG_EOF; \
324 goto fail_rle; \
325 } \
326 ((void)0)
327
328 MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(MFILE_DATA(inf) + (2 * tablen));
329
330 readtab(inf, starttab, tablen);
331 readtab(inf, lengthtab, tablen);
332
333 /* check data order */
334 cur = 0;
335 badorder = 0;
336 for (size_t y = 0; y < ysize; y++) {
337 for (size_t z = 0; z < zsize_file; z++) {
338 if (starttab[y + z * ysize] < cur) {
339 badorder = 1;
340 break;
341 }
342 cur = starttab[y + z * ysize];
343 }
344 if (badorder) {
345 break;
346 }
347 }
348
349 if (bpp == 1) {
350
351 ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize_read, IB_byte_data);
352 if (!ibuf) {
353 goto fail_rle;
354 }
355 ibuf->planes = std::min<int>(ibuf->planes, 32);
356 base = (uint *)ibuf->byte_buffer.data;
357
358 if (badorder) {
359 for (size_t z = 0; z < zsize_read; z++) {
360 lptr = base;
361 for (size_t y = 0; y < ysize; y++) {
362 MFILE_SEEK(inf, starttab[y + z * ysize]);
363 rledat = MFILE_DATA(inf);
364 MFILE_STEP(inf, lengthtab[y + z * ysize]);
365 const uchar *rledat_next = MFILE_DATA(inf);
366 uint *lptr_next = lptr + xsize;
368 dirty_flag |= expandrow((uchar *)lptr, (uchar *)lptr_next, rledat, rledat_next, 3 - z);
369 lptr = lptr_next;
370 }
371 }
372 }
373 else {
374 lptr = base;
375 for (size_t y = 0; y < ysize; y++) {
376
377 uint *lptr_next = lptr + xsize;
378
379 for (size_t z = 0; z < zsize_read; z++) {
380 MFILE_SEEK(inf, starttab[y + z * ysize]);
381 rledat = MFILE_DATA(inf);
382 MFILE_STEP(inf, lengthtab[y + z * ysize]);
383 const uchar *rledat_next = MFILE_DATA(inf);
385 if (z < 4) {
386 dirty_flag |= expandrow(
387 (uchar *)lptr, (uchar *)lptr_next, rledat, rledat_next, 3 - z);
388 }
389 else {
390 break;
391 }
392 }
393 lptr = lptr_next;
394 }
395 }
396 }
397 else { /* bpp == 2 */
398
399 ibuf = IMB_allocImBuf(xsize, ysize, 32, (flags & IB_byte_data) | IB_float_data);
400 if (!ibuf) {
401 goto fail_rle;
402 }
403
404 fbase = ibuf->float_buffer.data;
405
406 if (badorder) {
407 for (size_t z = 0; z < zsize_read; z++) {
408 fptr = fbase;
409 for (size_t y = 0; y < ysize; y++) {
410 MFILE_SEEK(inf, starttab[y + z * ysize]);
411 rledat = MFILE_DATA(inf);
412 MFILE_STEP(inf, lengthtab[y + z * ysize]);
413 const uchar *rledat_next = MFILE_DATA(inf);
415 float *fptr_next = fptr + (xsize * 4);
416 dirty_flag |= expandrow2(fptr, fptr_next, rledat, rledat_next, 3 - z);
417 fptr = fptr_next;
418 }
419 }
420 }
421 else {
422 fptr = fbase;
423 float *fptr_next = fptr + (xsize * 4);
424
425 for (size_t y = 0; y < ysize; y++) {
426
427 for (size_t z = 0; z < zsize_read; z++) {
428 MFILE_SEEK(inf, starttab[y + z * ysize]);
429 rledat = MFILE_DATA(inf);
430 MFILE_STEP(inf, lengthtab[y + z * ysize]);
431 const uchar *rledat_next = MFILE_DATA(inf);
433 dirty_flag |= expandrow2(fptr, fptr_next, rledat, rledat_next, 3 - z);
434 }
435 fptr = fptr_next;
436 }
437 }
438 }
439#undef MFILE_CAPACITY_AT_PTR_OK_OR_FAIL
440 fail_rle:
441 MEM_freeN(starttab);
442 MEM_freeN(lengthtab);
443
444 if (!ibuf) {
445 return nullptr;
446 }
447 }
448 else {
449
450#define MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(p) \
451 if (UNLIKELY((p) > mem_end)) { \
452 dirty_flag |= DIRTY_FLAG_EOF; \
453 goto fail_uncompressed; \
454 } \
455 ((void)0)
456
457 if (bpp == 1) {
458
459 ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize_read, IB_byte_data);
460 if (!ibuf) {
461 goto fail_uncompressed;
462 }
463 ibuf->planes = std::min<int>(ibuf->planes, 32);
464
465 base = (uint *)ibuf->byte_buffer.data;
466
468 rledat = MFILE_DATA(inf);
469
470 for (size_t z = 0; z < zsize_read; z++) {
471
472 if (z < 4) {
473 lptr = base;
474 }
475 else {
476 break;
477 }
478
479 for (size_t y = 0; y < ysize; y++) {
480 const uchar *rledat_next = rledat + xsize;
481 const int z_ofs = 3 - z;
482 MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next + z_ofs);
483 interleaverow((uchar *)lptr, rledat, z_ofs, xsize);
484 rledat = rledat_next;
485 lptr += xsize;
486 }
487 }
488 }
489 else { /* bpp == 2 */
490
491 ibuf = IMB_allocImBuf(xsize, ysize, 32, (flags & IB_byte_data) | IB_float_data);
492 if (!ibuf) {
493 goto fail_uncompressed;
494 }
495
496 fbase = ibuf->float_buffer.data;
497
499 rledat = MFILE_DATA(inf);
500
501 for (size_t z = 0; z < zsize_read; z++) {
502
503 fptr = fbase;
504
505 for (size_t y = 0; y < ysize; y++) {
506 const uchar *rledat_next = rledat + xsize * 2;
507 const int z_ofs = 3 - z;
508 MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next + z_ofs);
509 interleaverow2(fptr, rledat, z_ofs, xsize);
510 rledat = rledat_next;
511 fptr += xsize * 4;
512 }
513 }
514 }
515#undef MFILE_CAPACITY_AT_PTR_OK_OR_FAIL
516 fail_uncompressed:
517 if (!ibuf) {
518 return nullptr;
519 }
520 }
521
522 if (bpp == 1) {
523 uchar *rect;
524
525 if (image.zsize == 1) {
526 rect = ibuf->byte_buffer.data;
527 for (size_t x = size_t(ibuf->x) * size_t(ibuf->y); x > 0; x--) {
528 rect[0] = 255;
529 rect[1] = rect[2] = rect[3];
530 rect += 4;
531 }
532 }
533 else if (image.zsize == 2) {
534 /* Gray-scale with alpha. */
535 rect = ibuf->byte_buffer.data;
536 for (size_t x = size_t(ibuf->x) * size_t(ibuf->y); x > 0; x--) {
537 rect[0] = rect[2];
538 rect[1] = rect[2] = rect[3];
539 rect += 4;
540 }
541 }
542 else if (image.zsize == 3) {
543 /* add alpha */
544 rect = ibuf->byte_buffer.data;
545 for (size_t x = size_t(ibuf->x) * size_t(ibuf->y); x > 0; x--) {
546 rect[0] = 255;
547 rect += 4;
548 }
549 }
550 }
551 else { /* bpp == 2 */
552
553 if (image.zsize == 1) {
554 fbase = ibuf->float_buffer.data;
555 for (size_t x = size_t(ibuf->x) * size_t(ibuf->y); x > 0; x--) {
556 fbase[0] = 1;
557 fbase[1] = fbase[2] = fbase[3];
558 fbase += 4;
559 }
560 }
561 else if (image.zsize == 2) {
562 /* Gray-scale with alpha. */
563 fbase = ibuf->float_buffer.data;
564 for (size_t x = size_t(ibuf->x) * size_t(ibuf->y); x > 0; x--) {
565 fbase[0] = fbase[2];
566 fbase[1] = fbase[2] = fbase[3];
567 fbase += 4;
568 }
569 }
570 else if (image.zsize == 3) {
571 /* add alpha */
572 fbase = ibuf->float_buffer.data;
573 for (size_t x = size_t(ibuf->x) * size_t(ibuf->y); x > 0; x--) {
574 fbase[0] = 1;
575 fbase += 4;
576 }
577 }
578
579 if (flags & IB_byte_data) {
581 }
582 }
583
584 if (dirty_flag) {
585 fprintf(stderr, "%s: corrupt file content (%d)\n", __func__, dirty_flag);
586 }
587 ibuf->ftype = IMB_FTYPE_IRIS;
588
589 if (ibuf->byte_buffer.data) {
590 imbuf_rgba_to_abgr(ibuf);
591 }
592
593 return ibuf;
594}
595
596/* Static utility functions for loading image data. */
597
598static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n)
599{
600 lptr += z;
601 while (n--) {
602 *lptr = *cptr++;
603 lptr += 4;
604 }
605}
606
607static void interleaverow2(float *lptr, const uchar *cptr, int z, int n)
608{
609 lptr += z;
610 while (n--) {
611 *lptr = ((cptr[0] << 8) | (cptr[1] << 0)) / float(0xFFFF);
612 cptr += 2;
613 lptr += 4;
614 }
615}
616
617static int expandrow2(
618 float *optr, const float *optr_end, const uchar *iptr, const uchar *iptr_end, int z)
619{
620 ushort pixel, count;
621 float pixel_f;
622
623#define EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next) \
624 if (UNLIKELY(iptr_next > iptr_end)) { \
625 goto fail; \
626 } \
627 ((void)0)
628
629#define EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next) \
630 if (UNLIKELY(optr_next > optr_end)) { \
631 goto fail; \
632 } \
633 ((void)0)
634
635 optr += z;
636 optr_end += z;
637 while (true) {
638 const uchar *iptr_next = iptr + 2;
640 pixel = (iptr[0] << 8) | (iptr[1] << 0);
641 iptr = iptr_next;
642
643 if (!(count = (pixel & 0x7f))) {
644 return false;
645 }
646 const float *optr_next = optr + (int(count) * 4);
648 if (pixel & 0x80) {
649 iptr_next = iptr + (count * 2);
651 while (count >= 8) {
652 optr[0 * 4] = ((iptr[0] << 8) | (iptr[1] << 0)) / float(0xFFFF);
653 optr[1 * 4] = ((iptr[2] << 8) | (iptr[3] << 0)) / float(0xFFFF);
654 optr[2 * 4] = ((iptr[4] << 8) | (iptr[5] << 0)) / float(0xFFFF);
655 optr[3 * 4] = ((iptr[6] << 8) | (iptr[7] << 0)) / float(0xFFFF);
656 optr[4 * 4] = ((iptr[8] << 8) | (iptr[9] << 0)) / float(0xFFFF);
657 optr[5 * 4] = ((iptr[10] << 8) | (iptr[11] << 0)) / float(0xFFFF);
658 optr[6 * 4] = ((iptr[12] << 8) | (iptr[13] << 0)) / float(0xFFFF);
659 optr[7 * 4] = ((iptr[14] << 8) | (iptr[15] << 0)) / float(0xFFFF);
660 optr += 8 * 4;
661 iptr += 8 * 2;
662 count -= 8;
663 }
664 while (count--) {
665 *optr = ((iptr[0] << 8) | (iptr[1] << 0)) / float(0xFFFF);
666 iptr += 2;
667 optr += 4;
668 }
669 BLI_assert(iptr == iptr_next);
670 }
671 else {
672 iptr_next = iptr + 2;
674 pixel_f = ((iptr[0] << 8) | (iptr[1] << 0)) / float(0xFFFF);
675 iptr = iptr_next;
676
677 while (count >= 8) {
678 optr[0 * 4] = pixel_f;
679 optr[1 * 4] = pixel_f;
680 optr[2 * 4] = pixel_f;
681 optr[3 * 4] = pixel_f;
682 optr[4 * 4] = pixel_f;
683 optr[5 * 4] = pixel_f;
684 optr[6 * 4] = pixel_f;
685 optr[7 * 4] = pixel_f;
686 optr += 8 * 4;
687 count -= 8;
688 }
689 while (count--) {
690 *optr = pixel_f;
691 optr += 4;
692 }
693 BLI_assert(iptr == iptr_next);
694 }
695 BLI_assert(optr == optr_next);
696 }
697 return false;
698
699#undef EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL
700#undef EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL
701fail:
702 return DIRTY_FLAG_ENCODING;
703}
704
705static int expandrow(
706 uchar *optr, const uchar *optr_end, const uchar *iptr, const uchar *iptr_end, int z)
707{
708 uchar pixel, count;
709
710#define EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next) \
711 if (UNLIKELY(iptr_next > iptr_end)) { \
712 goto fail; \
713 } \
714 ((void)0)
715
716#define EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next) \
717 if (UNLIKELY(optr_next > optr_end)) { \
718 goto fail; \
719 } \
720 ((void)0)
721
722 optr += z;
723 optr_end += z;
724 while (true) {
725 const uchar *iptr_next = iptr + 1;
727 pixel = *iptr;
728 iptr = iptr_next;
729 if (!(count = (pixel & 0x7f))) {
730 return false;
731 }
732 const uchar *optr_next = optr + (int(count) * 4);
734
735 if (pixel & 0x80) {
736 iptr_next = iptr + count;
738 while (count >= 8) {
739 optr[0 * 4] = iptr[0];
740 optr[1 * 4] = iptr[1];
741 optr[2 * 4] = iptr[2];
742 optr[3 * 4] = iptr[3];
743 optr[4 * 4] = iptr[4];
744 optr[5 * 4] = iptr[5];
745 optr[6 * 4] = iptr[6];
746 optr[7 * 4] = iptr[7];
747 optr += 8 * 4;
748 iptr += 8;
749 count -= 8;
750 }
751 while (count--) {
752 *optr = *iptr++;
753 optr += 4;
754 }
755 BLI_assert(iptr == iptr_next);
756 }
757 else {
758 iptr_next = iptr + 1;
760 pixel = *iptr++;
761 while (count >= 8) {
762 optr[0 * 4] = pixel;
763 optr[1 * 4] = pixel;
764 optr[2 * 4] = pixel;
765 optr[3 * 4] = pixel;
766 optr[4 * 4] = pixel;
767 optr[5 * 4] = pixel;
768 optr[6 * 4] = pixel;
769 optr[7 * 4] = pixel;
770 optr += 8 * 4;
771 count -= 8;
772 }
773 while (count--) {
774 *optr = pixel;
775 optr += 4;
776 }
777 BLI_assert(iptr == iptr_next);
778 }
779 BLI_assert(optr == optr_next);
780 }
781
782 return false;
783
784#undef EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL
785#undef EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL
786fail:
787 return DIRTY_FLAG_ENCODING;
788}
789
803static bool output_iris(const char *filepath,
804 const uint *lptr,
805 const int *zptr,
806 const int xsize,
807 const int ysize,
808 const int zsize)
809{
810 FILE *outf;
811 IRIS_Header *image;
812 int tablen, y, z, pos, len = 0;
813 uint *starttab, *lengthtab;
814 uchar *rlebuf;
815 uint *lumbuf;
816 int rlebuflen, goodwrite;
817
818 goodwrite = 1;
819 outf = BLI_fopen(filepath, "wb");
820 if (!outf) {
821 return false;
822 }
823
824 tablen = ysize * zsize * sizeof(int);
825
826 image = MEM_mallocN<IRIS_Header>("iris image");
827 starttab = MEM_malloc_arrayN<uint>(size_t(tablen), "iris starttab");
828 lengthtab = MEM_malloc_arrayN<uint>(size_t(tablen), "iris lengthtab");
829 rlebuflen = 1.05 * xsize + 10;
830 rlebuf = MEM_malloc_arrayN<uchar>(size_t(rlebuflen), "iris rlebuf");
831 lumbuf = MEM_malloc_arrayN<uint>(size_t(xsize), "iris lumbuf");
832
833 memset(image, 0, sizeof(IRIS_Header));
834 image->imagic = IRIS_MAGIC;
835 image->type = RLE(1);
836 if (zsize > 1) {
837 image->dim = 3;
838 }
839 else {
840 image->dim = 2;
841 }
842 image->xsize = xsize;
843 image->ysize = ysize;
844 image->zsize = zsize;
845 image->min = 0;
846 image->max = 255;
847 goodwrite *= writeheader(outf, image);
848 fseek(outf, HEADER_SIZE + (2 * tablen), SEEK_SET);
849 pos = HEADER_SIZE + (2 * tablen);
850
851 for (y = 0; y < ysize; y++) {
852 for (z = 0; z < zsize; z++) {
853
854 if (zsize == 1) {
855 lumrow((const uchar *)lptr, (uchar *)lumbuf, xsize);
856 len = compressrow((const uchar *)lumbuf, rlebuf, CHANOFFSET(z), xsize);
857 }
858 else {
859 if (z < 4) {
860 len = compressrow((const uchar *)lptr, rlebuf, CHANOFFSET(z), xsize);
861 }
862 else if (z < 8 && zptr) {
863 len = compressrow((const uchar *)zptr, rlebuf, CHANOFFSET(z - 4), xsize);
864 }
865 }
866
867 BLI_assert_msg(len <= rlebuflen, "The length calculated for 'rlebuflen' was too small!");
868
869 goodwrite *= fwrite(rlebuf, len, 1, outf);
870 starttab[y + z * ysize] = pos;
871 lengthtab[y + z * ysize] = len;
872 pos += len;
873 }
874 lptr += xsize;
875 if (zptr) {
876 zptr += xsize;
877 }
878 }
879
880 fseek(outf, HEADER_SIZE, SEEK_SET);
881 goodwrite *= writetab(outf, starttab, tablen);
882 goodwrite *= writetab(outf, lengthtab, tablen);
883 MEM_freeN(image);
884 MEM_freeN(starttab);
885 MEM_freeN(lengthtab);
886 MEM_freeN(rlebuf);
887 MEM_freeN(lumbuf);
888 fclose(outf);
889 if (goodwrite) {
890 return true;
891 }
892
893 fprintf(stderr, "%s: not enough space for image!!\n", __func__);
894 return false;
895}
896
897/* static utility functions for output_iris */
898
899static void lumrow(const uchar *rgbptr, uchar *lumptr, int n)
900{
901 lumptr += CHANOFFSET(0);
902 while (n--) {
903 *lumptr = ILUM(rgbptr[OFFSET_R], rgbptr[OFFSET_G], rgbptr[OFFSET_B]);
904 lumptr += 4;
905 rgbptr += 4;
906 }
907}
908
909static int compressrow(const uchar *lbuf, uchar *rlebuf, const int z, const int row_len)
910{
911 const uchar *iptr, *ibufend, *sptr;
912 uchar *optr;
913 short todo, cc;
914 int count;
915
916 lbuf += z;
917 iptr = lbuf;
918 ibufend = iptr + row_len * 4;
919 optr = rlebuf;
920
921 while (iptr < ibufend) {
922 sptr = iptr;
923 iptr += 8;
924 while ((iptr < ibufend) && ((iptr[-8] != iptr[-4]) || (iptr[-4] != iptr[0]))) {
925 iptr += 4;
926 }
927 iptr -= 8;
928 count = (iptr - sptr) / 4;
929 while (count) {
930 todo = count > 126 ? 126 : count;
931 count -= todo;
932 *optr++ = 0x80 | todo;
933 while (todo > 8) {
934 optr[0] = sptr[0 * 4];
935 optr[1] = sptr[1 * 4];
936 optr[2] = sptr[2 * 4];
937 optr[3] = sptr[3 * 4];
938 optr[4] = sptr[4 * 4];
939 optr[5] = sptr[5 * 4];
940 optr[6] = sptr[6 * 4];
941 optr[7] = sptr[7 * 4];
942
943 optr += 8;
944 sptr += 8 * 4;
945 todo -= 8;
946 }
947 while (todo--) {
948 *optr++ = *sptr;
949 sptr += 4;
950 }
951 }
952 sptr = iptr;
953 cc = *iptr;
954 iptr += 4;
955 while ((iptr < ibufend) && (*iptr == cc)) {
956 iptr += 4;
957 }
958 count = (iptr - sptr) / 4;
959 while (count) {
960 todo = count > 126 ? 126 : count;
961 count -= todo;
962 *optr++ = todo;
963 *optr++ = cc;
964 }
965 }
966 *optr++ = 0;
967 return optr - rlebuf;
968}
969
970bool imb_saveiris(ImBuf *ibuf, const char *filepath, int /*flags*/)
971{
972 const uint limit = std::numeric_limits<ushort>::max();
973 if (ibuf->x > limit || ibuf->y > limit) {
974 fprintf(stderr, "%s: image x/y exceeds %u\n", __func__, limit);
975 return false;
976 }
977
978 const short zsize = (ibuf->planes + 7) >> 3;
979
980 imbuf_rgba_to_abgr(ibuf);
981
982 const bool ok = output_iris(
983 filepath, (uint *)ibuf->byte_buffer.data, nullptr, ibuf->x, ibuf->y, zsize);
984
985 /* restore! Quite clumsy, 2 times a switch... maybe better a malloc ? */
986 imbuf_rgba_to_abgr(ibuf);
987
988 return ok;
989}
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:83
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
File and directory operations.
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
MINLINE int min_ii(int a, int b)
unsigned char uchar
unsigned int uint
unsigned short ushort
#define ELEM(...)
void IMB_byte_from_float(ImBuf *ibuf)
size_t IMB_get_pixel_count(const ImBuf *ibuf)
Get the length of the data of the given image buffer in pixels.
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
@ IMB_FTYPE_IRIS
@ IB_float_data
@ IB_byte_data
@ IB_test
Read Guarded memory(de)allocation.
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
static bool output_iris(const char *filepath, const uint *lptr, const int *zptr, const int xsize, const int ysize, const int zsize)
#define ILUM(r, g, b)
#define OFFSET_R
#define DIRTY_FLAG_ENCODING
bool imb_saveiris(ImBuf *ibuf, const char *filepath, int)
static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n)
static int writeheader(FILE *outf, const IRIS_Header *image)
bool imb_is_a_iris(const uchar *mem, size_t size)
static void readheader(MFileOffset *inf, IRIS_Header *image)
#define BPP(type)
static int expandrow2(float *optr, const float *optr_end, const uchar *iptr, const uchar *iptr_end, int z)
static void putshort(FILE *outf, ushort val)
static uint getlong(MFileOffset *mofs)
#define EXPAND_CAPACITY_AT_OUTPUT_OK_OR_FAIL(optr_next)
#define HEADER_SIZE
static void lumrow(const uchar *rgbptr, uchar *lumptr, int n)
#define ISRLE(type)
static int expandrow(uchar *optr, const uchar *optr_end, const uchar *iptr, const uchar *iptr_end, int z)
#define IRIS_MAGIC
#define OFFSET_B
static void imbuf_rgba_to_abgr(ImBuf *ibuf)
#define CHANOFFSET(z)
#define OFFSET_G
static ushort getshort(MFileOffset *inf)
static int compressrow(const uchar *lbuf, uchar *rlebuf, int z, int row_len)
ImBuf * imb_loadiris(const uchar *mem, size_t size, int flags, ImFileColorSpace &)
#define MFILE_STEP(inf, step)
static void readtab(MFileOffset *inf, uint *tab, int len)
static void interleaverow2(float *lptr, const uchar *cptr, int z, int n)
#define GS(x)
static int writetab(FILE *outf, const uint *tab, int len)
#define MFILE_DATA(inf)
#define MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(p)
static int putlong(FILE *outf, uint val)
#define EXPAND_CAPACITY_AT_INPUT_OK_OR_FAIL(iptr_next)
#define MFILE_SEEK(inf, pos)
#define RLE(bpp)
uint pos
int count
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
char name[80]
ushort imagic
uchar _pad1[4]
uchar _pad2[404]
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
unsigned char planes
enum eImbFileType ftype
uint _file_offset
const uchar * _file_data
uint len