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 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