dcmdata/include/dcmtk/dcmdata/dcrleenc.h

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


Generated on 6 Jan 2011 for OFFIS DCMTK Version 3.6.0 by Doxygen 1.5.1