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