style cleanup: brace placement/newlines
[blender.git] / source / blender / imbuf / intern / cineon / dpxlib.c
1 /*
2  *       Dpx image file format library routines.
3  *
4  *       Copyright 1999 - 2002 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  */
21
22 /** \file blender/imbuf/intern/cineon/dpxlib.c
23  *  \ingroup imbcineon
24  */
25
26 #include "dpxfile.h"
27 #include "dpxlib.h"
28
29 #include <stdio.h>
30 #include <math.h>
31 #include <stdlib.h>
32 #include <time.h>                                /* strftime() */
33 #include <sys/types.h>
34 #ifdef WIN32
35 #include <winsock.h>
36 #else
37 #include <netinet/in.h>  /* htonl() */
38 #endif
39 #include <string.h>                      /* memset */
40 #include "cin_debug_stuff.h"
41 #include "logmemfile.h"
42 #include "BLI_fileops.h"
43
44 static void
45 fillDpxChannelInfo(DpxFile* dpx, DpxChannelInformation* chan, int des) {
46
47         (void)dpx; /* unused */
48         
49         chan->signage = 0;
50         chan->ref_low_data = htonl(0);
51         chan->ref_low_quantity = htonf(0.0);
52         chan->ref_high_data = htonl(1023);
53         chan->ref_high_quantity = htonf(2.046);
54         chan->designator1 = des;
55         chan->transfer_characteristics = 0;
56         chan->colourimetry = 0;
57         chan->bits_per_pixel = 10;
58         chan->packing = htons(1);
59         chan->encoding = 0;
60         chan->data_offset = 0;
61         chan->line_padding = htonl(0);
62         chan->channel_padding = htonl(0);
63         chan->description[0] = 0;
64 }
65
66 static void
67 dumpDpxChannelInfo(DpxChannelInformation* chan) {
68         d_printf("      Signage %ld", (intptr_t)ntohl(chan->signage));
69         d_printf("      Ref low data %ld\n", (intptr_t)ntohl(chan->ref_low_data));
70         d_printf("      Ref low quantity %f\n", ntohf(chan->ref_low_quantity));
71         d_printf("      Ref high data %ld\n", (intptr_t)ntohl(chan->ref_high_data));
72         d_printf("      Ref high quantity %f\n", ntohf(chan->ref_high_quantity));
73         d_printf("      Designator1: %d,", chan->designator1);
74         d_printf("      Bits per pixel %d\n", chan->bits_per_pixel);
75         d_printf("      Packing: %d,", ntohs(chan->packing));
76         d_printf("      Data Offset: %ld,", (intptr_t)ntohl(chan->data_offset));
77 }
78
79 static void
80 fillDpxFileInfo(
81         DpxFile* dpx, DpxFileInformation* fileInfo, const char* filename) {
82
83         time_t fileClock;
84         struct tm* fileTime;
85
86         /* Note: always write files in network order */
87         /* By the spec, it shouldn't matter, but ... */
88
89         fileInfo->magic_num = htonl(DPX_FILE_MAGIC);
90         fileInfo->offset = htonl(dpx->imageOffset);
91         strcpy(fileInfo->vers, "v1.0");
92         fileInfo->file_size = htonl(dpx->imageOffset +
93                 pixelsToLongs(dpx->height * dpx->width * dpx->depth) * 4);
94         fileInfo->ditto_key = 0;
95         fileInfo->gen_hdr_size = htonl(
96                 sizeof(DpxFileInformation) +
97                 sizeof(DpxImageInformation) +
98                 sizeof(DpxOriginationInformation));
99         fileInfo->ind_hdr_size = htonl(sizeof(DpxMPIInformation));
100         fileInfo->user_data_size = 0;
101         strncpy(fileInfo->file_name, filename, 99);
102         fileInfo->file_name[99] = 0;
103
104         fileClock = time(0);
105         fileTime = localtime(&fileClock);
106         strftime(fileInfo->create_date, 24, "%Y:%m:%d:%H:%M:%S%Z", fileTime);
107         /* Question: is %Z in strftime guaranteed to return 3 chars? */
108         fileInfo->create_date[23] = 0;
109
110         strcpy(fileInfo->creator, "David's DPX writer");
111         fileInfo->project[0] = 0;
112         fileInfo->copyright[0] = 0;
113         fileInfo->key = 0xFFFFFFFF; /* same in any byte order */
114 }
115
116 static void
117 dumpDpxFileInfo(DpxFileInformation* fileInfo) {
118         d_printf("\n--File Information--\n");
119         d_printf("Magic: %8.8lX\n", (unsigned long)ntohl(fileInfo->magic_num));
120         d_printf("Image Offset %ld\n", (intptr_t)ntohl(fileInfo->offset));
121         d_printf("Version \"%s\"\n", fileInfo->vers);
122         d_printf("File size %ld\n", (intptr_t)ntohl(fileInfo->file_size));
123         d_printf("Ditto key %ld\n", (intptr_t)ntohl(fileInfo->ditto_key));
124         d_printf("Generic Header size %ld\n", (intptr_t)ntohl(fileInfo->gen_hdr_size));
125         d_printf("Industry Header size %ld\n", (intptr_t)ntohl(fileInfo->ind_hdr_size));
126         d_printf("User Data size %ld\n", (intptr_t)ntohl(fileInfo->user_data_size));
127         d_printf("File name \"%s\"\n", fileInfo->file_name);
128         d_printf("Creation date \"%s\"\n", fileInfo->create_date);
129         d_printf("Creator \"%s\"\n", fileInfo->creator);
130         d_printf("Project \"%s\"\n", fileInfo->project);
131         d_printf("Copyright \"%s\"\n", fileInfo->copyright);
132         d_printf("Key %ld\n", (intptr_t)ntohl(fileInfo->key));
133 }
134
135 static void
136 fillDpxImageInfo(
137         DpxFile* dpx, DpxImageInformation* imageInfo) {
138         imageInfo->orientation = 0;
139         imageInfo->channels_per_image = htons(1);
140         imageInfo->pixels_per_line = htonl(dpx->width);
141         imageInfo->lines_per_image = htonl(dpx->height);
142
143         if (dpx->depth == 1) {
144                 fillDpxChannelInfo(dpx, &imageInfo->channel[0], 0);
145
146         }
147         else if (dpx->depth == 3) {
148                 fillDpxChannelInfo(dpx, &imageInfo->channel[0], 50);
149         }
150 }
151
152 static void
153 dumpDpxImageInfo(DpxImageInformation* imageInfo) {
154
155         int n;
156         int i;
157         d_printf("\n--Image Information--\n");
158         d_printf("Image orientation %d,", ntohs(imageInfo->orientation));
159         n = ntohs(imageInfo->channels_per_image);
160         d_printf("Channels %d\n", n);
161         d_printf("Pixels per line %ld\n", (intptr_t)ntohl(imageInfo->pixels_per_line));
162         d_printf("Lines per image %ld\n", (intptr_t)ntohl(imageInfo->lines_per_image));
163         for (i = 0; i < n; ++i) {
164                 d_printf("      --Channel %d--\n", i);
165                 dumpDpxChannelInfo(&imageInfo->channel[i]);
166         }
167 }
168
169 static void
170 fillDpxOriginationInfo(
171         DpxFile* dpx, DpxOriginationInformation* originInfo, DpxFileInformation* fileInfo)
172 {
173         /* unused */
174         (void)dpx;
175         (void)originInfo;
176         (void)fileInfo;
177 }
178
179 static void
180 dumpDpxOriginationInfo(DpxOriginationInformation* originInfo) {
181         d_printf("\n--Origination Information--\n");
182         d_printf("X offset %ld\n", (intptr_t)ntohl(originInfo->x_offset));
183         d_printf("Y offset %ld\n", (intptr_t)ntohl(originInfo->y_offset));
184         d_printf("X centre %f\n", ntohf(originInfo->x_centre));
185         d_printf("Y centre %f\n", ntohf(originInfo->y_centre));
186         d_printf("Original X %ld\n", (intptr_t)ntohl(originInfo->x_original_size));
187         d_printf("Original Y %ld\n", (intptr_t)ntohl(originInfo->y_original_size));
188         d_printf("File name \"%s\"\n", originInfo->file_name);
189         d_printf("Creation time \"%s\"\n", originInfo->creation_time);
190         d_printf("Input device \"%s\"\n", originInfo->input_device);
191         d_printf("Serial number \"%s\"\n", originInfo->input_serial_number);
192 }
193
194 static void
195 initDpxMainHeader(DpxFile* dpx, DpxMainHeader* header, const char* shortFilename) {
196         memset(header, 0, sizeof(DpxMainHeader));
197         fillDpxFileInfo(dpx, &header->fileInfo, shortFilename);
198         fillDpxImageInfo(dpx, &header->imageInfo);
199         fillDpxOriginationInfo(dpx, &header->originInfo, &header->fileInfo);
200 #if 0
201         fillDpxMPIInfo(dpx, &header->filmHeader);
202 #endif
203 }
204
205 static void
206 dumpDpxMainHeader(DpxMainHeader* header) {
207         dumpDpxFileInfo(&header->fileInfo);
208         dumpDpxImageInfo(&header->imageInfo);
209         dumpDpxOriginationInfo(&header->originInfo);
210 #if 0
211         dumpDpxMPIInformation(&header->filmHeader);
212 #endif
213 }
214
215 static int verbose = 0;
216 void
217 dpxSetVerbose(int verbosity) {
218         verbose = verbosity;
219 }
220
221 static void
222 verboseMe(DpxFile* dpx) {
223
224         d_printf("size %d x %d x %d\n", dpx->width, dpx->height, dpx->depth);
225         d_printf("ImageStart %d, lineBufferLength %d, implied length %d\n",
226                 dpx->imageOffset, dpx->lineBufferLength * 4,
227                 dpx->imageOffset + pixelsToLongs(dpx->width * dpx->depth * dpx->height) * 4);
228 }
229
230 int
231 dpxGetRowBytes(DpxFile* dpx, unsigned short* row, int y) {
232
233         /* Note: this code is bizarre because DPX files can wrap */
234         /* packed longwords across line boundaries!!!! */
235
236         size_t readLongs;
237         unsigned int longIndex;
238         int numPixels = dpx->width * dpx->depth;
239         int pixelIndex;
240
241         /* only seek if not reading consecutive lines */
242         /* this is not quite right yet, need to account for leftovers */
243         if (y != dpx->fileYPos) {
244                 int lineOffset = pixelsToLongs(y * dpx->width * dpx->depth) * 4;
245                 if (verbose) d_printf("Seek in getRowBytes\n");
246                 if (logimage_fseek(dpx, dpx->imageOffset + lineOffset, SEEK_SET) != 0) {
247                         if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, dpx->imageOffset + lineOffset);
248                         return 1;
249                 }
250                 dpx->fileYPos = y;
251         }
252
253         /* read enough longwords */
254         readLongs = pixelsToLongs(numPixels - dpx->pixelBufferUsed);
255         if (logimage_fread(dpx->lineBuffer, 4, readLongs, dpx) != readLongs) {
256                 if (verbose) d_printf("Couldn't read line %d length %d\n", y, (int)readLongs * 4);
257                 return 1;
258         }
259         ++dpx->fileYPos;
260
261         /* convert longwords to pixels */
262         pixelIndex = dpx->pixelBufferUsed;
263
264         /* this is just strange */
265         if (dpx->depth == 1) {
266                 for (longIndex = 0; longIndex < readLongs; ++longIndex) {
267                         unsigned int t = ntohl(dpx->lineBuffer[longIndex]);
268                         dpx->pixelBuffer[pixelIndex] = t & 0x3ff;
269                         t = t >> 10;
270                         dpx->pixelBuffer[pixelIndex+1] = t & 0x3ff;
271                         t = t >> 10;
272                         dpx->pixelBuffer[pixelIndex+2] = t & 0x3ff;
273                         pixelIndex += 3;
274                 }
275         }
276         else /* if (dpx->depth == 3) */ {
277                 for (longIndex = 0; longIndex < readLongs; ++longIndex) {
278                         unsigned int t = ntohl(dpx->lineBuffer[longIndex]);
279                         t = t >> 2;
280                         dpx->pixelBuffer[pixelIndex+2] = t & 0x3ff;
281                         t = t >> 10;
282                         dpx->pixelBuffer[pixelIndex+1] = t & 0x3ff;
283                         t = t >> 10;
284                         dpx->pixelBuffer[pixelIndex] = t & 0x3ff;
285                         pixelIndex += 3;
286                 }
287         }
288         dpx->pixelBufferUsed = pixelIndex;
289
290         /* extract required pixels */
291         for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
292                 if (dpx->params.doLogarithm)
293                         row[pixelIndex] = dpx->lut10_16[dpx->pixelBuffer[pixelIndex]];
294                 else
295                         row[pixelIndex] = dpx->pixelBuffer[pixelIndex] << 6;
296         }
297
298         /* save remaining pixels */
299         while (pixelIndex < dpx->pixelBufferUsed) {
300                 dpx->pixelBuffer[pixelIndex - numPixels] = dpx->pixelBuffer[pixelIndex];
301                 ++pixelIndex;
302         }
303         dpx->pixelBufferUsed -= numPixels;
304
305         /* done! */
306         return 0;
307 }
308
309 int
310 dpxSetRowBytes(DpxFile* dpx, const unsigned short* row, int y) {
311
312         /* Note: this code is bizarre because DPX files can wrap */
313         /* packed longwords across line boundaries!!!! */
314
315         size_t writeLongs;
316         int longIndex;
317         int numPixels = dpx->width * dpx->depth;
318         int pixelIndex;
319         int pixelIndex2;
320
321         /* only seek if not reading consecutive lines */
322         /* this is not quite right yet */
323         if (y != dpx->fileYPos) {
324                 int lineOffset = pixelsToLongs(y * dpx->width * dpx->depth) * 4;
325                 if (verbose) d_printf("Seek in getRowBytes\n");
326                 if (logimage_fseek(dpx, dpx->imageOffset + lineOffset, SEEK_SET) != 0) {
327                         if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, dpx->imageOffset + lineOffset);
328                         return 1;
329                 }
330                 dpx->fileYPos = y;
331         }
332
333         /* put new pixels into pixelBuffer */
334         for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
335                 if (dpx->params.doLogarithm)
336                         dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = dpx->lut16_16[row[pixelIndex]];
337                 else
338                         dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = row[pixelIndex] >> 6;
339         }
340         dpx->pixelBufferUsed += numPixels;
341
342         /* pack into longwords */
343         writeLongs = dpx->pixelBufferUsed / 3;
344         /* process whole line at image end */
345         if (dpx->fileYPos == (dpx->height - 1)) {
346                 writeLongs = pixelsToLongs(dpx->pixelBufferUsed);
347         }
348         pixelIndex = 0;
349         if (dpx->depth == 1) {
350                 for (longIndex = 0; longIndex < writeLongs; ++longIndex) {
351                         unsigned int t = dpx->pixelBuffer[pixelIndex] |
352                                         (dpx->pixelBuffer[pixelIndex+1] << 10) |
353                                         (dpx->pixelBuffer[pixelIndex+2] << 20);
354                         dpx->lineBuffer[longIndex] = htonl(t);
355                         pixelIndex += 3;
356                 }
357         }
358         else {
359                 for (longIndex = 0; longIndex < writeLongs; ++longIndex) {
360                         unsigned int t = dpx->pixelBuffer[pixelIndex+2] << 2 |
361                                         (dpx->pixelBuffer[pixelIndex+1] << 12) |
362                                         (dpx->pixelBuffer[pixelIndex] << 22);
363                         dpx->lineBuffer[longIndex] = htonl(t);
364                         pixelIndex += 3;
365                 }
366         }
367
368         /* write them */
369         if (fwrite(dpx->lineBuffer, 4, writeLongs, dpx->file) != writeLongs) {
370                 if (verbose) d_printf("Couldn't write line %d length %d\n", y, (int)writeLongs * 4);
371                 return 1;
372         }
373         ++dpx->fileYPos;
374
375         /* save remaining pixels */
376         pixelIndex2 = 0;
377         while (pixelIndex < dpx->pixelBufferUsed) {
378                 dpx->pixelBuffer[pixelIndex2] = dpx->pixelBuffer[pixelIndex];
379                 ++pixelIndex;
380                 ++pixelIndex2;
381         }
382         dpx->pixelBufferUsed = pixelIndex2;
383
384         return 0;
385 }
386
387 #define LFMEMFILE       0
388 #define LFREALFILE      1
389
390 static DpxFile* 
391 intern_dpxOpen(int mode, const char* bytestuff, int bufsize) {
392
393         DpxMainHeader header;
394         const char *filename = bytestuff;
395         DpxFile* dpx = (DpxFile*)malloc(sizeof(DpxFile));
396         
397         if (dpx == 0) {
398                 if (verbose) d_printf("Failed to malloc dpx file structure.\n");
399                 return 0;
400         }
401
402         /* for close routine */
403         dpx->file = 0;
404         dpx->lineBuffer = 0;
405         dpx->pixelBuffer = 0;
406
407         if (mode == LFREALFILE) {
408                 filename = bytestuff;
409                 dpx->file = BLI_fopen(filename, "rb");
410                 if (dpx->file == 0) {   
411                         if (verbose) d_printf("Failed to open file \"%s\".\n", filename);
412                         dpxClose(dpx);
413                         return 0;
414                 }
415                 dpx->membuffer = 0;
416                 dpx->memcursor = 0;
417                 dpx->membuffersize = 0;
418         }
419         else if (mode == LFMEMFILE) {
420                 dpx->membuffer = (unsigned char *)bytestuff;
421                 dpx->memcursor = (unsigned char *)bytestuff;
422                 dpx->membuffersize = bufsize;
423         }
424         
425         dpx->reading = 1;
426
427         if (logimage_fread(&header, sizeof(header), 1, dpx) == 0) {
428                 if (verbose) d_printf("Not enough data for header in \"%s\".\n", filename);
429                 dpxClose(dpx);
430                 return 0;
431         }
432
433         /* let's assume dpx files are always network order */
434         if (header.fileInfo.magic_num != ntohl(DPX_FILE_MAGIC)) {
435                 if (verbose) d_printf("Bad magic number %8.8lX in \"%s\".\n",
436                         (uintptr_t)ntohl(header.fileInfo.magic_num), filename);
437                 dpxClose(dpx);
438                 return 0;
439         }
440
441         if (ntohs(header.imageInfo.channel[0].packing) != 1) {
442                 if (verbose) d_printf("Unknown packing %d\n", header.imageInfo.channel[0].packing);
443                 dpxClose(dpx);
444                 return 0;
445         }
446
447
448         dpx->width = ntohl(header.imageInfo.pixels_per_line);
449         dpx->height = ntohl(header.imageInfo.lines_per_image);
450         dpx->depth = ntohs(header.imageInfo.channels_per_image);
451         /* Another DPX vs Cineon wierdness */
452         if (dpx->depth == 1) {
453                 switch (header.imageInfo.channel[0].designator1) {
454                 case 50: dpx->depth = 3; break;
455                 case 51: dpx->depth = 4; break;
456                 case 52: dpx->depth = 4; break;
457                 default: break;
458                 }
459         }
460         /* dpx->bitsPerPixel = 10; */
461         dpx->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel;
462         if (dpx->bitsPerPixel != 10) {
463                 if (verbose) d_printf("Don't support depth: %d\n", dpx->bitsPerPixel);
464                 dpxClose(dpx);
465                 return 0;
466         }
467
468         dpx->imageOffset = ntohl(header.fileInfo.offset);
469         dpx->lineBufferLength = pixelsToLongs(dpx->width * dpx->depth);
470         dpx->lineBuffer = malloc(dpx->lineBufferLength * 4);
471         if (dpx->lineBuffer == 0) {
472                 if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", dpx->lineBufferLength * 4);
473                 dpxClose(dpx);
474                 return 0;
475         }
476
477         /* could have 2 pixels left over */
478         dpx->pixelBuffer = malloc((dpx->lineBufferLength * 3 + 2) * sizeof(unsigned short));
479         if (dpx->pixelBuffer == 0) {
480                 if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
481                                 (dpx->width * dpx->depth + 2 + 2) * (int)sizeof(unsigned short));
482                 dpxClose(dpx);
483                 return 0;
484         }
485         dpx->pixelBufferUsed = 0;
486
487         if (logimage_fseek(dpx, dpx->imageOffset, SEEK_SET) != 0) {
488                 if (verbose) d_printf("Couldn't seek to image data start at %d\n", dpx->imageOffset);
489                 dpxClose(dpx);
490                 return 0;
491         }
492         dpx->fileYPos = 0;
493
494         logImageGetByteConversionDefaults(&dpx->params);
495         /* The SMPTE define this code:
496          *  0 - User-defined
497          *  1 - Printing density
498          *  2 - Linear
499          *  3 - Logarithmic
500          *  4 - Unspecified video
501          *  5 - SMPTE 240M
502          *  6 - CCIR 709-1
503          *  7 - CCIR 601-2 system B or G
504          *  8 - CCIR 601-2 system M
505          *  9 - NTSC composite video
506          *  10 - PAL composite video
507          *  11 - Z linear
508          *  12 - homogeneous
509          *
510          * Note that transfer_characteristics is U8, don't need
511          * check the byte order.
512          */
513         
514         switch (header.imageInfo.channel[0].transfer_characteristics) {
515                 case 1:
516                 case 2: /* linear */
517                         dpx->params.doLogarithm= 0;
518                         break;
519                 
520                 case 3:
521                         dpx->params.doLogarithm= 1;
522                         break;
523                 
524                 /* TODO - Unsupported, but for now just load them,
525                  * colors may look wrong, but can solve color conversion later
526                  */
527                 case 4: 
528                 case 5:
529                 case 6:
530                 case 7:
531                 case 8:
532                 case 9:
533                 case 10:
534                 case 11:
535                 case 12:
536                         if (verbose) d_printf("Un-supported Transfer Characteristics: %d using linear color conversion\n", header.imageInfo.channel[0].transfer_characteristics);
537                         dpx->params.doLogarithm= 0;
538                         break;
539                 default:
540                         if (verbose) d_printf("Un-supported Transfer Characteristics: %d\n", header.imageInfo.channel[0].transfer_characteristics);
541                         dpxClose(dpx);
542                         return 0;
543                         break;
544         }
545         setupLut(dpx);
546
547         dpx->getRow = &dpxGetRowBytes;
548         dpx->setRow = 0;
549         dpx->close = &dpxClose;
550
551         if (verbose) {
552                 verboseMe(dpx);
553         }
554
555         return dpx;
556 }
557
558 DpxFile* 
559 dpxOpen(const char *filename) {
560         return intern_dpxOpen(LFREALFILE, filename, 0);
561 }
562
563 DpxFile* 
564 dpxOpenFromMem(unsigned char *buffer, unsigned int size) {
565         return intern_dpxOpen(LFMEMFILE, (const char *) buffer, size);
566 }
567
568 int 
569 dpxIsMemFileCineon(void *buffer) {
570         int magicnum = 0;
571         magicnum = *((int*)buffer);
572         if (magicnum == ntohl(DPX_FILE_MAGIC)) return 1;
573         else return 0;
574 }
575
576 DpxFile*
577 dpxCreate(const char* filename, int width, int height, int depth) {
578
579         /* Note: always write files in network order */
580         /* By the spec, it shouldn't matter, but ... */
581
582         DpxMainHeader header;
583         const char* shortFilename = 0;
584
585         DpxFile* dpx = (DpxFile*)malloc(sizeof(DpxFile));
586         if (dpx == 0) {
587                 if (verbose) d_printf("Failed to malloc dpx file structure.\n");
588                 return 0;
589         }
590
591         memset(&header, 0, sizeof(header));
592
593         /* for close routine */
594         dpx->file = 0;
595         dpx->lineBuffer = 0;
596         dpx->pixelBuffer = 0;
597
598         dpx->file = BLI_fopen(filename, "wb");
599         if (dpx->file == 0) {
600                 if (verbose) d_printf("Couldn't open file %s\n", filename);
601                 dpxClose(dpx);
602                 return 0;
603         }
604         dpx->reading = 0;
605
606         dpx->width = width;
607         dpx->height = height;
608         dpx->depth = depth;
609         dpx->bitsPerPixel = 10;
610         dpx->imageOffset = sizeof(DpxMainHeader);
611
612         dpx->lineBufferLength = pixelsToLongs(dpx->width * dpx->depth);
613         dpx->lineBuffer = malloc(dpx->lineBufferLength * 4);
614         if (dpx->lineBuffer == 0) {
615                 if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", dpx->lineBufferLength * 4);
616                 dpxClose(dpx);
617                 return 0;
618         }
619
620         dpx->pixelBuffer = malloc((dpx->lineBufferLength * 3 + 2) * sizeof(unsigned short));
621         if (dpx->pixelBuffer == 0) {
622                 if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
623                                 (dpx->width * dpx->depth + 2 + 2) * (int)sizeof(unsigned short));
624                 dpxClose(dpx);
625                 return 0;
626         }
627         dpx->pixelBufferUsed = 0;
628
629         /* find trailing part of filename */
630         shortFilename = strrchr(filename, '/');
631         if (shortFilename == 0) {
632                 shortFilename = filename;
633         }
634         else {
635                 ++shortFilename;
636         }
637         initDpxMainHeader(dpx, &header, shortFilename);
638         logImageGetByteConversionDefaults(&dpx->params);
639         /* Need set the file type before write the header!
640          *  2 - Linear
641          *  3 - Logarithmic
642          *
643          * Note that transfer characteristics is U8, don't need
644          * check the byte order.
645          */
646         if (dpx->params.doLogarithm == 0)
647                 header.imageInfo.channel[0].transfer_characteristics= 2;
648         else
649                 header.imageInfo.channel[0].transfer_characteristics= 3;
650
651         if (fwrite(&header, sizeof(header), 1, dpx->file) == 0) {
652                 if (verbose) d_printf("Couldn't write image header\n");
653                 dpxClose(dpx);
654                 return 0;
655         }
656         dpx->fileYPos = 0;
657         setupLut(dpx);
658
659         dpx->getRow = 0;
660         dpx->setRow = &dpxSetRowBytes;
661         dpx->close = &dpxClose;
662
663         return dpx;
664 }
665
666 void
667 dpxClose(DpxFile* dpx) {
668
669         if (dpx == 0) {
670                 return;
671         }
672
673         if (dpx->file) {
674                 fclose(dpx->file);
675                 dpx->file = 0;
676         }
677
678         if (dpx->lineBuffer) {
679                 free(dpx->lineBuffer);
680                 dpx->lineBuffer = 0;
681         }
682
683         if (dpx->pixelBuffer) {
684                 free(dpx->pixelBuffer);
685                 dpx->pixelBuffer = 0;
686         }
687
688         free(dpx);
689 }
690
691 void
692 dpxDump(const char* filename) {
693
694         DpxMainHeader header;
695         FILE* file;
696
697         file = BLI_fopen(filename, "rb");
698         if (file == 0) {
699                 d_printf("Failed to open file \"%s\".\n", filename);
700                 return;
701         }
702
703         if (fread(&header, sizeof(header), 1, file) == 0) {
704                 d_printf("Not enough data for header in \"%s\".\n", filename);
705                 fclose(file);
706                 return;
707         }
708
709         fclose(file);
710         dumpDpxMainHeader(&header);
711 }