TuttleOFX  1
WriterInternal.h
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 
00036 #ifndef _DPX_WRITERINTERNAL_H
00037 #define _DPX_WRITERINTERNAL_H 1
00038 
00039 
00040 #include "BaseTypeConverter.h"
00041 
00042 
00043 namespace dpx 
00044 {
00045         
00046 
00047         void EndianBufferSwap(int bitdepth, dpx::Packing packing, void *buf, const size_t size)
00048         {
00049                 switch (bitdepth)
00050                 {
00051                 case 8:
00052                         break;
00053                 case 12:
00054                         if (packing == dpx::kPacked)
00055                                 dpx::EndianSwapImageBuffer<dpx::kInt>(buf, size / sizeof(U32));
00056                         else
00057                                 dpx::EndianSwapImageBuffer<dpx::kWord>(buf, size / sizeof(U16));
00058                         break;
00059                 case 16:
00060                         dpx::EndianSwapImageBuffer<dpx::kWord>(buf, size / sizeof(U16));
00061                         break;
00062                 default:                // 10-bit, 32-bit, 64-bit
00063                         dpx::EndianSwapImageBuffer<dpx::kInt>(buf, size / sizeof(U32));
00064                 }       
00065         }
00066 
00067 
00068         template <typename T1, typename T2>
00069         void MultiTypeBufferCopy(T1 *dst, T2 *src, const int len)
00070         {
00071                 for (int i = 0; i < len; i++)
00072                         BaseTypeConverter(src[i], dst[i]);
00073         }
00074 
00075 
00076         template <typename IB>
00077         void CopyWriteBuffer(DataSize src_size, unsigned char *src, IB * dst, const int len)
00078         {
00079                 if (src_size == kByte)
00080                         MultiTypeBufferCopy<IB, U8>(dst, reinterpret_cast<U8 *>(src), len);
00081                 else if (src_size == kWord)
00082                         MultiTypeBufferCopy<IB, U16>(dst, reinterpret_cast<U16 *>(src), len);
00083                 else if (src_size == kFloat)
00084                         MultiTypeBufferCopy<IB, R32>(dst, reinterpret_cast<R32 *>(src), len);
00085                 else if (src_size == kDouble)
00086                         MultiTypeBufferCopy<IB, R64>(dst, reinterpret_cast<R64 *>(src), len);
00087 
00088         }
00089 
00090 
00091         // access modifications to the buffer based on compression and packing
00092         struct BufferAccess 
00093         { 
00094                 int offset; 
00095                 int length;
00096                 BufferAccess() : offset(0), length(0) { }
00097         };
00098 
00099 
00100         
00101         // \todo NOT DONE
00102         template <typename IB, int BITDEPTH>
00103         void RleCompress(IB *src, IB *dst, const int bufsize, const int len, BufferAccess &access)
00104         {
00105                 IB ch;
00106                 int count;
00107                 int i;
00108                 int index = bufsize - 1;
00109                 bool start = true;
00110                 //bool match = true;
00111                 
00112                 // for each data type, have maximum length of rle datum
00113                 // subtract one so it the LSBit can be used to state
00114                 int maxCount;           
00115                 if (BITDEPTH == 8)
00116                         maxCount = 0xff - 1;
00117                 else if (BITDEPTH == 10)
00118                         maxCount = 0x3ff - 1;
00119                 else if (BITDEPTH == 12)
00120                         maxCount = 0xfff - 1;
00121                 else if (BITDEPTH == 16)
00122                         maxCount = 0xffff - 1;
00123                 else 
00124                         maxCount = 1000000;             // high number for floats, doubles
00125 
00126                 
00127                 for (i = len - 1; i >= 0; i--)
00128                 {
00129                         if (start)
00130                         {
00131                                 count = 1;
00132                                 start = false;
00133                                 ch = src[i];
00134                                 dst[index--] = ch;
00135                         }
00136                 }
00137                 
00138                 access.offset = index;
00139                 access.length = bufsize - index;
00140         }
00141 
00142 
00143         template <typename IB, int BITDEPTH>
00144         void WritePackedMethod(IB *src, IB *dst, const int len, const bool reverse, BufferAccess &access)
00145         {       
00146                 // pack into the same memory space
00147                 U32 *dst_u32 = reinterpret_cast<U32*>(dst);
00148 
00149                 // bit shift count for U16 source
00150                 const int shift = 16 - BITDEPTH;
00151                 
00152                 // bit mask
00153                 U32 mask = 0;
00154                 if (BITDEPTH == 10)
00155                         mask = 0x03ff;
00156                 else if (BITDEPTH == 12)
00157                         mask = 0x0fff;
00158                 else if (BITDEPTH == 8)
00159                         return;
00160 
00161                 int i, entry;
00162                 for (i = 0; i < len; i++)
00163                 {
00164                         // read value and determine write location
00165                         U32 value = static_cast<U32>(src[i+access.offset]) >> shift;
00166 
00167                         // if reverse the order
00168 /*** XXX TODO REVERSE
00169                         if (reverse)
00170                                 // reverse the triplets so entry would be 2,1,0,5,4,3,8,7,6,...
00171                                 entry = ((i / 3) * 3) + (2 - (i % 3));
00172                         else
00173 ***/
00174                                 entry = i;
00175 
00176                         int div = (entry * BITDEPTH) / 32;                      // 32 bits in a U32
00177                         int rem = (entry * BITDEPTH) % 32;
00178                         
00179                         // write the bits that belong in the first U32
00180                         // calculate the masked bits for the added value
00181                         U32 shift_mask = mask << rem;
00182                         
00183                         // mask sure to mask the bits to save as part of the src_buf
00184                         // so if writing bits 8-18, save the bits of the source material
00185                         dst_u32[div] = (dst_u32[div] & ~shift_mask) | ((value << rem) & shift_mask);
00186 
00187                         // write across multiple U16? count the carry bits
00188                         int carry = BITDEPTH - (32 - rem);
00189                         if (carry > 0)
00190                         {
00191                                 U32 save = BITDEPTH - carry;
00192                                 dst_u32[div+1] = (dst_u32[div+1] & ~(mask >> save)) | ((value >> save) & (mask >> save));
00193                         }
00194                 }
00195                 
00196                 // adjust offset/length
00197                 access.offset = 0;
00198                 access.length = (((len * BITDEPTH) / 32) + ((len * BITDEPTH) % 32 ? 1 : 0)) * 2;
00199         }       
00200 
00201 
00202 
00203         // this routine expects a type of U16
00204         template <typename IB, Packing METHOD>
00205         void WritePackedMethodAB_10bit(IB *src, IB *dst, const int len, const bool reverse, BufferAccess &access)
00206         {       
00207                 // pack into the same memory space
00208                 U32 *dst_u32 = reinterpret_cast<U32*>(dst);
00209         
00210                 // bit shift count
00211                 const U32 shift = 6;  // (16 - BITDEPTH)
00212                 const U32 bitdepth = 10;
00213                 const U32 bitmask = 0x03ff;
00214                 
00215                 // shift bits over 2 if Method A
00216                 const int method_shift = (METHOD == kFilledMethodA ? 2 : 0);
00217                 
00218                 // loop through the buffer
00219                 int i;
00220                 U32 value = 0;
00221                 for (i = 0; i < len; i++)
00222                 {
00223                         int div = i / 3;                        // 3 10-bit values in a U32
00224                         int rem = i % 3;
00225         
00226                         // write previously calculated value
00227                         if (i && rem == 0)
00228                         {
00229                                 dst_u32[div-1] = value;
00230                                 value = 0;
00231                         }
00232 
00233                         // if reverse the order
00234                         if (reverse)
00235                                 rem = 2 - rem;
00236 
00237                         // place the 10 bits in the proper place with mask
00238                         U32 comp = ((static_cast<U32>(src[i+access.offset]) >> shift) << (bitdepth * rem)) << method_shift;
00239                         U32 mask = (bitmask << (bitdepth * rem)) << method_shift ;
00240                         
00241                         // overwrite only the proper 10 bits
00242                         value = (value & ~mask) | (comp & mask);
00243                 }
00244                 
00245                 // write last
00246                 dst_u32[(len+2)/3-1] = value;
00247 
00248                 // adjust offset/length
00249                 // multiply * 2 because it takes two U16 = U32 and this func packs into a U32
00250                 access.offset = 0;
00251                 access.length = ((len / 3) + (len % 3 ? 1 : 0)) * 2;
00252         }       
00253         
00254                         
00255         
00256         template <typename IB, int BITDEPTH, bool SAMEBUFTYPE>
00257         int WriteBuffer(OutStream *fd, DataSize src_size, void *src_buf, const U32 width, const U32 height, const int noc, const Packing packing, 
00258                                         const bool rle, const bool reverse, const int eolnPad, char *blank, bool &status, bool swapEndian)
00259         {
00260                 int fileOffset = 0;
00261                 
00262                 // determine any impact on the max line size due to RLE
00263                 // impact may be that rle is true but the data can not be compressed at all
00264                 // the worst possible compression with RLE is increasing the image size by 1/3
00265                 // so we will just double the destination size if RLE
00266                 int rleBufAdd = (rle ? ((width * noc / 3) + 1) : 0);
00267 
00268                 // buffer access parameters
00269                 BufferAccess bufaccess;
00270                 bufaccess.offset = 0;
00271                 bufaccess.length = width * noc;
00272                 
00273                 // allocate one line
00274                 IB *src;
00275                 IB *dst = new IB[(width * noc) + 1 + rleBufAdd];
00276 
00277                 // each line in the buffer
00278                 for (U32 h = 0; h < height; h++)
00279                 {
00280                         // image buffer
00281                         unsigned char *imageBuf = reinterpret_cast<unsigned char*>(src_buf);
00282                         const int bytes = Header::DataSizeByteCount(src_size);
00283 
00284                         // copy buffer if need to promote data types from src to destination
00285                         if (!SAMEBUFTYPE)
00286                         {
00287                                 src = dst;
00288                                 CopyWriteBuffer<IB>(src_size, (imageBuf+(h*width*noc*bytes)+(h*eolnPad)), dst, (width*noc));
00289                         } 
00290                         else
00291                                 // not a copy, access source
00292                                 src = reinterpret_cast<IB*>(imageBuf + (h * width * noc * bytes) + (h*eolnPad));
00293 
00294                         // if rle, compress
00295                         if (rle)
00296                         {
00297                                 RleCompress<IB, BITDEPTH>(src, dst, ((width * noc) + rleBufAdd), width * noc, bufaccess);
00298                                 src = dst;
00299                         }
00300                         
00301                         // if 10 or 12 bit, pack
00302                         if (BITDEPTH == 10)
00303                         {
00304                                 if (packing == dpx::kPacked)
00305                                 {
00306                                         WritePackedMethod<IB, BITDEPTH>(src, dst, (width*noc), reverse, bufaccess);
00307                                 }
00308                                 else if (packing == kFilledMethodA)
00309                                 {
00310                                         WritePackedMethodAB_10bit<IB, dpx::kFilledMethodA>(src, dst, (width*noc), reverse, bufaccess);
00311                                 }
00312                                 else // if (packing == dpx::kFilledMethodB)
00313                                 {
00314                                         WritePackedMethodAB_10bit<IB, dpx::kFilledMethodB>(src, dst, (width*noc), reverse, bufaccess);
00315                                 }                               
00316                         }
00317                         else if (BITDEPTH == 12)
00318                         {
00319                                 if (packing == dpx::kPacked)
00320                                 {
00321                                         WritePackedMethod<IB, BITDEPTH>(src, dst, (width*noc), reverse, bufaccess);
00322                                 }
00323                                 else if (packing == dpx::kFilledMethodB)
00324                                 {
00325                                         // shift 4 MSB down, so 0x0f00 would become 0x00f0
00326                                         for (int w = 0; w < bufaccess.length; w++)
00327                                                 dst[w] = src[bufaccess.offset+w] >> 4;
00328                                         bufaccess.offset = 0;
00329                                 }
00330                                 // a bitdepth of 12 by default is packed with dpx::kFilledMethodA
00331                                 // assumes that either a copy or rle was required
00332                                 // otherwise this routine should not be called with:
00333                                 //     12-bit Method A with the source buffer data type is kWord                                
00334                         }
00335                         
00336                         // write line
00337                         fileOffset += (bufaccess.length * sizeof(IB));
00338                         if (swapEndian)
00339                             EndianBufferSwap(BITDEPTH, packing, dst + bufaccess.offset, bufaccess.length * sizeof(IB));
00340                         if (fd->Write(dst+bufaccess.offset, (bufaccess.length * sizeof(IB))) == false)
00341                         {
00342                                 status = false;
00343                                 break;
00344                         }
00345                         
00346                         // end of line padding
00347                         if (eolnPad)
00348                         {
00349                                 fileOffset += eolnPad;
00350                                 if (fd->Write(blank, eolnPad) == false)
00351                                 {
00352                                         status = false;
00353                                         break;
00354                                 }
00355                         }       
00356         
00357                 }
00358                 
00359                 // done with buffer
00360                 delete [] dst;
00361                 
00362                 return fileOffset;
00363         }
00364 
00365 
00366         template <typename IB, int BITDEPTH, bool SAMEBUFTYPE>
00367         int WriteFloatBuffer(OutStream *fd, DataSize src_size, void *src_buf, const U32 width, const U32 height, const int noc, const Packing packing, 
00368                                         const bool rle, const int eolnPad, char *blank, bool &status, bool swapEndian)
00369         {
00370                 int fileOffset = 0;
00371                 
00372                 // determine any impact on the max line size due to RLE
00373                 // impact may be that rle is true but the data can not be compressed at all
00374                 // the worst possible compression with RLE is increasing the image size by 1/3
00375                 // so we will just double the destination size if RLE
00376                 int rleBufAdd = (rle ? ((width * noc / 3) + 1) : 0);
00377 
00378                 // buffer access parameters
00379                 BufferAccess bufaccess;
00380                 bufaccess.offset = 0;
00381                 bufaccess.length = width * noc;
00382                 
00383                 // allocate one line
00384                 IB *src;
00385                 IB *dst = new IB[(width * noc) + rleBufAdd];
00386 
00387                 // each line in the buffer
00388                 for (U32 h = 0; h < height; h++)
00389                 {
00390                         // image buffer
00391                         unsigned char *imageBuf = reinterpret_cast<unsigned char*>(src_buf);
00392                         const int bytes = Header::DataSizeByteCount(src_size);
00393 
00394                         // copy buffer if need to promote data types from src to destination
00395                         if (!SAMEBUFTYPE)
00396                         {
00397                                 src = dst;
00398                                 CopyWriteBuffer<IB>(src_size, (imageBuf+(h*width*noc*bytes)+(h*eolnPad)), dst, (width*noc));
00399                         } 
00400                         else
00401                                 // not a copy, access source
00402                                 src = reinterpret_cast<IB*>(imageBuf + (h * width * noc * bytes) + (h*eolnPad));
00403 
00404                         // if rle, compress
00405                         if (rle)
00406                         {
00407                                 RleCompress<IB, BITDEPTH>(src, dst, ((width * noc) + rleBufAdd), width * noc, bufaccess);
00408                                 src = dst;
00409                         }
00410                         
00411                         // write line
00412                         fileOffset += (bufaccess.length * sizeof(IB));
00413                         if (swapEndian)
00414                             EndianBufferSwap(BITDEPTH, packing, dst + bufaccess.offset, bufaccess.length * sizeof(IB));
00415                         if (fd->Write(dst+bufaccess.offset, (bufaccess.length * sizeof(IB))) == false)
00416                         {
00417                                 status = false;
00418                                 break;
00419                         }
00420                         
00421                         // end of line padding
00422                         if (eolnPad)
00423                         {
00424                                 fileOffset += eolnPad;
00425                                 if (fd->Write(blank, eolnPad) == false)
00426                                 {
00427                                         status = false;
00428                                         break;
00429                                 }
00430                         }       
00431         
00432                 }
00433                 
00434                 // done with buffer
00435                 delete [] dst;
00436                 
00437                 return fileOffset;
00438         }       
00439 }
00440 
00441 #endif
00442 
00443