New: Import/Export of Cineon and DPX image files. The first is Kodak's
authorTon Roosendaal <ton@blender.org>
Sun, 12 Mar 2006 14:11:23 +0000 (14:11 +0000)
committerTon Roosendaal <ton@blender.org>
Sun, 12 Mar 2006 14:11:23 +0000 (14:11 +0000)
standard for film scanning, 10 bits/channel and logarithmic. DPX is
derived from Cineon as the ANSI/SMPTE industry standard.
DPX supports 16 bits color/channel, linear as well as logarithmic.

Code has been gratefully copied from CinePaint and was integrated in
Blender by Joe Eagar.

According to CinePaint's dev Robin Rowe the DPX code defaults to log
colorspace. Can't find in the code clues yet how to enable/disable that.
However, tests with write/read of DPX seems to show no visible loss by
log conversion code. Might be because it uses the entire 16 bit range...

CinePaint dpx files have been succesfully imported in a Quantel IQ HD/2K
finishing/grading set without problem, so for now I guess we can
use it! :)

Changes in code: added tests for image magic numbers before entering
the actual reading code. Prevents error prints, and makes it faster too.
(Note; this because Blender doesn't check for extensions, but calls
reading functions on every file until one accepts it. :)

29 files changed:
source/blender/blenkernel/intern/image.c
source/blender/blenkernel/intern/writeffmpeg.c
source/blender/imbuf/IMB_imbuf_types.h
source/blender/imbuf/SConscript
source/blender/imbuf/intern/IMB_dpxcineon.h [new file with mode: 0644]
source/blender/imbuf/intern/Makefile
source/blender/imbuf/intern/cineon/Makefile [new file with mode: 0644]
source/blender/imbuf/intern/cineon/README [new file with mode: 0644]
source/blender/imbuf/intern/cineon/cin_debug_stuff.h [new file with mode: 0644]
source/blender/imbuf/intern/cineon/cineon_dpx.c [new file with mode: 0644]
source/blender/imbuf/intern/cineon/cineonfile.h [new file with mode: 0644]
source/blender/imbuf/intern/cineon/cineonlib.c [new file with mode: 0644]
source/blender/imbuf/intern/cineon/cineonlib.h [new file with mode: 0644]
source/blender/imbuf/intern/cineon/dpxfile.h [new file with mode: 0644]
source/blender/imbuf/intern/cineon/dpxlib.c [new file with mode: 0644]
source/blender/imbuf/intern/cineon/dpxlib.h [new file with mode: 0644]
source/blender/imbuf/intern/cineon/logImageCore.c [new file with mode: 0644]
source/blender/imbuf/intern/cineon/logImageCore.h [new file with mode: 0644]
source/blender/imbuf/intern/cineon/logImageLib.c [new file with mode: 0644]
source/blender/imbuf/intern/cineon/logImageLib.h [new file with mode: 0644]
source/blender/imbuf/intern/cineon/logmemfile.c [new file with mode: 0644]
source/blender/imbuf/intern/cineon/logmemfile.h [new file with mode: 0644]
source/blender/imbuf/intern/readimage.c
source/blender/imbuf/intern/util.c
source/blender/imbuf/intern/writeimage.c
source/blender/makesdna/DNA_scene_types.h
source/blender/src/buttons_scene.c
source/blender/src/filesel.c
source/blender/src/writeimage.c

index 2cafc4e94ce0d2ca5cb44651cebd8453051fd0a5..9f19735da5b10f00af39aaf47d9ded38a1dbbd40 100644 (file)
@@ -357,6 +357,14 @@ void BKE_add_image_extension(char *string, int imtype)
                        extension= ".exr";
        }
 #endif
