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