Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

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 8 Dec 2004 for OFFIS DCMTK Version 3.5.3 by Doxygen 1.3.9.1