TuttleOFX  1
Reader.cpp
Go to the documentation of this file.
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