]> Creatis software - gdcm.git/blob - src/gdcmPixelConvert.cxx
* CLEANUP_ROUND (8) for gdcmPixelConvert (end of RLE nigthmare)
[gdcm.git] / src / gdcmPixelConvert.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmPixelConvert.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/10/08 16:27:20 $
7   Version:   $Revision: 1.3 $
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 //////////////////   TEMPORARY NOT
20 // look for "fixMem" and convert that to a member of this class
21 // Removing the prefix fixMem and dealing with allocations should do the trick
22 #define str2num(str, typeNum) *((typeNum *)(str))
23
24 #include "gdcmDebug.h"
25 #include "gdcmPixelConvert.h"
26
27
28 //-----------------------------------------------------------------------------
29 // Constructor / Destructor
30 gdcmPixelConvert::gdcmPixelConvert() 
31 {
32    RGB = 0;
33    RGBSize = 0;
34    Uncompressed = 0;
35    UncompressedSize = 0;
36 }
37
38 void gdcmPixelConvert::Squeeze() 
39 {
40    if ( RGB ) {
41       delete [] RGB;
42    } 
43    if ( Uncompressed ) {
44       delete [] Uncompressed;
45    }
46 }
47
48 gdcmPixelConvert::~gdcmPixelConvert() 
49 {
50    Squeeze();
51 }
52
53 void gdcmPixelConvert::AllocateRGB()
54 {
55   if ( RGB ) {
56      delete [] RGB;
57   }
58   RGB = new uint8_t[RGBSize];
59 }
60
61 void gdcmPixelConvert::AllocateUncompressed()
62 {
63   if ( Uncompressed ) {
64      delete [] Uncompressed;
65   }
66   Uncompressed = new uint8_t[ UncompressedSize ];
67 }
68
69 /**
70  * \brief Read from file a 12 bits per pixel image and uncompress it
71  *        into a 16 bits per pixel image.
72  */
73 bool gdcmPixelConvert::ReadAndUncompress12Bits( FILE* filePointer,
74                                                 size_t uncompressedSize,
75                                                 size_t PixelNumber )
76 {
77    SetUncompressedSize( uncompressedSize );
78    AllocateUncompressed();
79
80    uint16_t* pdestination = (uint16_t*)Uncompressed;
81                                                                                 
82    for(int p = 0; p < PixelNumber; p += 2 )
83    {
84       // 2 pixels 12bit =     [0xABCDEF]
85       // 2 pixels 16bit = [0x0ABD] + [0x0FCE]
86       uint8_t b0, b1, b2;
87       size_t ItemRead;
88       ItemRead = fread( &b0, 1, 1, filePointer);
89       if ( ItemRead != 1 )
90       {
91          return false;
92       }
93       ItemRead = fread( &b1, 1, 1, filePointer);
94       if ( ItemRead != 1 )
95       {
96          return false;
97       }
98       ItemRead = fread( &b2, 1, 1, filePointer);
99       if ( ItemRead != 1 )
100       {
101          return false;
102       }
103                                                                                 
104       //Two steps are necessary to please VC++
105       *pdestination++ =  ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f);
106       //                     A                     B                 D
107       *pdestination++ =  ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4);
108       //                     F                     C                 E
109                                                                                 
110       /// \todo JPR Troubles expected on Big-Endian processors ?
111    }
112    return true;
113 }
114
115 /**
116  * \brief Read from file an uncompressed image.
117  */
118 bool gdcmPixelConvert::ReadUncompressed( FILE* filePointer,
119                                          size_t uncompressedSize,
120                                          size_t expectedSize )
121 {
122    if ( expectedSize > uncompressedSize )
123    {
124       dbg.Verbose(0, "gdcmPixelConvert::ReadUncompressed: expectedSize"
125                      "is bigger than it should");
126       return false;
127    }
128    SetUncompressedSize( uncompressedSize );
129    AllocateUncompressed();
130    size_t ItemRead = fread( (void*)Uncompressed, expectedSize, 1, filePointer);
131    if ( ItemRead != 1 )
132    {
133       return false;
134    }
135    return true;
136 }
137
138 /**
139  * \brief  Convert a Gray plane and ( Lut R, Lut G, Lut B ) into an
140  *         RGB plane.
141  * @return True on success.
142  */
143 bool gdcmPixelConvert::ConvertGrayAndLutToRGB( uint8_t *lutRGBA )
144
145 {
146    /// We assume Uncompressed contains the decompressed gray plane
147    /// and build the RGB image.
148    SetRGBSize( UncompressedSize );
149    AllocateRGB();
150
151 //aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
152 //AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
153 //COPY HERE THE CODE OF GetImageDataIntoVector
154       
155    /// \todo check that operator new []didn't fail, and sometimes return false
156    return true;
157 }
158
159 /**
160  * \brief     Try to deal with RLE 16 Bits. 
161  *            We assume the RLE has allready been parsed and loaded in
162  *            Uncompressed (through \ref ReadAndUncompressRLE8Bits ).
163  *            We here need to make 16 Bits Pixels from Low Byte and
164  *            High Byte 'Planes'...(for what it may mean)
165  * @return    Boolean
166  */
167 bool gdcmPixelConvert::UncompressRLE16BitsFromRLE8Bits(
168                        int XSize,
169                        int YSize,
170                        int NumberOfFrames,
171                        uint8_t* fixMemUncompressed )
172 {
173    size_t PixelNumber = XSize * YSize;
174    size_t fixMemUncompressedSize = XSize * YSize * NumberOfFrames;
175
176    // We assumed Uncompressed contains the decoded RLE pixels but as
177    // 8 bits per pixel. In order to convert those pixels to 16 bits
178    // per pixel we cannot work in place within Uncompressed and hence
179    // we copy Uncompressed in a safe place, say OldUncompressed.
180
181    uint8_t* OldUncompressed = new uint8_t[ fixMemUncompressedSize * 2 ];
182    memmove( OldUncompressed, fixMemUncompressed, fixMemUncompressedSize * 2);
183
184    uint8_t* x = fixMemUncompressed;
185    uint8_t* a = OldUncompressed;
186    uint8_t* b = a + PixelNumber;
187
188    for ( int i = 0; i < NumberOfFrames; i++ )
189    {
190       for ( int j = 0; j < PixelNumber; j++ )
191       {
192          *(x++) = *(a++);
193          *(x++) = *(b++);
194       }
195    }
196
197    delete[] OldUncompressed;
198       
199    /// \todo check that operator new []didn't fail, and sometimes return false
200    return true;
201 }
202
203 /**
204  * \brief Implementation of the RLE decoding algorithm for uncompressing
205  *        a RLE fragment. [refer to PS 3.5-2003, section G.3.2 p 86]
206  */
207 bool gdcmPixelConvert::ReadAndUncompressRLEFragment( uint8_t* decodedZone,
208                                                long fragmentSize,
209                                                long uncompressedSegmentSize,
210                                                FILE* fp )
211 {
212    int8_t count;
213    long numberOfOutputBytes = 0;
214    long numberOfReadBytes = 0;
215                                                                                 
216    while( numberOfOutputBytes < uncompressedSegmentSize )
217    {
218       fread( &count, 1, 1, fp );
219       numberOfReadBytes += 1;
220       if ( count >= 0 )
221       // Note: count <= 127 comparison is always true due to limited range
222       //       of data type int8_t [since the maximum of an exact width
223       //       signed integer of width N is 2^(N-1) - 1, which for int8_t
224       //       is 127].
225       {
226          fread( decodedZone, count + 1, 1, fp);
227          numberOfReadBytes += count + 1;
228          decodedZone         += count + 1;
229          numberOfOutputBytes += count + 1;
230       }
231       else
232       {
233          if ( ( count <= -1 ) && ( count >= -127 ) )
234          {
235             int8_t newByte;
236             fread( &newByte, 1, 1, fp);
237             numberOfReadBytes += 1;
238             for( int i = 0; i < -count + 1; i++ )
239             {
240                decodedZone[i] = newByte;
241             }
242             decodedZone         += -count + 1;
243             numberOfOutputBytes += -count + 1;
244          }
245       }
246       // if count = 128 output nothing
247                                                                                 
248       if ( numberOfReadBytes > fragmentSize )
249       {
250          dbg.Verbose(0, "gdcmFile::gdcm_read_RLE_fragment: we read more "
251                         "bytes than the segment size.");
252          return false;
253       }
254    }
255    return true;
256 }
257
258 /**
259  * \brief     Reads from disk the Pixel Data of 'Run Length Encoded'
260  *            Dicom encapsulated file and uncompress it.
261  * @param     fp already open File Pointer
262  * @param     image_buffer destination Address (in caller's memory space)
263  *            at which the pixel data should be copied
264  * @return    Boolean
265  */
266 bool gdcmPixelConvert::gdcm_read_RLE_file( void* image_buffer,
267                                    int XSize,
268                                    int YSize,
269                                    int ZSize,
270                                    int BitsAllocated,
271                                    gdcmRLEFramesInfo* RLEInfo,
272                                    FILE* fp )
273 {
274    uint8_t* im = (uint8_t*)image_buffer;
275    long uncompressedSegmentSize = XSize * YSize;
276                                                                                 
277                                                                                 
278    // Loop on the frame[s]
279    for( gdcmRLEFramesInfo::RLEFrameList::iterator
280         it  = RLEInfo->Frames.begin();
281         it != RLEInfo->Frames.end();
282       ++it )
283    {
284       // Loop on the fragments
285       for( unsigned int k = 1; k <= (*it)->NumberFragments; k++ )
286       {
287          fseek( fp, (*it)->Offset[k] ,SEEK_SET);
288          (void)gdcmPixelConvert::ReadAndUncompressRLEFragment(
289                                  (uint8_t*) im, (*it)->Length[k],
290                                  uncompressedSegmentSize, fp );
291          im += uncompressedSegmentSize;
292       }
293    }
294                                                                                 
295    if ( BitsAllocated == 16 )
296    {
297       // Try to deal with RLE 16 Bits
298       (void)gdcmPixelConvert::UncompressRLE16BitsFromRLE8Bits(
299                                              XSize,
300                                              YSize,
301                                              ZSize,
302                                              (uint8_t*) image_buffer);
303    }
304                                                                                 
305    return true;
306 }
307