TuttleOFX  1
Writer.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 <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