OFFIS DCMTK  Version 3.6.0
dcrleenc.h
1 /*
2  *
3  * Copyright (C) 2002-2010, OFFIS e.V.
4  * All rights reserved. See COPYRIGHT file for details.
5  *
6  * This software and supporting documentation were developed by
7  *
8  * OFFIS e.V.
9  * R&D Division Health
10  * Escherweg 2
11  * D-26121 Oldenburg, Germany
12  *
13  *
14  * Module: dcmdata
15  *
16  * Author: Marco Eichelberg
17  *
18  * Purpose: RLE compressor
19  *
20  * Last Update: $Author: joergr $
21  * Update Date: $Date: 2010-10-14 13:15:42 $
22  * CVS/RCS Revision: $Revision: 1.13 $
23  * Status: $State: Exp $
24  *
25  * CVS/RCS Log at end of file
26  *
27  */
28 
29 #ifndef DCRLEENC_H
30 #define DCRLEENC_H
31 
32 #include "dcmtk/config/osconfig.h"
33 #include "dcmtk/ofstd/oflist.h" /* for class OFList<> */
34 
35 #define INCLUDE_CSTRING
36 #include "dcmtk/ofstd/ofstdinc.h"
37 
38 #define DcmRLEEncoder_BLOCKSIZE 16384
39 
40 
46 {
47 public:
52  virtual void write(const unsigned char *buf, size_t bufsize) =0;
53 
57 
58 };
59 
60 
65 {
66 public:
67 
71  DcmRLEEncoder(int doPad)
72  : fail_(0)
73  , pad_(doPad)
74  , currentBlock_(new unsigned char[DcmRLEEncoder_BLOCKSIZE])
75  , offset_(0)
76  , blockList_()
77  , RLE_buff_(new unsigned char[132])
78  , RLE_prev_(-1)
79  , RLE_pcount_(0)
80  , RLE_bindex_(1)
81  {
82  if ((! RLE_buff_)||(! currentBlock_)) fail_ = 1;
83  else RLE_buff_[0] = 0;
84  }
85 
88  {
89  delete[] currentBlock_;
90  delete[] RLE_buff_;
91  OFListIterator(unsigned char *) first = blockList_.begin();
92  OFListIterator(unsigned char *) last = blockList_.end();
93  while (first != last)
94  {
95  delete[] *first;
96  first = blockList_.erase(first);
97  }
98  }
99 
104  inline void add(unsigned char ch)
105  {
106  if (! fail_) // if fail_ is true, just ignore input
107  {
108  // if the current byte equals the last byte read
109  // (which is initialized with the "impossible" value -1),
110  // just increase the repeat counter
111  if (OFstatic_cast(int, ch) == RLE_prev_) RLE_pcount_++;
112  else
113  {
114  // byte is different from last byte read.
115  // flush replicate run if necessary
116  switch (RLE_pcount_)
117  {
118  case 0:
119  // happens only after construction or flush()
120  break;
121  case 2:
122  // two bytes in repeat buffer. Convert to literal run
123  RLE_buff_[RLE_bindex_++] = OFstatic_cast(unsigned char, RLE_prev_);
124  // no break. Fall-through into next case statement is intended.
125  case 1:
126  // one (or two) bytes in repeat buffer. Convert to literal run
127  RLE_buff_[RLE_bindex_++] = OFstatic_cast(unsigned char, RLE_prev_);
128  break;
129  default:
130  // more than two bytes in repeat buffer. Convert to replicate run
131  if (RLE_bindex_ > 1)
132  {
133  // there is a literal run in the buffer that must be flushed
134  // before the replicate run. Flush literal run now.
135  RLE_buff_[0] = OFstatic_cast(unsigned char, RLE_bindex_-2);
136  move(RLE_bindex_);
137  }
138  // this is the byte value for the repeat run
139  RLE_buff_[1] = OFstatic_cast(unsigned char, RLE_prev_);
140  // write as many repeat runs as necessary
141  for (; RLE_pcount_>0; RLE_pcount_-=128)
142  {
143  // different PackBit schemes exist. The original from which
144  // this code is derived used 0x80 | (RLE_pcount_ - 1)
145  // to represent replicate runs.
146  // DICOM instead uses 257 - RLE_pcount_
147  if (RLE_pcount_ > 128) RLE_buff_[0] = 0x81;
148  else RLE_buff_[0] = OFstatic_cast(unsigned char, 257 - RLE_pcount_);
149  move(2);
150  }
151  // now the buffer is guaranteed to be empty
152  RLE_buff_[0] = 0;
153  RLE_bindex_ = 1;
154  break;
155  }
156 
157  // if we have 128 or more bytes in the literal run, flush buffer
158  if (RLE_bindex_ > 129)
159  {
160  RLE_buff_[0] = 127;
161  move(129);
162  RLE_bindex_ -= 128;
163  if (RLE_bindex_ > 1)
164  RLE_buff_[1] = RLE_buff_[129];
165  if (RLE_bindex_ > 2)
166  RLE_buff_[2] = RLE_buff_[130];
167  }
168 
169  // current byte is stored in RLE_prev_, RLE_pcount_ is 1.
170  RLE_prev_ = ch;
171  RLE_pcount_ = 1;
172  }
173  }
174  }
175 
181  inline void add(const unsigned char *buf, size_t bufcount)
182  {
183  if (buf)
184  {
185  while (bufcount--) add(*buf++);
186  }
187  }
188 
195  inline void flush()
196  {
197  if (! fail_) // if fail_ is true, do nothing
198  {
199  // if there are max 1 bytes in the repeat counter, convert to literal run
200  if (RLE_pcount_ < 2)
201  {
202  for (; RLE_pcount_>0; --RLE_pcount_) RLE_buff_[RLE_bindex_++] = OFstatic_cast(unsigned char, RLE_prev_);
203  }
204 
205  // if we have 128 or more bytes in the literal run, flush buffer
206  if (RLE_bindex_ > 129)
207  {
208  RLE_buff_[0] = 127;
209  move(129);
210  RLE_bindex_ -= 128;
211  if (RLE_bindex_ > 1)
212  RLE_buff_[1] = RLE_buff_[129];
213  if (RLE_bindex_ > 2)
214  RLE_buff_[2] = RLE_buff_[130];
215  }
216 
217  // if there is still a literal run in the buffer, flush literal run
218  if (RLE_bindex_ > 1)
219  {
220  RLE_buff_[0] = OFstatic_cast(unsigned char, RLE_bindex_-2);
221  move(RLE_bindex_);
222  }
223 
224  // if there is a remaining repeat run, flush this one as well
225  if (RLE_pcount_ >= 2)
226  {
227  RLE_buff_[1] = OFstatic_cast(unsigned char, RLE_prev_);
228  // write as many repeat runs as necessary
229  for (; RLE_pcount_>0; RLE_pcount_-=128)
230  {
231  // different PackBit schemes exist. The original from which
232  // this code is derived used 0x80 | (RLE_pcount_ - 1)
233  // to represent replicate runs.
234  // DICOM instead uses 257 - RLE_pcount_
235  if (RLE_pcount_ > 128) RLE_buff_[0] = 0x81;
236  else RLE_buff_[0] = OFstatic_cast(unsigned char, 257 - RLE_pcount_);
237  move(2);
238  }
239  }
240 
241  // now the buffer is guaranteed to be empty, re-initialize
242  RLE_buff_[0] = 0;
243  RLE_prev_ = -1;
244  RLE_pcount_ = 0;
245  RLE_bindex_ = 1;
246  }
247  }
248 
256  inline size_t size() const
257  {
258  size_t result = blockList_.size() * DcmRLEEncoder_BLOCKSIZE + offset_;
259  if (pad_ && (result & 1)) result++; // enforce even number of bytes
260  return result;
261  }
262 
266  inline OFBool fail() const
267  {
268  if (fail_) return OFTrue; else return OFFalse;
269  }
270 
275  inline void write(void *target) const
276  {
277  if ((!fail_) && target)
278  {
279  unsigned char *current = NULL;
280  unsigned char *target8 = OFstatic_cast(unsigned char *, target);
281  OFListConstIterator(unsigned char *) first = blockList_.begin();
282  OFListConstIterator(unsigned char *) last = blockList_.end();
283  while (first != last)
284  {
285  current = *first;
286  memcpy(target8, current, DcmRLEEncoder_BLOCKSIZE);
287  target8 += DcmRLEEncoder_BLOCKSIZE;
288  ++first;
289  }
290  if (offset_ > 0)
291  {
292  memcpy(target8, currentBlock_, offset_);
293  }
294 
295  // pad to even number of bytes if necessary
296  if (pad_ && ((blockList_.size() * DcmRLEEncoder_BLOCKSIZE + offset_) & 1))
297  {
298  target8 += offset_;
299  *target8 = 0;
300  }
301  }
302  }
303 
308  inline void write(DcmEncoderOutputStream& os) const
309  {
310  if (!fail_)
311  {
312  OFListConstIterator(unsigned char *) first = blockList_.begin();
313  OFListConstIterator(unsigned char *) last = blockList_.end();
314  while (first != last)
315  {
316  os.write(*first, DcmRLEEncoder_BLOCKSIZE);
317  ++first;
318  }
319  if (offset_ > 0)
320  {
322  }
323 
324  // pad to even number of bytes if necessary
325  if (pad_ && ((blockList_.size() * DcmRLEEncoder_BLOCKSIZE + offset_) & 1))
326  {
327  unsigned char c = 0;
328  os.write(&c, 1);
329  }
330  }
331  }
332 
333 private:
334 
337 
340 
346  inline void move(size_t numberOfBytes)
347  {
348  size_t i=0;
349  while (i < numberOfBytes)
350  {
351  if (offset_ == DcmRLEEncoder_BLOCKSIZE)
352  {
354  currentBlock_ = new unsigned char[DcmRLEEncoder_BLOCKSIZE];
355  offset_ = 0;
356  if (! currentBlock_) // out of memory
357  {
358  fail_ = 1;
359  break; // exit while loop
360  }
361  }
362  currentBlock_[offset_++] = RLE_buff_[i++];
363  }
364  }
365 
366  /* member variables */
367 
373  int fail_;
374 
379  int pad_;
380 
385  unsigned char *currentBlock_;
386 
391  size_t offset_;
392 
398 
402  unsigned char *RLE_buff_;
403 
409 
414 
417  unsigned int RLE_bindex_;
418 
419 };
420 
421 #endif
422 
423 
424 /*
425  * CVS/RCS Log
426  * $Log: dcrleenc.h,v $
427  * Revision 1.13 2010-10-14 13:15:42 joergr
428  * Updated copyright header. Added reference to COPYRIGHT file.
429  *
430  * Revision 1.12 2005/12/16 09:04:47 onken
431  * - Added virtual (dummy) destructor to avoid compiler warnings
432  *
433  * Revision 1.11 2005/12/08 16:28:38 meichel
434  * Changed include path schema for all DCMTK header files
435  *
436  * Revision 1.10 2004/01/16 14:06:20 joergr
437  * Removed acknowledgements with e-mail addresses from CVS log.
438  *
439  * Revision 1.9 2003/08/14 09:00:56 meichel
440  * Adapted type casts to new-style typecast operators defined in ofcast.h
441  *
442  * Revision 1.8 2003/06/12 18:21:24 joergr
443  * Modified code to use const_iterators where appropriate (required for STL).
444  *
445  * Revision 1.7 2003/06/12 13:32:59 joergr
446  * Fixed inconsistent API documentation reported by Doxygen.
447  *
448  * Revision 1.6 2003/03/21 13:06:46 meichel
449  * Minor code purifications for warnings reported by MSVC in Level 4
450  *
451  * Revision 1.5 2002/11/27 12:07:22 meichel
452  * Adapted module dcmdata to use of new header file ofstdinc.h
453  *
454  * Revision 1.4 2002/07/18 12:16:52 joergr
455  * Replaced return statement by break in a while loop of an inline function (not
456  * supported by Sun CC 2.0.1).
457  *
458  * Revision 1.3 2002/07/08 07:02:50 meichel
459  * RLE codec now includes <string.h>, needed for memcpy on Win32
460  *
461  * Revision 1.2 2002/06/27 15:15:42 meichel
462  * Modified RLE encoder to make it usable for other purposes than
463  * DICOM encoding as well (e.g. PostScript, TIFF)
464  *
465  * Revision 1.1 2002/06/06 14:52:37 meichel
466  * Initial release of the new RLE codec classes
467  * and the dcmcrle/dcmdrle tools in module dcmdata
468  *
469  *
470  */


Generated on Thu Dec 20 2012 for OFFIS DCMTK Version 3.6.0 by Doxygen 1.8.2