dcrleenc.h

00001 /*
00002  *
00003  *  Copyright (C) 2002-2005, 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: onken $
00025  *  Update Date:      $Date: 2005/12/16 09:04:47 $
00026  *  CVS/RCS Revision: $Revision: 1.12 $
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 "dcmtk/config/osconfig.h"
00037 #include "dcmtk/ofstd/oflist.h"   /* for class OFList<> */
00038 
00039 #define INCLUDE_CSTRING
00040 #include "dcmtk/ofstd/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 
00060   virtual ~DcmEncoderOutputStream() {}
00061 
00062 };
00063 
00064 
00068 class DcmRLEEncoder
00069 {
00070 public:
00071 
00075   DcmRLEEncoder(int doPad)
00076   : fail_(0)
00077   , pad_(doPad)
00078   , currentBlock_(new unsigned char[DcmRLEEncoder_BLOCKSIZE])
00079   , offset_(0)
00080   , blockList_()
00081   , RLE_buff_(new unsigned char[132])
00082   , RLE_prev_(-1)
00083   , RLE_pcount_(0)
00084   , RLE_bindex_(1)
00085   {
00086     if ((! RLE_buff_)||(! currentBlock_)) fail_ = 1;
00087     else RLE_buff_[0] = 0;
00088   }
00089 
00091   ~DcmRLEEncoder()
00092   {
00093     delete[] currentBlock_;
00094     delete[] RLE_buff_;
00095     OFListIterator(unsigned char *) first = blockList_.begin();
00096     OFListIterator(unsigned char *) last = blockList_.end();
00097     while (first != last)
00098     {
00099         delete[] *first;
00100         first = blockList_.erase(first);
00101     }
00102   }
00103 
00108   inline void add(unsigned char ch)
00109   {
00110     if (! fail_) // if fail_ is true, just ignore input
00111     {
00112       // if the current byte equals the last byte read
00113       // (which is initialized with the "impossible" value -1),
00114       // just increase the repeat counter
00115       if (OFstatic_cast(int, ch) == RLE_prev_) RLE_pcount_++;
00116       else
00117       {
00118           // byte is different from last byte read.
00119           // flush replicate run if necessary
00120           switch (RLE_pcount_)
00121           {
00122             case 0:
00123               // happens only after construction or flush()
00124               break;
00125             case 2:
00126               // two bytes in repeat buffer. Convert to literal run
00127               RLE_buff_[RLE_bindex_++] = OFstatic_cast(unsigned char, RLE_prev_);
00128               // no break. Fall-through into next case statement is intended.
00129             case 1:
00130               // one (or two) bytes in repeat buffer. Convert to literal run
00131               RLE_buff_[RLE_bindex_++] = OFstatic_cast(unsigned char, RLE_prev_);
00132               break;
00133             default:
00134               // more than two bytes in repeat buffer. Convert to replicate run
00135               if (RLE_bindex_ > 1)
00136               {
00137                   // there is a literal run in the buffer that must be flushed
00138                   // before the replicate run.  Flush literal run now.
00139                   RLE_buff_[0] = OFstatic_cast(unsigned char, RLE_bindex_-2);
00140                   move(RLE_bindex_);
00141               }
00142               // this is the byte value for the repeat run
00143               RLE_buff_[1] = OFstatic_cast(unsigned char, RLE_prev_);
00144               // write as many repeat runs as necessary
00145               for (; RLE_pcount_>0; RLE_pcount_-=128)
00146               {
00147                   // different PackBit schemes exist. The original from which
00148                   // this code is derived used 0x80 | (RLE_pcount_ - 1)
00149                   // to represent replicate runs.
00150                   // DICOM instead uses 257 - RLE_pcount_
00151                   if (RLE_pcount_ > 128) RLE_buff_[0] = 0x81;
00152                     else RLE_buff_[0] = OFstatic_cast(unsigned char, 257 - RLE_pcount_);
00153                   move(2);
00154               }
00155               // now the buffer is guaranteed to be empty
00156               RLE_buff_[0] = 0;
00157               RLE_bindex_ = 1;
00158               break;
00159           }
00160 
00161           // if we have 128 or more bytes in the literal run, flush buffer
00162           if (RLE_bindex_ > 129)
00163           {
00164               RLE_buff_[0] = 127;
00165               move(129);
00166               RLE_bindex_ -= 128;
00167               if (RLE_bindex_ > 1)
00168                   RLE_buff_[1] = RLE_buff_[129];
00169               if (RLE_bindex_ > 2)
00170                   RLE_buff_[2] = RLE_buff_[130];
00171           }
00172 
00173           // current byte is stored in RLE_prev_, RLE_pcount_ is 1.
00174           RLE_prev_ = ch;
00175           RLE_pcount_ = 1;
00176       }
00177     }
00178   }
00179 
00185   inline void add(const unsigned char *buf, size_t bufcount)
00186   {
00187     if (buf)
00188     {
00189       while (bufcount--) add(*buf++);
00190     }
00191   }
00192 
00199   inline void flush()
00200   {
00201     if (! fail_) // if fail_ is true, do nothing
00202     {
00203       // if there are max 1 bytes in the repeat counter, convert to literal run
00204       if (RLE_pcount_ < 2)
00205       {
00206         for (; RLE_pcount_>0; --RLE_pcount_) RLE_buff_[RLE_bindex_++] = OFstatic_cast(unsigned char, RLE_prev_);
00207       }
00208 
00209       // if we have 128 or more bytes in the literal run, flush buffer
00210       if (RLE_bindex_ > 129)
00211       {
00212           RLE_buff_[0] = 127;
00213           move(129);
00214           RLE_bindex_ -= 128;
00215           if (RLE_bindex_ > 1)
00216               RLE_buff_[1] = RLE_buff_[129];
00217           if (RLE_bindex_ > 2)
00218               RLE_buff_[2] = RLE_buff_[130];
00219       }
00220 
00221       // if there is still a literal run in the buffer, flush literal run
00222       if (RLE_bindex_ > 1)
00223       {
00224           RLE_buff_[0] = OFstatic_cast(unsigned char, RLE_bindex_-2);
00225           move(RLE_bindex_);
00226       }
00227 
00228       // if there is a remaining repeat run, flush this one as well
00229       if (RLE_pcount_ >= 2)
00230       {
00231           RLE_buff_[1] = OFstatic_cast(unsigned char, RLE_prev_);
00232           // write as many repeat runs as necessary
00233           for (; RLE_pcount_>0; RLE_pcount_-=128)
00234           {
00235             // different PackBit schemes exist. The original from which
00236             // this code is derived used 0x80 | (RLE_pcount_ - 1)
00237             // to represent replicate runs.
00238             // DICOM instead uses 257 - RLE_pcount_
00239             if (RLE_pcount_ > 128) RLE_buff_[0] = 0x81;
00240               else RLE_buff_[0] = OFstatic_cast(unsigned char, 257 - RLE_pcount_);
00241             move(2);
00242           }
00243       }
00244 
00245       // now the buffer is guaranteed to be empty, re-initialize
00246       RLE_buff_[0] = 0;
00247       RLE_prev_ = -1;
00248       RLE_pcount_ = 0;
00249       RLE_bindex_ = 1;
00250     }
00251   }
00252 
00260   inline size_t size() const
00261   {
00262     size_t result = blockList_.size() * DcmRLEEncoder_BLOCKSIZE + offset_;
00263     if (pad_ && (result & 1)) result++; // enforce even number of bytes
00264     return result;
00265   }
00266 
00270   inline OFBool fail() const
00271   {
00272     if (fail_) return OFTrue; else return OFFalse;
00273   }
00274 
00279   inline void write(void *target) const
00280   {
00281     if ((!fail_) && target)
00282     {
00283       unsigned char *current = NULL;
00284       unsigned char *target8 = OFstatic_cast(unsigned char *, target);
00285       OFListConstIterator(unsigned char *) first = blockList_.begin();
00286       OFListConstIterator(unsigned char *) last = blockList_.end();
00287       while (first != last)
00288       {
00289         current = *first;
00290         memcpy(target8, current, DcmRLEEncoder_BLOCKSIZE);
00291         target8 += DcmRLEEncoder_BLOCKSIZE;
00292         ++first;
00293       }
00294       if (offset_ > 0)
00295       {
00296         memcpy(target8, currentBlock_, offset_);
00297       }
00298 
00299       // pad to even number of bytes if necessary
00300       if (pad_ && ((blockList_.size() * DcmRLEEncoder_BLOCKSIZE + offset_) & 1))
00301       {
00302         target8 += offset_;
00303         *target8 = 0;
00304       }
00305     }
00306   }
00307 
00312   inline void write(DcmEncoderOutputStream& os) const
00313   {
00314     if (!fail_)
00315     {
00316       OFListConstIterator(unsigned char *) first = blockList_.begin();
00317       OFListConstIterator(unsigned char *) last = blockList_.end();
00318       while (first != last)
00319       {
00320         os.write(*first, DcmRLEEncoder_BLOCKSIZE);
00321         ++first;
00322       }
00323       if (offset_ > 0)
00324       {
00325         os.write(currentBlock_, offset_);
00326       }
00327 
00328       // pad to even number of bytes if necessary
00329       if (pad_ && ((blockList_.size() * DcmRLEEncoder_BLOCKSIZE + offset_) & 1))
00330       {
00331         unsigned char c = 0;
00332         os.write(&c, 1);
00333       }
00334     }
00335   }
00336 
00337 private:
00338 
00340   DcmRLEEncoder(const DcmRLEEncoder&);
00341 
00343   DcmRLEEncoder& operator=(const DcmRLEEncoder&);
00344 
00350   inline void move(size_t numberOfBytes)
00351   {
00352     size_t i=0;
00353     while (i < numberOfBytes)
00354     {
00355       if (offset_ == DcmRLEEncoder_BLOCKSIZE)
00356       {
00357         blockList_.push_back(currentBlock_);
00358         currentBlock_ = new unsigned char[DcmRLEEncoder_BLOCKSIZE];
00359         offset_ = 0;
00360         if (! currentBlock_) // out of memory
00361         {
00362           fail_ = 1;
00363           break;    // exit while loop
00364         }
00365       }
00366       currentBlock_[offset_++] = RLE_buff_[i++];
00367     }
00368   }
00369 
00370   /* member variables */
00371 
00377   int fail_;
00378 
00383   int pad_;
00384 
00389   unsigned char *currentBlock_;
00390 
00395   size_t offset_;
00396 
00401   OFList<unsigned char *> blockList_;
00402 
00406   unsigned char *RLE_buff_;
00407 
00412   int RLE_prev_;
00413 
00417   int RLE_pcount_;
00418 
00421   unsigned int RLE_bindex_;
00422 
00423 };
00424 
00425 #endif
00426 
00427 
00428 /*
00429  * CVS/RCS Log
00430  * $Log: dcrleenc.h,v $
00431  * Revision 1.12  2005/12/16 09:04:47  onken
00432  * - Added virtual (dummy) destructor to avoid compiler warnings
00433  *
00434  * Revision 1.11  2005/12/08 16:28:38  meichel
00435  * Changed include path schema for all DCMTK header files
00436  *
00437  * Revision 1.10  2004/01/16 14:06:20  joergr
00438  * Removed acknowledgements with e-mail addresses from CVS log.
00439  *
00440  * Revision 1.9  2003/08/14 09:00:56  meichel
00441  * Adapted type casts to new-style typecast operators defined in ofcast.h
00442  *
00443  * Revision 1.8  2003/06/12 18:21:24  joergr
00444  * Modified code to use const_iterators where appropriate (required for STL).
00445  *
00446  * Revision 1.7  2003/06/12 13:32:59  joergr
00447  * Fixed inconsistent API documentation reported by Doxygen.
00448  *
00449  * Revision 1.6  2003/03/21 13:06:46  meichel
00450  * Minor code purifications for warnings reported by MSVC in Level 4
00451  *
00452  * Revision 1.5  2002/11/27 12:07:22  meichel
00453  * Adapted module dcmdata to use of new header file ofstdinc.h
00454  *
00455  * Revision 1.4  2002/07/18 12:16:52  joergr
00456  * Replaced return statement by break in a while loop of an inline function (not
00457  * supported by Sun CC 2.0.1).
00458  *
00459  * Revision 1.3  2002/07/08 07:02:50  meichel
00460  * RLE codec now includes <string.h>, needed for memcpy on Win32
00461  *
00462  * Revision 1.2  2002/06/27 15:15:42  meichel
00463  * Modified RLE encoder to make it usable for other purposes than
00464  *   DICOM encoding as well (e.g. PostScript, TIFF)
00465  *
00466  * Revision 1.1  2002/06/06 14:52:37  meichel
00467  * Initial release of the new RLE codec classes
00468  *   and the dcmcrle/dcmdrle tools in module dcmdata
00469  *
00470  *
00471  */


Generated on 20 Dec 2005 for OFFIS DCMTK Version 3.5.4 by Doxygen 1.4.5