+       else if(imtype==R_CINEON){
+               if (!BLI_testextensie(string, ".cin"))
+                       extension= ".cin";
+       }
+       else if(imtype==R_DPX){
+               if (!BLI_testextensie(string, ".dpx"))
+                       extension= ".dpx";
+       }
        else {  /* targa default */
                if(!BLI_testextensie(string, ".tga"))
                        extension= ".tga";
@@ -396,6 +404,12 @@ int BKE_write_ibuf(ImBuf *ibuf, char *name, int imtype, int subimtype, int quali
                
        }
 #endif
+       else if (imtype==R_CINEON) {
+               ibuf->ftype = CINEON;
+       }
+       else if (imtype==R_DPX) {
+               ibuf->ftype = DPX;
+       }
        else if (imtype==R_TARGA) {
                ibuf->ftype= TGA;
        }
index 71f7f7c029492166fcec218ba6a90b4cb7b19bcc..c7ea4f55941fafd15d8e77dd54aa97d0c836b125 100644 (file)
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <stdio.h>
 
+#include <stdint.h>
 #include <stdlib.h>
 #include <ffmpeg/avformat.h>
 #include <ffmpeg/avcodec.h>
index db17884197998cbad33fab085c7f38acabe694b2..586dedc54e819fa9098c20d734675b9a8a125b6f 100644 (file)
@@ -163,6 +163,9 @@ typedef enum {
 #define OPENEXR_HALF   (1 << 8 )
 #define OPENEXR_COMPRESS (7)   
 
+#define CINEON                 (1 << 21)
+#define DPX                            (1 << 20)
+
 #define RAWTGA         (TGA | 1)
 
 #define JPG_STD                (JPG | (0 << 8))
@@ -199,6 +202,8 @@ typedef enum {
 #define IS_tga(x)              (x->ftype & TGA)
 #define IS_png(x)              (x->ftype & PNG)
 #define IS_openexr(x)  (x->ftype & OPENEXR)
+#define IS_cineon(x)   (x->ftype & CINEON)
+#define IS_dpx(x)              (x->ftype & DPX)
 #define IS_bmp(x)              (x->ftype & BMP)
 #define IS_tiff(x)             (x->ftype & TIF)
 #define IS_radhdr(x)   (x->ftype & RADHDR)
index 93041ab97cff7898fc151b2829ca145d6aceb09a..2cc67df9e0cf5f78384c283d3ed80597775bc884 100644 (file)
@@ -24,3 +24,4 @@ if env['WITH_BF_QUICKTIME']==1:
        defs.append('WITH_QUICKTIME')
 
 env.BlenderLib ( libname = 'bf_imbuf', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [80, 40] )
+env.BlenderLib ( libname = "bf_imbuf_cineondpx" sources = cineon, includes = Split(cincs), defines = defs, libtype=['core', 'player'] priority = [81, 41] )
\ No newline at end of file
diff --git a/source/blender/imbuf/intern/IMB_dpxcineon.h b/source/blender/imbuf/intern/IMB_dpxcineon.h
new file mode 100644 (file)
index 0000000..9846d01
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * IMB_dpxcineon.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_dpxcineon.h
+ * \ingroup imbuf
+ */
+#ifndef _IMB_DPX_CINEON_H
+#define _IMB_DPX_CINEON_H
+
+struct ImBuf;
+
+short imb_savecineon(struct ImBuf *buf, char *myfil, int flags);
+struct ImBuf *imb_loadcineon(unsigned char *mem, int size, int flags);
+int imb_is_cineon(void *buf);
+short imb_save_dpx(struct ImBuf *buf, char *myfile, int flags);
+struct ImBuf *imb_loaddpx(unsigned char *mem, int size, int flags);
+int imb_is_dpx(void *buf);
+
+#endif /*_IMB_DPX_CINEON_H*/
index 19040abd5f63e0b8b72eb22cefd05a1331658245..f51844aad96e4b55ae64c0ec6d05d2d610a3ef26 100644 (file)
@@ -39,8 +39,10 @@ include nan_subdirs.mk
 include nan_compile.mk
 include nan_definitions.mk
 
+DIRS = cineon
+
 ifeq ($(WITH_OPENEXR), true)
-    DIRS = openexr
+    DIRS += openexr 
     CFLAGS += -DWITH_OPENEXR
 endif
 
diff --git a/source/blender/imbuf/intern/cineon/Makefile b/source/blender/imbuf/intern/cineon/Makefile
new file mode 100644 (file)
index 0000000..596a664
--- /dev/null
@@ -0,0 +1,64 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = cineon
+DIR = $(OCGDIR)/blender/imbuf/cineon
+SOURCEDIR = source/blender/imbuf/intern/cineon
+
+include nan_compile.mk
+include nan_definitions.mk
+
+ifeq ($(OS),$(findstring $(OS), "beos darwin freebsd linux openbsd solaris windows"))
+    CFLAGS += -funsigned-char
+endif
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I$(NAN_JPEG)/include
+CPPFLAGS += -I$(NAN_PNG)/include
+CPPFLAGS += -I$(NAN_ZLIB)/include
+CPPFLAGS += -I$(NAN_TIFF)/include
+CPPFLAGS += -I../../../include
+CPPFLAGS += -I../../../blenkernel
+CPPFLAGS += -I../../../blenlib
+CPPFLAGS += -I../../../avi
+CPPFLAGS += -I../../../quicktime
+# path to the guarded memory allocator
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I$(NAN_MEMUTIL)/include
+# This is not really needed, but until /include is cleaned, it must be
+# there for proper compilation.
+# - No, it is also needed in antialias, for listbase (nzc)
+CPPFLAGS += -I../../../makesdna
+# external interface of this module
+CPPFLAGS += -I../..
diff --git a/source/blender/imbuf/intern/cineon/README b/source/blender/imbuf/intern/cineon/README
new file mode 100644 (file)
index 0000000..5554e85
--- /dev/null
@@ -0,0 +1,8 @@
+Files:
+
+logImageLib.h, logImageLib.c: combined cineon/dpx image library
+dpxlib.h, dpxlib.c: dpx specific library
+dpxfile.h: dpx file structure
+cineonlib.h, cineonlib.c: cineon specific library
+cineonfile.h: cineon file structure
+logImageCore.h, logImageCore.c: log image routines common to cineon amd dpx
diff --git a/source/blender/imbuf/intern/cineon/cin_debug_stuff.h b/source/blender/imbuf/intern/cineon/cin_debug_stuff.h
new file mode 100644 (file)
index 0000000..148e4e4
--- /dev/null
@@ -0,0 +1,2 @@
+#define d_printf printf
+
diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c
new file mode 100644 (file)
index 0000000..d3cf74f
--- /dev/null
@@ -0,0 +1,195 @@
+/**
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA       02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * cineon.c
+ * contributors: joeedh
+ * I hearby donate this code and all rights to the Blender Foundation.
+ * $Id$
+ */
+#include <stdio.h>
+#include <string.h> /*for memcpy*/
+
+#include "logImageLib.h"
+#include "cineonlib.h"
+#include "dpxlib.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "MEM_guardedalloc.h"
+
+static struct ImBuf *imb_load_dpx_cineon(unsigned char *mem, int use_cineon, int size, int flags)
+{
+       ImBuf *ibuf;
+       LogImageFile *image;
+       int x, y;
+       unsigned short *row;
+       int width, height, depth;
+       float *frow;
+       
+       image = logImageOpenFromMem(mem, size, use_cineon);
+       
+       if (!image) {
+               printf("no image!\n");
+               return NULL;
+       }
+       
+       logImageGetSize(image, &width, &height, &depth);
+       
+       if (depth != 3) { /*need to do greyscale loading eventually.*/
+               logImageClose(image);
+               return NULL;
+       }
+       if (width == 0 && height == 0) {
+               logImageClose(image);
+               return NULL;
+       }
+       
+       ibuf = IMB_allocImBuf(width, height, 32, IB_rectfloat | flags, 0);
+
+       row = MEM_mallocN(sizeof(unsigned short)*width*depth, "row in cineon_dpx.c");
+       
+       for (y = 0; y < height; y++) {
+               unsigned int index = (width) * (height-y-1);
+               index = index * 4;
+               
+               frow = &ibuf->rect_float[index];
+               
+               logImageGetRowBytes(image, row, y);
+               
+               for (x=0; x<width; x++) {
+                       unsigned short *upix = &row[x*depth];
+                       float *fpix = &frow[x*4];
+                       fpix[0] = ((float)upix[0]) / 65535.0f;
+                       fpix[1] = ((float)upix[1]) / 65535.0f;
+                       fpix[2] = ((float)upix[2]) / 65535.0f;
+                       fpix[3] = 1.0f;
+               }
+       }
+
+       MEM_freeN(row);
+       logImageClose(image);
+       
+       if (flags & IB_rect) {
+               IMB_rect_from_float(ibuf);
+       }
+       return ibuf;
+}
+
+static int imb_save_dpx_cineon(ImBuf *buf, char *filename, int use_cineon, int flags)
+{
+       LogImageByteConversionParameters conversion;
+       int width, height, depth;
+       LogImageFile* logImage;
+       unsigned short* line, *pixel;
+       int i, j;
+       int index;
+       float *fline;
+       
+       conversion.blackPoint = 95;
+       conversion.whitePoint = 685;
+       conversion.gamma = 1;
+       /*
+        * Get the drawable for the current image...
+        */
+
+       width = buf->x;
+       height = buf->y;
+       depth = 3;
+       
+       if (!buf->rect_float) return 0;
+       
+       logImageSetVerbose(0);
+       logImage = logImageCreate(filename, use_cineon, width, height, depth);
+
+       if (!logImage) return 0;
+       
+       logImageSetByteConversion(logImage, &conversion);
+
+       index = 0;
+       line = MEM_mallocN(sizeof(unsigned short)*depth*width, "line");
+       
+       /*note that image is flipped when sent to logImageSetRowBytes (see last passed parameter).*/
+       for (j = 0; j < height; ++j) {
+       fline = &buf->rect_float[width*j*4];
+       for (i=0; i<width; i++) {
+               float *fpix, fpix2[3];
+               /*we have to convert to cinepaint's 16-bit-per-channel here*/
+               pixel = &line[i*depth];
+               fpix = &fline[i*4];
+               memcpy(fpix2, fpix, sizeof(float)*3);
+               
+               if (fpix2[0]>=1) fpix2[0] = 1; 
+               if (fpix2[1]>=1) fpix2[1] = 1; 
+               if (fpix2[2]>=1) fpix2[2] = 1;
+               
+               pixel[0] = (unsigned short)(fpix2[0] * 65535.0f); /*float-float math is faster*/
+               pixel[1] = (unsigned short)(fpix2[1] * 65535.0f);
+               pixel[2] = (unsigned short)(fpix2[2] * 65535.0f);
+       }
+               logImageSetRowBytes(logImage, (const unsigned short*)line, height-1-j);
+       }
+       logImageClose(logImage);
+
+       MEM_freeN(line);
+       return 1;
+}
+
+short imb_savecineon(struct ImBuf *buf, char *myfile, int flags)
+{
+       return imb_save_dpx_cineon(buf, myfile, 1, flags);
+}
+
+int imb_is_cineon(void *buf)
+{
+       return cineonIsMemFileCineon(buf);
+}
+
+ImBuf *imb_loadcineon(unsigned char *mem, int size, int flags)
+{
+       if(imb_is_cineon(mem))
+               return imb_load_dpx_cineon(mem, 1, size, flags);
+       return NULL;
+}
+
+short imb_save_dpx(struct ImBuf *buf, char *myfile, int flags)
+{
+       return imb_save_dpx_cineon(buf, myfile, 0, flags);
+}
+
+short imb_is_dpx(void *buf)
+{
+       return dpxIsMemFileCineon(buf);
+}
+
+ImBuf *imb_loaddpx(unsigned char *mem, int size, int flags)
+{
+       if(imb_is_dpx(mem))
+               return imb_load_dpx_cineon(mem, 0, size, flags);
+       return NULL;
+}
diff --git a/source/blender/imbuf/intern/cineon/cineonfile.h b/source/blender/imbuf/intern/cineon/cineonfile.h
new file mode 100644 (file)
index 0000000..7f6f113
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ *      Cineon image file format library definitions.
+ *      Cineon file format structures.
+ *
+ *      This header file contains private details.
+ *      User code should generally use cineonlib.h only.
+ *
+ *      Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
+ *
+ *      This program is free software; you can redistribute it and/or modify it
+ *      under the terms of the GNU General Public License as published by the Free
+ *      Software Foundation; either version 2 of the License, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful, but
+ *      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *      or FITNESS FOR A PARTICULAR PURPOSE.    See the GNU General Public License
+ *      for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _CINEON_FILE_H_
+#define _CINEON_FILE_H_
+
+#include "logImageCore.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+               U32             magic_num;                              /* magic number */
+               U32             image_offset;                   /* offset to image data in bytes */
+               U32             gen_hdr_size;                   /* generic header length in bytes */
+               U32             ind_hdr_size;                   /* industry header length in bytes */
+               U32             user_data_size;         /* user-defined data length in bytes */
+               U32             file_size;                              /* file size in bytes */
+               ASCII vers[8];                                  /* which header format version is being used (v4.5) */
+               ASCII file_name[100];           /* image file name */
+               ASCII create_date[12];  /* file creation date */
+               ASCII create_time[12];  /* file creation time */
+               ASCII Reserved[36];                     /* reserved field TBD (need to pad) */
+} CineonFileInformation;
+
+typedef struct {
+               U8               designator1;
+               U8               designator2;
+               U8               bits_per_pixel;
+               U8               filler;
+               U32              pixels_per_line;
+               U32              lines_per_image;
+               U32              ref_low_data;           /* reference low data code value */
+               R32              ref_low_quantity; /* reference low quantity represented */
+               U32              ref_high_data;          /* reference high data code value */
+               R32              ref_high_quantity;/* reference high quantity represented */
+} CineonChannelInformation;
+
+typedef struct {
+               U8               orientation;                                    /* image orientation */
+               U8               channels_per_image;
+               U16              filler;
+               CineonChannelInformation channel[8];
+               R32              white_point_x;
+               R32              white_point_y;
+               R32              red_primary_x;
+               R32              red_primary_y;
+               R32              green_primary_x;
+               R32              green_primary_y;
+               R32              blue_primary_x;
+               R32              blue_primary_y;
+               ASCII    label[200];
+               ASCII    reserved[28];
+} CineonImageInformation;
+
+typedef struct {
+               U8              interleave;
+               U8              packing;
+               U8              signage;
+               U8              sense;
+               U32             line_padding;
+               U32             channel_padding;
+               ASCII reserved[20];
+} CineonFormatInformation;
+
+typedef struct {
+               S32             x_offset;
+               S32             y_offset;
+               ASCII file_name[100];
+               ASCII create_date[12];  /* file creation date */
+               ASCII create_time[12];  /* file creation time */
+               ASCII input_device[64];
+               ASCII model_number[32];
+               ASCII serial_number[32];
+               R32             x_input_samples_per_mm;
+               R32             y_input_samples_per_mm;
+               R32             input_device_gamma;
+               ASCII reserved[40];
+} CineonOriginationInformation;
+
+typedef struct {
+       CineonFileInformation fileInfo;
+       CineonImageInformation imageInfo;
+       CineonFormatInformation formatInfo;
+       CineonOriginationInformation originInfo;
+} CineonGenericHeader;
+
+typedef struct {
+       U8 filmCode;
+       U8 filmType;
+       U8 perfOffset;
+       U8 filler;
+       U32 keycodePrefix;
+       U32 keycodeCount;
+       ASCII format[32];
+       U32 framePosition; /* in sequence */
+       R32 frameRate; /* frames per second */
+       ASCII attribute[32];
+       ASCII slate[200];
+       ASCII reserved[740];
+} CineonMPISpecificInformation;
+
+#if 0
+/* create CineonFile from data in header */
+/* return 0 for OK */
+int readCineonGenericHeader(CineonFile* cineon, CineonGenericHeader* header);
+
+/* create header from data in CineonFile */
+int initCineonGenericHeader(
+       CineonFile* cineon, CineonGenericHeader* header, const char* imagename);
+
+/* Note: dump routine assumes network byte order */
+void dumpCineonGenericHeader(CineonGenericHeader* header);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CINEON_FILE_H_ */
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c
new file mode 100644 (file)
index 0000000..5253646
--- /dev/null
@@ -0,0 +1,801 @@
+/*
+ *      Cineon image file format library routines.
+ *
+ *      Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
+ *
+ *      This program is free software; you can redistribute it and/or modify it
+ *      under the terms of the GNU General Public License as published by the Free
+ *      Software Foundation; either version 2 of the License, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful, but
+ *      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *      or FITNESS FOR A PARTICULAR PURPOSE.    See the GNU General Public License
+ *      for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "cineonlib.h"
+#include "cineonfile.h"
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <time.h>                               /* strftime() */
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock.h>
+#else
+#include <netinet/in.h>         /* htonl() */
+#endif
+#include <string.h>                     /* memset */
+#include "cin_debug_stuff.h"
+#include "logmemfile.h"
+
+static void
+fillCineonFileInfo(CineonFile* cineon, CineonFileInformation* fileInfo, const char* filename) {
+
+       time_t fileClock;
+       struct tm* fileTime;
+
+       fileInfo->magic_num = htonl(CINEON_FILE_MAGIC);
+       fileInfo->image_offset = htonl(cineon->imageOffset);
+       fileInfo->gen_hdr_size = htonl(
+               sizeof(CineonFileInformation) +
+               sizeof(CineonImageInformation) +
+               sizeof(CineonFormatInformation) +
+               sizeof(CineonOriginationInformation));
+       fileInfo->ind_hdr_size = 0;
+       fileInfo->user_data_size = 0;
+       fileInfo->file_size = htonl(cineon->imageOffset + cineon->height * cineon->lineBufferLength);
+       strcpy(fileInfo->vers, "V4.5");
+       strncpy(fileInfo->file_name, filename, 99);
+       fileInfo->file_name[99] = 0;
+
+       fileClock = time(0);
+       fileTime = localtime(&fileClock);
+       strftime(fileInfo->create_date, 12, "%Y:%m:%d", fileTime);
+       /* Question: is %Z in strftime guaranteed to return 3 chars? */
+       strftime(fileInfo->create_time, 12, "%H:%M:%S%Z", fileTime);
+       fileInfo->create_time[11] = 0;
+}
+
+static void
+dumpCineonFileInfo(CineonFileInformation* fileInfo) {
+       d_printf("\n--File Information--\n");
+       d_printf("Magic: %8.8lX\n", ntohl(fileInfo->magic_num));
+       d_printf("Image Offset %ld\n", ntohl(fileInfo->image_offset));
+       d_printf("Generic Header size %ld\n", ntohl(fileInfo->gen_hdr_size));
+       d_printf("Industry Header size %ld\n", ntohl(fileInfo->ind_hdr_size));
+       d_printf("User Data size %ld\n", ntohl(fileInfo->user_data_size));
+       d_printf("File size %ld\n", ntohl(fileInfo->file_size));
+       d_printf("Version \"%s\"\n", fileInfo->vers);
+       d_printf("File name \"%s\"\n", fileInfo->file_name);
+       d_printf("Creation date \"%s\"\n", fileInfo->create_date);
+       d_printf("Creation time \"%s\"\n", fileInfo->create_time);
+}
+
+static void
+fillCineonChannelInfo(CineonFile* cineon, CineonChannelInformation* chan, int des) {
+
+       chan->designator1 = 0;
+       chan->designator2 = des;
+       chan->bits_per_pixel = 10;
+       chan->pixels_per_line = htonl(cineon->width);
+       chan->lines_per_image = htonl(cineon->height);
+       chan->ref_low_data = htonl(0);
+       chan->ref_low_quantity = htonf(0.0);
+       chan->ref_high_data = htonl(1023);
+       chan->ref_high_quantity = htonf(2.046);
+}
+
+static void
+dumpCineonChannelInfo(CineonChannelInformation* chan) {
+       d_printf("      Metric selector: %d", chan->designator1);
+       switch (chan->designator1) {
+               case 0: d_printf(" (Universal)\n"); break;
+               default: d_printf(" (Vendor specific)\n"); break;
+       }
+       d_printf("      Metric: %d,", chan->designator2);
+       switch (chan->designator2) {
+               case 0: d_printf(" B&W (printing density?)\n"); break;
+               case 1: d_printf(" Red printing density\n"); break;
+               case 2: d_printf(" Green printing density\n"); break;
+               case 3: d_printf(" Blue printing density\n"); break;
+               case 4: d_printf(" Red CCIR XA/11\n"); break;
+               case 5: d_printf(" Green CCIR XA/11\n"); break;
+               case 6: d_printf(" Blue CCIR XA/11\n"); break;
+               default: d_printf(" (unknown)\n"); break;
+       }
+       d_printf("      Bits per pixel %d\n", chan->bits_per_pixel);
+       d_printf("      Pixels per line %ld\n", ntohl(chan->pixels_per_line));
+       d_printf("      Lines per image %ld\n", ntohl(chan->lines_per_image));
+       d_printf("      Ref low data %ld\n", ntohl(chan->ref_low_data));
+       d_printf("      Ref low quantity %f\n", ntohf(chan->ref_low_quantity));
+       d_printf("      Ref high data %ld\n", ntohl(chan->ref_high_data));
+       d_printf("      Ref high quantity %f\n", ntohf(chan->ref_high_quantity));
+}
+
+static void
+fillCineonImageInfo(CineonFile* cineon, CineonImageInformation* imageInfo) {
+
+       imageInfo->orientation = 0;
+       imageInfo->channels_per_image = cineon->depth;
+
+       if (cineon->depth == 1) {
+               fillCineonChannelInfo(cineon, &imageInfo->channel[0], 0);
+
+       } else if (cineon->depth == 3) {
+               fillCineonChannelInfo(cineon, &imageInfo->channel[0], 1);
+               fillCineonChannelInfo(cineon, &imageInfo->channel[1], 2);
+               fillCineonChannelInfo(cineon, &imageInfo->channel[2], 3);
+       }
+
+       imageInfo->white_point_x = htonf(undefined());
+       imageInfo->white_point_y = htonf(undefined());
+       imageInfo->red_primary_x = htonf(undefined());
+       imageInfo->red_primary_y = htonf(undefined());
+       imageInfo->green_primary_x = htonf(undefined());
+       imageInfo->green_primary_y = htonf(undefined());
+       imageInfo->blue_primary_x = htonf(undefined());
+       imageInfo->blue_primary_y = htonf(undefined());
+
+       strcpy(imageInfo->label, "David's Cineon writer.");
+
+}
+
+static void
+dumpCineonImageInfo(CineonImageInformation* imageInfo) {
+
+       int i;
+       d_printf("\n--Image Information--\n");
+       d_printf("Image orientation %d,", imageInfo->orientation);
+       switch (imageInfo->orientation) {
+               case 0: d_printf(" LRTB\n"); break;
+               case 1: d_printf(" LRBT\n"); break;
+               case 2: d_printf(" RLTB\n"); break;
+               case 3: d_printf(" RLBT\n"); break;
+               case 4: d_printf(" TBLR\n"); break;
+               case 5: d_printf(" TBRL\n"); break;
+               case 6: d_printf(" BTLR\n"); break;
+               case 7: d_printf(" BTRL\n"); break;
+               default: d_printf(" (unknown)\n"); break;
+       }
+       d_printf("Channels %d\n", imageInfo->channels_per_image);
+       for (i = 0; i < imageInfo->channels_per_image; ++i) {
+               d_printf("      --Channel %d--\n", i);
+               dumpCineonChannelInfo(&imageInfo->channel[i]);
+       }
+
+       d_printf("White point x %f\n", ntohf(imageInfo->white_point_x));
+       d_printf("White point y %f\n", ntohf(imageInfo->white_point_y));
+       d_printf("Red primary x %f\n", ntohf(imageInfo->red_primary_x));
+       d_printf("Red primary y %f\n", ntohf(imageInfo->red_primary_y));
+       d_printf("Green primary x %f\n", ntohf(imageInfo->green_primary_x));
+       d_printf("Green primary y %f\n", ntohf(imageInfo->green_primary_y));
+       d_printf("Blue primary x %f\n", ntohf(imageInfo->blue_primary_x));
+       d_printf("Blue primary y %f\n", ntohf(imageInfo->blue_primary_y));
+       d_printf("Label \"%s\"\n", imageInfo->label);
+}
+
+static void
+fillCineonFormatInfo(CineonFile* cineon, CineonFormatInformation* formatInfo) {
+
+       formatInfo->interleave = 0;
+       formatInfo->packing = 5;
+       formatInfo->signage = 0;
+       formatInfo->sense = 0;
+       formatInfo->line_padding = htonl(0);
+       formatInfo->channel_padding = htonl(0);
+}
+
+static void
+dumpCineonFormatInfo(CineonFormatInformation* formatInfo) {
+       d_printf("\n--Format Information--\n");
+       d_printf("Interleave %d,", formatInfo->interleave);
+       switch (formatInfo->interleave) {
+               case 0: d_printf(" pixel interleave\n"); break;
+               case 1: d_printf(" line interleave\n"); break;
+               case 2: d_printf(" channel interleave\n"); break;
+               default: d_printf(" (unknown)\n"); break;
+       }
+       d_printf("Packing %d,", formatInfo->packing);
+       if (formatInfo->packing & 0x80) { 
+               d_printf(" multi pixel,");
+       } else {
+               d_printf(" single pixel,");
+       }
+       switch (formatInfo->packing & 0x7F) {
+               case 0: d_printf(" tight\n"); break;
+               case 1: d_printf(" byte packed left\n"); break;
+               case 2: d_printf(" byte packed right\n"); break;
+               case 3: d_printf(" word packed left\n"); break;
+               case 4: d_printf(" word packed right\n"); break;
+               case 5: d_printf(" long packed left\n"); break;
+               case 6: d_printf(" long packed right\n"); break;
+               default: d_printf(" (unknown)\n"); break;
+       }
+       d_printf("Sign %d,", formatInfo->signage);
+       if (formatInfo->signage) { 
+               d_printf(" signed\n");
+       } else {
+               d_printf(" unsigned\n");
+       }
+       d_printf("Sense %d,", formatInfo->signage);
+       if (formatInfo->signage) { 
+               d_printf(" negative\n");
+       } else {
+               d_printf(" positive\n");
+       }
+       d_printf("End of line padding %ld\n", ntohl(formatInfo->line_padding));
+       d_printf("End of channel padding %ld\n", ntohl(formatInfo->channel_padding));
+}
+
+static void
+fillCineonOriginationInfo(CineonFile* cineon,
+       CineonOriginationInformation* originInfo, CineonFileInformation* fileInfo) {
+
+       originInfo->x_offset = htonl(0);
+       originInfo->y_offset = htonl(0);
+       strcpy(originInfo->file_name, fileInfo->file_name);
+       strcpy(originInfo->create_date, fileInfo->create_date);
+       strcpy(originInfo->create_time, fileInfo->create_time);
+       strncpy(originInfo->input_device, "David's Cineon writer", 64);
+       strncpy(originInfo->model_number, "Software", 32);
+       strncpy(originInfo->serial_number, "001", 32);
+       originInfo->x_input_samples_per_mm = htonf(undefined());
+       originInfo->y_input_samples_per_mm =    htonf(undefined());
+       /* this should probably be undefined, too */
+       originInfo->input_device_gamma = htonf(1.0);
+}
+
+static void
+dumpCineonOriginationInfo(CineonOriginationInformation* originInfo) {
+       d_printf("\n--Origination Information--\n");
+       d_printf("X offset %ld\n", ntohl(originInfo->x_offset));
+       d_printf("Y offset %ld\n", ntohl(originInfo->y_offset));
+       d_printf("File name \"%s\"\n", originInfo->file_name);
+       d_printf("Creation date \"%s\"\n", originInfo->create_date);
+       d_printf("Creation time \"%s\"\n", originInfo->create_time);
+       d_printf("Input device \"%s\"\n", originInfo->input_device);
+       d_printf("Model number \"%s\"\n", originInfo->model_number);
+       d_printf("Serial number \"%s\"\n", originInfo->serial_number);
+       d_printf("Samples per mm in x %f\n", ntohf(originInfo->x_input_samples_per_mm));
+       d_printf("Samples per mm in y %f\n", ntohf(originInfo->y_input_samples_per_mm));
+       d_printf("Input device gamma %f\n", ntohf(originInfo->input_device_gamma));
+}
+
+int
+initCineonGenericHeader(CineonFile* cineon, CineonGenericHeader* header, const char* imagename) {
+
+       fillCineonFileInfo(cineon, &header->fileInfo, imagename);
+       fillCineonImageInfo(cineon, &header->imageInfo);
+       fillCineonFormatInfo(cineon, &header->formatInfo);
+       fillCineonOriginationInfo(cineon, &header->originInfo, &header->fileInfo);
+
+       return 0;
+}
+
+void
+dumpCineonGenericHeader(CineonGenericHeader* header) {
+       dumpCineonFileInfo(&header->fileInfo);
+       dumpCineonImageInfo(&header->imageInfo);
+       dumpCineonFormatInfo(&header->formatInfo);
+       dumpCineonOriginationInfo(&header->originInfo);
+}
+
+static int verbose = 0;
+void
+cineonSetVerbose(int verbosity) {
+       verbose = verbosity;
+}
+
+static void
+verboseMe(CineonFile* cineon) {
+
+       d_printf("size %d x %d x %d\n", cineon->width, cineon->height, cineon->depth);
+       d_printf("ImageStart %d, lineBufferLength %d, implied length %d\n",
+               cineon->imageOffset, cineon->lineBufferLength * 4,
+               cineon->imageOffset + cineon->lineBufferLength * 4 * cineon->height);
+}
+
+int
+cineonGetRowBytes(CineonFile* cineon, unsigned short* row, int y) {
+
+       int longsRead;
+       int pixelIndex;
+       int longIndex;
+       int numPixels = cineon->width * cineon->depth;
+
+
+       /* only seek if not reading consecutive lines */
+       if (y != cineon->fileYPos) {
+               int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
+               if (verbose) d_printf("Seek in getRowBytes\n");
+               if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
+                       if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
+                       return 1;
+               }
+               cineon->fileYPos = y;
+       }
+
+       longsRead = logimage_fread(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon);
+       if (longsRead != cineon->lineBufferLength) {
+               if (verbose) 
+       {       d_printf("Couldn't read line %d length %d\n", y, cineon->lineBufferLength * 4);
+               perror("cineonGetRowBytes");
+       }
+               return 1;
+       }
+
+       /* remember where we left the car, honey */
+       ++cineon->fileYPos;
+
+       /* convert longwords to pixels */
+       pixelIndex = 0;
+       for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
+               unsigned int t = ntohl(cineon->lineBuffer[longIndex]);
+               t = t >> 2;
+               cineon->pixelBuffer[pixelIndex+2] = (unsigned short) t & 0x3ff;
+               t = t >> 10;
+               cineon->pixelBuffer[pixelIndex+1] = (unsigned short) t & 0x3ff;
+               t = t >> 10;
+               cineon->pixelBuffer[pixelIndex] = (unsigned short) t & 0x3ff;
+               pixelIndex += 3;
+       }
+
+       /* extract required pixels */
+       for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
+               /* row[pixelIndex] = cineon->lut10[cineon->pixelBuffer[pixelIndex]]; */
+               row[pixelIndex] = cineon->pixelBuffer[pixelIndex] << 6;
+       }
+
+       return 0;
+}
+
+int
+cineonSetRowBytes(CineonFile* cineon, const unsigned short* row, int y) {
+
+       int pixelIndex;
+       int numPixels = cineon->width * cineon->depth;
+       int longIndex;
+       int longsWritten;
+
+       /* put new pixels into pixelBuffer */
+       for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
+               /* cineon->pixelBuffer[pixelIndex] = cineon->lut8[row[pixelIndex]]; */
+               cineon->pixelBuffer[pixelIndex] = row[pixelIndex] >> 6;
+       }
+
+       /* pack into longwords */
+       pixelIndex = 0;
+       for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
+               unsigned int t =
+                               (cineon->pixelBuffer[pixelIndex] << 22) |
+                               (cineon->pixelBuffer[pixelIndex+1] << 12) |
+                               (cineon->pixelBuffer[pixelIndex+2] << 2);
+               cineon->lineBuffer[longIndex] = htonl(t);
+               pixelIndex += 3;
+       }
+
+       /* only seek if not reading consecutive lines */
+       if (y != cineon->fileYPos) {
+               int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
+               if (verbose) d_printf("Seek in setRowBytes\n");
+               if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
+                       if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
+                       return 1;
+               }
+               cineon->fileYPos = y;
+       }
+
+       longsWritten = fwrite(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon->file);
+       if (longsWritten != cineon->lineBufferLength) {
+               if (verbose) d_printf("Couldn't write line %d length %d\n", y, cineon->lineBufferLength * 4);
+               return 1;
+       }
+
+       ++cineon->fileYPos;
+
+       return 0;
+}
+
+int
+cineonGetRow(CineonFile* cineon, unsigned short* row, int y) {
+
+       int longsRead;
+       int pixelIndex;
+       int longIndex;
+/*     int numPixels = cineon->width * cineon->depth;
+*/
+       /* only seek if not reading consecutive lines */
+       if (y != cineon->fileYPos) {
+               int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
+               if (verbose) d_printf("Seek in getRow\n");
+               if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
+                       if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
+                       return 1;
+               }
+               cineon->fileYPos = y;
+       }
+
+       longsRead = logimage_fread(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon);
+       if (longsRead != cineon->lineBufferLength) {
+               if (verbose) d_printf("Couldn't read line %d length %d\n", y, cineon->lineBufferLength * 4);
+               return 1;
+       }
+
+       /* remember where we left the car, honey */
+       ++cineon->fileYPos;
+
+       /* convert longwords to pixels */
+       pixelIndex = 0;
+       for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
+               unsigned int t = ntohl(cineon->lineBuffer[longIndex]);
+               t = t >> 2;
+               row[pixelIndex+2] = (unsigned short) t & 0x3ff;
+               t = t >> 10;
+               row[pixelIndex+1] = (unsigned short) t & 0x3ff;
+               t = t >> 10;
+               row[pixelIndex] = (unsigned short) t & 0x3ff;
+               pixelIndex += 3;
+       }
+
+       return 0;
+}
+
+int
+cineonSetRow(CineonFile* cineon, const unsigned short* row, int y) {
+
+       int pixelIndex;
+/*     int numPixels = cineon->width * cineon->depth;
+*/     int longIndex;
+       int longsWritten;
+
+       /* pack into longwords */
+       pixelIndex = 0;
+       for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
+               unsigned int t =
+                               (row[pixelIndex] << 22) |
+                               (row[pixelIndex+1] << 12) |
+                               (row[pixelIndex+2] << 2);
+               cineon->lineBuffer[longIndex] = htonl(t);
+               pixelIndex += 3;
+       }
+
+       /* only seek if not reading consecutive lines */
+       if (y != cineon->fileYPos) {
+               int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
+               if (verbose) d_printf("Seek in setRowBytes\n");
+               if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
+                       if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
+                       return 1;
+               }
+               cineon->fileYPos = y;
+       }
+
+       longsWritten = fwrite(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon->file);
+       if (longsWritten != cineon->lineBufferLength) {
+               if (verbose) d_printf("Couldn't write line %d length %d\n", y, cineon->lineBufferLength * 4);
+               return 1;
+       }
+
+       ++cineon->fileYPos;
+
+       return 0;
+}
+
+CineonFile* 
+cineonOpen(const char* filename) {
+
+       CineonGenericHeader header;
+
+       CineonFile* cineon = (CineonFile* )malloc(sizeof(CineonFile));
+       if (cineon == 0) {
+               if (verbose) d_printf("Failed to malloc cineon file structure.\n");
+               return 0;
+       }
+
+       /* for close routine */
+       cineon->file = 0;
+       cineon->lineBuffer = 0;
+       cineon->pixelBuffer = 0;
+       cineon->membuffer = 0;
+       cineon->memcursor = 0;
+       cineon->membuffersize = 0;
+       
+       cineon->file = fopen(filename, "rb");
+       if (cineon->file == 0) {
+               if (verbose) d_printf("Failed to open file \"%s\".\n", filename);
+               cineonClose(cineon);
+               return 0;
+       }
+       cineon->reading = 1;
+
+       if (logimage_fread(&header, sizeof(CineonGenericHeader), 1, cineon) == 0) {
+               if (verbose) d_printf("Not enough data for header in \"%s\".\n", filename);
+               cineonClose(cineon);
+               return 0;
+       }
+
+       /* let's assume cineon files are always network order */
+       if (header.fileInfo.magic_num != ntohl(CINEON_FILE_MAGIC)) {
+               if (verbose) d_printf("Bad magic number %8.8lX in \"%s\".\n",
+                       ntohl(header.fileInfo.magic_num), filename);
+               cineonClose(cineon);
+               return 0;
+       }
+
+       if (header.formatInfo.packing != 5) {
+               if (verbose) d_printf("Can't understand packing %d\n", header.formatInfo.packing);
+               cineonClose(cineon);
+               return 0;
+       }
+
+       cineon->width = ntohl(header.imageInfo.channel[0].pixels_per_line);
+       cineon->height = ntohl(header.imageInfo.channel[0].lines_per_image);
+       cineon->depth = header.imageInfo.channels_per_image;
+       /* cineon->bitsPerPixel = 10; */
+       cineon->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel;
+       cineon->imageOffset = ntohl(header.fileInfo.image_offset);
+
+       cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth);
+       cineon->lineBuffer = malloc(cineon->lineBufferLength * 4);
+       if (cineon->lineBuffer == 0) {
+               if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4);
+               cineonClose(cineon);
+               return 0;
+       }
+
+       cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short));
+       if (cineon->pixelBuffer == 0) {
+               if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
+                               (cineon->width * cineon->depth) * sizeof(unsigned short));
+               cineonClose(cineon);
+               return 0;
+       }
+       cineon->pixelBufferUsed = 0;
+
+       if (logimage_fseek(cineon, cineon->imageOffset, SEEK_SET) != 0) {
+               if (verbose) d_printf("Couldn't seek to image data at %d\n", cineon->imageOffset);
+               cineonClose(cineon);
+               return 0;
+       }
+       cineon->fileYPos = 0;
+
+       logImageGetByteConversionDefaults(&cineon->params);
+       setupLut(cineon);
+
+       cineon->getRow = &cineonGetRowBytes;
+       cineon->setRow = 0;
+       cineon->close = &cineonClose;
+
+       if (verbose) {
+               verboseMe(cineon);
+       }
+
+       return cineon;
+}
+
+int cineonIsMemFileCineon(unsigned char *mem)
+{
+       unsigned int num;
+       memcpy(&num, mem, sizeof(unsigned int));
+       
+       if (num != ntohl(CINEON_FILE_MAGIC)) {
+               return 0;
+       } else return 1;
+}
+
+CineonFile* 
+cineonOpenFromMem(unsigned char *mem, unsigned int size) {
+
+       CineonGenericHeader header;
+       int i;
+       
+       CineonFile* cineon = (CineonFile* )malloc(sizeof(CineonFile));
+       if (cineon == 0) {
+               if (verbose) d_printf("Failed to malloc cineon file structure.\n");
+               return 0;
+       }
+
+       /* for close routine */
+       cineon->file = 0;
+       cineon->lineBuffer = 0;
+       cineon->pixelBuffer = 0;
+       cineon->membuffer = mem;
+       cineon->membuffersize = size;
+       cineon->memcursor = mem;
+       
+       cineon->file = 0;
+       cineon->reading = 1;
+       verbose = 1;
+       if (size < sizeof(CineonGenericHeader)) {
+               if (verbose) d_printf("Not enough data for header!\n");
+               cineonClose(cineon);
+               return 0;
+       }
+
+       logimage_fread(&header, sizeof(CineonGenericHeader), 1, cineon);
+
+       /* let's assume cineon files are always network order */
+       if (header.fileInfo.magic_num != ntohl(CINEON_FILE_MAGIC)) {
+               if (verbose) d_printf("Bad magic number %8.8lX in\n", ntohl(header.fileInfo.magic_num));
+
+               cineonClose(cineon);
+               return 0;
+       }
+
+       if (header.formatInfo.packing != 5) {
+               if (verbose) d_printf("Can't understand packing %d\n", header.formatInfo.packing);
+               cineonClose(cineon);
+               return 0;
+       }
+
+       cineon->width = ntohl(header.imageInfo.channel[0].pixels_per_line);
+       cineon->height = ntohl(header.imageInfo.channel[0].lines_per_image);
+       cineon->depth = header.imageInfo.channels_per_image;
+       /* cineon->bitsPerPixel = 10; */
+       cineon->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel;
+       cineon->imageOffset = ntohl(header.fileInfo.image_offset);
+
+       cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth);
+       cineon->lineBuffer = malloc(cineon->lineBufferLength * 4);
+       if (cineon->lineBuffer == 0) {
+               if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4);
+               cineonClose(cineon);
+               return 0;
+       }
+
+       cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short));
+       if (cineon->pixelBuffer == 0) {
+               if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
+                               (cineon->width * cineon->depth) * sizeof(unsigned short));
+               cineonClose(cineon);
+               return 0;
+       }
+       cineon->pixelBufferUsed = 0;
+
+       i = cineon->imageOffset;
+       
+       if (i >= size) {
+               if (verbose) d_printf("Couldn't seek to image data at %d\n", cineon->imageOffset);
+               cineonClose(cineon);
+               return 0;
+       }
+       cineon->fileYPos = 0;
+
+       logImageGetByteConversionDefaults(&cineon->params);
+       setupLut(cineon);
+
+       cineon->getRow = &cineonGetRowBytes;
+       cineon->setRow = 0;
+       cineon->close = &cineonClose;
+
+       if (verbose) {
+               verboseMe(cineon);
+       }
+
+       return cineon;
+}
+
+
+int
+cineonGetSize(const CineonFile* cineon, int* width, int* height, int* depth) {
+       *width = cineon->width;
+       *height = cineon->height;
+       *depth = cineon->depth;
+       return 0;
+}
+
+CineonFile*
+cineonCreate(const char* filename, int width, int height, int depth) {
+
+       /* Note: always write files in network order */
+       /* By the spec, it shouldn't matter, but ... */
+
+       CineonGenericHeader header;
+       const char* shortFilename = 0;
+
+       CineonFile* cineon = (CineonFile*)malloc(sizeof(CineonFile));
+       if (cineon == 0) {
+               if (verbose) d_printf("Failed to malloc cineon file structure.\n");
+               return 0;
+       }
+
+       memset(&header, 0, sizeof(header));
+
+       /* for close routine */
+       cineon->file = 0;
+       cineon->lineBuffer = 0;
+       cineon->pixelBuffer = 0;
+
+       cineon->file = fopen(filename, "wb");
+       if (cineon->file == 0) {
+               if (verbose) d_printf("Couldn't open file %s\n", filename);
+               cineonClose(cineon);
+               return 0;
+       }
+       cineon->reading = 0;
+
+       cineon->width = width;
+       cineon->height = height;
+       cineon->depth = depth;
+       cineon->bitsPerPixel = 10;
+       cineon->imageOffset = sizeof(CineonGenericHeader);
+
+       cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth);
+       cineon->lineBuffer = malloc(cineon->lineBufferLength * 4);
+       if (cineon->lineBuffer == 0) {
+               if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4);
+               cineonClose(cineon);
+               return 0;
+       }
+
+       cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short));
+       if (cineon->pixelBuffer == 0) {
+               if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
+                               (cineon->width * cineon->depth) * sizeof(unsigned short));
+               cineonClose(cineon);
+               return 0;
+       }
+       cineon->pixelBufferUsed = 0;
+
+       /* find trailing part of filename */
+       shortFilename = strrchr(filename, '/');
+       if (shortFilename == 0) {
+               shortFilename = filename;
+       } else {
+               ++shortFilename;
+       }
+
+       if (initCineonGenericHeader(cineon, &header, shortFilename) != 0) {
+               cineonClose(cineon);
+               return 0;
+       }
+
+       if (fwrite(&header, sizeof(header), 1, cineon->file) == 0) {
+               if (verbose) d_printf("Couldn't write image header\n");
+               cineonClose(cineon);
+               return 0;
+       }
+       cineon->fileYPos = 0;
+
+       logImageGetByteConversionDefaults(&cineon->params);
+       setupLut(cineon);
+
+       cineon->getRow = 0;
+       cineon->setRow = &cineonSetRowBytes;
+       cineon->close = &cineonClose;
+
+       return cineon;
+}
+
+void
+cineonClose(CineonFile* cineon) {
+
+       if (cineon == 0) {
+               return;
+       }
+
+       if (cineon->file) {
+               fclose(cineon->file);
+               cineon->file = 0;
+       }
+
+       if (cineon->lineBuffer) {
+               free(cineon->lineBuffer);
+               cineon->lineBuffer = 0;
+       }
+
+       if (cineon->pixelBuffer) {
+               free(cineon->pixelBuffer);
+               cineon->pixelBuffer = 0;
+       }
+
+       free(cineon);
+}
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.h b/source/blender/imbuf/intern/cineon/cineonlib.h
new file mode 100644 (file)
index 0000000..87fc7ad
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *      Cineon image file format library definitions.
+ *      Also handles DPX files (almost)
+ *
+ *      Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
+ *
+ *      This program is free software; you can redistribute it and/or modify it
+ *      under the terms of the GNU General Public License as published by the Free
+ *      Software Foundation; either version 2 of the License, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful, but
+ *      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *      or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *      for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _CINEON_LIB_H_
+#define _CINEON_LIB_H_
+
+#include "logImageCore.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Cineon image structure. You don't care what this is.
+ */
+
+typedef struct _Log_Image_File_t_ CineonFile;
+
+/* int functions return 0 for OK */
+
+void cineonSetVerbose(int);
+
+CineonFile* cineonOpenFromMem(unsigned char *mem, unsigned int size);
+
+CineonFile* cineonOpen(const char* filename);
+int cineonGetSize(const CineonFile* cineon, int* xsize, int* ysize, int* channels);
+CineonFile* cineonCreate(const char* filename, int xsize, int ysize, int channels);
+int cineonIsMemFileCineon(unsigned char *mem);
+
+/* get / set header block NYI */
+int cineonGetHeader(CineonFile*, int*, void**);
+int cineonSetHeader(CineonFile*, int, void*);
+
+/* get/set scanline of converted bytes */
+int cineonGetRowBytes(CineonFile* cineon, unsigned short* row, int y);
+int cineonSetRowBytes(CineonFile* cineon, const unsigned short* row, int y);
+
+/* get/set scanline of unconverted shorts */
+int cineonGetRow(CineonFile* cineon, unsigned short* row, int y);
+int cineonSetRow(CineonFile* cineon, const unsigned short* row, int y);
+
+/* closes file and deletes data */
+void cineonClose(CineonFile* cineon);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CINEON_LIB_H_ */
diff --git a/source/blender/imbuf/intern/cineon/dpxfile.h b/source/blender/imbuf/intern/cineon/dpxfile.h
new file mode 100644 (file)
index 0000000..9414550
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ *      Cineon image file format library definitions.
+ *      Dpx file format structures.
+ *
+ *      This header file contains private details.
+ *      User code should generally use cineonlib.h only.
+ *
+ *      Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
+ *
+ *      This program is free software; you can redistribute it and/or modify it
+ *      under the terms of the GNU General Public License as published by the Free
+ *      Software Foundation; either version 2 of the License, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful, but
+ *      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *      or FITNESS FOR A PARTICULAR PURPOSE.    See the GNU General Public License
+ *      for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _DPX_FILE_H_
+#define _DPX_FILE_H_
+
+#include "logImageCore.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+               U32             magic_num;                              /* magic number */
+               U32             offset;                                         /* offset to image data in bytes */
+               ASCII vers[8];                                  /* which header format version is being used (v1.0) */
+               U32             file_size;                              /* file size in bytes */
+               U32             ditto_key;                              /* I bet some people use this */
+               U32             gen_hdr_size;                   /* generic header length in bytes */
+               U32             ind_hdr_size;                   /* industry header length in bytes */
+               U32             user_data_size;         /* user-defined data length in bytes */
+               ASCII file_name[100];           /* image file name */
+               ASCII create_date[24];  /* file creation date, yyyy:mm:dd:hh:mm:ss:LTZ */
+               ASCII creator[100];
+               ASCII project[200];
+               ASCII copyright[200];
+               U32             key;                                                    /* encryption key, FFFFFFF = unencrypted */
+               ASCII Reserved[104];            /* reserved field TBD (need to pad) */
+} DpxFileInformation;
+
+typedef struct {
+               U32              signage;
+               U32              ref_low_data;           /* reference low data code value */
+               R32              ref_low_quantity; /* reference low quantity represented */
+               U32              ref_high_data;          /* reference high data code value */
+               R32              ref_high_quantity;/* reference high quantity represented */
+               U8               designator1;
+               U8               transfer_characteristics;
+               U8               colourimetry;
+               U8               bits_per_pixel;
+               U16              packing;
+               U16              encoding;
+               U32              data_offset;
+               U32              line_padding;
+               U32              channel_padding;
+               ASCII    description[32];
+} DpxChannelInformation;
+
+typedef struct {
+               U16              orientation;
+               U16              channels_per_image;
+               U32              pixels_per_line;
+               U32              lines_per_image;
+               DpxChannelInformation channel[8];
+               ASCII    reserved[52];
+} DpxImageInformation;
+
+typedef struct {
+               U32             x_offset;
+               U32             y_offset;
+               R32             x_centre;
+               R32             y_centre;
+               U32             x_original_size;
+               U32             y_original_size;
+               ASCII file_name[100];
+               ASCII creation_time[24];
+               ASCII input_device[32];
+               ASCII input_serial_number[32];
+               U16             border_validity[4];
+               U32             pixel_aspect_ratio[2]; /* h:v */
+               ASCII reserved[28];
+} DpxOriginationInformation;
+
+typedef struct {
+               ASCII film_manufacturer_id[2];
+               ASCII film_type[2];
+               ASCII edge_code_perforation_offset[2];
+               ASCII edge_code_prefix[6];
+               ASCII edge_code_count[4];
+               ASCII film_format[32];
+               U32             frame_position;
+               U32             sequence_length;
+               U32             held_count;
+               R32             frame_rate;
+               R32             shutter_angle;
+               ASCII frame_identification[32];
+               ASCII slate_info[100];
+               ASCII reserved[56];
+} DpxMPIInformation;
+
+typedef struct {
+       DpxFileInformation fileInfo;
+       DpxImageInformation imageInfo;
+       DpxOriginationInformation originInfo;
+       DpxMPIInformation filmHeader;
+} DpxMainHeader;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DPX_FILE_H_ */
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c
new file mode 100644 (file)
index 0000000..bb12f93
--- /dev/null
@@ -0,0 +1,625 @@
+/*
+ *      Dpx image file format library routines.
+ *
+ *      Copyright 1999 - 2002 David Hodson <hodsond@acm.org>
+ *
+ *      This program is free software; you can redistribute it and/or modify it
+ *      under the terms of the GNU General Public License as published by the Free
+ *      Software Foundation; either version 2 of the License, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful, but
+ *      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *      or FITNESS FOR A PARTICULAR PURPOSE.    See the GNU General Public License
+ *      for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "dpxfile.h"
+#include "dpxlib.h"
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <time.h>                               /* strftime() */
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock.h>
+#else
+#include <netinet/in.h>         /* htonl() */
+#endif
+#include <string.h>                     /* memset */
+#include "cin_debug_stuff.h"
+#include "logmemfile.h"
+
+static void
+fillDpxChannelInfo(DpxFile* dpx, DpxChannelInformation* chan, int des) {
+
+       chan->signage = 0;
+       chan->ref_low_data = htonl(0);
+       chan->ref_low_quantity = htonf(0.0);
+       chan->ref_high_data = htonl(1023);
+       chan->ref_high_quantity = htonf(2.046);
+       chan->designator1 = des;
+       chan->transfer_characteristics = 0;
+       chan->colourimetry = 0;
+       chan->bits_per_pixel = 10;
+       chan->packing = htons(1);
+       chan->encoding = 0;
+       chan->data_offset = 0;
+       chan->line_padding = htonl(0);
+       chan->channel_padding = htonl(0);
+       chan->description[0] = 0;
+}
+
+static void
+dumpDpxChannelInfo(DpxChannelInformation* chan) {
+       d_printf("      Signage %ld", ntohl(chan->signage));
+       d_printf("      Ref low data %ld\n", ntohl(chan->ref_low_data));
+       d_printf("      Ref low quantity %f\n", ntohf(chan->ref_low_quantity));
+       d_printf("      Ref high data %ld\n", ntohl(chan->ref_high_data));
+       d_printf("      Ref high quantity %f\n", ntohf(chan->ref_high_quantity));
+       d_printf("      Designator1: %d,", chan->designator1);
+       d_printf("      Bits per pixel %d\n", chan->bits_per_pixel);
+       d_printf("      Packing: %d,", ntohs(chan->packing));
+       d_printf("      Data Offset: %ld,", ntohl(chan->data_offset));
+}
+
+static void
+fillDpxFileInfo(
+       DpxFile* dpx, DpxFileInformation* fileInfo, const char* filename) {
+
+       time_t fileClock;
+       struct tm* fileTime;
+
+       /* Note: always write files in network order */
+       /* By the spec, it shouldn't matter, but ... */
+
+       fileInfo->magic_num = htonl(DPX_FILE_MAGIC);
+       fileInfo->offset = htonl(dpx->imageOffset);
+       strcpy(fileInfo->vers, "v1.0");
+       fileInfo->file_size = htonl(dpx->imageOffset +
+               pixelsToLongs(dpx->height * dpx->width * dpx->depth) * 4);
+       fileInfo->ditto_key = 0;
+       fileInfo->gen_hdr_size = htonl(
+               sizeof(DpxFileInformation) +
+               sizeof(DpxImageInformation) +
+               sizeof(DpxOriginationInformation));
+       fileInfo->ind_hdr_size = htonl(sizeof(DpxMPIInformation));
+       fileInfo->user_data_size = 0;
+       strncpy(fileInfo->file_name, filename, 99);
+       fileInfo->file_name[99] = 0;
+
+       fileClock = time(0);
+       fileTime = localtime(&fileClock);
+       strftime(fileInfo->create_date, 24, "%Y:%m:%d:%H:%M:%S%Z", fileTime);
+       /* Question: is %Z in strftime guaranteed to return 3 chars? */
+       fileInfo->create_date[23] = 0;
+
+       strcpy(fileInfo->creator, "David's DPX writer");
+       fileInfo->project[0] = 0;
+       fileInfo->copyright[0] = 0;
+       fileInfo->key = 0xFFFFFFFF; /* same in any byte order */
+}
+
+static void
+dumpDpxFileInfo(DpxFileInformation* fileInfo) {
+       d_printf("\n--File Information--\n");
+       d_printf("Magic: %8.8lX\n", ntohl(fileInfo->magic_num));
+       d_printf("Image Offset %ld\n", ntohl(fileInfo->offset));
+       d_printf("Version \"%s\"\n", fileInfo->vers);
+       d_printf("File size %ld\n", ntohl(fileInfo->file_size));
+       d_printf("Ditto key %ld\n", ntohl(fileInfo->ditto_key));
+       d_printf("Generic Header size %ld\n", ntohl(fileInfo->gen_hdr_size));
+       d_printf("Industry Header size %ld\n", ntohl(fileInfo->ind_hdr_size));
+       d_printf("User Data size %ld\n", ntohl(fileInfo->user_data_size));
+       d_printf("File name \"%s\"\n", fileInfo->file_name);
+       d_printf("Creation date \"%s\"\n", fileInfo->create_date);
+       d_printf("Creator \"%s\"\n", fileInfo->creator);
+       d_printf("Project \"%s\"\n", fileInfo->project);
+       d_printf("Copyright \"%s\"\n", fileInfo->copyright);
+       d_printf("Key %ld\n", ntohl(fileInfo->key));
+}
+
+static void
+fillDpxImageInfo(
+       DpxFile* dpx, DpxImageInformation* imageInfo) {
+       imageInfo->orientation = 0;
+       imageInfo->channels_per_image = htons(1);
+       imageInfo->pixels_per_line = htonl(dpx->width);
+       imageInfo->lines_per_image = htonl(dpx->height);
+
+       if (dpx->depth == 1) {
+               fillDpxChannelInfo(dpx, &imageInfo->channel[0], 0);
+
+       } else if (dpx->depth == 3) {
+               fillDpxChannelInfo(dpx, &imageInfo->channel[0], 50);
+       }
+}
+
+static void
+dumpDpxImageInfo(DpxImageInformation* imageInfo) {
+
+       int n;
+       int i;
+       d_printf("\n--Image Information--\n");
+       d_printf("Image orientation %d,", ntohs(imageInfo->orientation));
+       n = ntohs(imageInfo->channels_per_image);
+       d_printf("Channels %d\n", n);
+       d_printf("Pixels per line %ld\n", ntohl(imageInfo->pixels_per_line));
+       d_printf("Lines per image %ld\n", ntohl(imageInfo->lines_per_image));
+       for (i = 0; i < n; ++i) {
+               d_printf("      --Channel %d--\n", i);
+               dumpDpxChannelInfo(&imageInfo->channel[i]);
+       }
+}
+
+static void
+fillDpxOriginationInfo(
+       DpxFile* dpx, DpxOriginationInformation* originInfo, DpxFileInformation* fileInfo) {
+}
+
+static void
+dumpDpxOriginationInfo(DpxOriginationInformation* originInfo) {
+       d_printf("\n--Origination Information--\n");
+       d_printf("X offset %ld\n", ntohl(originInfo->x_offset));
+       d_printf("Y offset %ld\n", ntohl(originInfo->y_offset));
+       d_printf("X centre %f\n", ntohf(originInfo->x_centre));
+       d_printf("Y centre %f\n", ntohf(originInfo->y_centre));
+       d_printf("Original X %ld\n", ntohl(originInfo->x_original_size));
+       d_printf("Original Y %ld\n", ntohl(originInfo->y_original_size));
+       d_printf("File name \"%s\"\n", originInfo->file_name);
+       d_printf("Creation time \"%s\"\n", originInfo->creation_time);
+       d_printf("Input device \"%s\"\n", originInfo->input_device);
+       d_printf("Serial number \"%s\"\n", originInfo->input_serial_number);
+}
+
+static void
+initDpxMainHeader(DpxFile* dpx, DpxMainHeader* header, const char* shortFilename) {
+       memset(header, 0, sizeof(DpxMainHeader));
+       fillDpxFileInfo(dpx, &header->fileInfo, shortFilename);
+       fillDpxImageInfo(dpx, &header->imageInfo);
+       fillDpxOriginationInfo(dpx, &header->originInfo, &header->fileInfo);
+#if 0
+       fillDpxMPIInfo(dpx, &header->filmHeader);
+#endif
+}
+
+static void
+dumpDpxMainHeader(DpxMainHeader* header) {
+       dumpDpxFileInfo(&header->fileInfo);
+       dumpDpxImageInfo(&header->imageInfo);
+       dumpDpxOriginationInfo(&header->originInfo);
+#if 0
+       dumpDpxMPIInformation(&header->filmHeader);
+#endif
+}
+
+static int verbose = 0;
+void
+dpxSetVerbose(int verbosity) {
+       verbose = verbosity;
+}
+
+static void
+verboseMe(DpxFile* dpx) {
+
+       d_printf("size %d x %d x %d\n", dpx->width, dpx->height, dpx->depth);
+       d_printf("ImageStart %d, lineBufferLength %d, implied length %d\n",
+               dpx->imageOffset, dpx->lineBufferLength * 4,
+               dpx->imageOffset + pixelsToLongs(dpx->width * dpx->depth * dpx->height) * 4);
+}
+
+int
+dpxGetRowBytes(DpxFile* dpx, unsigned short* row, int y) {
+
+       /* Note: this code is bizarre because DPX files can wrap */
+       /* packed longwords across line boundaries!!!! */
+
+       size_t readLongs;
+       unsigned int longIndex;
+       int numPixels = dpx->width * dpx->depth;
+       int pixelIndex;
+
+       /* only seek if not reading consecutive lines */
+       /* this is not quite right yet, need to account for leftovers */
+       if (y != dpx->fileYPos) {
+               int lineOffset = pixelsToLongs(y * dpx->width * dpx->depth) * 4;
+               if (verbose) d_printf("Seek in getRowBytes\n");
+               if (logimage_fseek(dpx, dpx->imageOffset + lineOffset, SEEK_SET) != 0) {
+                       if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, dpx->imageOffset + lineOffset);
+                       return 1;
+               }
+               dpx->fileYPos = y;
+       }
+
+       /* read enough longwords */
+       readLongs = pixelsToLongs(numPixels - dpx->pixelBufferUsed);
+       if (logimage_fread(dpx->lineBuffer, 4, readLongs, dpx) != readLongs) {
+               if (verbose) d_printf("Couldn't read line %d length %d\n", y, readLongs * 4);
+               return 1;
+       }
+       ++dpx->fileYPos;
+
+       /* convert longwords to pixels */
+       pixelIndex = dpx->pixelBufferUsed;
+
+       /* this is just strange */
+       if (dpx->depth == 1) {
+               for (longIndex = 0; longIndex < readLongs; ++longIndex) {
+                       unsigned int t = ntohl(dpx->lineBuffer[longIndex]);
+                       dpx->pixelBuffer[pixelIndex] = t & 0x3ff;
+                       t = t >> 10;
+                       dpx->pixelBuffer[pixelIndex+1] = t & 0x3ff;
+                       t = t >> 10;
+                       dpx->pixelBuffer[pixelIndex+2] = t & 0x3ff;
+                       pixelIndex += 3;
+               }
+       } else /* if (dpx->depth == 3) */ {
+               for (longIndex = 0; longIndex < readLongs; ++longIndex) {
+                       unsigned int t = ntohl(dpx->lineBuffer[longIndex]);
+                       t = t >> 2;
+                       dpx->pixelBuffer[pixelIndex+2] = t & 0x3ff;
+                       t = t >> 10;
+                       dpx->pixelBuffer[pixelIndex+1] = t & 0x3ff;
+                       t = t >> 10;
+                       dpx->pixelBuffer[pixelIndex] = t & 0x3ff;
+                       pixelIndex += 3;
+               }
+       }
+       dpx->pixelBufferUsed = pixelIndex;
+
+       /* extract required pixels */
+       for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
+               /* row[pixelIndex] = dpx->lut10[dpx->pixelBuffer[pixelIndex]]; */
+               row[pixelIndex] = dpx->pixelBuffer[pixelIndex] << 6;
+       }
+
+       /* save remaining pixels */
+       while (pixelIndex < dpx->pixelBufferUsed) {
+               dpx->pixelBuffer[pixelIndex - numPixels] = dpx->pixelBuffer[pixelIndex];
+               ++pixelIndex;
+       }
+       dpx->pixelBufferUsed -= numPixels;
+
+       /* done! */
+       return 0;
+}
+
+int
+dpxSetRowBytes(DpxFile* dpx, const unsigned short* row, int y) {
+
+       /* Note: this code is bizarre because DPX files can wrap */
+       /* packed longwords across line boundaries!!!! */
+
+       size_t writeLongs;
+       int longIndex;
+       int numPixels = dpx->width * dpx->depth;
+       int pixelIndex;
+       int pixelIndex2;
+
+       /* only seek if not reading consecutive lines */
+       /* this is not quite right yet */
+       if (y != dpx->fileYPos) {
+               int lineOffset = pixelsToLongs(y * dpx->width * dpx->depth) * 4;
+               if (verbose) d_printf("Seek in getRowBytes\n");
+               if (logimage_fseek(dpx, dpx->imageOffset + lineOffset, SEEK_SET) != 0) {
+                       if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, dpx->imageOffset + lineOffset);
+                       return 1;
+               }
+               dpx->fileYPos = y;
+       }
+
+       /* put new pixels into pixelBuffer */
+       for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
+               /* dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = dpx->lut8[row[pixelIndex]]; */
+               dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = row[pixelIndex] >> 6;
+       }
+       dpx->pixelBufferUsed += numPixels;
+
+       /* pack into longwords */
+       writeLongs = dpx->pixelBufferUsed / 3;
+       /* process whole line at image end */
+       if (dpx->fileYPos == (dpx->height - 1)) {
+               writeLongs = pixelsToLongs(dpx->pixelBufferUsed);
+       }
+       pixelIndex = 0;
+       if (dpx->depth == 1) {
+               for (longIndex = 0; longIndex < writeLongs; ++longIndex) {
+                       unsigned int t = dpx->pixelBuffer[pixelIndex] |
+                                       (dpx->pixelBuffer[pixelIndex+1] << 10) |
+                                       (dpx->pixelBuffer[pixelIndex+2] << 20);
+                       dpx->lineBuffer[longIndex] = htonl(t);
+                       pixelIndex += 3;
+               }
+       } else {
+               for (longIndex = 0; longIndex < writeLongs; ++longIndex) {
+                       unsigned int t = dpx->pixelBuffer[pixelIndex+2] << 2 |
+                                       (dpx->pixelBuffer[pixelIndex+1] << 12) |
+                                       (dpx->pixelBuffer[pixelIndex] << 22);
+                       dpx->lineBuffer[longIndex] = htonl(t);
+                       pixelIndex += 3;
+               }
+       }
+
+       /* write them */
+       if (fwrite(dpx->lineBuffer, 4, writeLongs, dpx->file) != writeLongs) {
+               if (verbose) d_printf("Couldn't write line %d length %d\n", y, writeLongs * 4);
+               return 1;
+       }
+       ++dpx->fileYPos;
+
+       /* save remaining pixels */
+       pixelIndex2 = 0;
+       while (pixelIndex < dpx->pixelBufferUsed) {
+               dpx->pixelBuffer[pixelIndex2] = dpx->pixelBuffer[pixelIndex];
+               ++pixelIndex;
+               ++pixelIndex2;
+       }
+       dpx->pixelBufferUsed = pixelIndex2;
+
+       return 0;
+}
+
+#define LFMEMFILE      0
+#define LFREALFILE     1
+
+static DpxFile* 
+intern_dpxOpen(int mode, const char* bytestuff, int bufsize) {
+
+       DpxMainHeader header;
+       const char *filename = bytestuff;
+       DpxFile* dpx = (DpxFile*)malloc(sizeof(DpxFile));
+       
+       if (dpx == 0) {
+               if (verbose) d_printf("Failed to malloc dpx file structure.\n");
+               return 0;
+       }
+
+       /* for close routine */
+       dpx->file = 0;
+       dpx->lineBuffer = 0;
+       dpx->pixelBuffer = 0;
+
+       if (mode == LFREALFILE) {
+               filename = bytestuff;
+               dpx->file = fopen(filename, "rb");
+               if (dpx->file == 0) {   
+                       if (verbose) d_printf("Failed to open file \"%s\".\n", filename);
+                       dpxClose(dpx);
+                       return 0;
+               }
+               dpx->membuffer = 0;
+               dpx->memcursor = 0;
+               dpx->membuffersize = 0;
+       } else if (mode == LFMEMFILE) {
+               dpx->membuffer = (unsigned char *)bytestuff;
+               dpx->memcursor = (unsigned char *)bytestuff;
+               dpx->membuffersize = bufsize;
+       }
+       
+       dpx->reading = 1;
+
+       if (logimage_fread(&header, sizeof(header), 1, dpx) == 0) {
+               if (verbose) d_printf("Not enough data for header in \"%s\".\n", filename);
+               dpxClose(dpx);
+               return 0;
+       }
+
+       /* let's assume dpx files are always network order */
+       if (header.fileInfo.magic_num != ntohl(DPX_FILE_MAGIC)) {
+               if (verbose) d_printf("Bad magic number %8.8lX in \"%s\".\n",
+                       ntohl(header.fileInfo.magic_num), filename);
+               dpxClose(dpx);
+               return 0;
+       }
+
+       if (ntohs(header.imageInfo.channel[0].packing) != 1) {
+               if (verbose) d_printf("Unknown packing %d\n", header.imageInfo.channel[0].packing);
+               dpxClose(dpx);
+               return 0;
+       }
+
+
+       dpx->width = ntohl(header.imageInfo.pixels_per_line);
+       dpx->height = ntohl(header.imageInfo.lines_per_image);
+       dpx->depth = ntohs(header.imageInfo.channels_per_image);
+       /* Another DPX vs Cineon wierdness */
+       if (dpx->depth == 1) {
+               switch (header.imageInfo.channel[0].designator1) {
+               case 50: dpx->depth = 3; break;
+               case 51: dpx->depth = 4; break;
+               case 52: dpx->depth = 4; break;
+               default: break;
+               }
+       }
+       dpx->bitsPerPixel = 10;
+       /* dpx->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel; */
+       dpx->imageOffset = ntohl(header.fileInfo.offset);
+
+       dpx->lineBufferLength = pixelsToLongs(dpx->width * dpx->depth);
+       dpx->lineBuffer = malloc(dpx->lineBufferLength * 4);
+       if (dpx->lineBuffer == 0) {
+               if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", dpx->lineBufferLength * 4);
+               dpxClose(dpx);
+               return 0;
+       }
+
+       /* could have 2 pixels left over */
+       dpx->pixelBuffer = malloc((dpx->lineBufferLength * 3 + 2) * sizeof(unsigned short));
+       if (dpx->pixelBuffer == 0) {
+               if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
+                               (dpx->width * dpx->depth + 2 + 2) * sizeof(unsigned short));
+               dpxClose(dpx);
+               return 0;
+       }
+       dpx->pixelBufferUsed = 0;
+
+       if (logimage_fseek(dpx, dpx->imageOffset, SEEK_SET) != 0) {
+               if (verbose) d_printf("Couldn't seek to image data start at %d\n", dpx->imageOffset);
+               dpxClose(dpx);
+               return 0;
+       }
+       dpx->fileYPos = 0;
+
+       logImageGetByteConversionDefaults(&dpx->params);
+       setupLut(dpx);
+
+       dpx->getRow = &dpxGetRowBytes;
+       dpx->setRow = 0;
+       dpx->close = &dpxClose;
+
+       if (verbose) {
+               verboseMe(dpx);
+       }
+
+       return dpx;
+}
+
+DpxFile* 
+dpxOpen(const char *filename) {
+       return intern_dpxOpen(LFREALFILE, filename, 0);
+}
+
+DpxFile* 
+dpxOpenFromMem(unsigned char *buffer, unsigned int size) {
+       return intern_dpxOpen(LFMEMFILE, (const char *) buffer, size);
+}
+
+int 
+dpxIsMemFileCineon(void *buffer) {
+       int magicnum = 0;
+       magicnum = *((int*)buffer);
+       if (magicnum == ntohl(DPX_FILE_MAGIC)) return 1;
+       else return 0;
+}
+
+DpxFile*
+dpxCreate(const char* filename, int width, int height, int depth) {
+
+       /* Note: always write files in network order */
+       /* By the spec, it shouldn't matter, but ... */
+
+       DpxMainHeader header;
+       const char* shortFilename = 0;
+
+       DpxFile* dpx = (DpxFile*)malloc(sizeof(DpxFile));
+       if (dpx == 0) {
+               if (verbose) d_printf("Failed to malloc dpx file structure.\n");
+               return 0;
+       }
+
+       memset(&header, 0, sizeof(header));
+
+       /* for close routine */
+       dpx->file = 0;
+       dpx->lineBuffer = 0;
+       dpx->pixelBuffer = 0;
+
+       dpx->file = fopen(filename, "wb");
+       if (dpx->file == 0) {
+               if (verbose) d_printf("Couldn't open file %s\n", filename);
+               dpxClose(dpx);
+               return 0;
+       }
+       dpx->reading = 0;
+
+       dpx->width = width;
+       dpx->height = height;
+       dpx->depth = depth;
+       dpx->bitsPerPixel = 10;
+       dpx->imageOffset = sizeof(DpxMainHeader);
+
+       dpx->lineBufferLength = pixelsToLongs(dpx->width * dpx->depth);
+       dpx->lineBuffer = malloc(dpx->lineBufferLength * 4);
+       if (dpx->lineBuffer == 0) {
+               if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", dpx->lineBufferLength * 4);
+               dpxClose(dpx);
+               return 0;
+       }
+
+       dpx->pixelBuffer = malloc((dpx->lineBufferLength * 3 + 2) * sizeof(unsigned short));
+       if (dpx->pixelBuffer == 0) {
+               if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
+                               (dpx->width * dpx->depth + 2 + 2) * sizeof(unsigned short));
+               dpxClose(dpx);
+               return 0;
+       }
+       dpx->pixelBufferUsed = 0;
+
+       /* find trailing part of filename */
+       shortFilename = strrchr(filename, '/');
+       if (shortFilename == 0) {
+               shortFilename = filename;
+       } else {
+               ++shortFilename;
+       }
+       initDpxMainHeader(dpx, &header, shortFilename);
+
+       if (fwrite(&header, sizeof(header), 1, dpx->file) == 0) {
+               if (verbose) d_printf("Couldn't write image header\n");
+               dpxClose(dpx);
+               return 0;
+       }
+       dpx->fileYPos = 0;
+
+       logImageGetByteConversionDefaults(&dpx->params);
+       setupLut(dpx);
+
+       dpx->getRow = 0;
+       dpx->setRow = &dpxSetRowBytes;
+       dpx->close = &dpxClose;
+
+       return dpx;
+}
+
+void
+dpxClose(DpxFile* dpx) {
+
+       if (dpx == 0) {
+               return;
+       }
+
+       if (dpx->file) {
+               fclose(dpx->file);
+               dpx->file = 0;
+       }
+
+       if (dpx->lineBuffer) {
+               free(dpx->lineBuffer);
+               dpx->lineBuffer = 0;
+       }
+
+       if (dpx->pixelBuffer) {
+               free(dpx->pixelBuffer);
+               dpx->pixelBuffer = 0;
+       }
+
+       free(dpx);
+}
+
+void
+dpxDump(const char* filename) {
+
+       DpxMainHeader header;
+       FILE* file;
+
+       file = fopen(filename, "rb");
+       if (file == 0) {
+               d_printf("Failed to open file \"%s\".\n", filename);
+               return;
+       }
+
+       if (fread(&header, sizeof(header), 1, file) == 0) {
+               d_printf("Not enough data for header in \"%s\".\n", filename);
+               fclose(file);
+               return;
+       }
+
+       fclose(file);
+       dumpDpxMainHeader(&header);
+}
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.h b/source/blender/imbuf/intern/cineon/dpxlib.h
new file mode 100644 (file)
index 0000000..25fe84e
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *      DPX image file format library definitions.
+ *
+ *      Copyright 1999 - 2002 David Hodson <hodsond@acm.org>
+ *
+ *      This program is free software; you can redistribute it and/or modify it
+ *      under the terms of the GNU General Public License as published by the Free
+ *      Software Foundation; either version 2 of the License, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful, but
+ *      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *      or FITNESS FOR A PARTICULAR PURPOSE.    See the GNU General Public License
+ *      for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _DPX_LIB_H_
+#define _DPX_LIB_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "logImageCore.h"
+
+typedef struct _Log_Image_File_t_ DpxFile;
+
+/* int functions return 0 for OK */
+
+void dpxSetVerbose(int);
+
+DpxFile* dpxOpen(const char* filename);
+DpxFile* dpxCreate(const char* filename, int xsize, int ysize, int channels);
+DpxFile* dpxOpenFromMem(unsigned char *buffer, unsigned int size);
+int dpxIsMemFileCineon(void *buffer);
+
+/* get/set scanline of converted bytes */
+int dpxGetRowBytes(DpxFile* dpx, unsigned short* row, int y);
+int dpxSetRowBytes(DpxFile* dpx, const unsigned short* row, int y);
+
+/* closes file and deletes data */
+void dpxClose(DpxFile* dpx);
+
+/* dumps file to stdout */
+void dpxDump(const char* filename);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DPX_LIB_H_ */
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c
new file mode 100644 (file)
index 0000000..e88e924
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ *      Cineon image file format library routines.
+ *
+ *      Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
+ *
+ *      This program is free software; you can redistribute it and/or modify it
+ *      under the terms of the GNU General Public License as published by the Free
+ *      Software Foundation; either version 2 of the License, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful, but
+ *      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *      or FITNESS FOR A PARTICULAR PURPOSE.    See the GNU General Public License
+ *      for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "logImageCore.h"
+
+#include <time.h>                               /* strftime() */
+#include <math.h>
+/* Makes rint consistent in Windows and Linux: */
+#define rint(x) floor(x+0.5)
+
+#ifdef WIN32
+#include <winsock.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/param.h>
+#endif
+
+#if defined(__hpux)
+/* These are macros in hpux */
+#ifdef htonl
+#undef htonl
+#undef htons
+#undef ntohl
+#undef ntohs
+#endif
+unsigned int htonl(h) unsigned int h; { return(h); }
+unsigned short htons(h) unsigned short h; { return(h); }
+unsigned int ntohl(n) unsigned int n; { return(n); }
+unsigned short ntohs(n) unsigned short n; { return(n); }
+#endif
+       
+       
+/* obscure LogImage conversion */
+/* from 10 bit int to 0.0 - 1.0 */
+/* magic numbers left intact */
+static double
+convertTo(int inp, int white, float gamma) {
+       /*      return pow(pow(10.0, ((inp - white) * 0.002 / 0.6)), gamma); */
+       return pow(10.0, (inp - white) * gamma * 0.002 / 0.6);
+}
+
+static double
+convertFrom(double inp, int white, float gamma) {
+       return white + log10(inp) / (gamma * 0.002 / 0.6);
+}
+
+/* set up the 10 bit to 8 bit and 8 bit to 10 bit tables */
+void
+setupLut(LogImageFile *logImage) {
+
+       int i;
+       double f_black;
+       double scale;
+
+       f_black = convertTo(logImage->params.blackPoint, logImage->params.whitePoint, logImage->params.gamma);
+       scale = 255.0 / (1.0 - f_black);
+
+       for (i = 0; i <= logImage->params.blackPoint; ++i) {
+               logImage->lut10[i] = 0;
+       }
+       for (; i < logImage->params.whitePoint; ++i) {
+               double f_i;
+               f_i = convertTo(i, logImage->params.whitePoint, logImage->params.gamma);
+               logImage->lut10[i] = (int)rint(scale * (f_i - f_black));
+       }
+       for (; i < 1024; ++i) {
+               logImage->lut10[i] = 255;
+       }
+
+       for (i = 0; i < 256; ++i) {
+               double f_i = f_black + (i / 255.0) * (1.0 - f_black);
+               logImage->lut8[i] = convertFrom(f_i, logImage->params.whitePoint, logImage->params.gamma);
+       }
+}
+
+/* how many longwords to hold this many pixels? */
+int
+pixelsToLongs(int numPixels) {
+       return (numPixels + 2) / 3;
+}
+
+/* byte reversed float */
+
+typedef union {
+       U32 i;
+       R32 f;
+} Hack;
+
+R32
+htonf(R32 f) {
+       Hack hack;
+       hack.f = f;
+       hack.i = htonl(hack.i);
+       return hack.f;
+}
+
+R32
+ntohf(R32 f) {
+       Hack hack;
+       hack.f = f;
+       hack.i = ntohl(hack.i);
+       return hack.f;
+}
+
+#define UNDEF_FLOAT 0x7F800000
+
+R32
+undefined() {
+       Hack hack;
+       hack.i = UNDEF_FLOAT;
+       return hack.f;
+}
+
+/* reverse an endian-swapped U16 */
+U16
+reverseU16(U16 value) {
+
+       union {
+               U16 whole;
+               char part[2];
+       } buff;
+       char temp;
+       buff.whole = value;
+       temp = buff.part[0];
+       buff.part[0] = buff.part[1];
+       buff.part[1] = temp;
+       return buff.whole;
+}
+
+/* reverse an endian-swapped U32 */
+U32
+reverseU32(U32 value) {
+
+       union {
+               U32 whole;
+               char part[4];
+       } buff;
+       char temp;
+       buff.whole = value;
+       temp = buff.part[0];
+       buff.part[0] = buff.part[3];
+       buff.part[3] = temp;
+       temp = buff.part[1];
+       buff.part[1] = buff.part[2];
+       buff.part[2] = temp;
+       return buff.whole;
+}
+
+/* reverse an endian-swapped R32 */
+R32
+reverseR32(R32 value) {
+
+       union {
+               R32 whole;
+               char part[4];
+       } buff;
+       char temp;
+       buff.whole = value;
+       temp = buff.part[0];
+       buff.part[0] = buff.part[3];
+       buff.part[3] = temp;
+       temp = buff.part[1];
+       buff.part[1] = buff.part[2];
+       buff.part[2] = temp;
+       return buff.whole;
+}
+
+#if 0
+/* bytes per line for images packed 3 10 bit pixels to 32 bits, 32 bit aligned */
+int
+bytesPerLine_10_4(int numPixels) {
+       return ((numPixels + 2) / 3) * 4;
+}
+
+void
+seekLine_noPadding(LogImageFile* logImage, int lineNumber) {
+       int fileOffset = bytesPerLine_10_4(lineNumber * logImage->width * logImage->depth);
+       int filePos = logImage->imageOffset + fileOffset;
+       if (fseek(logImage->file, filePos, SEEK_SET) != 0) {
+               /* complain? */
+       }
+}
+
+void
+seekLine_padding(LogImageFile* logImage, int lineNumber) {
+       int fileOffset = lineNumber * bytesPerLine_10_4(logImage->width * logImage->depth);
+       int filePos = logImage->imageOffset + fileOffset;
+       if (fseek(logImage->file, filePos, SEEK_SET) != 0) {
+               /* complain? */
+       }
+}
+#endif
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h
new file mode 100644 (file)
index 0000000..1af18d5
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ *      Cineon image file format library definitions.
+ *      Cineon and DPX common structures.
+ *
+ *      This header file contains private details.
+ *      User code should generally use cineonlib.h and dpxlib.h only.
+ *      Hmm. I thought the two formats would have more in common!
+ *
+ *      Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
+ *
+ *      This program is free software; you can redistribute it and/or modify it
+ *      under the terms of the GNU General Public License as published by the Free
+ *      Software Foundation; either version 2 of the License, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful, but
+ *      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *      or FITNESS FOR A PARTICULAR PURPOSE.    See the GNU General Public License
+ *      for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _LOG_IMAGE_CORE_H_
+#define _LOG_IMAGE_CORE_H_
+
+#include <stdio.h>
+#include "logImageLib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef int (GetRowFn)(LogImageFile* logImage, unsigned short* row, int lineNum);
+typedef int (SetRowFn)(LogImageFile* logImage, const unsigned short* row, int lineNum);
+typedef void (CloseFn)(LogImageFile* logImage);
+
+struct _Log_Image_File_t_
+{
+       /* specified in header */
+       int width;
+       int height;
+       int depth;
+       int bitsPerPixel;
+       int imageOffset;
+
+       /* file buffer, measured in longwords (4 byte) */
+       int lineBufferLength;
+       unsigned int* lineBuffer;
+
+       /* pixel buffer, holds 10 bit pixel values */
+       unsigned short* pixelBuffer;
+       int pixelBufferUsed;
+
+       /* io stuff */
+       FILE* file;
+       int reading;
+       int fileYPos;
+
+       /* byte conversion stuff */
+       LogImageByteConversionParameters params;
+#if 0
+       float gamma;
+       int blackPoint;
+       int whitePoint;
+#endif
+       unsigned char lut10[1024];
+       unsigned short lut8[256];
+
+       /* pixel access functions */
+       GetRowFn* getRow;
+       SetRowFn* setRow;
+       CloseFn* close;
+       
+       unsigned char *membuffer;
+       unsigned long membuffersize;
+       unsigned char *memcursor;
+};
+
+void setupLut(LogImageFile*);
+
+int pixelsToLongs(int numPixels);
+
+/* typedefs used in original docs */
+/* note size assumptions! */
+
+typedef unsigned int U32;
+typedef unsigned short U16;
+typedef unsigned char U8;
+typedef signed int S32;
+typedef float R32;
+typedef char ASCII;
+
+R32 htonf(R32 f);
+R32 ntohf(R32 f);
+R32 undefined();
+U16 reverseU16(U16 value);
+U32 reverseU32(U32 value);
+R32 reverseR32(R32 value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LOG_IMAGE_CORE_H_ */
diff --git a/source/blender/imbuf/intern/cineon/logImageLib.c b/source/blender/imbuf/intern/cineon/logImageLib.c
new file mode 100644 (file)
index 0000000..ff209d5
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ *      Cineon and DPX image file format library routines.
+ *
+ *      Copyright 1999 - 2002 David Hodson <hodsond@acm.org>
+ *
+ *      This program is free software; you can redistribute it and/or modify it
+ *      under the terms of the GNU General Public License as published by the Free
+ *      Software Foundation; either version 2 of the License, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful, but
+ *      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *      or FITNESS FOR A PARTICULAR PURPOSE.    See the GNU General Public License
+ *      for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "cineonlib.h"
+#include "dpxlib.h"
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <time.h>                               /* strftime() */
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock.h>
+#else
+#include <netinet/in.h>         /* htonl() */
+#endif
+#include <string.h>                     /* memset */
+
+#define MIN_GAMMA 0.01
+#define MAX_GAMMA 99.9
+#define DEFAULT_GAMMA 1.0
+#define DEFAULT_BLACK_POINT 95
+#define DEFAULT_WHITE_POINT 685
+
+void
+logImageSetVerbose(int verbosity) {
+       cineonSetVerbose(verbosity);
+       dpxSetVerbose(verbosity);
+}
+
+LogImageFile*
+logImageOpen(const char* filename, int cineon) {
+       if (cineon) {
+               return cineonOpen(filename);
+       } else {
+               return dpxOpen(filename);
+       }
+       return 0;
+}
+
+LogImageFile*
+logImageOpenFromMem(unsigned char *buffer, unsigned int size, int cineon) {
+       if (cineon) {
+               return cineonOpenFromMem(buffer, size);
+       } else {
+               return dpxOpenFromMem(buffer, size);
+       }
+       return 0;
+}
+
+LogImageFile*
+logImageCreate(const char* filename, int cineon, int width, int height, int depth) {
+       if (cineon) {
+               return cineonCreate(filename, width, height, depth);
+       } else {
+               return dpxCreate(filename, width, height, depth);
+       }
+       return 0;
+}
+
+int
+logImageGetSize(const LogImageFile* logImage, int* width, int* height, int* depth) {
+       *width = logImage->width;
+       *height = logImage->height;
+       *depth = logImage->depth;
+       return 0;
+}
+
+int
+logImageGetByteConversionDefaults(LogImageByteConversionParameters* params) {
+       params->gamma = DEFAULT_GAMMA;
+       params->blackPoint = DEFAULT_BLACK_POINT;
+       params->whitePoint = DEFAULT_WHITE_POINT;
+       return 0;
+}
+
+int
+logImageGetByteConversion(const LogImageFile* logImage, LogImageByteConversionParameters* params) {
+       params->gamma = logImage->params.gamma;
+       params->blackPoint = logImage->params.blackPoint;
+       params->whitePoint = logImage->params.whitePoint;
+       return 0;
+}
+
+int
+logImageSetByteConversion(LogImageFile* logImage, const LogImageByteConversionParameters* params) {
+       if ((params->gamma >= MIN_GAMMA) &&
+                       (params->gamma <= MAX_GAMMA) &&
+                       (params->blackPoint >= 0) &&
+                       (params->blackPoint < params->whitePoint) &&
+                       (params->whitePoint <= 1023)) {
+               logImage->params.gamma = params->gamma;
+               logImage->params.blackPoint = params->blackPoint;
+               logImage->params.whitePoint = params->whitePoint;
+               setupLut(logImage);
+               return 0;
+       }
+       return 1;
+}
+
+int
+logImageGetRowBytes(LogImageFile* logImage, unsigned short* row, int y) {
+       return logImage->getRow(logImage, row, y);
+}
+
+int
+logImageSetRowBytes(LogImageFile* logImage, const unsigned short* row, int y) {
+       return logImage->setRow(logImage, row, y);
+}
+
+void
+logImageClose(LogImageFile* logImage) {
+       logImage->close(logImage);
+}
+
+void
+logImageDump(const char* filename) {
+
+       U32 magic;
+
+       FILE* foo = fopen(filename, "rb");
+       if (foo == 0) {
+               return;
+       }
+
+       if (fread(&magic, sizeof(magic), 1, foo) == 0) {
+               fclose(foo);
+               return;
+       }
+
+       fclose(foo);
+
+       if (magic == ntohl(CINEON_FILE_MAGIC)) {
+#if 0
+               cineonDump(filename);
+#endif
+       } else if (magic == ntohl(DPX_FILE_MAGIC)) {
+               dpxDump(filename);
+       }
+}
diff --git a/source/blender/imbuf/intern/cineon/logImageLib.h b/source/blender/imbuf/intern/cineon/logImageLib.h
new file mode 100644 (file)
index 0000000..ea45c67
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *      Common library definitions for Cineon and DPX image files.
+ *
+ *      Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
+ *
+ *      This program is free software; you can redistribute it and/or modify it
+ *      under the terms of the GNU General Public License as published by the Free
+ *      Software Foundation; either version 2 of the License, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful, but
+ *      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *      or FITNESS FOR A PARTICULAR PURPOSE.    See the GNU General Public License
+ *      for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _LOG_IMAGE_LIB_H_
+#define _LOG_IMAGE_LIB_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Image structure. You don't care what this is.
+ */
+
+typedef struct _Log_Image_File_t_ LogImageFile;
+
+/*
+ * Magic numbers for normal and byte-swapped Cineon and Dpx files
+ */
+
+#define CINEON_FILE_MAGIC 0x802A5FD7
+#define DPX_FILE_MAGIC 0x53445058
+
+/*
+ * Image 8 bit <-> 10 bit conversion parameters.
+ */
+
+typedef struct {
+       float gamma;
+       int blackPoint;
+       int whitePoint;
+} LogImageByteConversionParameters;
+
+/* int functions return 0 for OK */
+
+void logImageSetVerbose(int);
+
+LogImageFile* logImageOpenFromMem(unsigned char *buffer, unsigned int size, int cineon);
+LogImageFile* logImageOpen(const char* filename, int cineon);
+int logImageGetSize(const LogImageFile* logImage, int* xsize, int* ysize, int* channels);
+LogImageFile* logImageCreate(const char* filename, int cineon, int xsize, int ysize, int channels);
+
+/* get / set header block NYI */
+int logImageGetHeader(LogImageFile*, int*, void**);
+int logImageSetHeader(LogImageFile*, int, void*);
+
+/* byte conversion routines for mapping logImage (usually) 10 bit values to 8 bit */
+/* see Kodak docs for details... */
+
+int logImageGetByteConversionDefaults(LogImageByteConversionParameters* params);
+int logImageGetByteConversion(const LogImageFile* logImage, LogImageByteConversionParameters* params);
+int logImageSetByteConversion(LogImageFile* logImage, const LogImageByteConversionParameters* params);
+
+/* get/set scanline of converted bytes */
+int logImageGetRowBytes(LogImageFile* logImage, unsigned short* row, int y);
+int logImageSetRowBytes(LogImageFile* logImage, const unsigned short* row, int y);
+
+/* closes file and deletes data */
+void logImageClose(LogImageFile* logImage);
+
+/* read file and dump header info */
+void logImageDump(const char* filename);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LOG_IMAGE_LIB_H_ */
diff --git a/source/blender/imbuf/intern/cineon/logmemfile.c b/source/blender/imbuf/intern/cineon/logmemfile.c
new file mode 100644 (file)
index 0000000..2035933
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ *      Cineon image file format library routines.
+ *
+ *      Copyright 2006 Joseph Eagar (joeedh@gmail.com)
+ *
+ *      This program is free software; you can redistribute it and/or modify it
+ *      under the terms of the GNU General Public License as published by the Free
+ *      Software Foundation; either version 2 of the License, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful, but
+ *      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *      or FITNESS FOR A PARTICULAR PURPOSE.    See the GNU General Public License
+ *      for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "logImageCore.h"
+
+int logimage_fseek(void* logfile, long offsett, int origin)
+{      
+       struct _Log_Image_File_t_ *file = (struct _Log_Image_File_t_*) logfile;
+       long offset = offsett;
+       
+       if (file->file) fseek(file->file, offset, origin);
+       else { /*we're seeking in memory*/
+               if (origin==SEEK_SET) {
+                       if (offset > file->membuffersize) return 1;
+                       file->memcursor = file->membuffer + offset;
+               } else if (origin==SEEK_END) {
+                       if (offset > file->membuffersize) return 1;
+                       file->memcursor = (file->membuffer + file->membuffersize) - offset;
+               } else if (origin==SEEK_CUR) {
+                       unsigned long pos = (unsigned long)file->membuffer - (unsigned long)file->memcursor;
+                       if (pos + offset > file->membuffersize) return 1;
+                       if (pos < 0) return 1;
+                       file->memcursor += offset;
+               }
+       }
+       return 0;
+}
+
+int logimage_fwrite(void *buffer, unsigned int size, unsigned int count, void *logfile)
+{
+       struct _Log_Image_File_t_ *file = (struct _Log_Image_File_t_*) logfile;
+       if (file->file) return fwrite(buffer, size, count, file->file);
+       else { /*we're writing to memory*/
+               /*do nothing as this isn't supported yet*/
+               return count;
+       }
+}
+
+int logimage_fread(void *buffer, unsigned int size, unsigned int count, void *logfile)
+{
+       struct _Log_Image_File_t_ *file = (struct _Log_Image_File_t_*) logfile;
+       if (file->file) return fread(buffer, size, count, file->file);
+       else { /*we're reading from memory*/
+               int i;
+               /*we convert ot uchar just on the off chance some platform can't handle
+                 pointer arithmetic with type (void*). */
+               unsigned char *buf = (unsigned char *) buffer; 
+               
+               for (i=0; i<count; i++) {
+                       memcpy(buf, file->memcursor, size);
+                       file->memcursor += size;
+                       buf += size;
+               }
+               return count;
+       }
+}
diff --git a/source/blender/imbuf/intern/cineon/logmemfile.h b/source/blender/imbuf/intern/cineon/logmemfile.h
new file mode 100644 (file)
index 0000000..6e82cf2
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ *      Cineon image file format library routines.
+ *
+ *      Copyright 2006 Joseph Eagar (joeedh@gmail.com)
+ *
+ *      This program is free software; you can redistribute it and/or modify it
+ *      under the terms of the GNU General Public License as published by the Free
+ *      Software Foundation; either version 2 of the License, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful, but
+ *      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *      or FITNESS FOR A PARTICULAR PURPOSE.    See the GNU General Public License
+ *      for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+#ifndef _LOGMEMFILE_H
+#define _LOGMEMFILE_H
+
+int logimage_fseek(void* logfile, long offsett, int origin);
+int logimage_fwrite(void *buffer, unsigned int size, unsigned int count, void *logfile);
+int logimage_fread(void *buffer, unsigned int size, unsigned int count, void *logfile);
+
+#endif /* _LOGMEMFILE_H */
index 23fe3f0a6d2bb52438cd44db6667e170483b239f..45ef191277b770098593aecfc20f4238b1bd9311 100644 (file)
@@ -52,6 +52,7 @@
 #include "IMB_bmp.h"
 #include "IMB_tiff.h"
 #include "IMB_radiance_hdr.h"
+#include "IMB_dpxcineon.h"
 #include "BKE_global.h"
 
 #ifdef WITH_OPENEXR
@@ -134,6 +135,12 @@ ImBuf *IMB_ibImageFromMemory(int *mem, int size, int flags) {
                ibuf = imb_loadtarga((uchar *)mem, flags);
                if (ibuf) return(ibuf);
 
+               ibuf = imb_loaddpx((uchar *)mem, size, flags);
+               if (ibuf) return(ibuf);
+
+               ibuf = imb_loadcineon((uchar *)mem, size, flags);
+               if (ibuf) return(ibuf);
+       
                if (G.have_libtiff) {
                        ibuf = imb_loadtiff((uchar *)mem, size, flags);
                        if (ibuf) return(ibuf);
index 56a03f56ce2dab3fe7442a6e22c910a559d8221c..d741665f6ead287cfb2719ce0fba3f10fe2d768e 100644 (file)
@@ -47,6 +47,7 @@
 #include "IMB_bmp.h"
 #include "IMB_tiff.h"
 #include "IMB_radiance_hdr.h"
+#include "IMB_dpxcineon.h"
 
 #include "IMB_anim.h"
 
@@ -117,7 +118,8 @@ static int IMB_ispic_name(char *name)
                                if (imb_is_a_openexr((uchar *)buf)) return(OPENEXR);
 #endif
                                if (imb_is_a_tiff(buf)) return(TIF);
-
+                               if (imb_is_dpx(buf)) return (DPX);
+                               if (imb_is_cineon(buf)) return(CINEON);
                                /* radhdr: check if hdr format */
                                if (imb_is_a_hdr(buf)) return(RADHDR);
 
@@ -168,6 +170,7 @@ int IMB_ispic(char *filename)
                                ||      BLI_testextensie(filename, ".pict")
                                ||      BLI_testextensie(filename, ".pntg") //macpaint
                                ||      BLI_testextensie(filename, ".qtif")
+                               ||  BLI_testextensie(filename, ".cin")
                                ||      BLI_testextensie(filename, ".sgi")) {
                                return IMB_ispic_name(filename);
                        } else {
@@ -181,6 +184,7 @@ int IMB_ispic(char *filename)
                                ||      BLI_testextensie(filename, ".rgb")
                                ||      BLI_testextensie(filename, ".bmp")
                                ||      BLI_testextensie(filename, ".png")
+                               ||  BLI_testextensie(filename, ".cin")
                                ||      BLI_testextensie(filename, ".iff")
                                ||      BLI_testextensie(filename, ".lbm")
                                ||      BLI_testextensie(filename, ".sgi")) {
index ae75de8f54f991169e3bc4e59e387ea94bb7abc8..2e922c65827ace551ed3eb3fdab6301eee371d52 100644 (file)
@@ -47,6 +47,7 @@
 
 #include "IMB_allocimbuf.h"
 
+#include "IMB_dpxcineon.h"
 #include "IMB_targa.h"
 #include "IMB_jpeg.h"
 #include "IMB_iris.h"
@@ -114,7 +115,13 @@ short IMB_saveiff(struct ImBuf *ibuf, char *name, int flags)
                return imb_save_openexr(ibuf, name, flags);
        }
 #endif
-
+       if (IS_cineon(ibuf)) {
+               return imb_savecineon(ibuf, name, flags);
+               
+       }
+       if (IS_dpx(ibuf)) {
+               return imb_save_dpx(ibuf, name, flags);
+       }
        file = open(name, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, 0666);
        if (file < 0) return (FALSE);
 
index 7e56b276d590c3f88a7d5d4444653e45ccff0990..035dab4a683be9d1b855b87cd98f0c929c8d8cf9 100644 (file)
@@ -477,6 +477,8 @@ typedef struct Scene {
 #define R_OPENEXR      23
 #define R_FFMPEG        24
 #define R_FRAMESERVER   25
+#define R_CINEON       26
+#define R_DPX          27
 
 /* subimtype, flag options for imtype */
 #define R_OPENEXR_HALF 1
index 778a0aa88d6fd284e0f9469c563931694de94035..3de232c69efd7d67c3aee7b5fc307e818619d4ae 100644 (file)
@@ -1101,7 +1101,9 @@ static char *imagetype_pup(void)
        strcat(formatstring, "|%s %%x%d");      // add space for PNG
        strcat(formatstring, "|%s %%x%d");      // add space for BMP
        strcat(formatstring, "|%s %%x%d");      // add space for Radiance HDR
-
+       strcat(formatstring, "|%s %%x%d");      // add space for Cineon
+       strcat(formatstring, "|%s %%x%d");      // add space for DPX
+       
 #ifdef _WIN32
        strcat(formatstring, "|%s %%x%d");      // add space for AVI Codec
 #endif
@@ -1138,7 +1140,9 @@ static char *imagetype_pup(void)
                        "HamX",           R_HAMX,
                        "Iris",           R_IRIS,
                        "Iris + Zbuffer", R_IRIZ,
-                       "Radiance HDR",   R_RADHDR
+                       "Radiance HDR",   R_RADHDR,
+                       "Cineon",                 R_CINEON,
+                       "DPX",                    R_DPX
 #ifdef __sgi
                        ,"Movie",          R_MOVIE
 #endif
@@ -1162,7 +1166,9 @@ static char *imagetype_pup(void)
                        "HamX",           R_HAMX,
                        "Iris",           R_IRIS,
                        "Iris + Zbuffer", R_IRIZ,
-                       "Radiance HDR",   R_RADHDR
+                       "Radiance HDR",   R_RADHDR,
+                       "Cineon",                 R_CINEON,
+                       "DPX",                    R_DPX
 #ifdef __sgi
                        ,"Movie",          R_MOVIE
 #endif
index f2e2fe216e018eba1b5434e1eabc9d847ca32ca9..003fee46173860388b8168f95596aec1cc2a67b6 100644 (file)
@@ -523,6 +523,8 @@ void test_flags_file(SpaceFile *sfile)
                                        ||      BLI_testextensie(file->relname, ".pict")
                                        ||      BLI_testextensie(file->relname, ".pntg") //macpaint
                                        ||      BLI_testextensie(file->relname, ".qtif")
+                                       ||  BLI_testextensie(file->relname, ".cin")
+                                       ||  BLI_testextensie(file->relname, ".dpx")
                                        ||      BLI_testextensie(file->relname, ".sgi")) {
                                        file->flags |= IMAGEFILE;                       
                                }
@@ -544,6 +546,8 @@ void test_flags_file(SpaceFile *sfile)
                                        ||      BLI_testextensie(file->relname, ".png")
                                        ||      BLI_testextensie(file->relname, ".iff")
                                        ||      BLI_testextensie(file->relname, ".lbm")
+                                       ||  BLI_testextensie(file->relname, ".cin")
+                                       ||  BLI_testextensie(file->relname, ".dpx")
                                        ||      BLI_testextensie(file->relname, ".sgi")) {
                                        file->flags |= IMAGEFILE;                       
                                }
index 547e12a8a736dcf4ba0d62f4957646813c373c18..6239f980335c71019102702feb684817be340fbd 100644 (file)
@@ -177,6 +177,12 @@ void save_image_filesel_str(char *str)
                        strcpy(str, "Save OpenEXR");
                        break;
 #endif
+               case R_CINEON:
+                       strcpy(str, "Save Cineon");
+                       break;
+               case R_DPX:
+                       strcpy(str, "Save DPX");
+                       break;
                case R_RAWTGA:
                        strcpy(str, "Save Raw Targa");
                        break;