dcmdata/include/dcrleenc.h

00001 /* 00002 * 00003 * Copyright (C) 2002-2004, OFFIS 00004 * 00005 * This software and supporting documentation were developed by 00006 * 00007 * Kuratorium OFFIS e.V. 00008 * Healthcare Information and Communication Systems 00009 * Escherweg 2 00010 * D-26121 Oldenburg, Germany 00011 * 00012 * THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND OFFIS MAKES NO WARRANTY 00013 * REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR 00014 * FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES OR 00015 * ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND 00016 * PERFORMANCE OF THE SOFTWARE IS WITH THE USER. 00017 * 00018 * Module: dcmdata 00019 * 00020 * Author: Marco Eichelberg 00021 * 00022 * Purpose: RLE compressor 00023 * 00024 * Last Update: $Author: joergr $ 00025 * Update Date: $Date: 2004/01/16 14:06:20 $ 00026 * CVS/RCS Revision: $Revision: 1.10 $ 00027 * Status: $State: Exp $ 00028 * 00029 * CVS/RCS Log at end of file 00030 * 00031 */ 00032 00033 #ifndef DCRLEENC_H 00034 #define DCRLEENC_H 00035 00036 #include "osconfig.h" 00037 #include "oflist.h" /* for class OFList<> */ 00038 00039 #define INCLUDE_CSTRING 00040 #include "ofstdinc.h" 00041 00042 #define DcmRLEEncoder_BLOCKSIZE 16384 00043 00044 00049 class DcmEncoderOutputStream 00050 { 00051 public: 00056 virtual void write(const unsigned char *buf, size_t bufsize) =0; 00057 }; 00058 00059 00063 class DcmRLEEncoder 00064 { 00065 public: 00066 00070 DcmRLEEncoder(int doPad) 00071 : fail_(0) 00072 , pad_(doPad) 00073 , currentBlock_(new unsigned char[DcmRLEEncoder_BLOCKSIZE]) 00074 , offset_(0) 00075 , blockList_() 00076 , RLE_buff_(new unsigned char[132]) 00077 , RLE_prev_(-1) 00078 , RLE_pcount_(0) 00079 , RLE_bindex_(1) 00080 { 00081 if ((! RLE_buff_)||(! currentBlock_)) fail_ = 1; 00082 else RLE_buff_[0] = 0; 00083 } 00084 00086 ~DcmRLEEncoder() 00087 { 00088 delete[] currentBlock_; 00089 delete[] RLE_buff_; 00090 OFListIterator(unsigned char *) first = blockList_.begin(); 00091 OFListIterator(unsigned char *) last = blockList_.end(); 00092 while (first != last) 00093 { 00094 delete[] *first; 00095 first = blockList_.erase(first); 00096 } 00097 } 00098 00103 inline void add(unsigned char ch) 00104 { 00105 if (! fail_) // if fail_ is true, just ignore input 00106 { 00107 // if the current byte equals the last byte read 00108 // (which is initialized with the "impossible" value -1), 00109 // just increase the repeat counter 00110 if (OFstatic_cast(int, ch) == RLE_prev_) RLE_pcount_++; 00111 else 00112 { 00113 // byte is different from last byte read. 00114 // flush replicate run if necessary 00115 switch (RLE_pcount_) 00116 { 00117 case 0: 00118 // happens only after construction or flush() 00119 break; 00120 case 2: 00121 // two bytes in repeat buffer. Convert to literal run 00122 RLE_buff_[RLE_bindex_++] = OFstatic_cast(unsigned char, RLE_prev_); 00123 // no break. Fall-through into next case statement is intended. 00124 case 1: 00125 // one (or two) bytes in repeat buffer. Convert to literal run 00126 RLE_buff_[RLE_bindex_++] = OFstatic_cast(unsigned char, RLE_prev_); 00127 break; 00128 default: 00129 // more than two bytes in repeat buffer. Convert to replicate run 00130 if (RLE_bindex_ > 1) 00131 { 00132 // there is a literal run in the buffer that must be flushed 00133 // before the replicate run. Flush literal run now. 00134 RLE_buff_[0] = OFstatic_cast(unsigned char, RLE_bindex_-2); 00135 move(RLE_bindex_); 00136 } 00137 // this is the byte value for the repeat run 00138 RLE_buff_[1] = OFstatic_cast(unsigned char, RLE_prev_); 00139 // write as many repeat runs as necessary 00140 for (; RLE_pcount_>0; RLE_pcount_-=128) 00141 { 00142 // different PackBit schemes exist. The original from which 00143 // this code is derived used 0x80 | (RLE_pcount_ - 1) 00144 // to represent replicate runs. 00145 // DICOM instead uses 257 - RLE_pcount_ 00146 if (RLE_pcount_ > 128) RLE_buff_[0] = 0x81; 00147 else RLE_buff_[0] = OFstatic_cast(unsigned char, 257 - RLE_pcount_); 00148 move(2); 00149 } 00150 // now the buffer is guaranteed to be empty 00151 RLE_buff_[0] = 0; 00152 RLE_bindex_ = 1; 00153 break; 00154 } 00155 00156 // if we have 128 or more bytes in the literal run, flush buffer 00157 if (RLE_bindex_ > 129) 00158 { 00159 RLE_buff_[0] = 127; 00160 move(129); 00161 RLE_bindex_ -= 128; 00162 if (RLE_bindex_ > 1) 00163 RLE_buff_[1] = RLE_buff_[129]; 00164 if (RLE_bindex_ > 2) 00165 RLE_buff_[2] = RLE_buff_[130]; 00166 } 00167 00168 // current byte is stored in RLE_prev_, RLE_pcount_ is 1. 00169 RLE_prev_ = ch; 00170 RLE_pcount_ = 1; 00171 } 00172 } 00173 } 00174 00180 inline void add(const unsigned char *buf, size_t bufcount) 00181 { 00182 if (buf) 00183 { 00184 while (bufcount--) add(*buf++); 00185 } 00186 } 00187 00194 inline void flush() 00195 { 00196 if (! fail_) // if fail_ is true, do nothing 00197 { 00198 // if there are max 1 bytes in the repeat counter, convert to literal run 00199 if (RLE_pcount_ < 2) 00200 { 00201 for (; RLE_pcount_>0; --RLE_pcount_) RLE_buff_[RLE_bindex_++] = OFstatic_cast(unsigned char, RLE_prev_); 00202 } 00203 00204 // if we have 128 or more bytes in the literal run, flush buffer 00205 if (RLE_bindex_ > 129) 00206 { 00207 RLE_buff_[0] = 127; 00208 move(129); 00209 RLE_bindex_ -= 128; 00210 if (RLE_bindex_ > 1) 00211 RLE_buff_[1] = RLE_buff_[129]; 00212 if (RLE_bindex_ > 2) 00213 RLE_buff_[2] = RLE_buff_[130]; 00214 } 00215 00216 // if there is still a literal run in the buffer, flush literal run 00217 if (RLE_bindex_ > 1) 00218 { 00219 RLE_buff_[0] = OFstatic_cast(unsigned char, RLE_bindex_-2); 00220 move(RLE_bindex_); 00221 } 00222 00223 // if there is a remaining repeat run, flush this one as well 00224 if (RLE_pcount_ >= 2) 00225 { 00226 RLE_buff_[1] = OFstatic_cast(unsigned char, RLE_prev_); 00227 // write as many repeat runs as necessary 00228 for (; RLE_pcount_>0; RLE_pcount_-=128) 00229 { 00230 // different PackBit schemes exist. The original from which 00231 // this code is derived used 0x80 | (RLE_pcount_ - 1) 00232 // to represent replicate runs. 00233 // DICOM instead uses 257 - RLE_pcount_ 00234 if (RLE_pcount_ > 128) RLE_buff_[0] = 0x81; 00235 else RLE_buff_[0] = OFstatic_cast(unsigned char, 257 - RLE_pcount_); 00236 move(2); 00237 } 00238 } 00239 00240 // now the buffer is guaranteed to be empty, re-initialize 00241 RLE_buff_[0] = 0; 00242 RLE_prev_ = -1; 00243 RLE_pcount_ = 0; 00244 RLE_bindex_ = 1; 00245 } 00246 } 00247 00255 inline size_t size() const 00256 { 00257 size_t result = blockList_.size() * DcmRLEEncoder_BLOCKSIZE + offset_; 00258 if (pad_ && (result & 1)) result++; // enforce even number of bytes 00259 return result; 00260 } 00261 00265 inline OFBool fail() const 00266 { 00267 if (fail_) return OFTrue; else return OFFalse; 00268 } 00269 00274 inline void write(void *target) const 00275 { 00276 if ((!fail_) && target) 00277 { 00278 unsigned char *current = NULL; 00279 unsigned char *target8 = OFstatic_cast(unsigned char *, target); 00280 OFListConstIterator(unsigned char *) first = blockList_.begin(); 00281 OFListConstIterator(unsigned char *) last = blockList_.end(); 00282 while (first != last) 00283 { 00284 current = *first; 00285 memcpy(target8, current, DcmRLEEncoder_BLOCKSIZE); 00286 target8 += DcmRLEEncoder_BLOCKSIZE; 00287 ++first; 00288 } 00289 if (offset_ > 0) 00290 { 00291 memcpy(target8, currentBlock_, offset_); 00292 } 00293 00294 // pad to even number of bytes if necessary 00295 if (pad_ && ((blockList_.size() * DcmRLEEncoder_BLOCKSIZE + offset_) & 1)) 00296 { 00297 target8 += offset_; 00298 *target8 = 0; 00299 } 00300 } 00301 } 00302 00307 inline void write(DcmEncoderOutputStream& os) const 00308 { 00309 if (!fail_) 00310 { 00311 OFListConstIterator(unsigned char *) first = blockList_.begin(); 00312 OFListConstIterator(unsigned char *) last = blockList_.end(); 00313 while (first != last) 00314 { 00315 os.write(*first, DcmRLEEncoder_BLOCKSIZE); 00316 ++first; 00317 } 00318 if (offset_ > 0) 00319 { 00320 os.write(currentBlock_, offset_); 00321 } 00322 00323 // pad to even number of bytes if necessary 00324 if (pad_ && ((blockList_.size() * DcmRLEEncoder_BLOCKSIZE + offset_) & 1)) 00325 { 00326 unsigned char c = 0; 00327 os.write(&c, 1); 00328 } 00329 } 00330 } 00331 00332 private: 00333 00335 DcmRLEEncoder(const DcmRLEEncoder&); 00336 00338 DcmRLEEncoder& operator=(const DcmRLEEncoder&); 00339 00345 inline void move(size_t numberOfBytes) 00346 { 00347 size_t i=0; 00348 while (i < numberOfBytes) 00349 { 00350 if (offset_ == DcmRLEEncoder_BLOCKSIZE) 00351 { 00352 blockList_.push_back(currentBlock_); 00353 currentBlock_ = new unsigned char[DcmRLEEncoder_BLOCKSIZE]; 00354 offset_ = 0; 00355 if (! currentBlock_) // out of memory 00356 { 00357 fail_ = 1; 00358 break; // exit while loop 00359 } 00360 } 00361 currentBlock_[offset_++] = RLE_buff_[i++]; 00362 } 00363 } 00364 00365 /* member variables */ 00366 00372 int fail_; 00373 00378 int pad_; 00379 00384 unsigned char *currentBlock_; 00385 00390 size_t offset_; 00391 00396 OFList<unsigned char *> blockList_; 00397 00401 unsigned char *RLE_buff_; 00402 00407 int RLE_prev_; 00408 00412 int RLE_pcount_; 00413 00416 unsigned int RLE_bindex_; 00417 00418 }; 00419 00420 #endif 00421 00422 00423 /* 00424 * CVS/RCS Log 00425 * $Log: dcrleenc.h,v $ 00426 * Revision 1.10 2004/01/16 14:06:20 joergr 00427 * Removed acknowledgements with e-mail addresses from CVS log. 00428 * 00429 * Revision 1.9 2003/08/14 09:00:56 meichel 00430 * Adapted type casts to new-style typecast operators defined in ofcast.h 00431 * 00432 * Revision 1.8 2003/06/12 18:21:24 joergr 00433 * Modified code to use const_iterators where appropriate (required for STL). 00434 * 00435 * Revision 1.7 2003/06/12 13:32:59 joergr 00436 * Fixed inconsistent API documentation reported by Doxygen. 00437 * 00438 * Revision 1.6 2003/03/21 13:06:46 meichel 00439 * Minor code purifications for warnings reported by MSVC in Level 4 00440 * 00441 * Revision 1.5 2002/11/27 12:07:22 meichel 00442 * Adapted module dcmdata to use of new header file ofstdinc.h 00443 * 00444 * Revision 1.4 2002/07/18 12:16:52 joergr 00445 * Replaced return statement by break in a while loop of an inline function (not 00446 * supported by Sun CC 2.0.1). 00447 * 00448 * Revision 1.3 2002/07/08 07:02:50 meichel 00449 * RLE codec now includes <string.h>, needed for memcpy on Win32 00450 * 00451 * Revision 1.2 2002/06/27 15:15:42 meichel 00452 * Modified RLE encoder to make it usable for other purposes than 00453 * DICOM encoding as well (e.g. PostScript, TIFF) 00454 * 00455 * Revision 1.1 2002/06/06 14:52:37 meichel 00456 * Initial release of the new RLE codec classes 00457 * and the dcmcrle/dcmdrle tools in module dcmdata 00458 * 00459 * 00460 */


Generated on 4 Nov 2004 for OFFIS DCMTK Version 3.5.3 by Doxygen 1.3.8