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