Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/imbuf/intern/cineon/dpxlib.c')
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.c625
1 files changed, 625 insertions, 0 deletions
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);
+}