style cleanup, brackets in else/if, some indentation.
[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
343                 return 1;
344         }
345
346         /* remember where we left the car, honey */
347         ++cineon->fileYPos;
348
349         /* convert longwords to pixels */
350         pixelIndex = 0;
351         for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
352                 unsigned int t = ntohl(cineon->lineBuffer[longIndex]);
353                 t = t >> 2;
354                 cineon->pixelBuffer[pixelIndex+2] = (unsigned short) t & 0x3ff;
355                 t = t >> 10;
356                 cineon->pixelBuffer[pixelIndex+1] = (unsigned short) t & 0x3ff;
357                 t = t >> 10;
358                 cineon->pixelBuffer[pixelIndex] = (unsigned short) t & 0x3ff;
359                 pixelIndex += 3;
360         }
361
362         /* extract required pixels */
363         for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
364                 if(cineon->params.doLogarithm)
365                         row[pixelIndex] = cineon->lut10_16[cineon->pixelBuffer[pixelIndex]];
366                 else
367                         row[pixelIndex] = cineon->pixelBuffer[pixelIndex] << 6;
368         }
369
370         return 0;
371 }
372
373 int
374 cineonSetRowBytes(CineonFile* cineon, const unsigned short* row, int y) {
375
376         int pixelIndex;
377         int numPixels = cineon->width * cineon->depth;
378         int longIndex;
379         int longsWritten;
380
381         /* put new pixels into pixelBuffer */
382         for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
383                 if(cineon->params.doLogarithm)
384                         cineon->pixelBuffer[pixelIndex] = cineon->lut16_16[row[pixelIndex]];
385                 else
386                         cineon->pixelBuffer[pixelIndex] = row[pixelIndex] >> 6;
387         }
388
389         /* pack into longwords */
390         pixelIndex = 0;
391         for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
392                 unsigned int t =
393                                 (cineon->pixelBuffer[pixelIndex] << 22) |
394                                 (cineon->pixelBuffer[pixelIndex+1] << 12) |
395                                 (cineon->pixelBuffer[pixelIndex+2] << 2);
396                 cineon->lineBuffer[longIndex] = htonl(t);
397                 pixelIndex += 3;
398         }
399
400         /* only seek if not reading consecutive lines */
401         if (y != cineon->fileYPos) {
402                 int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
403                 if (verbose) d_printf("Seek in setRowBytes\n");
404                 if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
405                         if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
406                         return 1;
407                 }
408                 cineon->fileYPos = y;
409         }
410
411         longsWritten = fwrite(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon->file);
412         if (longsWritten != cineon->lineBufferLength) {
413                 if (verbose) d_printf("Couldn't write line %d length %d\n", y, cineon->lineBufferLength * 4);
414                 return 1;
415         }
416
417         ++cineon->fileYPos;
418
419         return 0;
420 }
421
422 int
423 cineonGetRow(CineonFile* cineon, unsigned short* row, int y) {
424
425         int longsRead;
426         int pixelIndex;
427         int longIndex;
428 /*      int numPixels = cineon->width * cineon->depth;
429 */
430         /* only seek if not reading consecutive lines */
431         if (y != cineon->fileYPos) {
432                 int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
433                 if (verbose) d_printf("Seek in getRow\n");
434                 if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
435                         if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
436                         return 1;
437                 }
438                 cineon->fileYPos = y;
439         }
440
441         longsRead = logimage_fread(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon);
442         if (longsRead != cineon->lineBufferLength) {
443                 if (verbose) d_printf("Couldn't read line %d length %d\n", y, cineon->lineBufferLength * 4);
444                 return 1;
445         }
446
447         /* remember where we left the car, honey */
448         ++cineon->fileYPos;
449
450         /* convert longwords to pixels */
451         pixelIndex = 0;
452         for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
453                 unsigned int t = ntohl(cineon->lineBuffer[longIndex]);
454                 t = t >> 2;
455                 row[pixelIndex+2] = (unsigned short) t & 0x3ff;
456                 t = t >> 10;
457                 row[pixelIndex+1] = (unsigned short) t & 0x3ff;
458                 t = t >> 10;
459                 row[pixelIndex] = (unsigned short) t & 0x3ff;
460                 pixelIndex += 3;
461         }
462
463         return 0;
464 }
465
466 int
467 cineonSetRow(CineonFile* cineon, const unsigned short* row, int y) {
468
469         int pixelIndex;
470 /*      int numPixels = cineon->width * cineon->depth;
471 */      int longIndex;
472         int longsWritten;
473
474         /* pack into longwords */
475         pixelIndex = 0;
476         for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
477                 unsigned int t =
478                                 (row[pixelIndex] << 22) |
479                                 (row[pixelIndex+1] << 12) |
480                                 (row[pixelIndex+2] << 2);
481                 cineon->lineBuffer[longIndex] = htonl(t);
482                 pixelIndex += 3;
483         }
484
485         /* only seek if not reading consecutive lines */
486         if (y != cineon->fileYPos) {
487                 int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
488                 if (verbose) d_printf("Seek in setRowBytes\n");
489                 if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
490                         if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
491                         return 1;
492                 }
493                 cineon->fileYPos = y;
494         }
495
496         longsWritten = fwrite(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon->file);
497         if (longsWritten != cineon->lineBufferLength) {
498                 if (verbose) d_printf("Couldn't write line %d length %d\n", y, cineon->lineBufferLength * 4);
499                 return 1;
500         }
501
502         ++cineon->fileYPos;
503
504         return 0;
505 }
506
507 CineonFile* 
508 cineonOpen(const char* filename) {
509
510         CineonGenericHeader header;
511
512         CineonFile* cineon = (CineonFile* )malloc(sizeof(CineonFile));
513         if (cineon == 0) {
514                 if (verbose) d_printf("Failed to malloc cineon file structure.\n");
515                 return 0;
516         }
517
518         /* for close routine */
519         cineon->file = 0;
520         cineon->lineBuffer = 0;
521         cineon->pixelBuffer = 0;
522         cineon->membuffer = 0;
523         cineon->memcursor = 0;
524         cineon->membuffersize = 0;
525         
526         cineon->file = fopen(filename, "rb");
527         if (cineon->file == 0) {
528                 if (verbose) d_printf("Failed to open file \"%s\".\n", filename);
529                 cineonClose(cineon);
530                 return 0;
531         }
532         cineon->reading = 1;
533
534         if (logimage_fread(&header, sizeof(CineonGenericHeader), 1, cineon) == 0) {
535                 if (verbose) d_printf("Not enough data for header in \"%s\".\n", filename);
536                 cineonClose(cineon);
537                 return 0;
538         }
539
540         /* let's assume cineon files are always network order */
541         if (header.fileInfo.magic_num != ntohl(CINEON_FILE_MAGIC)) {
542                 if (verbose) d_printf("Bad magic number %8.8lX in \"%s\".\n",
543                         (uintptr_t)ntohl(header.fileInfo.magic_num), filename);
544                 cineonClose(cineon);
545                 return 0;
546         }
547
548         if (header.formatInfo.packing != 5) {
549                 if (verbose) d_printf("Can't understand packing %d\n", header.formatInfo.packing);
550                 cineonClose(cineon);
551                 return 0;
552         }
553
554         cineon->width = ntohl(header.imageInfo.channel[0].pixels_per_line);
555         cineon->height = ntohl(header.imageInfo.channel[0].lines_per_image);
556         cineon->depth = header.imageInfo.channels_per_image;
557         /* cineon->bitsPerPixel = 10; */
558         cineon->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel;
559         cineon->imageOffset = ntohl(header.fileInfo.image_offset);
560
561         cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth);
562         cineon->lineBuffer = malloc(cineon->lineBufferLength * 4);
563         if (cineon->lineBuffer == 0) {
564                 if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4);
565                 cineonClose(cineon);
566                 return 0;
567         }
568
569         cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short));
570         if (cineon->pixelBuffer == 0) {
571                 if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
572                                 (cineon->width * cineon->depth) * (int)sizeof(unsigned short));
573                 cineonClose(cineon);
574                 return 0;
575         }
576         cineon->pixelBufferUsed = 0;
577
578         if (logimage_fseek(cineon, cineon->imageOffset, SEEK_SET) != 0) {
579                 if (verbose) d_printf("Couldn't seek to image data at %d\n", cineon->imageOffset);
580                 cineonClose(cineon);
581                 return 0;
582         }
583         cineon->fileYPos = 0;
584
585         logImageGetByteConversionDefaults(&cineon->params);
586         setupLut(cineon);
587
588         cineon->getRow = &cineonGetRowBytes;
589         cineon->setRow = 0;
590         cineon->close = &cineonClose;
591
592         if (verbose) {
593                 verboseMe(cineon);
594         }
595
596         return cineon;
597 }
598
599 int cineonIsMemFileCineon(unsigned char *mem)
600 {
601         unsigned int num;
602         memcpy(&num, mem, sizeof(unsigned int));
603         
604         if (num != ntohl(CINEON_FILE_MAGIC)) {
605                 return 0;
606         } else return 1;
607 }
608
609 CineonFile* 
610 cineonOpenFromMem(unsigned char *mem, unsigned int size) {
611
612         CineonGenericHeader header;
613         
614         CineonFile* cineon = (CineonFile* )malloc(sizeof(CineonFile));
615         if (cineon == 0) {
616                 if (verbose) d_printf("Failed to malloc cineon file structure.\n");
617                 return 0;
618         }
619
620         /* for close routine */
621         cineon->file = 0;
622         cineon->lineBuffer = 0;
623         cineon->pixelBuffer = 0;
624         cineon->membuffer = mem;
625         cineon->membuffersize = size;
626         cineon->memcursor = mem;
627         
628         cineon->file = 0;
629         cineon->reading = 1;
630         verbose = 0;
631         if (size < sizeof(CineonGenericHeader)) {
632                 if (verbose) d_printf("Not enough data for header!\n");
633                 cineonClose(cineon);
634                 return 0;
635         }
636
637         logimage_fread(&header, sizeof(CineonGenericHeader), 1, cineon);
638
639         /* let's assume cineon files are always network order */
640         if (header.fileInfo.magic_num != ntohl(CINEON_FILE_MAGIC)) {
641                 if (verbose) d_printf("Bad magic number %8.8lX in\n", (uintptr_t)ntohl(header.fileInfo.magic_num));
642
643                 cineonClose(cineon);
644                 return 0;
645         }
646
647         if (header.formatInfo.packing != 5) {
648                 if (verbose) d_printf("Can't understand packing %d\n", header.formatInfo.packing);
649                 cineonClose(cineon);
650                 return 0;
651         }
652
653         cineon->width = ntohl(header.imageInfo.channel[0].pixels_per_line);
654         cineon->height = ntohl(header.imageInfo.channel[0].lines_per_image);
655         cineon->depth = header.imageInfo.channels_per_image;
656         /* cineon->bitsPerPixel = 10; */
657         cineon->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel;
658         cineon->imageOffset = ntohl(header.fileInfo.image_offset);
659
660         cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth);
661         cineon->lineBuffer = malloc(cineon->lineBufferLength * 4);
662         if (cineon->lineBuffer == 0) {
663                 if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4);
664                 cineonClose(cineon);
665                 return 0;
666         }
667
668         cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short));
669         if (cineon->pixelBuffer == 0) {
670                 if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
671                                 (cineon->width * cineon->depth) * (int)sizeof(unsigned short));
672                 cineonClose(cineon);
673                 return 0;
674         }
675         cineon->pixelBufferUsed = 0;
676         
677         if (logimage_fseek(cineon, cineon->imageOffset, SEEK_SET) != 0) {
678                 if (verbose) d_printf("Couldn't seek to image data at %d\n", cineon->imageOffset);
679                 cineonClose(cineon);
680                 return 0;
681         }
682         
683         cineon->fileYPos = 0;
684
685         logImageGetByteConversionDefaults(&cineon->params);
686         setupLut(cineon);
687
688         cineon->getRow = &cineonGetRowBytes;
689         cineon->setRow = 0;
690         cineon->close = &cineonClose;
691
692         if (verbose) {
693                 verboseMe(cineon);
694         }
695
696         return cineon;
697 }
698
699
700 int
701 cineonGetSize(const CineonFile* cineon, int* width, int* height, int* depth) {
702         *width = cineon->width;
703         *height = cineon->height;
704         *depth = cineon->depth;
705         return 0;
706 }
707
708 CineonFile*
709 cineonCreate(const char* filename, int width, int height, int depth) {
710
711         /* Note: always write files in network order */
712         /* By the spec, it shouldn't matter, but ... */
713
714         CineonGenericHeader header;
715         const char* shortFilename = 0;
716
717         CineonFile* cineon = (CineonFile*)malloc(sizeof(CineonFile));
718         if (cineon == 0) {
719                 if (verbose) d_printf("Failed to malloc cineon file structure.\n");
720                 return 0;
721         }
722
723         memset(&header, 0, sizeof(header));
724
725         /* for close routine */
726         cineon->file = 0;
727         cineon->lineBuffer = 0;
728         cineon->pixelBuffer = 0;
729
730         cineon->file = fopen(filename, "wb");
731         if (cineon->file == 0) {
732                 if (verbose) d_printf("Couldn't open file %s\n", filename);
733                 cineonClose(cineon);
734                 return 0;
735         }
736         cineon->reading = 0;
737
738         cineon->width = width;
739         cineon->height = height;
740         cineon->depth = depth;
741         cineon->bitsPerPixel = 10;
742         cineon->imageOffset = sizeof(CineonGenericHeader);
743
744         cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth);
745         cineon->lineBuffer = malloc(cineon->lineBufferLength * 4);
746         if (cineon->lineBuffer == 0) {
747                 if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4);
748                 cineonClose(cineon);
749                 return 0;
750         }
751
752         cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short));
753         if (cineon->pixelBuffer == 0) {
754                 if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
755                                 (cineon->width * cineon->depth) * (int)sizeof(unsigned short));
756                 cineonClose(cineon);
757                 return 0;
758         }
759         cineon->pixelBufferUsed = 0;
760
761         /* find trailing part of filename */
762         shortFilename = strrchr(filename, '/');
763         if (shortFilename == 0) {
764                 shortFilename = filename;
765         } else {
766                 ++shortFilename;
767         }
768
769         if (initCineonGenericHeader(cineon, &header, shortFilename) != 0) {
770                 cineonClose(cineon);
771                 return 0;
772         }
773
774         if (fwrite(&header, sizeof(header), 1, cineon->file) == 0) {
775                 if (verbose) d_printf("Couldn't write image header\n");
776                 cineonClose(cineon);
777                 return 0;
778         }
779         cineon->fileYPos = 0;
780
781         logImageGetByteConversionDefaults(&cineon->params);
782         setupLut(cineon);
783
784         cineon->getRow = 0;
785         cineon->setRow = &cineonSetRowBytes;
786         cineon->close = &cineonClose;
787
788         return cineon;
789 }
790
791 void
792 cineonClose(CineonFile* cineon) {
793
794         if (cineon == 0) {
795                 return;
796         }
797
798         if (cineon->file) {
799                 fclose(cineon->file);
800                 cineon->file = 0;
801         }
802
803         if (cineon->lineBuffer) {
804                 free(cineon->lineBuffer);
805                 cineon->lineBuffer = 0;
806         }
807
808         if (cineon->pixelBuffer) {
809                 free(cineon->pixelBuffer);
810                 cineon->pixelBuffer = 0;
811         }
812
813         free(cineon);
814 }