]> Creatis software - gdcm.git/blob - src/gdcmRLEFramesInfo.cxx
ENH: Getting toward a nice gdcmDecompressor. Now RLE and JPEG are getting similar...
[gdcm.git] / src / gdcmRLEFramesInfo.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmRLEFramesInfo.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/01/31 05:24:21 $
7   Version:   $Revision: 1.9 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18
19 #include "gdcmRLEFramesInfo.h"
20 #include "gdcmDebug.h"
21
22 namespace gdcm 
23 {
24
25 RLEFramesInfo::~RLEFramesInfo()
26 {
27    for(RLEFrameList::iterator it = Frames.begin(); it != Frames.end(); ++it)
28    {
29       delete (*it);
30    }
31    Frames.clear();
32 }
33
34 /**
35  * \brief        Print self.
36  * @param indent Indentation string to be prepended during printing.
37  * @param os     Stream to print to.
38  */
39 void RLEFramesInfo::Print( std::ostream &os, std::string indent )
40 {
41    os << std::endl;
42    os << indent
43       << "----------------- RLE frames --------------------------------"
44       << std::endl;
45    os << indent
46       << "Total number of Frames : " << Frames.size()
47       << std::endl;
48    int frameNumber = 0;
49    for(RLEFrameList::iterator it = Frames.begin(); it != Frames.end(); ++it)
50    {
51       os << indent
52          << "   frame number :" << frameNumber++
53          << std::endl;
54       (*it)->Print( os, indent + "   " );
55    }
56 }
57
58 void RLEFramesInfo::AddFrame(RLEFrame *frame)
59 {
60    Frames.push_back(frame);
61 }
62
63 RLEFrame *RLEFramesInfo::GetFirstFrame()
64 {
65    ItFrames = Frames.begin();
66    if (ItFrames != Frames.end())
67       return  *ItFrames;
68    return NULL;
69 }
70
71 RLEFrame *RLEFramesInfo::GetNextFrame()
72 {
73    gdcmAssertMacro (ItFrames != Frames.end());
74
75    ++ItFrames;
76    if (ItFrames != Frames.end())
77       return  *ItFrames;
78    return NULL;
79 }
80
81 /**
82  * \brief     Reads from disk the Pixel Data of 'Run Length Encoded'
83  *            Dicom encapsulated file and decompress it.
84  * @param     fp already open File Pointer
85  *            at which the pixel data should be copied
86  * @return    Boolean
87  */
88 bool RLEFramesInfo::ReadAndDecompressRLEFile( std::ifstream *fp , uint8_t *raw, int xSize, int ySize, int zSize, int bitsAllocated )
89 {
90    uint8_t *subRaw = raw;
91    long RawSegmentSize = xSize * ySize;
92
93    // Loop on the frame[s]
94    for(RLEFrameList::iterator it = Frames.begin(); it != Frames.end(); ++it)
95    {
96       // Loop on the fragments
97       for( unsigned int k = 1; k <= (*it)->GetNumberOfFragments(); k++ )
98       {
99          fp->seekg((*it)->GetOffset(k),std::ios::beg);
100          ReadAndDecompressRLEFragment(subRaw,
101                                       (*it)->GetLength(k),
102                                       RawSegmentSize, 
103                                       fp);
104          subRaw += RawSegmentSize;
105       }
106    }
107
108    if ( bitsAllocated == 16 )
109    {
110       // Try to deal with RLE 16 Bits
111       (void)DecompressRLE16BitsFromRLE8Bits( raw, xSize, ySize, zSize );
112    }
113
114    return true;
115 }
116
117 /**
118  * \brief Implementation of the RLE decoding algorithm for decompressing
119  *        a RLE fragment. [refer to PS 3.5-2003, section G.3.2 p 86]
120  * @param subRaw Sub region of \ref Raw where the decoded fragment
121  *        should be placed.
122  * @param fragmentSize The length of the binary fragment as found on the disk.
123  * @param RawSegmentSize The expected length of the fragment ONCE
124  *        Raw.
125  * @param fp File Pointer: on entry the position should be the one of
126  *        the fragment to be decoded.
127  */
128 bool RLEFramesInfo::ReadAndDecompressRLEFragment( uint8_t *subRaw,
129                                                  long fragmentSize,
130                                                  long RawSegmentSize,
131                                                  std::ifstream *fp )
132 {
133    int8_t count;
134    long numberOfOutputBytes = 0;
135    long numberOfReadBytes = 0;
136
137    while( numberOfOutputBytes < RawSegmentSize )
138    {
139       fp->read( (char*)&count, 1 );
140       numberOfReadBytes += 1;
141       if ( count >= 0 )
142       // Note: count <= 127 comparison is always true due to limited range
143       //       of data type int8_t [since the maximum of an exact width
144       //       signed integer of width N is 2^(N-1) - 1, which for int8_t
145       //       is 127].
146       {
147          fp->read( (char*)subRaw, count + 1);
148          numberOfReadBytes   += count + 1;
149          subRaw     += count + 1;
150          numberOfOutputBytes += count + 1;
151       }
152       else
153       {
154          if ( count <= -1 && count >= -127 )
155          {
156             int8_t newByte;
157             fp->read( (char*)&newByte, 1);
158             numberOfReadBytes += 1;
159             for( int i = 0; i < -count + 1; i++ )
160             {
161                subRaw[i] = newByte;
162             }
163             subRaw     += -count + 1;
164             numberOfOutputBytes += -count + 1;
165          }
166       }
167       // if count = 128 output nothing
168                                                                                 
169       if ( numberOfReadBytes > fragmentSize )
170       {
171          gdcmVerboseMacro( "Read more bytes than the segment size.");
172          return false;
173       }
174    }
175    return true;
176 }
177
178 /**
179  * \brief     Try to deal with RLE 16 Bits. 
180  *            We assume the RLE has already been parsed and loaded in
181  *            Raw (through \ref ReadAndDecompressJPEGFile ).
182  *            We here need to make 16 Bits Pixels from Low Byte and
183  *            High Byte 'Planes'...(for what it may mean)
184  * @return    Boolean
185  */
186 bool RLEFramesInfo::DecompressRLE16BitsFromRLE8Bits( uint8_t* raw, int xSize, int ySize,int numberOfFrames  )
187 {
188    size_t pixelNumber = xSize * ySize;
189    size_t rawSize = xSize * ySize * numberOfFrames;
190
191    // We assumed Raw contains the decoded RLE pixels but as
192    // 8 bits per pixel. In order to convert those pixels to 16 bits
193    // per pixel we cannot work in place within Raw and hence
194    // we copy it in a safe place, say copyRaw.
195
196    uint8_t* copyRaw = new uint8_t[rawSize * 2];
197    memmove( copyRaw, raw, rawSize * 2 );
198
199    uint8_t* x = raw;
200    uint8_t* a = copyRaw;
201    uint8_t* b = a + pixelNumber;
202
203    for ( int i = 0; i < numberOfFrames; i++ )
204    {
205       for ( unsigned int j = 0; j < pixelNumber; j++ )
206       {
207          *(x++) = *(b++);
208          *(x++) = *(a++);
209       }
210    }
211
212    delete[] copyRaw;
213       
214    /// \todo check that operator new []didn't fail, and sometimes return false
215    return true;
216 }
217
218
219 } // end namespace gdcm