code cleanup: cmake - add missing headers, remove directories from source listing.
[blender.git] / source / blender / imbuf / intern / cineon / cineonlib.c
1 /*
2  * Cineon image file format library routines.
3  *
4  * Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 2 of the License, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Contributor(s): Julien Enche.
21  *
22  */
23
24 /** \file blender/imbuf/intern/cineon/cineonlib.c
25  *  \ingroup imbcineon
26  */
27
28
29 #include "cineonlib.h"
30 #include "logmemfile.h"
31
32 #include <stdio.h>
33 #include <math.h>
34 #include <stdlib.h>
35 #include <time.h>
36 #include <sys/types.h>
37 #include <string.h>
38
39 #include "BLI_fileops.h"
40 #include "BLI_math_base.h"
41 #include "BLI_utildefines.h"
42
43 #include "logImageLib.h"
44
45 #include "MEM_guardedalloc.h"
46
47 /*
48  * For debug purpose
49  */
50
51 static int verbose = 0;
52
53 void cineonSetVerbose(int verbosity) {
54         verbose = verbosity;
55 }
56
57 static void fillCineonMainHeader(LogImageFile *cineon, CineonMainHeader *header,
58                                  const char *filename, const char *creator)
59 {
60         time_t fileClock;
61         struct tm *fileTime;
62         int i;
63
64         memset(header, 0, sizeof(CineonMainHeader));
65
66         /* --- File header --- */
67         header->fileHeader.magic_num = swap_uint(CINEON_FILE_MAGIC, cineon->isMSB);
68         header->fileHeader.offset = swap_uint(cineon->element[0].dataOffset, cineon->isMSB);
69         header->fileHeader.gen_hdr_size = swap_uint(sizeof(CineonFileHeader) + sizeof(CineonImageHeader) +
70                                                     sizeof(CineonOriginationHeader), cineon->isMSB);
71         header->fileHeader.ind_hdr_size = 0;
72         header->fileHeader.user_data_size = 0;
73         header->fileHeader.file_size = swap_uint(cineon->element[0].dataOffset + cineon->height * getRowLength(cineon->width, cineon->element[0]), cineon->isMSB);
74         strcpy(header->fileHeader.version, "v4.5");
75         strncpy(header->fileHeader.file_name, filename, 99);
76         header->fileHeader.file_name[99] = 0;
77         fileClock = time(0);
78         fileTime = localtime(&fileClock);
79         strftime(header->fileHeader.creation_date, 12, "%Y:%m:%d", fileTime);
80         strftime(header->fileHeader.creation_time, 12, "%H:%M:%S%Z", fileTime);
81         header->fileHeader.creation_time[11] = 0;
82
83         /* --- Image header --- */
84         header->imageHeader.orientation = 0;
85         header->imageHeader.elements_per_image = cineon->depth;
86
87         for (i = 0; i < 3; i++) {
88                 header->imageHeader.element[i].descriptor1 = 0;
89                 header->imageHeader.element[i].descriptor2 = i;
90                 header->imageHeader.element[i].bits_per_sample = cineon->element[0].bitsPerSample;
91                 header->imageHeader.element[i].pixels_per_line = swap_uint(cineon->width, cineon->isMSB);
92                 header->imageHeader.element[i].lines_per_image = swap_uint(cineon->height, cineon->isMSB);
93                 header->imageHeader.element[i].ref_low_data = swap_uint(cineon->element[0].refLowData, cineon->isMSB);
94                 header->imageHeader.element[i].ref_low_quantity = swap_float(cineon->element[0].refLowQuantity, cineon->isMSB);
95                 header->imageHeader.element[i].ref_high_data = swap_uint(cineon->element[0].refHighData, cineon->isMSB);
96                 header->imageHeader.element[i].ref_high_quantity = swap_float(cineon->element[0].refHighQuantity, cineon->isMSB);
97         }
98
99         header->imageHeader.white_point_x = swap_float(0.0f, cineon->isMSB);
100         header->imageHeader.white_point_y = swap_float(0.0f, cineon->isMSB);
101         header->imageHeader.red_primary_x = swap_float(0.0f, cineon->isMSB);
102         header->imageHeader.red_primary_y = swap_float(0.0f, cineon->isMSB);
103         header->imageHeader.green_primary_x = swap_float(0.0f, cineon->isMSB);
104         header->imageHeader.green_primary_y = swap_float(0.0f, cineon->isMSB);
105         header->imageHeader.blue_primary_x = swap_float(0.0f, cineon->isMSB);
106         header->imageHeader.blue_primary_y = swap_float(0.0f, cineon->isMSB);
107         strncpy(header->imageHeader.label, creator, 199);
108         header->imageHeader.label[199] = 0;
109         header->imageHeader.interleave = 0;
110         header->imageHeader.data_sign = 0;
111         header->imageHeader.sense = 0;
112         header->imageHeader.line_padding = swap_uint(0, cineon->isMSB);
113         header->imageHeader.element_padding = swap_uint(0, cineon->isMSB);
114
115         switch (cineon->element[0].packing) {
116                 case 0:
117                         header->imageHeader.packing = 0;
118                         break;
119
120                 case 1:
121                         header->imageHeader.packing = 5;
122                         break;
123
124                 case 2:
125                         header->imageHeader.packing = 6;
126                         break;
127         }
128
129         /* --- Origination header --- */
130         /* we leave it blank */
131
132         /* --- Film header --- */
133         /* we leave it blank */
134 }
135
136 LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t bufferSize)
137 {
138         CineonMainHeader header;
139         LogImageFile *cineon = (LogImageFile *)MEM_mallocN(sizeof(LogImageFile), __func__);
140         char *filename = (char *)byteStuff;
141         int i;
142         unsigned int dataOffset;
143
144         if (cineon == 0) {
145                 if (verbose) printf("Cineon: Failed to malloc cineon file structure.\n");
146                 return 0;
147         }
148
149         /* zero the header */
150         memset(&header, 0, sizeof(CineonMainHeader));
151
152         /* for close routine */
153         cineon->file = 0;
154
155         if (fromMemory == 0) {
156                 /* byteStuff is then the filename */
157                 cineon->file = BLI_fopen(filename, "rb");
158                 if (cineon->file == 0) {
159                         if (verbose) printf("Cineon: Failed to open file \"%s\".\n", filename);
160                         logImageClose(cineon);
161                         return 0;
162                 }
163                 /* not used in this case */
164                 cineon->memBuffer = 0;
165                 cineon->memCursor = 0;
166                 cineon->memBufferSize = 0;
167         }
168         else {
169                 cineon->memBuffer = (unsigned char *)byteStuff;
170                 cineon->memCursor = (unsigned char *)byteStuff;
171                 cineon->memBufferSize = bufferSize;
172         }
173
174         if (logimage_fread(&header, sizeof(header), 1, cineon) == 0) {
175                 if (verbose) printf("Cineon: Not enough data for header in \"%s\".\n", byteStuff);
176                 logImageClose(cineon);
177                 return 0;
178         }
179
180         /* endianness determination */
181         if (header.fileHeader.magic_num == swap_uint(CINEON_FILE_MAGIC, 1)) {
182                 cineon->isMSB = 1;
183                 if (verbose) printf("Cineon: File is MSB.\n");
184         }
185         else if (header.fileHeader.magic_num == CINEON_FILE_MAGIC) {
186                 cineon->isMSB = 0;
187                 if (verbose) printf("Cineon: File is LSB.\n");
188         }
189         else {
190                 if (verbose) printf("Cineon: Bad magic number %lu in \"%s\".\n",
191                                         (uintptr_t)header.fileHeader.magic_num, byteStuff);
192                 logImageClose(cineon);
193                 return 0;
194         }
195
196         cineon->width = swap_uint(header.imageHeader.element[0].pixels_per_line, cineon->isMSB);
197         cineon->height = swap_uint(header.imageHeader.element[0].lines_per_image, cineon->isMSB);
198         cineon->depth = header.imageHeader.elements_per_image;
199         cineon->srcFormat = format_Cineon;
200
201         if (header.imageHeader.interleave == 0)
202                 cineon->numElements = 1;
203         else if (header.imageHeader.interleave == 2)
204                 cineon->numElements = header.imageHeader.elements_per_image;
205         else {
206                 if (verbose) printf("Cineon: Data interleave not supported: %d\n", header.imageHeader.interleave);
207                 return 0;
208         }
209
210         if (cineon->depth == 1) {
211                 /* Grayscale image */
212                 cineon->element[0].descriptor = descriptor_Luminance;
213                 cineon->element[0].transfer = transfer_Linear;
214                 cineon->element[0].depth = 1;
215         }
216         else if (cineon->depth == 3) {
217                 /* RGB image */
218                 if (cineon->numElements == 1) {
219                         cineon->element[0].descriptor = descriptor_RGB;
220                         cineon->element[0].transfer = transfer_PrintingDensity;
221                         cineon->element[0].depth = 3;
222                 }
223                 else if (cineon->numElements == 3) {
224                         cineon->element[0].descriptor = descriptor_Red;
225                         cineon->element[0].transfer = transfer_PrintingDensity;
226                         cineon->element[0].depth = 1;
227                         cineon->element[1].descriptor = descriptor_Green;
228                         cineon->element[1].transfer = transfer_PrintingDensity;
229                         cineon->element[1].depth = 1;
230                         cineon->element[2].descriptor = descriptor_Blue;
231                         cineon->element[2].transfer = transfer_PrintingDensity;
232                         cineon->element[2].depth = 1;
233                 }
234         }
235         else {
236                 if (verbose) printf("Cineon: Cineon image depth unsupported: %d\n", cineon->depth);
237                 return 0;
238         }
239
240         dataOffset = swap_uint(header.fileHeader.offset, cineon->isMSB);
241
242         for (i = 0; i < cineon->numElements; i++) {
243                 cineon->element[i].bitsPerSample = header.imageHeader.element[i].bits_per_sample;
244                 cineon->element[i].maxValue = powf(2, cineon->element[i].bitsPerSample) - 1.0f;
245                 cineon->element[i].refLowData = swap_uint(header.imageHeader.element[i].ref_low_data, cineon->isMSB);
246                 cineon->element[i].refLowQuantity = swap_float(header.imageHeader.element[i].ref_low_quantity, cineon->isMSB);
247                 cineon->element[i].refHighData = swap_uint(header.imageHeader.element[i].ref_high_data, cineon->isMSB);
248                 cineon->element[i].refHighQuantity = swap_float(header.imageHeader.element[i].ref_high_quantity, cineon->isMSB);
249
250                 switch (header.imageHeader.packing) {
251                         case 0:
252                                 cineon->element[i].packing = 0;
253                                 break;
254
255                         case 5:
256                                 cineon->element[i].packing = 1;
257                                 break;
258
259                         case 6:
260                                 cineon->element[i].packing = 2;
261                                 break;
262
263                         default:
264                                 /* Not supported */
265                                 if (verbose) printf("Cineon: packing unsupported: %d\n", header.imageHeader.packing);
266                                 return 0;
267                 }
268
269                 if (cineon->element[i].refLowData == CINEON_UNDEFINED_U32 || isnan(cineon->element[i].refLowData))
270                         cineon->element[i].refLowData = 0;
271
272                 if (cineon->element[i].refHighData == CINEON_UNDEFINED_U32 || isnan(cineon->element[i].refHighData))
273                         cineon->element[i].refHighData = (unsigned int)cineon->element[i].maxValue;
274
275                 if (cineon->element[i].refLowQuantity == CINEON_UNDEFINED_R32 || isnan(cineon->element[i].refLowQuantity))
276                         cineon->element[i].refLowQuantity = 0.0f;
277
278                 if (cineon->element[i].refHighQuantity == CINEON_UNDEFINED_R32 || isnan(cineon->element[i].refHighQuantity)) {
279                         if (cineon->element[i].transfer == transfer_PrintingDensity)
280                                 cineon->element[i].refHighQuantity = 2.048f;
281                         else
282                                 cineon->element[i].refHighQuantity = cineon->element[i].maxValue;
283                 }
284
285                 cineon->element[i].dataOffset = dataOffset;
286                 dataOffset += cineon->height * getRowLength(cineon->width, cineon->element[i]);
287         }
288
289         cineon->referenceBlack = 95.0f / 1023.0f * cineon->element[0].maxValue;
290         cineon->referenceWhite = 685.0f / 1023.0f * cineon->element[0].maxValue;
291         cineon->gamma = 1.7f;
292
293         if (verbose) {
294                 printf("size %d x %d x %d elements\n", cineon->width, cineon->height, cineon->numElements);
295                 for (i = 0; i < cineon->numElements; i++) {
296                         printf(" Element %d:\n", i);
297                         printf("  Bits per sample: %d\n", cineon->element[i].bitsPerSample);
298                         printf("  Depth: %d\n", cineon->element[i].depth);
299                         printf("  Transfer characteristics: %d\n", cineon->element[i].transfer);
300                         printf("  Packing: %d\n", cineon->element[i].packing);
301                         printf("  Descriptor: %d\n", cineon->element[i].descriptor);
302                         printf("  Data offset: %u\n", cineon->element[i].dataOffset);
303                         printf("  Reference low data: %u\n", cineon->element[i].refLowData);
304                         printf("  Reference low quantity: %f\n", cineon->element[i].refLowQuantity);
305                         printf("  Reference high data: %u\n", cineon->element[i].refHighData);
306                         printf("  Reference high quantity: %f\n", cineon->element[i].refHighQuantity);
307                         printf("\n");
308                 }
309
310                 printf("Gamma: %f\n", cineon->gamma);
311                 printf("Reference black: %f\n", cineon->referenceBlack);
312                 printf("Reference white: %f\n", cineon->referenceWhite);
313                 printf("----------------------------\n");
314         }
315         return cineon;
316 }
317
318 LogImageFile *cineonCreate(const char *filename, int width, int height, int bitsPerSample, const char *creator)
319 {
320         CineonMainHeader header;
321         const char *shortFilename = 0;
322         /* unsigned char pad[6044]; */
323
324         LogImageFile *cineon = (LogImageFile *)MEM_mallocN(sizeof(LogImageFile), __func__);
325         if (cineon == 0) {
326                 if (verbose) printf("cineon: Failed to malloc cineon file structure.\n");
327                 return 0;
328         }
329
330         /* Only 10 bits Cineon are supported */
331         if (bitsPerSample != 10) {
332                 if (verbose) printf("cineon: Only 10 bits Cineon are supported.\n");
333                 logImageClose(cineon);
334                 return 0;
335         }
336
337         cineon->width = width;
338         cineon->height = height;
339         cineon->element[0].bitsPerSample = 10;
340         cineon->element[0].dataOffset = sizeof(CineonMainHeader);
341         cineon->element[0].maxValue = 1023;
342         cineon->isMSB = 1;
343         cineon->numElements = 1;
344         cineon->element[0].packing = 1;
345         cineon->depth = 3;
346         cineon->element[0].depth = 3;
347         cineon->element[0].descriptor = descriptor_RGB;
348         cineon->element[0].transfer = transfer_PrintingDensity;
349         cineon->element[0].refHighQuantity = 2.048f;
350         cineon->element[0].refLowQuantity = 0;
351         cineon->element[0].refLowData = 0;
352         cineon->element[0].refHighData = cineon->element[0].maxValue;
353         cineon->referenceWhite = 685.0f;
354         cineon->referenceBlack = 95.0f;
355         cineon->gamma = 1.7f;
356
357         shortFilename = strrchr(filename, '/');
358         if (shortFilename == 0)
359                 shortFilename = filename;
360         else
361                 shortFilename++;
362
363         cineon->file = BLI_fopen(filename, "wb");
364         if (cineon->file == 0) {
365                 if (verbose) printf("cineon: Couldn't open file %s\n", filename);
366                 logImageClose(cineon);
367                 return 0;
368         }
369
370         fillCineonMainHeader(cineon, &header, shortFilename, creator);
371
372         if (fwrite(&header, sizeof(header), 1, cineon->file) == 0) {
373                 if (verbose) printf("cineon: Couldn't write image header\n");
374                 logImageClose(cineon);
375                 return 0;
376         }
377
378         return cineon;
379 }