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