svn merge -r36583:36603 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender.git] / source / blender / imbuf / intern / cineon / cineonlib.c
1 /** \file blender/imbuf/intern/cineon/cineonlib.c
2  *  \ingroup imbcineon
3  */
4 /*
5  *       Cineon image file format library routines.
6  *
7  *       Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
8  *
9  *       This program is free software; you can redistribute it and/or modify it
10  *       under the terms of the GNU General Public License as published by the Free
11  *       Software Foundation; either version 2 of the License, or (at your option)
12  *       any later version.
13  *
14  *       This program is distributed in the hope that it will be useful, but
15  *       WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  *       or FITNESS FOR A PARTICULAR PURPOSE.    See the GNU General Public License
17  *       for more details.
18  *
19  *       You should have received a copy of the GNU General Public License
20  *       along with this program; if not, write to the Free Software
21  *       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #include "cineonlib.h"
26 #include "cineonfile.h"
27
28 #include <stdio.h>
29 #include <math.h>
30 #include <stdlib.h>
31 #include <time.h>                                /* strftime() */
32 #include <sys/types.h>
33 #ifdef WIN32
34 #include <winsock.h>
35 #else
36 #include <netinet/in.h>  /* htonl() */
37 #endif
38 #include <string.h>                      /* memset */
39 #include "cin_debug_stuff.h"
40 #include "logmemfile.h"
41
42 static void
43 fillCineonFileInfo(CineonFile* cineon, CineonFileInformation* fileInfo, const char* filename) {
44
45         time_t fileClock;
46         struct tm* fileTime;
47
48         fileInfo->magic_num = htonl(CINEON_FILE_MAGIC);
49         fileInfo->image_offset = htonl(cineon->imageOffset);
50         fileInfo->gen_hdr_size = htonl(
51                 sizeof(CineonFileInformation) +
52                 sizeof(CineonImageInformation) +
53                 sizeof(CineonFormatInformation) +
54                 sizeof(CineonOriginationInformation));
55         fileInfo->ind_hdr_size = 0;
56         fileInfo->user_data_size = 0;
57         fileInfo->file_size = htonl(cineon->imageOffset + cineon->height * cineon->lineBufferLength);
58         strcpy(fileInfo->vers, "V4.5");
59         strncpy(fileInfo->file_name, filename, 99);
60         fileInfo->file_name[99] = 0;
61
62         fileClock = time(0);
63         fileTime = localtime(&fileClock);
64         strftime(fileInfo->create_date, 12, "%Y:%m:%d", fileTime);
65         /* Question: is %Z in strftime guaranteed to return 3 chars? */
66         strftime(fileInfo->create_time, 12, "%H:%M:%S%Z", fileTime);
67         fileInfo->create_time[11] = 0;
68 }
69
70 static void
71 dumpCineonFileInfo(CineonFileInformation* fileInfo) {
72         d_printf("\n--File Information--\n");
73         d_printf("Magic: %8.8lX\n", (uintptr_t)ntohl(fileInfo->magic_num));
74         d_printf("Image Offset %ld\n", (intptr_t)ntohl(fileInfo->image_offset));
75         d_printf("Generic Header size %ld\n", (intptr_t)ntohl(fileInfo->gen_hdr_size));
76         d_printf("Industry Header size %ld\n", (intptr_t)ntohl(fileInfo->ind_hdr_size));
77         d_printf("User Data size %ld\n", (intptr_t)ntohl(fileInfo->user_data_size));
78         d_printf("File size %ld\n", (intptr_t)ntohl(fileInfo->file_size));
79         d_printf("Version \"%s\"\n", fileInfo->vers);
80         d_printf("File name \"%s\"\n", fileInfo->file_name);
81         d_printf("Creation date \"%s\"\n", fileInfo->create_date);
82         d_printf("Creation time \"%s\"\n", fileInfo->create_time);
83 }
84
85 static void
86 fillCineonChannelInfo(CineonFile* cineon, CineonChannelInformation* chan, int des) {
87
88         chan->designator1 = 0;
89         chan->designator2 = des;
90         chan->bits_per_pixel = 10;
91         chan->pixels_per_line = htonl(cineon->width);
92         chan->lines_per_image = htonl(cineon->height);
93         chan->ref_low_data = htonl(0);
94         chan->ref_low_quantity = htonf(0.0);
95         chan->ref_high_data = htonl(1023);
96         chan->ref_high_quantity = htonf(2.046);
97 }
98
99 static void
100 dumpCineonChannelInfo(CineonChannelInformation* chan) {
101         d_printf("      Metric selector: %d", chan->designator1);
102         switch (chan->designator1) {
103                 case 0: d_printf(" (Universal)\n"); break;
104                 default: d_printf(" (Vendor specific)\n"); break;
105         }
106         d_printf("      Metric: %d,", chan->designator2);
107         switch (chan->designator2) {
108                 case 0: d_printf(" B&W (printing density?)\n"); break;
109                 case 1: d_printf(" Red printing density\n"); break;
110                 case 2: d_printf(" Green printing density\n"); break;
111                 case 3: d_printf(" Blue printing density\n"); break;
112                 case 4: d_printf(" Red CCIR XA/11\n"); break;
113                 case 5: d_printf(" Green CCIR XA/11\n"); break;
114                 case 6: d_printf(" Blue CCIR XA/11\n"); break;
115                 default: d_printf(" (unknown)\n"); break;
116         }
117         d_printf("      Bits per pixel %d\n", chan->bits_per_pixel);
118         d_printf("      Pixels per line %ld\n", (intptr_t)ntohl(chan->pixels_per_line));
119         d_printf("      Lines per image %ld\n", (intptr_t)ntohl(chan->lines_per_image));
120         d_printf("      Ref low data %ld\n", (intptr_t)ntohl(chan->ref_low_data));
121         d_printf("      Ref low quantity %f\n", ntohf(chan->ref_low_quantity));
122         d_printf("      Ref high data %ld\n", (intptr_t)ntohl(chan->ref_high_data));
123         d_printf("      Ref high quantity %f\n", ntohf(chan->ref_high_quantity));
124 }
125
126 static void
127 fillCineonImageInfo(CineonFile* cineon, CineonImageInformation* imageInfo) {
128
129         imageInfo->orientation = 0;
130         imageInfo->channels_per_image = cineon->depth;
131
132         if (cineon->depth == 1) {
133                 fillCineonChannelInfo(cineon, &imageInfo->channel[0], 0);
134
135         } else if (cineon->depth == 3) {
136                 fillCineonChannelInfo(cineon, &imageInfo->channel[0], 1);
137                 fillCineonChannelInfo(cineon, &imageInfo->channel[1], 2);
138                 fillCineonChannelInfo(cineon, &imageInfo->channel[2], 3);
139         }
140
141         imageInfo->white_point_x = htonf(undefined());
142         imageInfo->white_point_y = htonf(undefined());
143         imageInfo->red_primary_x = htonf(undefined());
144         imageInfo->red_primary_y = htonf(undefined());
145         imageInfo->green_primary_x = htonf(undefined());
146         imageInfo->green_primary_y = htonf(undefined());
147         imageInfo->blue_primary_x = htonf(undefined());
148         imageInfo->blue_primary_y = htonf(undefined());
149
150         strcpy(imageInfo->label, "David's Cineon writer.");
151
152 }
153
154 static void
155 dumpCineonImageInfo(CineonImageInformation* imageInfo) {
156
157         int i;
158         d_printf("\n--Image Information--\n");
159         d_printf("Image orientation %d,", imageInfo->orientation);
160         switch (imageInfo->orientation) {
161                 case 0: d_printf(" LRTB\n"); break;
162                 case 1: d_printf(" LRBT\n"); break;
163                 case 2: d_printf(" RLTB\n"); break;
164                 case 3: d_printf(" RLBT\n"); break;
165                 case 4: d_printf(" TBLR\n"); break;
166                 case 5: d_printf(" TBRL\n"); break;
167                 case 6: d_printf(" BTLR\n"); break;
168                 case 7: d_printf(" BTRL\n"); break;
169                 default: d_printf(" (unknown)\n"); break;
170         }
171         d_printf("Channels %d\n", imageInfo->channels_per_image);
172         for (i = 0; i < imageInfo->channels_per_image; ++i) {
173                 d_printf("      --Channel %d--\n", i);
174                 dumpCineonChannelInfo(&imageInfo->channel[i]);
175         }
176
177         d_printf("White point x %f\n", ntohf(imageInfo->white_point_x));
178         d_printf("White point y %f\n", ntohf(imageInfo->white_point_y));
179         d_printf("Red primary x %f\n", ntohf(imageInfo->red_primary_x));
180         d_printf("Red primary y %f\n", ntohf(imageInfo->red_primary_y));
181         d_printf("Green primary x %f\n", ntohf(imageInfo->green_primary_x));
182         d_printf("Green primary y %f\n", ntohf(imageInfo->green_primary_y));
183         d_printf("Blue primary x %f\n", ntohf(imageInfo->blue_primary_x));
184         d_printf("Blue primary y %f\n", ntohf(imageInfo->blue_primary_y));
185         d_printf("Label \"%s\"\n", imageInfo->label);
186 }
187
188 static void
189 fillCineonFormatInfo(CineonFile* cineon, CineonFormatInformation* formatInfo) {
190
191         (void)cineon; /* unused */
192         
193         formatInfo->interleave = 0;
194         formatInfo->packing = 5;
195         formatInfo->signage = 0;
196         formatInfo->sense = 0;
197         formatInfo->line_padding = htonl(0);
198         formatInfo->channel_padding = htonl(0);
199 }
200
201 static void
202 dumpCineonFormatInfo(CineonFormatInformation* formatInfo) {
203         d_printf("\n--Format Information--\n");
204         d_printf("Interleave %d,", formatInfo->interleave);
205         switch (formatInfo->interleave) {
206                 case 0: d_printf(" pixel interleave\n"); break;
207                 case 1: d_printf(" line interleave\n"); break;
208                 case 2: d_printf(" channel interleave\n"); break;
209                 default: d_printf(" (unknown)\n"); break;
210         }
211         d_printf("Packing %d,", formatInfo->packing);
212         if (formatInfo->packing & 0x80) { 
213                 d_printf(" multi pixel,");
214         } else {
215                 d_printf(" single pixel,");
216         }
217         switch (formatInfo->packing & 0x7F) {
218                 case 0: d_printf(" tight\n"); break;
219                 case 1: d_printf(" byte packed left\n"); break;
220                 case 2: d_printf(" byte packed right\n"); break;
221                 case 3: d_printf(" word packed left\n"); break;
222                 case 4: d_printf(" word packed right\n"); break;
223                 case 5: d_printf(" long packed left\n"); break;
224                 case 6: d_printf(" long packed right\n"); break;
225                 default: d_printf(" (unknown)\n"); break;
226         }
227         d_printf("Sign %d,", formatInfo->signage);
228         if (formatInfo->signage) { 
229                 d_printf(" signed\n");
230         } else {
231                 d_printf(" unsigned\n");
232         }
233         d_printf("Sense %d,", formatInfo->signage);
234         if (formatInfo->signage) { 
235                 d_printf(" negative\n");
236         } else {
237                 d_printf(" positive\n");
238         }
239         d_printf("End of line padding %ld\n", (intptr_t)ntohl(formatInfo->line_padding));
240         d_printf("End of channel padding %ld\n", (intptr_t)ntohl(formatInfo->channel_padding));
241 }
242
243 static void
244 fillCineonOriginationInfo(CineonFile* cineon,
245         CineonOriginationInformation* originInfo, CineonFileInformation* fileInfo) {
246         
247         (void)cineon; /* unused */
248
249         originInfo->x_offset = htonl(0);
250         originInfo->y_offset = htonl(0);
251         strcpy(originInfo->file_name, fileInfo->file_name);
252         strcpy(originInfo->create_date, fileInfo->create_date);
253         strcpy(originInfo->create_time, fileInfo->create_time);
254         strncpy(originInfo->input_device, "David's Cineon writer", 64);
255         strncpy(originInfo->model_number, "Software", 32);
256         strncpy(originInfo->serial_number, "001", 32);
257         originInfo->x_input_samples_per_mm = htonf(undefined());
258         originInfo->y_input_samples_per_mm =    htonf(undefined());
259         /* this should probably be undefined, too */
260         originInfo->input_device_gamma = htonf(1.0);
261 }
262
263 static void
264 dumpCineonOriginationInfo(CineonOriginationInformation* originInfo) {
265         d_printf("\n--Origination Information--\n");
266         d_printf("X offset %ld\n", (intptr_t)ntohl(originInfo->x_offset));
267         d_printf("Y offset %ld\n", (intptr_t)ntohl(originInfo->y_offset));
268         d_printf("File name \"%s\"\n", originInfo->file_name);
269         d_printf("Creation date \"%s\"\n", originInfo->create_date);
270         d_printf("Creation time \"%s\"\n", originInfo->create_time);
271         d_printf("Input device \"%s\"\n", originInfo->input_device);
272         d_printf("Model number \"%s\"\n", originInfo->model_number);
273         d_printf("Serial number \"%s\"\n", originInfo->serial_number);
274         d_printf("Samples per mm in x %f\n", ntohf(originInfo->x_input_samples_per_mm));
275         d_printf("Samples per mm in y %f\n", ntohf(originInfo->y_input_samples_per_mm));
276         d_printf("Input device gamma %f\n", ntohf(originInfo->input_device_gamma));
277 }
278
279 static int
280 initCineonGenericHeader(CineonFile* cineon, CineonGenericHeader* header, const char* imagename) {
281
282         fillCineonFileInfo(cineon, &header->fileInfo, imagename);
283         fillCineonImageInfo(cineon, &header->imageInfo);
284         fillCineonFormatInfo(cineon, &header->formatInfo);
285         fillCineonOriginationInfo(cineon, &header->originInfo, &header->fileInfo);
286
287         return 0;
288 }
289
290 static void
291 dumpCineonGenericHeader(CineonGenericHeader* header) {
292         dumpCineonFileInfo(&header->fileInfo);
293         dumpCineonImageInfo(&header->imageInfo);
294         dumpCineonFormatInfo(&header->formatInfo);
295         dumpCineonOriginationInfo(&header->originInfo);
296 }
297
298 static int verbose = 0;
299 void
300 cineonSetVerbose(int verbosity) {
301         verbose = verbosity;
302 }
303
304 static void
305 verboseMe(CineonFile* cineon) {
306
307         d_printf("size %d x %d x %d\n", cineon->width, cineon->height, cineon->depth);
308         d_printf("ImageStart %d, lineBufferLength %d, implied length %d\n",
309                 cineon->imageOffset, cineon->lineBufferLength * 4,
310                 cineon->imageOffset + cineon->lineBufferLength * 4 * cineon->height);
311 }
312
313 int
314 cineonGetRowBytes(CineonFile* cineon, unsigned short* row, int y) {
315
316         int longsRead;
317         int pixelIndex;
318         int longIndex;
319         int numPixels = cineon->width * cineon->depth;
320
321
322         /* only seek if not reading consecutive lines */
323         if (y != cineon->fileYPos) {
324                 int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
325                 if (verbose) d_printf("Seek in getRowBytes\n");
326                 if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
327                         if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
328                         return 1;
329                 }
330                 cineon->fileYPos = y;
331         }
332
333         longsRead = logimage_fread(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon);
334         if (longsRead != cineon->lineBufferLength) {
335                 if (verbose) 
336         {       d_printf("Couldn't read line %d length %d\n", y, cineon->lineBufferLength * 4);
337                 perror("cineonGetRowBytes");
338         }
339                 return 1;
340         }
341
342         /* remember where we left the car, honey */
343         ++cineon->fileYPos;
344
345         /* convert longwords to pixels */
346         pixelIndex = 0;
347         for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
348                 unsigned int t = ntohl(cineon->lineBuffer[longIndex]);
349                 t = t >> 2;
350                 cineon->pixelBuffer[pixelIndex+2] = (unsigned short) t & 0x3ff;
351                 t = t >> 10;
352                 cineon->pixelBuffer[pixelIndex+1] = (unsigned short) t & 0x3ff;
353                 t = t >> 10;
354                 cineon->pixelBuffer[pixelIndex] = (unsigned short) t & 0x3ff;
355                 pixelIndex += 3;
356         }
357
358         /* extract required pixels */
359         for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
360                 if(cineon->params.doLogarithm)
361                         row[pixelIndex] = cineon->lut10_16[cineon->pixelBuffer[pixelIndex]];
362                 else
363                         row[pixelIndex] = cineon->pixelBuffer[pixelIndex] << 6;
364         }
365
366         return 0;
367 }
368
369 int
370 cineonSetRowBytes(CineonFile* cineon, const unsigned short* row, int y) {
371
372         int pixelIndex;
373         int numPixels = cineon->width * cineon->depth;
374         int longIndex;
375         int longsWritten;
376
377         /* put new pixels into pixelBuffer */
378         for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
379                 if(cineon->params.doLogarithm)
380                         cineon->pixelBuffer[pixelIndex] = cineon->lut16_16[row[pixelIndex]];
381                 else
382                         cineon->pixelBuffer[pixelIndex] = row[pixelIndex] >> 6;
383         }
384
385         /* pack into longwords */
386         pixelIndex = 0;
387         for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
388                 unsigned int t =
389                                 (cineon->pixelBuffer[pixelIndex] << 22) |
390                                 (cineon->pixelBuffer[pixelIndex+1] << 12) |
391                                 (cineon->pixelBuffer[pixelIndex+2] << 2);
392                 cineon->lineBuffer[longIndex] = htonl(t);
393                 pixelIndex += 3;
394         }
395
396         /* only seek if not reading consecutive lines */
397         if (y != cineon->fileYPos) {
398                 int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
399                 if (verbose) d_printf("Seek in setRowBytes\n");
400                 if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
401                         if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
402                         return 1;
403                 }
404                 cineon->fileYPos = y;
405         }
406
407         longsWritten = fwrite(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon->file);
408         if (longsWritten != cineon->lineBufferLength) {
409                 if (verbose) d_printf("Couldn't write line %d length %d\n", y, cineon->lineBufferLength * 4);
410                 return 1;
411         }
412
413         ++cineon->fileYPos;
414
415         return 0;
416 }
417
418 int
419 cineonGetRow(CineonFile* cineon, unsigned short* row, int y) {
420
421         int longsRead;
422         int pixelIndex;
423         int longIndex;
424 /*      int numPixels = cineon->width * cineon->depth;
425 */
426         /* only seek if not reading consecutive lines */
427         if (y != cineon->fileYPos) {
428                 int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
429                 if (verbose) d_printf("Seek in getRow\n");
430                 if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
431                         if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
432                         return 1;
433                 }
434                 cineon->fileYPos = y;
435         }
436
437         longsRead = logimage_fread(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon);
438         if (longsRead != cineon->lineBufferLength) {
439                 if (verbose) d_printf("Couldn't read line %d length %d\n", y, cineon->lineBufferLength * 4);
440                 return 1;
441         }
442
443         /* remember where we left the car, honey */
444         ++cineon->fileYPos;
445
446         /* convert longwords to pixels */
447         pixelIndex = 0;
448         for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
449                 unsigned int t = ntohl(cineon->lineBuffer[longIndex]);
450                 t = t >> 2;
451                 row[pixelIndex+2] = (unsigned short) t & 0x3ff;
452                 t = t >> 10;
453                 row[pixelIndex+1] = (unsigned short) t & 0x3ff;
454                 t = t >> 10;
455                 row[pixelIndex] = (unsigned short) t & 0x3ff;
456                 pixelIndex += 3;
457         }
458
459         return 0;
460 }
461
462 int
463 cineonSetRow(CineonFile* cineon, const unsigned short* row, int y) {
464
465         int pixelIndex;
466 /*      int numPixels = cineon->width * cineon->depth;
467 */      int longIndex;
468         int longsWritten;
469
470         /* pack into longwords */
471         pixelIndex = 0;
472         for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
473                 unsigned int t =
474                                 (row[pixelIndex] << 22) |
475                                 (row[pixelIndex+1] << 12) |
476                                 (row[pixelIndex+2] << 2);
477                 cineon->lineBuffer[longIndex] = htonl(t);
478                 pixelIndex += 3;
479         }
480
481         /* only seek if not reading consecutive lines */
482         if (y != cineon->fileYPos) {
483                 int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
484                 if (verbose) d_printf("Seek in setRowBytes\n");
485                 if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
486                         if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
487                         return 1;
488                 }
489                 cineon->fileYPos = y;
490         }
491
492         longsWritten = fwrite(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon->file);
493         if (longsWritten != cineon->lineBufferLength) {
494                 if (verbose) d_printf("Couldn't write line %d length %d\n", y, cineon->lineBufferLength * 4);
495                 return 1;
496         }
497
498         ++cineon->fileYPos;
499
500         return 0;
501 }
502
503 CineonFile* 
504 cineonOpen(const char* filename) {
505
506         CineonGenericHeader header;
507
508         CineonFile* cineon = (CineonFile* )malloc(sizeof(CineonFile));
509         if (cineon == 0) {
510                 if (verbose) d_printf("Failed to malloc cineon file structure.\n");
511                 return 0;
512         }
513
514         /* for close routine */
515         cineon->file = 0;
516         cineon->lineBuffer = 0;
517         cineon->pixelBuffer = 0;
518         cineon->membuffer = 0;
519         cineon->memcursor = 0;
520         cineon->membuffersize = 0;
521         
522         cineon->file = fopen(filename, "rb");
523         if (cineon->file == 0) {
524                 if (verbose) d_printf("Failed to open file \"%s\".\n", filename);
525                 cineonClose(cineon);
526                 return 0;
527         }
528         cineon->reading = 1;
529
530         if (logimage_fread(&header, sizeof(CineonGenericHeader), 1, cineon) == 0) {
531                 if (verbose) d_printf("Not enough data for header in \"%s\".\n", filename);
532                 cineonClose(cineon);
533                 return 0;
534         }
535
536         /* let's assume cineon files are always network order */
537         if (header.fileInfo.magic_num != ntohl(CINEON_FILE_MAGIC)) {
538                 if (verbose) d_printf("Bad magic number %8.8lX in \"%s\".\n",
539                         (uintptr_t)ntohl(header.fileInfo.magic_num), filename);
540                 cineonClose(cineon);
541                 return 0;
542         }
543
544         if (header.formatInfo.packing != 5) {
545                 if (verbose) d_printf("Can't understand packing %d\n", header.formatInfo.packing);
546                 cineonClose(cineon);
547                 return 0;
548         }
549
550         cineon->width = ntohl(header.imageInfo.channel[0].pixels_per_line);
551         cineon->height = ntohl(header.imageInfo.channel[0].lines_per_image);
552         cineon->depth = header.imageInfo.channels_per_image;
553         /* cineon->bitsPerPixel = 10; */
554         cineon->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel;
555         cineon->imageOffset = ntohl(header.fileInfo.image_offset);
556
557         cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth);
558         cineon->lineBuffer = malloc(cineon->lineBufferLength * 4);
559         if (cineon->lineBuffer == 0) {
560                 if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4);
561                 cineonClose(cineon);
562                 return 0;
563         }
564
565         cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short));
566         if (cineon->pixelBuffer == 0) {
567                 if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
568                                 (cineon->width * cineon->depth) * (int)sizeof(unsigned short));
569                 cineonClose(cineon);
570                 return 0;
571         }
572         cineon->pixelBufferUsed = 0;
573
574         if (logimage_fseek(cineon, cineon->imageOffset, SEEK_SET) != 0) {
575                 if (verbose) d_printf("Couldn't seek to image data at %d\n", cineon->imageOffset);
576                 cineonClose(cineon);
577                 return 0;
578         }
579         cineon->fileYPos = 0;
580
581         logImageGetByteConversionDefaults(&cineon->params);
582         setupLut(cineon);
583
584         cineon->getRow = &cineonGetRowBytes;
585         cineon->setRow = 0;
586         cineon->close = &cineonClose;
587
588         if (verbose) {
589                 verboseMe(cineon);
590         }
591
592         return cineon;
593 }
594
595 int cineonIsMemFileCineon(unsigned char *mem)
596 {
597         unsigned int num;
598         memcpy(&num, mem, sizeof(unsigned int));
599         
600         if (num != ntohl(CINEON_FILE_MAGIC)) {
601                 return 0;
602         } else return 1;
603 }
604
605 CineonFile* 
606 cineonOpenFromMem(unsigned char *mem, unsigned int size) {
607
608         CineonGenericHeader header;
609         
610         CineonFile* cineon = (CineonFile* )malloc(sizeof(CineonFile));
611         if (cineon == 0) {
612                 if (verbose) d_printf("Failed to malloc cineon file structure.\n");
613                 return 0;
614         }
615
616         /* for close routine */
617         cineon->file = 0;
618         cineon->lineBuffer = 0;
619         cineon->pixelBuffer = 0;
620         cineon->membuffer = mem;
621         cineon->membuffersize = size;
622         cineon->memcursor = mem;
623         
624         cineon->file = 0;
625         cineon->reading = 1;
626         verbose = 0;
627         if (size < sizeof(CineonGenericHeader)) {
628                 if (verbose) d_printf("Not enough data for header!\n");
629                 cineonClose(cineon);
630                 return 0;
631         }
632
633         logimage_fread(&header, sizeof(CineonGenericHeader), 1, cineon);
634
635         /* let's assume cineon files are always network order */
636         if (header.fileInfo.magic_num != ntohl(CINEON_FILE_MAGIC)) {
637                 if (verbose) d_printf("Bad magic number %8.8lX in\n", (uintptr_t)ntohl(header.fileInfo.magic_num));
638
639                 cineonClose(cineon);
640                 return 0;
641         }
642
643         if (header.formatInfo.packing != 5) {
644                 if (verbose) d_printf("Can't understand packing %d\n", header.formatInfo.packing);
645                 cineonClose(cineon);
646                 return 0;
647         }
648
649         cineon->width = ntohl(header.imageInfo.channel[0].pixels_per_line);
650         cineon->height = ntohl(header.imageInfo.channel[0].lines_per_image);
651         cineon->depth = header.imageInfo.channels_per_image;
652         /* cineon->bitsPerPixel = 10; */
653         cineon->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel;
654         cineon->imageOffset = ntohl(header.fileInfo.image_offset);
655
656         cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth);
657         cineon->lineBuffer = malloc(cineon->lineBufferLength * 4);
658         if (cineon->lineBuffer == 0) {
659                 if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4);
660                 cineonClose(cineon);
661                 return 0;
662         }
663
664         cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short));
665         if (cineon->pixelBuffer == 0) {
666                 if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
667                                 (cineon->width * cineon->depth) * (int)sizeof(unsigned short));
668                 cineonClose(cineon);
669                 return 0;
670         }
671         cineon->pixelBufferUsed = 0;
672         
673         if (logimage_fseek(cineon, cineon->imageOffset, SEEK_SET) != 0) {
674                 if (verbose) d_printf("Couldn't seek to image data at %d\n", cineon->imageOffset);
675                 cineonClose(cineon);
676                 return 0;
677         }
678         
679         cineon->fileYPos = 0;
680
681         logImageGetByteConversionDefaults(&cineon->params);
682         setupLut(cineon);
683
684         cineon->getRow = &cineonGetRowBytes;
685         cineon->setRow = 0;
686         cineon->close = &cineonClose;
687
688         if (verbose) {
689                 verboseMe(cineon);
690         }
691
692         return cineon;
693 }
694
695
696 int
697 cineonGetSize(const CineonFile* cineon, int* width, int* height, int* depth) {
698         *width = cineon->width;
699         *height = cineon->height;
700         *depth = cineon->depth;
701         return 0;
702 }
703
704 CineonFile*
705 cineonCreate(const char* filename, int width, int height, int depth) {
706
707         /* Note: always write files in network order */
708         /* By the spec, it shouldn't matter, but ... */
709
710         CineonGenericHeader header;
711         const char* shortFilename = 0;
712
713         CineonFile* cineon = (CineonFile*)malloc(sizeof(CineonFile));
714         if (cineon == 0) {
715                 if (verbose) d_printf("Failed to malloc cineon file structure.\n");
716                 return 0;
717         }
718
719         memset(&header, 0, sizeof(header));
720
721         /* for close routine */
722         cineon->file = 0;
723         cineon->lineBuffer = 0;
724         cineon->pixelBuffer = 0;
725
726         cineon->file = fopen(filename, "wb");
727         if (cineon->file == 0) {
728                 if (verbose) d_printf("Couldn't open file %s\n", filename);
729                 cineonClose(cineon);
730                 return 0;
731         }
732         cineon->reading = 0;
733
734         cineon->width = width;
735         cineon->height = height;
736         cineon->depth = depth;
737         cineon->bitsPerPixel = 10;
738         cineon->imageOffset = sizeof(CineonGenericHeader);
739
740         cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth);
741         cineon->lineBuffer = malloc(cineon->lineBufferLength * 4);
742         if (cineon->lineBuffer == 0) {
743                 if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4);
744                 cineonClose(cineon);
745                 return 0;
746         }
747
748         cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short));
749         if (cineon->pixelBuffer == 0) {
750                 if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
751                                 (cineon->width * cineon->depth) * (int)sizeof(unsigned short));
752                 cineonClose(cineon);
753                 return 0;
754         }
755         cineon->pixelBufferUsed = 0;
756
757         /* find trailing part of filename */
758         shortFilename = strrchr(filename, '/');
759         if (shortFilename == 0) {
760                 shortFilename = filename;
761         } else {
762                 ++shortFilename;
763         }
764
765         if (initCineonGenericHeader(cineon, &header, shortFilename) != 0) {
766                 cineonClose(cineon);
767                 return 0;
768         }
769
770         if (fwrite(&header, sizeof(header), 1, cineon->file) == 0) {
771                 if (verbose) d_printf("Couldn't write image header\n");
772                 cineonClose(cineon);
773                 return 0;
774         }
775         cineon->fileYPos = 0;
776
777         logImageGetByteConversionDefaults(&cineon->params);
778         setupLut(cineon);
779
780         cineon->getRow = 0;
781         cineon->setRow = &cineonSetRowBytes;
782         cineon->close = &cineonClose;
783
784         return cineon;
785 }
786
787 void
788 cineonClose(CineonFile* cineon) {
789
790         if (cineon == 0) {
791                 return;
792         }
793
794         if (cineon->file) {
795                 fclose(cineon->file);
796                 cineon->file = 0;
797         }
798
799         if (cineon->lineBuffer) {
800                 free(cineon->lineBuffer);
801                 cineon->lineBuffer = 0;
802         }
803
804         if (cineon->pixelBuffer) {
805                 free(cineon->pixelBuffer);
806                 cineon->pixelBuffer = 0;
807         }
808
809         free(cineon);
810 }