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 <cstring> 00036 #include <ctime> 00037 00038 #include "DPX.h" 00039 #include "DPXStream.h" 00040 #include "EndianSwap.h" 00041 #include "WriterInternal.h" 00042 00043 dpx::Writer::Writer() : fileLoc(0) 00044 { 00045 } 00046 00047 00048 dpx::Writer::~Writer() 00049 { 00050 } 00051 00052 00053 void dpx::Writer::Start() 00054 { 00055 } 00056 00057 00058 void dpx::Writer::SetFileInfo(const char *fileName, const char *creationTimeDate, const char *creator, 00059 const char *project, const char *copyright, const U32 encryptKey, const bool swapEndian) 00060 { 00061 if (fileName) 00062 this->header.SetFileName(fileName); 00063 00064 if (creationTimeDate) 00065 this->header.SetCreationTimeDate(creationTimeDate); 00066 else 00067 { 00068 time_t seconds = time(0); 00069 this->header.SetCreationTimeDate(seconds); 00070 } 00071 00072 if (creator) 00073 this->header.SetCreator(creator); 00074 else 00075 this->header.SetCreator("OpenDPX library"); 00076 00077 if (project) 00078 this->header.SetProject(project); 00079 if (copyright) 00080 this->header.SetCopyright(copyright); 00081 this->header.SetEncryptKey(encryptKey); 00082 00083 if (swapEndian) 00084 this->header.magicNumber = SwapBytes(this->header.magicNumber); 00085 } 00086 00087 00088 void dpx::Writer::SetImageInfo(const U32 width, const U32 height) 00089 { 00090 this->header.SetImageOrientation(kLeftToRightTopToBottom); 00091 this->header.SetPixelsPerLine(width); 00092 this->header.SetLinesPerElement(height); 00093 } 00094 00095 00096 // returns next available or MAX_ELEMENTS if full 00097 int dpx::Writer::NextAvailElement() const 00098 { 00099 unsigned int i; 00100 00101 for (i = 0; i < MAX_ELEMENTS; i++) 00102 { 00103 if (this->header.ImageDescriptor(i) == kUndefinedDescriptor) 00104 break; 00105 } 00106 00107 return i; 00108 } 00109 00110 00111 void dpx::Writer::SetOutStream(OutStream *fd) 00112 { 00113 this->fd = fd; 00114 } 00115 00116 00117 bool dpx::Writer::WriteHeader() 00118 { 00119 // calculate any header info 00120 this->header.CalculateOffsets(); 00121 00122 // seek to the beginning of the file 00123 if (!this->fd->Seek(0, OutStream::kStart)) 00124 return false; 00125 00126 // writing the header count 00127 this->fileLoc = this->header.Size(); 00128 00129 return this->header.Write(fd); 00130 } 00131 00132 00133 void dpx::Writer::SetUserData(const long size) 00134 { 00135 // TODO 00136 } 00137 00138 00139 bool dpx::Writer::WriteUserData(void *data) 00140 { 00141 // XXX TODO 00142 return false; 00143 } 00144 00145 00146 void dpx::Writer::SetElement(const int num, const Descriptor desc, const U8 bitDepth, 00147 const Characteristic transfer, const Characteristic colorimetric, 00148 const Packing packing, const Encoding encoding, const U32 dataSign, 00149 const U32 lowData, const R32 lowQuantity, 00150 const U32 highData, const R32 highQuantity, 00151 const U32 eolnPadding, const U32 eoimPadding) 00152 { 00153 // make sure the range is good 00154 if (num < 0 || num >= MAX_ELEMENTS) 00155 return; 00156 00157 // set values 00158 this->header.SetDataSign(num, dataSign); 00159 this->header.SetLowData(num, lowData); 00160 this->header.SetLowQuantity(num, lowQuantity); 00161 this->header.SetHighData(num, highData); 00162 this->header.SetHighQuantity(num, highQuantity); 00163 this->header.SetImageDescriptor(num, desc); 00164 this->header.SetTransfer(num, transfer); 00165 this->header.SetColorimetric(num, colorimetric); 00166 this->header.SetBitDepth(num, bitDepth); 00167 this->header.SetImagePacking(num, packing); 00168 this->header.SetImageEncoding(num, encoding); 00169 this->header.SetEndOfLinePadding(num, eolnPadding); 00170 this->header.SetEndOfImagePadding(num, eoimPadding); 00171 00172 // determine if increases element count 00173 this->header.CalculateNumberOfElements(); 00174 } 00175 00176 00177 // the data is processed so write it straight through 00178 // argument count is total size in bytes of the passed data 00179 bool dpx::Writer::WriteElement(const int element, void *data, const long count) 00180 { 00181 // make sure the range is good 00182 if (element < 0 || element >= MAX_ELEMENTS) 00183 return false; 00184 00185 // make sure the entry is valid 00186 if (this->header.ImageDescriptor(element) == kUndefinedDescriptor) 00187 return false; 00188 00189 // update file ptr 00190 this->header.SetDataOffset(element, this->fileLoc); 00191 this->fileLoc += count; 00192 00193 // write 00194 return (this->fd->Write(data, count) > 0); 00195 } 00196 00197 00198 00199 bool dpx::Writer::WriteElement(const int element, void *data) 00200 { 00201 // make sure the range is good 00202 if (element < 0 || element >= MAX_ELEMENTS) 00203 return false; 00204 00205 // make sure the entry is valid 00206 if (this->header.ImageDescriptor(element) == kUndefinedDescriptor) 00207 return false; 00208 00209 return this->WriteElement(element, data, this->header.ComponentDataSize(element)); 00210 } 00211 00212 00213 00214 bool dpx::Writer::WriteElement(const int element, void *data, const DataSize size) 00215 { 00216 bool status = true; 00217 00218 // make sure the range is good 00219 if (element < 0 || element >= MAX_ELEMENTS) 00220 return false; 00221 00222 // make sure the entry is valid 00223 if (this->header.ImageDescriptor(element) == kUndefinedDescriptor) 00224 return false; 00225 00226 // mark location in headers 00227 if (element == 0) 00228 this->header.SetImageOffset(this->fileLoc); 00229 this->header.SetDataOffset(element, this->fileLoc); 00230 00231 // reverse the order of the components 00232 bool reverse = false; 00233 00234 // rle encoding? 00235 const bool rle = this->header.ImageEncoding(element) == kRLE; 00236 00237 // image parameters 00238 const U32 eolnPad = this->header.EndOfLinePadding(element); 00239 const U32 eoimPad = this->header.EndOfImagePadding(element); 00240 const U8 bitDepth = this->header.BitDepth(element); 00241 const U32 width = this->header.Width(); 00242 const U32 height = this->header.Height(); 00243 const int noc = this->header.ImageElementComponentCount(element); 00244 const Packing packing = this->header.ImagePacking(element); 00245 00246 // check width & height, just in case 00247 if (width == 0 || height == 0) 00248 return false; 00249 00250 // sizeof a component in an image 00251 const int bytes = (bitDepth + 7) / 8; 00252 00253 // allocate memory for use to write blank space 00254 char *blank = 0; 00255 if (eolnPad || eoimPad) 00256 { 00257 int bsize = eolnPad > eoimPad ? eolnPad : eoimPad; 00258 blank = new char[bsize]; 00259 memset(blank, 0, bsize * sizeof(char)); 00260 } 00261 00262 // can we write the entire memory chunk at once without any additional processing 00263 if (!rle && 00264 ((bitDepth == 8 && size == dpx::kByte) || 00265 (bitDepth == 12 && size == dpx::kWord && packing == kFilledMethodA) || 00266 (bitDepth == 16 && size == dpx::kWord) || 00267 (bitDepth == 32 && size == dpx::kFloat) || 00268 (bitDepth == 64 && size == dpx::kDouble))) 00269 { 00270 status = this->WriteThrough(data, width, height, noc, bytes, eolnPad, eoimPad, blank); 00271 if (blank) 00272 delete [] blank; 00273 return status; 00274 } 00275 else 00276 { 00277 switch (bitDepth) 00278 { 00279 case 8: 00280 if (size == dpx::kByte) 00281 this->fileLoc += WriteBuffer<U8, 8, true>(this->fd, size, data, width, height, noc, packing, rle, reverse, eolnPad, blank, status, this->header.RequiresByteSwap()); 00282 else 00283 this->fileLoc += WriteBuffer<U8, 8, false>(this->fd, size, data, width, height, noc, packing, rle, reverse, eolnPad, blank, status, this->header.RequiresByteSwap()); 00284 break; 00285 00286 case 10: 00287 // are the channels stored in reverse 00288 if (this->header.ImageDescriptor(element) == kRGB && this->header.DatumSwap(element) && bitDepth == 10) 00289 reverse = true; 00290 00291 if (size == dpx::kWord) 00292 this->fileLoc += WriteBuffer<U16, 10, true>(this->fd, size, data, width, height, noc, packing, rle, reverse, eolnPad, blank, status, this->header.RequiresByteSwap()); 00293 else 00294 this->fileLoc += WriteBuffer<U16, 10, false>(this->fd, size, data, width, height, noc, packing, rle, reverse, eolnPad, blank, status, this->header.RequiresByteSwap()); 00295 break; 00296 00297 case 12: 00298 if (size == dpx::kWord) 00299 this->fileLoc += WriteBuffer<U16, 12, true>(this->fd, size, data, width, height, noc, packing, rle, reverse, eolnPad, blank, status, this->header.RequiresByteSwap()); 00300 else 00301 this->fileLoc += WriteBuffer<U16, 12, false>(this->fd, size, data, width, height, noc, packing, rle, reverse, eolnPad, blank, status, this->header.RequiresByteSwap()); 00302 break; 00303 00304 case 16: 00305 if (size == dpx::kWord) 00306 this->fileLoc += WriteBuffer<U16, 16, true>(this->fd, size, data, width, height, noc, packing, rle, reverse, eolnPad, blank, status, this->header.RequiresByteSwap()); 00307 else 00308 this->fileLoc += WriteBuffer<U16, 16, false>(this->fd, size, data, width, height, noc, packing, rle, reverse, eolnPad, blank, status, this->header.RequiresByteSwap()); 00309 break; 00310 00311 case 32: 00312 if (size == dpx::kFloat) 00313 this->fileLoc += WriteFloatBuffer<R32, 32, true>(this->fd, size, data, width, height, noc, packing, rle, eolnPad, blank, status, this->header.RequiresByteSwap()); 00314 else 00315 this->fileLoc += WriteFloatBuffer<R32, 32, false>(this->fd, size, data, width, height, noc, packing, rle, eolnPad, blank, status, this->header.RequiresByteSwap()); 00316 break; 00317 00318 case 64: 00319 if (size == dpx::kDouble) 00320 this->fileLoc += WriteFloatBuffer<R64, 64, true>(this->fd, size, data, width, height, noc, packing, rle, eolnPad, blank, status, this->header.RequiresByteSwap()); 00321 else 00322 this->fileLoc += WriteFloatBuffer<R64, 64, false>(this->fd, size, data, width, height, noc, packing, rle, eolnPad, blank, status, this->header.RequiresByteSwap()); 00323 break; 00324 } 00325 } 00326 00327 // if successful 00328 if (status && eoimPad) 00329 { 00330 // end of image padding 00331 this->fileLoc += eoimPad; 00332 status = (this->fd->Write(blank, eoimPad) > 0); 00333 } 00334 00335 // rid of memory 00336 if (blank) 00337 delete [] blank; 00338 00339 return status; 00340 } 00341 00342 00343 // the passed in image buffer is written to the file untouched 00344 00345 bool dpx::Writer::WriteThrough(void *data, const U32 width, const U32 height, const int noc, const int bytes, const U32 eolnPad, const U32 eoimPad, char *blank) 00346 { 00347 bool status = true; 00348 const int count = width * height * noc; 00349 unsigned int i; 00350 unsigned char *imageBuf = reinterpret_cast<unsigned char*>(data); 00351 00352 // file pointer location after write 00353 this->fileLoc += bytes * count + (eolnPad * height); 00354 00355 // write data 00356 if (eolnPad) 00357 { 00358 // loop if have end of line padding 00359 for (i = 0; i < height; i++) 00360 { 00361 // write one line 00362 if (this->fd->Write(imageBuf+(width*bytes*i), bytes * width) == false) 00363 { 00364 status = false; 00365 break; 00366 } 00367 00368 // write end of line padding 00369 if (this->fd->Write(blank, eoimPad) == false) 00370 { 00371 status = false; 00372 break; 00373 } 00374 } 00375 } 00376 else 00377 { 00378 // write data as one chunk 00379 if (this->fd->Write(imageBuf, bytes * count) == false) 00380 { 00381 status = false; 00382 } 00383 } 00384 00385 // end of image padding 00386 if (status && eoimPad) 00387 { 00388 this->fileLoc += eoimPad; 00389 status = (this->fd->Write(blank, eoimPad) > 0); 00390 } 00391 00392 return status; 00393 } 00394 00395 00396 00397 00398 bool dpx::Writer::Finish() 00399 { 00400 // write the file size in the header 00401 this->header.SetFileSize(this->fileLoc); 00402 00403 // rewrite all of the offsets in the header 00404 return this->header.WriteOffsetData(this->fd); 00405 } 00406 00407 00408 00409