TuttleOFX
1
|
00001 // -*- mode: C++; tab-width: 4 -*- 00002 // vi: ts=4 00003 00004 /* 00005 * Copyright (c) 2009, Patrick A. Palmer. 00006 * All rights reserved. 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions are met: 00010 * 00011 * - Redistributions of source code must retain the above copyright notice, 00012 * this list of conditions and the following disclaimer. 00013 * 00014 * - Redistributions in binary form must reproduce the above copyright 00015 * notice, this list of conditions and the following disclaimer in the 00016 * documentation and/or other materials provided with the distribution. 00017 * 00018 * - Neither the name of Patrick A. Palmer nor the names of its 00019 * contributors may be used to endorse or promote products derived from 00020 * this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00023 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00024 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00025 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00026 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00027 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00028 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00029 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00030 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00031 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 * POSSIBILITY OF SUCH DAMAGE. 00033 */ 00034 00035 #include <cstdio> 00036 #include <cstring> 00037 #include <ctime> 00038 00039 #include "DPX.h" 00040 #include "EndianSwap.h" 00041 #include "ReaderInternal.h" 00042 #include "ElementReadStream.h" 00043 #include "Codec.h" 00044 #include "RunLengthEncoding.h" 00045 00046 00047 00048 dpx::Reader::Reader() : fd(0), rio(0) 00049 { 00050 // initialize all of the Codec* to NULL 00051 for (int i = 0; i < MAX_ELEMENTS; i++) 00052 this->codex[i] = 0; 00053 } 00054 00055 00056 dpx::Reader::~Reader() 00057 { 00058 this->Reset(); 00059 } 00060 00061 00062 void dpx::Reader::Reset() 00063 { 00064 // delete all of the Codec * entries 00065 for (int i = 0; i < MAX_ELEMENTS; i++) 00066 if (this->codex[i]) 00067 { 00068 delete codex[i]; 00069 this->codex[i] = 0; 00070 } 00071 00072 // Element Reader 00073 if (this->rio) 00074 { 00075 delete rio; 00076 this->rio = 0; 00077 } 00078 if (this->fd) 00079 this->rio = new ElementReadStream(this->fd); 00080 } 00081 00082 00083 void dpx::Reader::SetInStream(InStream *fd) 00084 { 00085 this->fd = fd; 00086 this->Reset(); 00087 } 00088 00089 00090 bool dpx::Reader::ReadHeader() 00091 { 00092 return this->header.Read(this->fd); 00093 } 00094 00095 00096 bool dpx::Reader::ReadImage(const int element, void *data) 00097 { 00098 // make sure the range is good 00099 if (element < 0 || element >= MAX_ELEMENTS) 00100 return false; 00101 00102 // make sure the entry is valid 00103 if (this->header.ImageDescriptor(element) == kUndefinedDescriptor) 00104 return false; 00105 00106 return this->ReadImage(data, this->header.ComponentDataSize(element), this->header.ImageDescriptor(element)); 00107 } 00108 00109 00110 bool dpx::Reader::ReadImage(void *data, const DataSize size, const Descriptor desc) 00111 { 00112 Block block(0, 0, this->header.Width()-1, this->header.Height()-1); 00113 return this->ReadBlock(data, size, block, desc); 00114 } 00115 00116 00117 00118 /** 00119 block - this contains the square block of data to read in. The data elements in this 00120 structure need to be normalized Left to Right, Top to Bottom. 00121 */ 00122 00123 00124 bool dpx::Reader::ReadBlock(const int element, unsigned char *data, Block &block) 00125 { 00126 // make sure the range is good 00127 if (element < 0 || element >= MAX_ELEMENTS) 00128 return false; 00129 00130 // make sure the entry is valid 00131 if (this->header.ImageDescriptor(element) == kUndefinedDescriptor) 00132 return false; 00133 00134 return this->ReadBlock(data, this->header.ComponentDataSize(element), block, this->header.ImageDescriptor(element)); 00135 } 00136 00137 00138 /* 00139 implementation notes: 00140 00141 dpx::readBlock reads in the image starting from the beginning of the channel. This can 00142 be optimized if the image isn't encoded; we can skip forward in the file to close to the 00143 start of (block.x1, block.y1) and determine exactly which bit will be the start. This 00144 certainly will save some time for cases where we are only reading ROIs (regions of interest). 00145 00146 */ 00147 00148 bool dpx::Reader::ReadBlock(void *data, const DataSize size, Block &block, const Descriptor desc) 00149 { 00150 int i; 00151 int element; 00152 00153 // check the block coordinates 00154 block.Check(); 00155 00156 // determine which element we are viewing 00157 for (i = 0; i < MAX_ELEMENTS; i++) 00158 { 00159 if (this->header.ImageDescriptor(i) == desc) 00160 { 00161 element = i; 00162 break; 00163 } 00164 } 00165 if (i == MAX_ELEMENTS) // was it found? 00166 return false; 00167 00168 00169 // get the number of components for this element descriptor 00170 const int numberOfComponents = this->header.ImageElementComponentCount(element); 00171 00172 // bit depth of the image element 00173 const int bitDepth = this->header.BitDepth(element); 00174 00175 // rle encoding? 00176 const bool rle = (this->header.ImageEncoding(element) == kRLE); 00177 00178 00179 // lets see if this can be done in a single fast read 00180 if (!rle && this->header.EndOfLinePadding(element) == 0 && 00181 ((bitDepth == 8 && size == dpx::kByte) || 00182 (bitDepth == 16 && size == dpx::kWord) || 00183 (bitDepth == 32 && size == dpx::kFloat) || 00184 (bitDepth == 64 && size == dpx::kDouble)) && 00185 block.x1 == 0 && block.x2 == (int)(this->header.Width()-1)) 00186 { 00187 // seek to the beginning of the image block 00188 if (this->fd->Seek((this->header.DataOffset(element) + (block.y1 * this->header.Width() * (bitDepth / 8) * numberOfComponents)), InStream::kStart) == false) 00189 return false; 00190 00191 // size of the image 00192 const size_t imageSize = this->header.Width() * (block.y2 - block.y1 + 1) * numberOfComponents; 00193 const size_t imageByteSize = imageSize * bitDepth / 8; 00194 00195 size_t rs = this->fd->ReadDirect(data, imageByteSize); 00196 if (rs != imageByteSize) 00197 return false; 00198 00199 // swap the bytes if different byte order 00200 if (this->header.RequiresByteSwap()) 00201 dpx::EndianSwapImageBuffer(size, data, imageSize); 00202 00203 return true; 00204 } 00205 00206 00207 // determine if the encoding system is loaded 00208 if (this->codex[element] == 0) 00209 { 00210 // this element reader has not been used 00211 if (rle) 00212 // TODO 00213 //this->codex[element] = new RunLengthEncoding; 00214 return false; 00215 else 00216 this->codex[element] = new Codec; 00217 } 00218 00219 // read the image block 00220 return this->codex[element]->Read(this->header, this->rio, element, block, data, size); 00221 } 00222 00223 00224 00225 bool dpx::Reader::ReadUserData(unsigned char *data) 00226 { 00227 // check to make sure there is some user data 00228 if (this->header.UserSize() == 0) 00229 return true; 00230 00231 // seek to the beginning of the user data block 00232 if (this->fd->Seek(sizeof(GenericHeader) + sizeof(IndustryHeader), InStream::kStart) == false) 00233 return false; 00234 00235 size_t rs = this->fd->ReadDirect(data, this->header.UserSize()); 00236 if (rs != this->header.UserSize()) 00237 return false; 00238 00239 return true; 00240 } 00241 00242 00243