diff options
Diffstat (limited to 'source/blender/imbuf/intern/cineon')
-rw-r--r-- | source/blender/imbuf/intern/cineon/Makefile | 64 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/README | 8 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/cin_debug_stuff.h | 2 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/cineon_dpx.c | 195 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/cineonfile.h | 143 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/cineonlib.c | 801 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/cineonlib.h | 68 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/dpxfile.h | 124 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/dpxlib.c | 625 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/dpxlib.h | 56 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/logImageCore.c | 212 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/logImageCore.h | 109 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/logImageLib.c | 158 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/logImageLib.h | 86 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/logmemfile.c | 77 | ||||
-rw-r--r-- | source/blender/imbuf/intern/cineon/logmemfile.h | 29 |
16 files changed, 2757 insertions, 0 deletions
diff --git a/source/blender/imbuf/intern/cineon/Makefile b/source/blender/imbuf/intern/cineon/Makefile new file mode 100644 index 00000000000..596a6647093 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/Makefile @@ -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 index 00000000000..5554e857c81 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/README @@ -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 index 00000000000..148e4e4be53 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/cin_debug_stuff.h @@ -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 index 00000000000..d3cf74f60a9 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c @@ -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 index 00000000000..7f6f1138902 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/cineonfile.h @@ -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 index 00000000000..5253646be4d --- /dev/null +++ b/source/blender/imbuf/intern/cineon/cineonlib.c @@ -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 index 00000000000..87fc7add9a6 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/cineonlib.h @@ -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 index 00000000000..94145500910 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/dpxfile.h @@ -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 index 00000000000..bb12f9307e3 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/dpxlib.c @@ -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 index 00000000000..25fe84e2296 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/dpxlib.h @@ -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 index 00000000000..e88e9241443 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/logImageCore.c @@ -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 index 00000000000..1af18d5e3b8 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/logImageCore.h @@ -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 index 00000000000..ff209d5ebd0 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/logImageLib.c @@ -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 index 00000000000..ea45c675fe2 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/logImageLib.h @@ -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 index 00000000000..20359335933 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/logmemfile.c @@ -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 index 00000000000..6e82cf2b145 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/logmemfile.h @@ -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 */ |