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