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