Blender V4.3
logImageCore.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 1999-2001 David Hodson <hodsond@acm.org>.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include "logImageCore.h"
12#include "cineonlib.h"
13#include "dpxlib.h"
14#include "logmemfile.h"
15
16#include <cmath>
17#include <cstdlib>
18#include <cstring>
19
20#include "BLI_fileops.h"
21#include "BLI_utildefines.h"
22
23#include "IMB_imbuf.hh"
24
25#include "MEM_guardedalloc.h"
26
27/*
28 * Declaration of static functions
29 */
30
31static int logImageSetData8(LogImageFile *logImage,
32 const LogImageElement &logElement,
33 const float *data);
34static int logImageSetData10(LogImageFile *logImage,
35 const LogImageElement &logElement,
36 const float *data);
37static int logImageSetData12(LogImageFile *logImage,
38 const LogImageElement &logElement,
39 const float *data);
40static int logImageSetData16(LogImageFile *logImage,
41 const LogImageElement &logElement,
42 const float *data);
43static int logImageElementGetData(LogImageFile *logImage,
44 const LogImageElement &logElement,
45 float *data);
46static int logImageElementGetData1(LogImageFile *logImage,
47 const LogImageElement &logElement,
48 float *data);
49static int logImageElementGetData8(LogImageFile *logImage,
50 const LogImageElement &logElement,
51 float *data);
52static int logImageElementGetData10(LogImageFile *logImage,
53 const LogImageElement &logElement,
54 float *data);
56 const LogImageElement &logElement,
57 float *data);
58static int logImageElementGetData12(LogImageFile *logImage,
59 const LogImageElement &logElement,
60 float *data);
62 const LogImageElement &logElement,
63 float *data);
64static int logImageElementGetData16(LogImageFile *logImage,
65 const LogImageElement &logElement,
66 float *data);
67static int convertLogElementToRGBA(const float *src,
68 float *dst,
69 const LogImageFile *logImage,
70 const LogImageElement &logElement,
71 int dstIsLinearRGB);
72static int convertRGBAToLogElement(const float *src,
73 float *dst,
74 const LogImageFile *logImage,
75 const LogImageElement &logElement,
76 int srcIsLinearRGB);
77
78/*
79 * For debug purpose
80 */
81
82static int verbose = 0;
83
84void logImageSetVerbose(int verbosity)
85{
86 verbose = verbosity;
87 cineonSetVerbose(verbosity);
88 dpxSetVerbose(verbosity);
89}
90
91/*
92 * IO stuff
93 */
94
95int logImageIsDpx(const void *buffer, const uint size)
96{
97 uint magicNum;
98 if (size < sizeof(magicNum)) {
99 return 0;
100 }
101 magicNum = *(uint *)buffer;
102 return (magicNum == DPX_FILE_MAGIC || magicNum == swap_uint(DPX_FILE_MAGIC, 1));
103}
104
105int logImageIsCineon(const void *buffer, const uint size)
106{
107 uint magicNum;
108 if (size < sizeof(magicNum)) {
109 return 0;
110 }
111 magicNum = *(uint *)buffer;
112 return (magicNum == CINEON_FILE_MAGIC || magicNum == swap_uint(CINEON_FILE_MAGIC, 1));
113}
114
115LogImageFile *logImageOpenFromFile(const char *filepath, int cineon)
116{
117 uint magicNum;
118 FILE *f = BLI_fopen(filepath, "rb");
119
120 (void)cineon;
121
122 if (f == nullptr) {
123 return nullptr;
124 }
125
126 if (fread(&magicNum, sizeof(magicNum), 1, f) != 1) {
127 fclose(f);
128 return nullptr;
129 }
130
131 fclose(f);
132
133 if (logImageIsDpx(&magicNum, sizeof(magicNum))) {
134 return dpxOpen((const uchar *)filepath, 0, 0);
135 }
136 if (logImageIsCineon(&magicNum, sizeof(magicNum))) {
137 return cineonOpen((const uchar *)filepath, 0, 0);
138 }
139
140 return nullptr;
141}
142
144{
145 if (logImageIsDpx(buffer, size)) {
146 return dpxOpen(buffer, 1, size);
147 }
148 if (logImageIsCineon(buffer, size)) {
149 return cineonOpen(buffer, 1, size);
150 }
151
152 return nullptr;
153}
154
155LogImageFile *logImageCreate(const char *filepath,
156 int cineon,
157 int width,
158 int height,
159 int bitsPerSample,
160 int isLogarithmic,
161 int hasAlpha,
162 int referenceWhite,
163 int referenceBlack,
164 float gamma,
165 const char *creator)
166{
167 /* referenceWhite, referenceBlack and gamma values are only supported for DPX file */
168 if (cineon) {
169 return cineonCreate(filepath, width, height, bitsPerSample, creator);
170 }
171
172 return dpxCreate(filepath,
173 width,
174 height,
175 bitsPerSample,
176 isLogarithmic,
177 hasAlpha,
178 referenceWhite,
179 referenceBlack,
180 gamma,
181 creator);
182}
183
185{
186 if (logImage != nullptr) {
187 if (logImage->file) {
188 fclose(logImage->file);
189 logImage->file = nullptr;
190 }
191 MEM_freeN(logImage);
192 }
193}
194
195void logImageGetSize(const LogImageFile *logImage, int *width, int *height, int *depth)
196{
197 *width = logImage->width;
198 *height = logImage->height;
199 *depth = logImage->depth;
200}
201
202/*
203 * Helper
204 */
205
206static size_t getRowLength(size_t width, const LogImageElement &logElement)
207{
208 /* return the row length in bytes according to width and packing method */
209 switch (logElement.bitsPerSample) {
210 case 1:
211 return ((width * logElement.depth - 1) / 32 + 1) * 4;
212
213 case 8:
214 return ((width * logElement.depth - 1) / 4 + 1) * 4;
215
216 case 10:
217 if (logElement.packing == 0) {
218 return ((width * logElement.depth * 10 - 1) / 32 + 1) * 4;
219 }
220 else if (ELEM(logElement.packing, 1, 2)) {
221 return ((width * logElement.depth - 1) / 3 + 1) * 4;
222 }
223 break;
224 case 12:
225 if (logElement.packing == 0) {
226 return ((width * logElement.depth * 12 - 1) / 32 + 1) * 4;
227 }
228 else if (ELEM(logElement.packing, 1, 2)) {
229 return width * logElement.depth * 2;
230 }
231 break;
232 case 16:
233 return width * logElement.depth * 2;
234 }
235 return 0;
236}
237
238size_t getRowLength(size_t width, const LogImageElement *logElement)
239{
240 /* For the C-API. */
241
242 return getRowLength(width, *logElement);
243}
244
245/*
246 * Data writing
247 */
248
249int logImageSetDataRGBA(LogImageFile *logImage, const float *data, int dataIsLinearRGB)
250{
251 float *elementData;
252 int returnValue;
253
254 elementData = (float *)imb_alloc_pixels(
255 logImage->width, logImage->height, logImage->depth, sizeof(float), true, __func__);
256 if (elementData == nullptr) {
257 return 1;
258 }
259
261 data, elementData, logImage, logImage->element[0], dataIsLinearRGB) != 0)
262 {
263 MEM_freeN(elementData);
264 return 1;
265 }
266
267 switch (logImage->element[0].bitsPerSample) {
268 case 8:
269 returnValue = logImageSetData8(logImage, logImage->element[0], elementData);
270 break;
271
272 case 10:
273 returnValue = logImageSetData10(logImage, logImage->element[0], elementData);
274 break;
275
276 case 12:
277 returnValue = logImageSetData12(logImage, logImage->element[0], elementData);
278 break;
279
280 case 16:
281 returnValue = logImageSetData16(logImage, logImage->element[0], elementData);
282 break;
283
284 default:
285 returnValue = 1;
286 break;
287 }
288
289 MEM_freeN(elementData);
290 return returnValue;
291}
292
293static int logImageSetData8(LogImageFile *logImage,
294 const LogImageElement &logElement,
295 const float *data)
296{
297 size_t rowLength = getRowLength(logImage->width, logElement);
298 uchar *row;
299
300 row = (uchar *)MEM_mallocN(rowLength, __func__);
301 if (row == nullptr) {
302 if (verbose) {
303 printf("DPX/Cineon: Cannot allocate row.\n");
304 }
305 return 1;
306 }
307 memset(row, 0, rowLength);
308
309 for (size_t y = 0; y < logImage->height; y++) {
310 for (size_t x = 0; x < logImage->width * logImage->depth; x++) {
311 row[x] = uchar(float_uint(data[y * logImage->width * logImage->depth + x], 255));
312 }
313
314 if (logimage_fwrite(row, rowLength, 1, logImage) == 0) {
315 if (verbose) {
316 printf("DPX/Cineon: Error while writing file.\n");
317 }
318 MEM_freeN(row);
319 return 1;
320 }
321 }
322 MEM_freeN(row);
323 return 0;
324}
325
326static int logImageSetData10(LogImageFile *logImage,
327 const LogImageElement &logElement,
328 const float *data)
329{
330 size_t rowLength = getRowLength(logImage->width, logElement);
331 uint pixel, index;
332 uint *row;
333
334 row = (uint *)MEM_mallocN(rowLength, __func__);
335 if (row == nullptr) {
336 if (verbose) {
337 printf("DPX/Cineon: Cannot allocate row.\n");
338 }
339 return 1;
340 }
341
342 for (size_t y = 0; y < logImage->height; y++) {
343 int offset = 22;
344 index = 0;
345 pixel = 0;
346
347 for (size_t x = 0; x < logImage->width * logImage->depth; x++) {
348 pixel |= uint(float_uint(data[y * logImage->width * logImage->depth + x], 1023)) << offset;
349 offset -= 10;
350 if (offset < 0) {
351 row[index] = swap_uint(pixel, logImage->isMSB);
352 index++;
353 pixel = 0;
354 offset = 22;
355 }
356 }
357 if (pixel != 0) {
358 row[index] = swap_uint(pixel, logImage->isMSB);
359 }
360
361 if (logimage_fwrite(row, rowLength, 1, logImage) == 0) {
362 if (verbose) {
363 printf("DPX/Cineon: Error while writing file.\n");
364 }
365 MEM_freeN(row);
366 return 1;
367 }
368 }
369 MEM_freeN(row);
370 return 0;
371}
372
373static int logImageSetData12(LogImageFile *logImage,
374 const LogImageElement &logElement,
375 const float *data)
376{
377 size_t rowLength = getRowLength(logImage->width, logElement);
378 ushort *row;
379
380 row = (ushort *)MEM_mallocN(rowLength, __func__);
381 if (row == nullptr) {
382 if (verbose) {
383 printf("DPX/Cineon: Cannot allocate row.\n");
384 }
385 return 1;
386 }
387
388 for (size_t y = 0; y < logImage->height; y++) {
389 for (size_t x = 0; x < logImage->width * logImage->depth; x++) {
390 row[x] = swap_ushort(
391 ushort(float_uint(data[y * logImage->width * logImage->depth + x], 4095)) << 4,
392 logImage->isMSB);
393 }
394
395 if (logimage_fwrite(row, rowLength, 1, logImage) == 0) {
396 if (verbose) {
397 printf("DPX/Cineon: Error while writing file.\n");
398 }
399 MEM_freeN(row);
400 return 1;
401 }
402 }
403 MEM_freeN(row);
404 return 0;
405}
406
407static int logImageSetData16(LogImageFile *logImage,
408 const LogImageElement &logElement,
409 const float *data)
410{
411 size_t rowLength = getRowLength(logImage->width, logElement);
412 ushort *row;
413
414 row = (ushort *)MEM_mallocN(rowLength, __func__);
415 if (row == nullptr) {
416 if (verbose) {
417 printf("DPX/Cineon: Cannot allocate row.\n");
418 }
419 return 1;
420 }
421
422 for (size_t y = 0; y < logImage->height; y++) {
423 for (size_t x = 0; x < logImage->width * logImage->depth; x++) {
424 row[x] = swap_ushort(
425 ushort(float_uint(data[y * logImage->width * logImage->depth + x], 65535)),
426 logImage->isMSB);
427 }
428
429 if (logimage_fwrite(row, rowLength, 1, logImage) == 0) {
430 if (verbose) {
431 printf("DPX/Cineon: Error while writing file.\n");
432 }
433 MEM_freeN(row);
434 return 1;
435 }
436 }
437 MEM_freeN(row);
438 return 0;
439}
440
441/*
442 * Data reading
443 */
444
445int logImageGetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB)
446{
447 /* Fills data with 32 bits float RGBA values */
448 int i, j, returnValue, sortedElementData[8], hasAlpha;
449 float *elementData[8];
450 float *elementData_ptr[8];
451 float *mergedData;
452 uint sampleIndex;
453 LogImageElement mergedElement;
454
455 /* Determine the depth of the picture and if there's a separate alpha element.
456 * If the element is supported, load it into an `uint` array. */
457 memset(&elementData, 0, 8 * sizeof(float *));
458 hasAlpha = 0;
459
460 for (i = 0; i < logImage->numElements; i++) {
461 /* descriptor_Depth and descriptor_Composite are not supported */
463 /* Allocate memory */
464 elementData[i] = static_cast<float *>(imb_alloc_pixels(logImage->width,
465 logImage->height,
466 logImage->element[i].depth,
467 sizeof(float),
468 true,
469 __func__));
470 if (elementData[i] == nullptr) {
471 if (verbose) {
472 printf("DPX/Cineon: Cannot allocate memory for elementData[%d]\n.", i);
473 }
474 for (j = 0; j < i; j++) {
475 if (elementData[j] != nullptr) {
476 MEM_freeN(elementData[j]);
477 }
478 }
479 return 1;
480 }
481 elementData_ptr[i] = elementData[i];
482
483 /* Load data */
484 if (logImageElementGetData(logImage, logImage->element[i], elementData[i]) != 0) {
485 if (verbose) {
486 printf("DPX/Cineon: Cannot read elementData[%d]\n.", i);
487 }
488 for (j = 0; j < i; j++) {
489 if (elementData[j] != nullptr) {
490 MEM_freeN(elementData[j]);
491 }
492 }
493 return 1;
494 }
495 }
496
497 if (logImage->element[i].descriptor == descriptor_Alpha) {
498 hasAlpha = 1;
499 }
500 }
501
502 /* Only one element, easy case, no need to do anything. */
503 if (logImage->numElements == 1) {
504 returnValue = convertLogElementToRGBA(
505 elementData[0], data, logImage, logImage->element[0], dataIsLinearRGB);
506 MEM_freeN(elementData[0]);
507 }
508 else {
509 /* The goal here is to merge every elements into only one
510 * to recreate a classic 16 bits RGB, RGBA or YCbCr element.
511 * Unsupported elements are skipped (depth, composite) */
512
513 memcpy(&mergedElement, &logImage->element[0], sizeof(LogImageElement));
514 mergedElement.descriptor = -1;
515 mergedElement.depth = logImage->depth;
516 memset(&sortedElementData, -1, sizeof(int[8]));
517
518 /* Try to know how to assemble the elements */
519 for (i = 0; i < logImage->numElements; i++) {
520 switch (logImage->element[i].descriptor) {
521 case descriptor_Red:
522 case descriptor_RGB:
523 if (hasAlpha == 0) {
524 mergedElement.descriptor = descriptor_RGB;
525 }
526 else {
527 mergedElement.descriptor = descriptor_RGBA;
528 }
529
530 sortedElementData[0] = i;
531 break;
532
533 case descriptor_Green:
534 if (hasAlpha == 0) {
535 mergedElement.descriptor = descriptor_RGB;
536 }
537 else {
538 mergedElement.descriptor = descriptor_RGBA;
539 }
540
541 sortedElementData[1] = i;
542 break;
543
544 case descriptor_Blue:
545 if (hasAlpha == 0) {
546 mergedElement.descriptor = descriptor_RGB;
547 }
548 else {
549 mergedElement.descriptor = descriptor_RGBA;
550 }
551
552 sortedElementData[2] = i;
553 break;
554
555 case descriptor_Alpha:
556 /* Alpha component is always the last one */
557 sortedElementData[mergedElement.depth - 1] = i;
558 break;
559
561 if (mergedElement.descriptor == -1) {
562 if (hasAlpha == 0) {
563 mergedElement.descriptor = descriptor_Luminance;
564 }
565 else {
566 mergedElement.descriptor = descriptor_YA;
567 }
568 }
569 else if (mergedElement.descriptor == descriptor_Chrominance) {
570 if (mergedElement.depth == 2) {
571 mergedElement.descriptor = descriptor_CbYCrY;
572 }
573 else if (mergedElement.depth == 3) {
574 if (hasAlpha == 0) {
575 mergedElement.descriptor = descriptor_CbYCr;
576 }
577 else {
578 mergedElement.descriptor = descriptor_CbYACrYA;
579 }
580 }
581 else if (mergedElement.depth == 4) {
582 mergedElement.descriptor = descriptor_CbYCrA;
583 }
584 }
585
586 /* Y component always in 1 except if it's alone or with alpha */
587 if (mergedElement.depth == 1 || (mergedElement.depth == 2 && hasAlpha == 1)) {
588 sortedElementData[0] = i;
589 }
590 else {
591 sortedElementData[1] = i;
592 }
593 break;
594
596 if (mergedElement.descriptor == -1) {
597 mergedElement.descriptor = descriptor_Chrominance;
598 }
599 else if (mergedElement.descriptor == descriptor_Luminance) {
600 if (mergedElement.depth == 2) {
601 mergedElement.descriptor = descriptor_CbYCrY;
602 }
603 else if (mergedElement.depth == 3) {
604 if (hasAlpha == 0) {
605 mergedElement.descriptor = descriptor_CbYCr;
606 }
607 else {
608 mergedElement.descriptor = descriptor_CbYACrYA;
609 }
610 }
611 else if (mergedElement.depth == 4) {
612 mergedElement.descriptor = descriptor_CbYCrA;
613 }
614 }
615
616 /* Cb and Cr always in 0 or 2 */
617 if (sortedElementData[0] == -1) {
618 sortedElementData[0] = i;
619 }
620 else {
621 sortedElementData[2] = i;
622 }
623 break;
624
625 case descriptor_CbYCr:
626 if (hasAlpha == 0) {
627 mergedElement.descriptor = descriptor_CbYCr;
628 }
629 else {
630 mergedElement.descriptor = descriptor_CbYCrA;
631 }
632
633 sortedElementData[0] = i;
634 break;
635
636 case descriptor_RGBA:
637 case descriptor_ABGR:
641 /* I don't think these ones can be seen in a planar image */
642 mergedElement.descriptor = logImage->element[i].descriptor;
643 sortedElementData[0] = i;
644 break;
645
646 case descriptor_Depth:
648 /* Not supported */
649 break;
650 }
651 }
652
653 mergedData = (float *)imb_alloc_pixels(
654 logImage->width, logImage->height, mergedElement.depth, sizeof(float), true, __func__);
655 if (mergedData == nullptr) {
656 if (verbose) {
657 printf("DPX/Cineon: Cannot allocate mergedData.\n");
658 }
659 for (i = 0; i < logImage->numElements; i++) {
660 if (elementData[i] != nullptr) {
661 MEM_freeN(elementData[i]);
662 }
663 }
664 return 1;
665 }
666
667 sampleIndex = 0;
668 while (sampleIndex < logImage->width * logImage->height * mergedElement.depth) {
669 for (i = 0; i < logImage->numElements; i++) {
670 for (j = 0; j < logImage->element[sortedElementData[i]].depth; j++) {
671 mergedData[sampleIndex++] = *(elementData_ptr[sortedElementData[i]]++);
672 }
673 }
674 }
675
676 /* Done with elements data, clean-up */
677 for (i = 0; i < logImage->numElements; i++) {
678 if (elementData[i] != nullptr) {
679 MEM_freeN(elementData[i]);
680 }
681 }
682
683 returnValue = convertLogElementToRGBA(
684 mergedData, data, logImage, mergedElement, dataIsLinearRGB);
685 MEM_freeN(mergedData);
686 }
687 return returnValue;
688}
689
691 const LogImageElement &logElement,
692 float *data)
693{
694 switch (logElement.bitsPerSample) {
695 case 1:
696 return logImageElementGetData1(logImage, logElement, data);
697
698 case 8:
699 return logImageElementGetData8(logImage, logElement, data);
700
701 case 10:
702 if (logElement.packing == 0) {
703 return logImageElementGetData10Packed(logImage, logElement, data);
704 }
705 else if (ELEM(logElement.packing, 1, 2)) {
706 return logImageElementGetData10(logImage, logElement, data);
707 }
708 break;
709
710 case 12:
711 if (logElement.packing == 0) {
712 return logImageElementGetData12Packed(logImage, logElement, data);
713 }
714 else if (ELEM(logElement.packing, 1, 2)) {
715 return logImageElementGetData12(logImage, logElement, data);
716 }
717 break;
718
719 case 16:
720 return logImageElementGetData16(logImage, logElement, data);
721 }
722 /* format not supported */
723 return 1;
724}
725
727 const LogImageElement &logElement,
728 float *data)
729{
730 uint pixel;
731
732 /* seek at the right place */
733 if (logimage_fseek(logImage, logElement.dataOffset, SEEK_SET) != 0) {
734 if (verbose) {
735 printf("DPX/Cineon: Couldn't seek at %d\n", logElement.dataOffset);
736 }
737 return 1;
738 }
739
740 /* read 1 bit data padded to 32 bits */
741 for (size_t y = 0; y < logImage->height; y++) {
742 for (size_t x = 0; x < logImage->width * logElement.depth; x += 32) {
743 if (logimage_read_uint(&pixel, logImage) != 0) {
744 if (verbose) {
745 printf("DPX/Cineon: EOF reached\n");
746 }
747 return 1;
748 }
749 pixel = swap_uint(pixel, logImage->isMSB);
750 for (int offset = 0; offset < 32 && x + offset < logImage->width; offset++) {
751 data[y * logImage->width * logElement.depth + x + offset] = float((pixel >> offset) &
752 0x01);
753 }
754 }
755 }
756 return 0;
757}
758
760 const LogImageElement &logElement,
761 float *data)
762{
763 size_t rowLength = getRowLength(logImage->width, logElement);
764 uchar pixel;
765
766 /* extract required pixels */
767 for (size_t y = 0; y < logImage->height; y++) {
768 /* 8 bits are 32-bits padded so we need to seek at each row */
769 if (logimage_fseek(logImage, logElement.dataOffset + y * rowLength, SEEK_SET) != 0) {
770 if (verbose) {
771 printf("DPX/Cineon: Couldn't seek at %d\n", int(logElement.dataOffset + y * rowLength));
772 }
773 return 1;
774 }
775
776 for (size_t x = 0; x < logImage->width * logElement.depth; x++) {
777 if (logimage_read_uchar(&pixel, logImage) != 0) {
778 if (verbose) {
779 printf("DPX/Cineon: EOF reached\n");
780 }
781 return 1;
782 }
783 data[y * logImage->width * logElement.depth + x] = float(pixel) / 255.0f;
784 }
785 }
786 return 0;
787}
788
790 const LogImageElement &logElement,
791 float *data)
792{
793 uint pixel;
794
795 /* seek to data */
796 if (logimage_fseek(logImage, logElement.dataOffset, SEEK_SET) != 0) {
797 if (verbose) {
798 printf("DPX/Cineon: Couldn't seek at %d\n", logElement.dataOffset);
799 }
800 return 1;
801 }
802
803 if (logImage->depth == 1 && logImage->srcFormat == format_DPX) {
804 for (size_t y = 0; y < logImage->height; y++) {
805 int offset = 32;
806 for (size_t x = 0; x < logImage->width * logElement.depth; x++) {
807 /* we need to read the next long */
808 if (offset >= 30) {
809 if (logElement.packing == 1) {
810 offset = 2;
811 }
812 else if (logElement.packing == 2) {
813 offset = 0;
814 }
815
816 if (logimage_read_uint(&pixel, logImage) != 0) {
817 if (verbose) {
818 printf("DPX/Cineon: EOF reached\n");
819 }
820 return 1;
821 }
822 pixel = swap_uint(pixel, logImage->isMSB);
823 }
824 data[y * logImage->width * logElement.depth + x] = float((pixel >> offset) & 0x3ff) /
825 1023.0f;
826 offset += 10;
827 }
828 }
829 }
830 else {
831 for (size_t y = 0; y < logImage->height; y++) {
832 int offset = -1;
833 for (size_t x = 0; x < logImage->width * logElement.depth; x++) {
834 /* we need to read the next long */
835 if (offset < 0) {
836 if (logElement.packing == 1) {
837 offset = 22;
838 }
839 else if (logElement.packing == 2) {
840 offset = 20;
841 }
842
843 if (logimage_read_uint(&pixel, logImage) != 0) {
844 if (verbose) {
845 printf("DPX/Cineon: EOF reached\n");
846 }
847 return 1;
848 }
849 pixel = swap_uint(pixel, logImage->isMSB);
850 }
851 data[y * logImage->width * logElement.depth + x] = float((pixel >> offset) & 0x3ff) /
852 1023.0f;
853 offset -= 10;
854 }
855 }
856 }
857
858 return 0;
859}
860
862 const LogImageElement &logElement,
863 float *data)
864{
865 size_t rowLength = getRowLength(logImage->width, logElement);
866 uint pixel, oldPixel;
867
868 /* converting bytes to pixels */
869 for (size_t y = 0; y < logImage->height; y++) {
870 /* seek to data */
871 if (logimage_fseek(logImage, y * rowLength + logElement.dataOffset, SEEK_SET) != 0) {
872 if (verbose) {
873 printf("DPX/Cineon: Couldn't seek at %u\n", uint(y * rowLength + logElement.dataOffset));
874 }
875 return 1;
876 }
877
878 oldPixel = 0;
879 int offset = 0;
880 int offset2 = 0;
881
882 for (size_t x = 0; x < logImage->width * logElement.depth; x++) {
883 if (offset2 != 0) {
884 offset = 10 - offset2;
885 offset2 = 0;
886 oldPixel = 0;
887 }
888 else if (offset == 32) {
889 offset = 0;
890 }
891 else if (offset + 10 > 32) {
892 /* next pixel is on two different longs */
893 oldPixel = (pixel >> offset);
894 offset2 = 32 - offset;
895 offset = 0;
896 }
897
898 if (offset == 0) {
899 /* we need to read the next long */
900 if (logimage_read_uint(&pixel, logImage) != 0) {
901 if (verbose) {
902 printf("DPX/Cineon: EOF reached\n");
903 }
904 return 1;
905 }
906 pixel = swap_uint(pixel, logImage->isMSB);
907 }
908 data[y * logImage->width * logElement.depth + x] =
909 float((((pixel << offset2) >> offset) & 0x3ff) | oldPixel) / 1023.0f;
910 offset += 10;
911 }
912 }
913 return 0;
914}
915
917 const LogImageElement &logElement,
918 float *data)
919{
920 uint sampleIndex;
921 uint numSamples = logImage->width * logImage->height * logElement.depth;
922 ushort pixel;
923
924 /* seek to data */
925 if (logimage_fseek(logImage, logElement.dataOffset, SEEK_SET) != 0) {
926 if (verbose) {
927 printf("DPX/Cineon: Couldn't seek at %d\n", logElement.dataOffset);
928 }
929 return 1;
930 }
931
932 /* convert bytes to pixels */
933 sampleIndex = 0;
934
935 for (sampleIndex = 0; sampleIndex < numSamples; sampleIndex++) {
936 if (logimage_read_ushort(&pixel, logImage) != 0) {
937 if (verbose) {
938 printf("DPX/Cineon: EOF reached\n");
939 }
940 return 1;
941 }
942 pixel = swap_ushort(pixel, logImage->isMSB);
943
944 if (logElement.packing == 1) { /* padded to the right */
945 data[sampleIndex] = float(pixel >> 4) / 4095.0f;
946 }
947 else if (logElement.packing == 2) { /* padded to the left */
948 data[sampleIndex] = float(pixel) / 4095.0f;
949 }
950 }
951 return 0;
952}
953
955 const LogImageElement &logElement,
956 float *data)
957{
958 size_t rowLength = getRowLength(logImage->width, logElement);
959 uint pixel, oldPixel;
960
961 /* converting bytes to pixels */
962 for (size_t y = 0; y < logImage->height; y++) {
963 /* seek to data */
964 if (logimage_fseek(logImage, y * rowLength + logElement.dataOffset, SEEK_SET) != 0) {
965 if (verbose) {
966 printf("DPX/Cineon: Couldn't seek at %u\n", uint(y * rowLength + logElement.dataOffset));
967 }
968 return 1;
969 }
970
971 oldPixel = 0;
972 int offset = 0;
973 int offset2 = 0;
974
975 for (size_t x = 0; x < logImage->width * logElement.depth; x++) {
976 if (offset2 != 0) {
977 offset = 12 - offset2;
978 offset2 = 0;
979 oldPixel = 0;
980 }
981 else if (offset == 32) {
982 offset = 0;
983 }
984 else if (offset + 12 > 32) {
985 /* next pixel is on two different longs */
986 oldPixel = (pixel >> offset);
987 offset2 = 32 - offset;
988 offset = 0;
989 }
990
991 if (offset == 0) {
992 /* we need to read the next long */
993 if (logimage_read_uint(&pixel, logImage) != 0) {
994 if (verbose) {
995 printf("DPX/Cineon: EOF reached\n");
996 }
997 return 1;
998 }
999 pixel = swap_uint(pixel, logImage->isMSB);
1000 }
1001 data[y * logImage->width * logElement.depth + x] =
1002 float((((pixel << offset2) >> offset) & 0xfff) | oldPixel) / 4095.0f;
1003 offset += 12;
1004 }
1005 }
1006 return 0;
1007}
1008
1010 const LogImageElement &logElement,
1011 float *data)
1012{
1013 uint numSamples = logImage->width * logImage->height * logElement.depth;
1014 uint sampleIndex;
1015 ushort pixel;
1016
1017 /* seek to data */
1018 if (logimage_fseek(logImage, logElement.dataOffset, SEEK_SET) != 0) {
1019 if (verbose) {
1020 printf("DPX/Cineon: Couldn't seek at %d\n", logElement.dataOffset);
1021 }
1022 return 1;
1023 }
1024
1025 for (sampleIndex = 0; sampleIndex < numSamples; sampleIndex++) {
1026 if (logimage_read_ushort(&pixel, logImage) != 0) {
1027 if (verbose) {
1028 printf("DPX/Cineon: EOF reached\n");
1029 }
1030 return 1;
1031 }
1032 pixel = swap_ushort(pixel, logImage->isMSB);
1033 data[sampleIndex] = float(pixel) / 65535.0f;
1034 }
1035
1036 return 0;
1037}
1038
1039/*
1040 * Color conversion
1041 */
1042
1043static int getYUVtoRGBMatrix(float *matrix, const LogImageElement &logElement)
1044{
1045 float scaleY, scaleCbCr;
1046 float refHighData = float(logElement.refHighData) / logElement.maxValue;
1047 float refLowData = float(logElement.refLowData) / logElement.maxValue;
1048
1049 scaleY = 1.0f / (refHighData - refLowData);
1050 scaleCbCr = scaleY * ((940.0f - 64.0f) / (960.0f - 64.0f));
1051
1052 switch (logElement.transfer) {
1053 case 2: /* linear */
1054 matrix[0] = 1.0f * scaleY;
1055 matrix[1] = 1.0f * scaleCbCr;
1056 matrix[2] = 1.0f * scaleCbCr;
1057 matrix[3] = 1.0f * scaleY;
1058 matrix[4] = 1.0f * scaleCbCr;
1059 matrix[5] = 1.0f * scaleCbCr;
1060 matrix[6] = 1.0f * scaleY;
1061 matrix[7] = 1.0f * scaleCbCr;
1062 matrix[8] = 1.0f * scaleCbCr;
1063 return 0;
1064
1065 case 5: /* SMPTE 240M */
1066 matrix[0] = 1.0000f * scaleY;
1067 matrix[1] = 0.0000f * scaleCbCr;
1068 matrix[2] = 1.5756f * scaleCbCr;
1069 matrix[3] = 1.0000f * scaleY;
1070 matrix[4] = -0.2253f * scaleCbCr;
1071 matrix[5] = -0.5000f * scaleCbCr;
1072 matrix[6] = 1.0000f * scaleY;
1073 matrix[7] = 1.8270f * scaleCbCr;
1074 matrix[8] = 0.0000f * scaleCbCr;
1075 return 0;
1076
1077 case 6: /* CCIR 709-1 */
1078 matrix[0] = 1.000000f * scaleY;
1079 matrix[1] = 0.000000f * scaleCbCr;
1080 matrix[2] = 1.574800f * scaleCbCr;
1081 matrix[3] = 1.000000f * scaleY;
1082 matrix[4] = -0.187324f * scaleCbCr;
1083 matrix[5] = -0.468124f * scaleCbCr;
1084 matrix[6] = 1.000000f * scaleY;
1085 matrix[7] = 1.855600f * scaleCbCr;
1086 matrix[8] = 0.000000f * scaleCbCr;
1087 return 0;
1088
1089 case 7: /* CCIR 601 */
1090 case 8: /* I'm not sure 7 and 8 should share the same matrix */
1091 matrix[0] = 1.000000f * scaleY;
1092 matrix[1] = 0.000000f * scaleCbCr;
1093 matrix[2] = 1.402000f * scaleCbCr;
1094 matrix[3] = 1.000000f * scaleY;
1095 matrix[4] = -0.344136f * scaleCbCr;
1096 matrix[5] = -0.714136f * scaleCbCr;
1097 matrix[6] = 1.000000f * scaleY;
1098 matrix[7] = 1.772000f * scaleCbCr;
1099 matrix[8] = 0.000000f * scaleCbCr;
1100 return 0;
1101
1102 default:
1103 return 1;
1104 }
1105}
1106
1107static float *getLinToLogLut(const LogImageFile *logImage, const LogImageElement &logElement)
1108{
1109 float *lut;
1110 float gain, negativeFilmGamma, offset, step;
1111 uint lutsize = uint(logElement.maxValue + 1);
1112 uint i;
1113
1114 lut = static_cast<float *>(MEM_mallocN(sizeof(float) * lutsize, "getLinToLogLut"));
1115
1116 negativeFilmGamma = 0.6;
1117 step = logElement.refHighQuantity / logElement.maxValue;
1118 gain = logElement.maxValue /
1119 (1.0f - powf(10,
1120 (logImage->referenceBlack - logImage->referenceWhite) * step /
1121 negativeFilmGamma * logImage->gamma / 1.7f));
1122 offset = gain - logElement.maxValue;
1123
1124 for (i = 0; i < lutsize; i++) {
1125 lut[i] = (logImage->referenceWhite +
1126 log10f(powf((i + offset) / gain, 1.7f / logImage->gamma)) /
1127 (step / negativeFilmGamma)) /
1128 logElement.maxValue;
1129 }
1130
1131 return lut;
1132}
1133
1134static float *getLogToLinLut(const LogImageFile *logImage, const LogImageElement &logElement)
1135{
1136 float *lut;
1137 float breakPoint, gain, kneeGain, kneeOffset, negativeFilmGamma, offset, step, softClip;
1138 /* float filmGamma; unused */
1139 uint lutsize = uint(logElement.maxValue + 1);
1140 uint i;
1141
1142 lut = static_cast<float *>(MEM_mallocN(sizeof(float) * lutsize, "getLogToLinLut"));
1143
1144 /* Building the Log -> Lin LUT */
1145 step = logElement.refHighQuantity / logElement.maxValue;
1146 negativeFilmGamma = 0.6;
1147
1148 /* these are default values */
1149 /* filmGamma = 2.2f; unused */
1150 softClip = 0;
1151
1152 breakPoint = logImage->referenceWhite - softClip;
1153 gain = logElement.maxValue /
1154 (1.0f - powf(10,
1155 (logImage->referenceBlack - logImage->referenceWhite) * step /
1156 negativeFilmGamma * logImage->gamma / 1.7f));
1157 offset = gain - logElement.maxValue;
1158 kneeOffset = powf(10,
1159 (breakPoint - logImage->referenceWhite) * step / negativeFilmGamma *
1160 logImage->gamma / 1.7f) *
1161 gain -
1162 offset;
1163 kneeGain = (logElement.maxValue - kneeOffset) / powf(5 * softClip, softClip / 100);
1164
1165 for (i = 0; i < lutsize; i++) {
1166 if (i < logImage->referenceBlack) {
1167 lut[i] = 0.0f;
1168 }
1169 else if (i > breakPoint) {
1170 lut[i] = (powf(i - breakPoint, softClip / 100) * kneeGain + kneeOffset) /
1171 logElement.maxValue;
1172 }
1173 else {
1174 lut[i] = (powf(10,
1175 (float(i) - logImage->referenceWhite) * step / negativeFilmGamma *
1176 logImage->gamma / 1.7f) *
1177 gain -
1178 offset) /
1179 logElement.maxValue;
1180 }
1181 }
1182
1183 return lut;
1184}
1185
1186static float *getLinToSrgbLut(const LogImageElement &logElement)
1187{
1188 float col, *lut;
1189 uint lutsize = uint(logElement.maxValue + 1);
1190 uint i;
1191
1192 lut = static_cast<float *>(MEM_mallocN(sizeof(float) * lutsize, "getLogToLinLut"));
1193
1194 for (i = 0; i < lutsize; i++) {
1195 col = float(i) / logElement.maxValue;
1196 if (col < 0.0031308f) {
1197 lut[i] = (col < 0.0f) ? 0.0f : col * 12.92f;
1198 }
1199 else {
1200 lut[i] = 1.055f * powf(col, 1.0f / 2.4f) - 0.055f;
1201 }
1202 }
1203
1204 return lut;
1205}
1206
1207static float *getSrgbToLinLut(const LogImageElement &logElement)
1208{
1209 float col, *lut;
1210 uint lutsize = uint(logElement.maxValue + 1);
1211 uint i;
1212
1213 lut = static_cast<float *>(MEM_mallocN(sizeof(float) * lutsize, "getLogToLinLut"));
1214
1215 for (i = 0; i < lutsize; i++) {
1216 col = float(i) / logElement.maxValue;
1217 if (col < 0.04045f) {
1218 lut[i] = (col < 0.0f) ? 0.0f : col * (1.0f / 12.92f);
1219 }
1220 else {
1221 lut[i] = powf((col + 0.055f) * (1.0f / 1.055f), 2.4f);
1222 }
1223 }
1224
1225 return lut;
1226}
1227
1228static int convertRGBA_RGB(const float *src,
1229 float *dst,
1230 const LogImageFile *logImage,
1231 const LogImageElement &logElement,
1232 int elementIsSource)
1233{
1234 uint i;
1235 const float *src_ptr = src;
1236 float *dst_ptr = dst;
1237
1238 switch (logElement.transfer) {
1241 case transfer_Linear:
1242 case transfer_Logarithmic: {
1243 for (i = 0; i < logImage->width * logImage->height; i++) {
1244 *(dst_ptr++) = *(src_ptr++);
1245 *(dst_ptr++) = *(src_ptr++);
1246 *(dst_ptr++) = *(src_ptr++);
1247 src_ptr++;
1248 }
1249
1250 return 0;
1251 }
1252
1254 float *lut;
1255
1256 if (elementIsSource == 1) {
1257 lut = getLogToLinLut(logImage, logElement);
1258 }
1259 else {
1260 lut = getLinToLogLut(logImage, logElement);
1261 }
1262
1263 for (i = 0; i < logImage->width * logImage->height; i++) {
1264 *(dst_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1265 *(dst_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1266 *(dst_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1267 src_ptr++;
1268 }
1269
1270 MEM_freeN(lut);
1271
1272 return 0;
1273 }
1274
1275 default:
1276 if (verbose) {
1277 printf("DPX/Cineon: Unknown transfer %d.\n", logElement.transfer);
1278 }
1279 return 1;
1280 }
1281}
1282
1283static int convertRGB_RGBA(const float *src,
1284 float *dst,
1285 const LogImageFile *logImage,
1286 const LogImageElement &logElement,
1287 int elementIsSource)
1288{
1289 uint i;
1290 const float *src_ptr = src;
1291 float *dst_ptr = dst;
1292
1293 switch (logElement.transfer) {
1296 case transfer_Linear:
1297 case transfer_Logarithmic: {
1298 for (i = 0; i < logImage->width * logImage->height; i++) {
1299 *(dst_ptr++) = *(src_ptr++);
1300 *(dst_ptr++) = *(src_ptr++);
1301 *(dst_ptr++) = *(src_ptr++);
1302 *(dst_ptr++) = 1.0f;
1303 }
1304
1305 return 0;
1306 }
1307
1309 float *lut;
1310
1311 if (elementIsSource == 1) {
1312 lut = getLogToLinLut(logImage, logElement);
1313 }
1314 else {
1315 lut = getLinToLogLut(logImage, logElement);
1316 }
1317
1318 for (i = 0; i < logImage->width * logImage->height; i++) {
1319 *(dst_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1320 *(dst_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1321 *(dst_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1322 *(dst_ptr++) = 1.0f;
1323 }
1324
1325 MEM_freeN(lut);
1326
1327 return 0;
1328 }
1329
1330 default:
1331 if (verbose) {
1332 printf("DPX/Cineon: Unknown transfer %d.\n", logElement.transfer);
1333 }
1334 return 1;
1335 }
1336}
1337
1338static int convertRGBA_RGBA(const float *src,
1339 float *dst,
1340 const LogImageFile *logImage,
1341 const LogImageElement &logElement,
1342 int elementIsSource)
1343{
1344 uint i;
1345 const float *src_ptr = src;
1346 float *dst_ptr = dst;
1347
1348 switch (logElement.transfer) {
1350 case transfer_Linear:
1351 case transfer_Logarithmic: {
1352 memcpy(dst, src, 4 * size_t(logImage->width) * size_t(logImage->height) * sizeof(float));
1353 return 0;
1354 }
1355
1357 float *lut;
1358
1359 if (elementIsSource == 1) {
1360 lut = getLogToLinLut(logImage, logElement);
1361 }
1362 else {
1363 lut = getLinToLogLut(logImage, logElement);
1364 }
1365
1366 for (i = 0; i < logImage->width * logImage->height; i++) {
1367 *(dst_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1368 *(dst_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1369 *(dst_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1370 *(dst_ptr++) = *(src_ptr++);
1371 }
1372
1373 MEM_freeN(lut);
1374
1375 return 0;
1376 }
1377
1378 default:
1379 return 1;
1380 }
1381}
1382
1383static int convertABGR_RGBA(const float *src,
1384 float *dst,
1385 const LogImageFile *logImage,
1386 const LogImageElement &logElement,
1387 int elementIsSource)
1388{
1389 uint i;
1390 const float *src_ptr = src;
1391 float *dst_ptr = dst;
1392
1393 switch (logElement.transfer) {
1395 case transfer_Linear:
1396 case transfer_Logarithmic: {
1397 for (i = 0; i < logImage->width * logImage->height; i++) {
1398 src_ptr += 4;
1399 *(dst_ptr++) = *(src_ptr--);
1400 *(dst_ptr++) = *(src_ptr--);
1401 *(dst_ptr++) = *(src_ptr--);
1402 *(dst_ptr++) = *(src_ptr--);
1403 src_ptr += 4;
1404 }
1405 return 0;
1406 }
1407
1409 float *lut;
1410
1411 if (elementIsSource == 1) {
1412 lut = getLogToLinLut(logImage, logElement);
1413 }
1414 else {
1415 lut = getLinToLogLut(logImage, logElement);
1416 }
1417
1418 for (i = 0; i < logImage->width * logImage->height; i++) {
1419 src_ptr += 4;
1420 *(dst_ptr++) = lut[float_uint(*(src_ptr--), logElement.maxValue)];
1421 *(dst_ptr++) = lut[float_uint(*(src_ptr--), logElement.maxValue)];
1422 *(dst_ptr++) = lut[float_uint(*(src_ptr--), logElement.maxValue)];
1423 *(dst_ptr++) = *(src_ptr--);
1424 src_ptr += 4;
1425 }
1426
1427 MEM_freeN(lut);
1428
1429 return 0;
1430 }
1431
1432 default:
1433 return 1;
1434 }
1435}
1436
1437static int convertCbYCr_RGBA(const float *src,
1438 float *dst,
1439 const LogImageFile *logImage,
1440 const LogImageElement &logElement)
1441{
1442 uint i;
1443 float conversionMatrix[9], refLowData, y, cb, cr;
1444 const float *src_ptr = src;
1445 float *dst_ptr = dst;
1446
1447 if (getYUVtoRGBMatrix((float *)&conversionMatrix, logElement) != 0) {
1448 return 1;
1449 }
1450
1451 refLowData = float(logElement.refLowData) / logElement.maxValue;
1452
1453 for (i = 0; i < logImage->width * logImage->height; i++) {
1454 cb = *(src_ptr++) - 0.5f;
1455 y = *(src_ptr++) - refLowData;
1456 cr = *(src_ptr++) - 0.5f;
1457
1458 *(dst_ptr++) = clamp_float(
1459 y * conversionMatrix[0] + cb * conversionMatrix[1] + cr * conversionMatrix[2], 0.0f, 1.0f);
1460 *(dst_ptr++) = clamp_float(
1461 y * conversionMatrix[3] + cb * conversionMatrix[4] + cr * conversionMatrix[5], 0.0f, 1.0f);
1462 *(dst_ptr++) = clamp_float(
1463 y * conversionMatrix[6] + cb * conversionMatrix[7] + cr * conversionMatrix[8], 0.0f, 1.0f);
1464 *(dst_ptr++) = 1.0f;
1465 }
1466 return 0;
1467}
1468
1469static int convertCbYCrA_RGBA(const float *src,
1470 float *dst,
1471 const LogImageFile *logImage,
1472 const LogImageElement &logElement)
1473{
1474 uint i;
1475 float conversionMatrix[9], refLowData, y, cb, cr, a;
1476 const float *src_ptr = src;
1477 float *dst_ptr = dst;
1478
1479 if (getYUVtoRGBMatrix((float *)&conversionMatrix, logElement) != 0) {
1480 return 1;
1481 }
1482
1483 refLowData = float(logElement.refLowData) / logElement.maxValue;
1484
1485 for (i = 0; i < logImage->width * logImage->height; i++) {
1486 cb = *(src_ptr++) - 0.5f;
1487 y = *(src_ptr++) - refLowData;
1488 cr = *(src_ptr++) - 0.5f;
1489 a = *(src_ptr++);
1490
1491 *(dst_ptr++) = clamp_float(
1492 y * conversionMatrix[0] + cb * conversionMatrix[1] + cr * conversionMatrix[2], 0.0f, 1.0f);
1493 *(dst_ptr++) = clamp_float(
1494 y * conversionMatrix[3] + cb * conversionMatrix[4] + cr * conversionMatrix[5], 0.0f, 1.0f);
1495 *(dst_ptr++) = clamp_float(
1496 y * conversionMatrix[6] + cb * conversionMatrix[7] + cr * conversionMatrix[8], 0.0f, 1.0f);
1497 *(dst_ptr++) = a;
1498 }
1499 return 0;
1500}
1501
1502static int convertCbYCrY_RGBA(const float *src,
1503 float *dst,
1504 const LogImageFile *logImage,
1505 const LogImageElement &logElement)
1506{
1507 uint i;
1508 float conversionMatrix[9], refLowData, y1, y2, cb, cr;
1509 const float *src_ptr = src;
1510 float *dst_ptr = dst;
1511
1512 if (getYUVtoRGBMatrix((float *)&conversionMatrix, logElement) != 0) {
1513 return 1;
1514 }
1515
1516 refLowData = float(logElement.refLowData) / logElement.maxValue;
1517
1518 for (i = 0; i < logImage->width * logImage->height / 2; i++) {
1519 cb = *(src_ptr++) - 0.5f;
1520 y1 = *(src_ptr++) - refLowData;
1521 cr = *(src_ptr++) - 0.5f;
1522 y2 = *(src_ptr++) - refLowData;
1523
1524 *(dst_ptr++) = clamp_float(y1 * conversionMatrix[0] + cb * conversionMatrix[1] +
1525 cr * conversionMatrix[2],
1526 0.0f,
1527 1.0f);
1528 *(dst_ptr++) = clamp_float(y1 * conversionMatrix[3] + cb * conversionMatrix[4] +
1529 cr * conversionMatrix[5],
1530 0.0f,
1531 1.0f);
1532 *(dst_ptr++) = clamp_float(y1 * conversionMatrix[6] + cb * conversionMatrix[7] +
1533 cr * conversionMatrix[8],
1534 0.0f,
1535 1.0f);
1536 *(dst_ptr++) = 1.0f;
1537 *(dst_ptr++) = clamp_float(y2 * conversionMatrix[0] + cb * conversionMatrix[1] +
1538 cr * conversionMatrix[2],
1539 0.0f,
1540 1.0f);
1541 *(dst_ptr++) = clamp_float(y2 * conversionMatrix[3] + cb * conversionMatrix[4] +
1542 cr * conversionMatrix[5],
1543 0.0f,
1544 1.0f);
1545 *(dst_ptr++) = clamp_float(y2 * conversionMatrix[6] + cb * conversionMatrix[7] +
1546 cr * conversionMatrix[8],
1547 0.0f,
1548 1.0f);
1549 *(dst_ptr++) = 1.0f;
1550 }
1551 return 0;
1552}
1553
1554static int convertCbYACrYA_RGBA(const float *src,
1555 float *dst,
1556 const LogImageFile *logImage,
1557 const LogImageElement &logElement)
1558{
1559 uint i;
1560 float conversionMatrix[9], refLowData, y1, y2, cb, cr, a1, a2;
1561 const float *src_ptr = src;
1562 float *dst_ptr = dst;
1563
1564 if (getYUVtoRGBMatrix((float *)&conversionMatrix, logElement) != 0) {
1565 return 1;
1566 }
1567
1568 refLowData = float(logElement.refLowData) / logElement.maxValue;
1569
1570 for (i = 0; i < logImage->width * logImage->height / 2; i++) {
1571 cb = *(src_ptr++) - 0.5f;
1572 y1 = *(src_ptr++) - refLowData;
1573 a1 = *(src_ptr++);
1574 cr = *(src_ptr++) - 0.5f;
1575 y2 = *(src_ptr++) - refLowData;
1576 a2 = *(src_ptr++);
1577
1578 *(dst_ptr++) = clamp_float(y1 * conversionMatrix[0] + cb * conversionMatrix[1] +
1579 cr * conversionMatrix[2],
1580 0.0f,
1581 1.0f);
1582 *(dst_ptr++) = clamp_float(y1 * conversionMatrix[3] + cb * conversionMatrix[4] +
1583 cr * conversionMatrix[5],
1584 0.0f,
1585 1.0f);
1586 *(dst_ptr++) = clamp_float(y1 * conversionMatrix[6] + cb * conversionMatrix[7] +
1587 cr * conversionMatrix[8],
1588 0.0f,
1589 1.0f);
1590 *(dst_ptr++) = a1;
1591 *(dst_ptr++) = clamp_float(y2 * conversionMatrix[0] + cb * conversionMatrix[1] +
1592 cr * conversionMatrix[2],
1593 0.0f,
1594 1.0f);
1595 *(dst_ptr++) = clamp_float(y2 * conversionMatrix[3] + cb * conversionMatrix[4] +
1596 cr * conversionMatrix[5],
1597 0.0f,
1598 1.0f);
1599 *(dst_ptr++) = clamp_float(y2 * conversionMatrix[6] + cb * conversionMatrix[7] +
1600 cr * conversionMatrix[8],
1601 0.0f,
1602 1.0f);
1603 *(dst_ptr++) = a2;
1604 }
1605 return 0;
1606}
1607
1608static int convertLuminance_RGBA(const float *src,
1609 float *dst,
1610 const LogImageFile *logImage,
1611 const LogImageElement &logElement)
1612{
1613 uint i;
1614 float conversionMatrix[9], value, refLowData;
1615 const float *src_ptr = src;
1616 float *dst_ptr = dst;
1617
1618 if (getYUVtoRGBMatrix((float *)&conversionMatrix, logElement) != 0) {
1619 return 1;
1620 }
1621
1622 refLowData = float(logElement.refLowData) / logElement.maxValue;
1623
1624 for (i = 0; i < logImage->width * logImage->height; i++) {
1625 value = clamp_float((*(src_ptr++) - refLowData) * conversionMatrix[0], 0.0f, 1.0f);
1626 *(dst_ptr++) = value;
1627 *(dst_ptr++) = value;
1628 *(dst_ptr++) = value;
1629 *(dst_ptr++) = 1.0f;
1630 }
1631 return 0;
1632}
1633
1634static int convertYA_RGBA(const float *src,
1635 float *dst,
1636 const LogImageFile *logImage,
1637 const LogImageElement &logElement)
1638{
1639 uint i;
1640 float conversionMatrix[9], value, refLowData;
1641 const float *src_ptr = src;
1642 float *dst_ptr = dst;
1643
1644 if (getYUVtoRGBMatrix((float *)&conversionMatrix, logElement) != 0) {
1645 return 1;
1646 }
1647
1648 refLowData = float(logElement.refLowData) / logElement.maxValue;
1649
1650 for (i = 0; i < logImage->width * logImage->height; i++) {
1651 value = clamp_float((*(src_ptr++) - refLowData) * conversionMatrix[0], 0.0f, 1.0f);
1652 *(dst_ptr++) = value;
1653 *(dst_ptr++) = value;
1654 *(dst_ptr++) = value;
1655 *(dst_ptr++) = *(src_ptr++);
1656 }
1657 return 0;
1658}
1659
1660static int convertLogElementToRGBA(const float *src,
1661 float *dst,
1662 const LogImageFile *logImage,
1663 const LogImageElement &logElement,
1664 int dstIsLinearRGB)
1665{
1666 int rvalue;
1667 uint i;
1668 float *src_ptr;
1669 float *dst_ptr;
1670
1671 /* Convert data in src to linear RGBA in dst */
1672 switch (logElement.descriptor) {
1673 case descriptor_RGB:
1674 rvalue = convertRGB_RGBA(src, dst, logImage, logElement, 1);
1675 break;
1676
1677 case descriptor_RGBA:
1678 rvalue = convertRGBA_RGBA(src, dst, logImage, logElement, 1);
1679 break;
1680
1681 case descriptor_ABGR:
1682 rvalue = convertABGR_RGBA(src, dst, logImage, logElement, 1);
1683 break;
1684
1686 rvalue = convertLuminance_RGBA(src, dst, logImage, logElement);
1687 break;
1688
1689 case descriptor_CbYCr:
1690 rvalue = convertCbYCr_RGBA(src, dst, logImage, logElement);
1691 break;
1692
1693 case descriptor_CbYCrY:
1694 rvalue = convertCbYCrY_RGBA(src, dst, logImage, logElement);
1695 break;
1696
1698 rvalue = convertCbYACrYA_RGBA(src, dst, logImage, logElement);
1699 break;
1700
1701 case descriptor_CbYCrA:
1702 rvalue = convertCbYCrA_RGBA(src, dst, logImage, logElement);
1703 break;
1704
1705 case descriptor_YA: /* this descriptor is for internal use only */
1706 rvalue = convertYA_RGBA(src, dst, logImage, logElement);
1707 break;
1708
1709 default:
1710 return 1;
1711 }
1712
1713 if (rvalue == 1) {
1714 return 1;
1715 }
1716 if (dstIsLinearRGB) {
1717 /* convert data from sRGB to Linear RGB via lut */
1718 float *lut = getSrgbToLinLut(logElement);
1719 src_ptr = dst; /* no error here */
1720 dst_ptr = dst;
1721 for (i = 0; i < logImage->width * logImage->height; i++) {
1722 *(dst_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1723 *(dst_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1724 *(dst_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1725 dst_ptr++;
1726 src_ptr++;
1727 }
1728 MEM_freeN(lut);
1729 }
1730 return 0;
1731}
1732
1733static int convertRGBAToLogElement(const float *src,
1734 float *dst,
1735 const LogImageFile *logImage,
1736 const LogImageElement &logElement,
1737 int srcIsLinearRGB)
1738{
1739 uint i;
1740 int rvalue;
1741 const float *srgbSrc;
1742 float *srgbSrc_alloc;
1743 float *srgbSrc_ptr;
1744 const float *src_ptr = src;
1745 float *lut;
1746
1747 if (srcIsLinearRGB != 0) {
1748 /* we need to convert src to sRGB */
1749 srgbSrc_alloc = (float *)imb_alloc_pixels(
1750 logImage->width, logImage->height, 4, sizeof(float), false, __func__);
1751 if (srgbSrc_alloc == nullptr) {
1752 return 1;
1753 }
1754
1755 memcpy(srgbSrc_alloc,
1756 src,
1757 4 * size_t(logImage->width) * size_t(logImage->height) * sizeof(float));
1758 srgbSrc_ptr = srgbSrc_alloc;
1759
1760 /* convert data from Linear RGB to sRGB via lut */
1761 lut = getLinToSrgbLut(logElement);
1762 for (i = 0; i < logImage->width * logImage->height; i++) {
1763 *(srgbSrc_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1764 *(srgbSrc_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1765 *(srgbSrc_ptr++) = lut[float_uint(*(src_ptr++), logElement.maxValue)];
1766 srgbSrc_ptr++;
1767 src_ptr++;
1768 }
1769 MEM_freeN(lut);
1770 srgbSrc = srgbSrc_alloc;
1771 }
1772 else {
1773 srgbSrc = src;
1774 }
1775
1776 /* Convert linear RGBA data in src to format described by logElement in dst */
1777 switch (logElement.descriptor) {
1778 case descriptor_RGB:
1779 rvalue = convertRGBA_RGB(srgbSrc, dst, logImage, logElement, 0);
1780 break;
1781
1782 case descriptor_RGBA:
1783 rvalue = convertRGBA_RGBA(srgbSrc, dst, logImage, logElement, 0);
1784 break;
1785
1786 /* these ones are not supported for the moment */
1787 case descriptor_ABGR:
1789 case descriptor_CbYCr:
1790 case descriptor_CbYCrY:
1792 case descriptor_CbYCrA:
1793 case descriptor_YA: /* this descriptor is for internal use only */
1794 default:
1795 rvalue = 1;
1796 break;
1797 }
1798
1799 if (srcIsLinearRGB != 0) {
1800 MEM_freeN(srgbSrc_alloc);
1801 }
1802
1803 return rvalue;
1804}
File and directory operations.
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
unsigned char uchar
unsigned short ushort
unsigned int uint
#define ELEM(...)
void * imb_alloc_pixels(unsigned int x, unsigned int y, unsigned int channels, size_t typesize, bool initialize_pixels, const char *alloc_name)
Read Guarded memory(de)allocation.
LogImageFile * cineonCreate(const char *filepath, int width, int height, int bitsPerSample, const char *creator)
Definition cineonlib.cc:354
void cineonSetVerbose(int verbosity)
Definition cineonlib.cc:33
LogImageFile * cineonOpen(const uchar *byteStuff, int fromMemory, size_t bufferSize)
Definition cineonlib.cc:125
#define CINEON_FILE_MAGIC
Definition cineonlib.h:20
#define printf
#define powf(x, y)
void dpxSetVerbose(int verbosity)
Definition dpxlib.cc:33
LogImageFile * dpxCreate(const char *filepath, int width, int height, int bitsPerSample, int hasAlpha, int isLogarithmic, int referenceWhite, int referenceBlack, float gamma, const char *creator)
Definition dpxlib.cc:410
LogImageFile * dpxOpen(const uchar *byteStuff, int fromMemory, size_t bufferSize)
Definition dpxlib.cc:123
#define DPX_FILE_MAGIC
Definition dpxlib.h:21
draw_view in_light_buf[] float
uint col
static float * getLinToSrgbLut(const LogImageElement &logElement)
static int logImageElementGetData12(LogImageFile *logImage, const LogImageElement &logElement, float *data)
static int verbose
static int logImageElementGetData12Packed(LogImageFile *logImage, const LogImageElement &logElement, float *data)
static int convertCbYCrA_RGBA(const float *src, float *dst, const LogImageFile *logImage, const LogImageElement &logElement)
int logImageIsDpx(const void *buffer, const uint size)
LogImageFile * logImageOpenFromFile(const char *filepath, int cineon)
int logImageIsCineon(const void *buffer, const uint size)
static size_t getRowLength(size_t width, const LogImageElement &logElement)
static int convertYA_RGBA(const float *src, float *dst, const LogImageFile *logImage, const LogImageElement &logElement)
static int convertCbYCrY_RGBA(const float *src, float *dst, const LogImageFile *logImage, const LogImageElement &logElement)
static int logImageSetData8(LogImageFile *logImage, const LogImageElement &logElement, const float *data)
void logImageSetVerbose(int verbosity)
static int logImageSetData10(LogImageFile *logImage, const LogImageElement &logElement, const float *data)
static int convertRGBAToLogElement(const float *src, float *dst, const LogImageFile *logImage, const LogImageElement &logElement, int srcIsLinearRGB)
int logImageSetDataRGBA(LogImageFile *logImage, const float *data, int dataIsLinearRGB)
static int logImageElementGetData1(LogImageFile *logImage, const LogImageElement &logElement, float *data)
static int convertLuminance_RGBA(const float *src, float *dst, const LogImageFile *logImage, const LogImageElement &logElement)
static int convertRGB_RGBA(const float *src, float *dst, const LogImageFile *logImage, const LogImageElement &logElement, int elementIsSource)
static int logImageElementGetData(LogImageFile *logImage, const LogImageElement &logElement, float *data)
static int convertRGBA_RGB(const float *src, float *dst, const LogImageFile *logImage, const LogImageElement &logElement, int elementIsSource)
static float * getLogToLinLut(const LogImageFile *logImage, const LogImageElement &logElement)
static int convertCbYCr_RGBA(const float *src, float *dst, const LogImageFile *logImage, const LogImageElement &logElement)
static float * getSrgbToLinLut(const LogImageElement &logElement)
static int convertABGR_RGBA(const float *src, float *dst, const LogImageFile *logImage, const LogImageElement &logElement, int elementIsSource)
static int logImageSetData12(LogImageFile *logImage, const LogImageElement &logElement, const float *data)
static int logImageElementGetData8(LogImageFile *logImage, const LogImageElement &logElement, float *data)
static int convertRGBA_RGBA(const float *src, float *dst, const LogImageFile *logImage, const LogImageElement &logElement, int elementIsSource)
static int logImageSetData16(LogImageFile *logImage, const LogImageElement &logElement, const float *data)
static int getYUVtoRGBMatrix(float *matrix, const LogImageElement &logElement)
void logImageClose(LogImageFile *logImage)
static int logImageElementGetData16(LogImageFile *logImage, const LogImageElement &logElement, float *data)
LogImageFile * logImageCreate(const char *filepath, int cineon, int width, int height, int bitsPerSample, int isLogarithmic, int hasAlpha, int referenceWhite, int referenceBlack, float gamma, const char *creator)
static float * getLinToLogLut(const LogImageFile *logImage, const LogImageElement &logElement)
static int logImageElementGetData10(LogImageFile *logImage, const LogImageElement &logElement, float *data)
static int convertLogElementToRGBA(const float *src, float *dst, const LogImageFile *logImage, const LogImageElement &logElement, int dstIsLinearRGB)
static int logImageElementGetData10Packed(LogImageFile *logImage, const LogImageElement &logElement, float *data)
int logImageGetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB)
LogImageFile * logImageOpenFromMemory(const uchar *buffer, uint size)
void logImageGetSize(const LogImageFile *logImage, int *width, int *height, int *depth)
static int convertCbYACrYA_RGBA(const float *src, float *dst, const LogImageFile *logImage, const LogImageElement &logElement)
BLI_INLINE float clamp_float(float x, float low, float high)
@ format_DPX
@ descriptor_Chrominance
@ descriptor_CbYCr
@ descriptor_Red
@ descriptor_YA
@ descriptor_Composite
@ descriptor_Depth
@ descriptor_CbYCrA
@ descriptor_Luminance
@ descriptor_Green
@ descriptor_ABGR
@ descriptor_CbYCrY
@ descriptor_Blue
@ descriptor_RGB
@ descriptor_CbYACrYA
@ descriptor_Alpha
@ descriptor_RGBA
@ transfer_PrintingDensity
@ transfer_UserDefined
@ transfer_Linear
@ transfer_Logarithmic
@ transfer_Unspecified
BLI_INLINE unsigned short swap_ushort(unsigned short x, int swap)
BLI_INLINE unsigned int swap_uint(unsigned int x, int swap)
BLI_INLINE unsigned int float_uint(float value, unsigned int max)
int logimage_read_uint(uint *x, LogImageFile *logFile)
int logimage_read_ushort(ushort *x, LogImageFile *logFile)
Definition logmemfile.cc:93
int logimage_read_uchar(uchar *x, LogImageFile *logFile)
Definition logmemfile.cc:81
int logimage_fseek(LogImageFile *logFile, intptr_t offset, int origin)
Definition logmemfile.cc:18
int logimage_fwrite(const void *buffer, size_t size, uint count, LogImageFile *logFile)
Definition logmemfile.cc:48
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
unsigned int refLowData
unsigned int refHighData
float referenceWhite
LogImageElement element[8]
float referenceBlack