]> Creatis software - gdcm.git/blob - src/gdcmPixelConvert.cxx
* CLEANUP_ROUND (9) for gdcmPixelConvert
[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 17:02:53 $
7   Version:   $Revision: 1.4 $
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 void gdcmPixelConvert::ConvertDecompress12BitsTo16Bits(
74                   uint8_t* pixelZone,
75                   int sizeX,
76                   int sizeY,
77                   FILE* filePtr)
78                throw ( gdcmFormatError )
79 {
80    int nbPixels = sizeX * sizeY;
81    uint16_t* destination = (uint16_t*)pixelZone;
82                                                                                 
83    for( int p = 0; p < nbPixels; p += 2 )
84    {
85       uint8_t b0, b1, b2;
86       size_t ItemRead;
87                                                                                 
88       ItemRead = fread( &b0, 1, 1, filePtr);
89       if ( ItemRead != 1 )
90       {
91          throw gdcmFormatError( "gdcmFile::ConvertDecompress12BitsTo16Bits()",
92                                 "Unfound first block" );
93       }
94                                                                                 
95       ItemRead = fread( &b1, 1, 1, filePtr);
96       if ( ItemRead != 1 )
97       {
98          throw gdcmFormatError( "gdcmFile::ConvertDecompress12BitsTo16Bits()",
99                                 "Unfound second block" );
100       }
101                                                                                 
102       ItemRead = fread( &b2, 1, 1, filePtr);
103       if ( ItemRead != 1 )
104       {
105          throw gdcmFormatError( "gdcmFile::ConvertDecompress12BitsTo16Bits()",
106                                 "Unfound second block" );
107       }
108                                                                                 
109       // Two steps are necessary to please VC++
110       //
111       // 2 pixels 12bit =     [0xABCDEF]
112       // 2 pixels 16bit = [0x0ABD] + [0x0FCE]
113       //                     A                     B                 D
114       *destination++ =  ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f);
115       //                     F                     C                 E
116       *destination++ =  ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4);
117                                                                                 
118       /// \todo JPR Troubles expected on Big-Endian processors ?
119    }
120 }
121
122 /**
123  * \brief Read from file an uncompressed image.
124  */
125 bool gdcmPixelConvert::ReadUncompressed( FILE* filePointer,
126                                          size_t uncompressedSize,
127                                          size_t expectedSize )
128 {
129    if ( expectedSize > uncompressedSize )
130    {
131       dbg.Verbose(0, "gdcmPixelConvert::ReadUncompressed: expectedSize"
132                      "is bigger than it should");
133       return false;
134    }
135    SetUncompressedSize( uncompressedSize );
136    AllocateUncompressed();
137    size_t ItemRead = fread( (void*)Uncompressed, expectedSize, 1, filePointer);
138    if ( ItemRead != 1 )
139    {
140       return false;
141    }
142    return true;
143 }
144
145 /**
146  * \brief  Convert a Gray plane and ( Lut R, Lut G, Lut B ) into an
147  *         RGB plane.
148  * @return True on success.
149  */
150 bool gdcmPixelConvert::ConvertGrayAndLutToRGB( uint8_t *lutRGBA )
151
152 {
153    /// We assume Uncompressed contains the decompressed gray plane
154    /// and build the RGB image.
155    SetRGBSize( UncompressedSize );
156    AllocateRGB();
157
158 //aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
159 //AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
160 //COPY HERE THE CODE OF GetImageDataIntoVector
161       
162    /// \todo check that operator new []didn't fail, and sometimes return false
163    return true;
164 }
165
166 /**
167  * \brief     Try to deal with RLE 16 Bits. 
168  *            We assume the RLE has allready been parsed and loaded in
169  *            Uncompressed (through \ref ReadAndUncompressRLE8Bits ).
170  *            We here need to make 16 Bits Pixels from Low Byte and
171  *            High Byte 'Planes'...(for what it may mean)
172  * @return    Boolean
173  */
174 bool gdcmPixelConvert::UncompressRLE16BitsFromRLE8Bits(
175                        int XSize,
176                        int YSize,
177                        int NumberOfFrames,
178                        uint8_t* fixMemUncompressed )
179 {
180    size_t PixelNumber = XSize * YSize;
181    size_t fixMemUncompressedSize = XSize * YSize * NumberOfFrames;
182
183    // We assumed Uncompressed contains the decoded RLE pixels but as
184    // 8 bits per pixel. In order to convert those pixels to 16 bits
185    // per pixel we cannot work in place within Uncompressed and hence
186    // we copy Uncompressed in a safe place, say OldUncompressed.
187
188    uint8_t* OldUncompressed = new uint8_t[ fixMemUncompressedSize * 2 ];
189    memmove( OldUncompressed, fixMemUncompressed, fixMemUncompressedSize * 2);
190
191    uint8_t* x = fixMemUncompressed;
192    uint8_t* a = OldUncompressed;
193    uint8_t* b = a + PixelNumber;
194
195    for ( int i = 0; i < NumberOfFrames; i++ )
196    {
197       for ( int j = 0; j < PixelNumber; j++ )
198       {
199          *(x++) = *(a++);
200          *(x++) = *(b++);
201       }
202    }
203
204    delete[] OldUncompressed;
205       
206    /// \todo check that operator new []didn't fail, and sometimes return false
207    return true;
208 }
209
210 /**
211  * \brief Implementation of the RLE decoding algorithm for uncompressing
212  *        a RLE fragment. [refer to PS 3.5-2003, section G.3.2 p 86]
213  */
214 bool gdcmPixelConvert::ReadAndUncompressRLEFragment( uint8_t* decodedZone,
215                                                long fragmentSize,
216                                                long uncompressedSegmentSize,
217                                                FILE* fp )
218 {
219    int8_t count;
220    long numberOfOutputBytes = 0;
221    long numberOfReadBytes = 0;
222                                                                                 
223    while( numberOfOutputBytes < uncompressedSegmentSize )
224    {
225       fread( &count, 1, 1, fp );
226       numberOfReadBytes += 1;
227       if ( count >= 0 )
228       // Note: count <= 127 comparison is always true due to limited range
229       //       of data type int8_t [since the maximum of an exact width
230       //       signed integer of width N is 2^(N-1) - 1, which for int8_t
231       //       is 127].
232       {
233          fread( decodedZone, count + 1, 1, fp);
234          numberOfReadBytes += count + 1;
235          decodedZone         += count + 1;
236          numberOfOutputBytes += count + 1;
237       }
238       else
239       {
240          if ( ( count <= -1 ) && ( count >= -127 ) )
241          {
242             int8_t newByte;
243             fread( &newByte, 1, 1, fp);
244             numberOfReadBytes += 1;
245             for( int i = 0; i < -count + 1; i++ )
246             {
247                decodedZone[i] = newByte;
248             }
249             decodedZone         += -count + 1;
250             numberOfOutputBytes += -count + 1;
251          }
252       }
253       // if count = 128 output nothing
254                                                                                 
255       if ( numberOfReadBytes > fragmentSize )
256       {
257          dbg.Verbose(0, "gdcmFile::gdcm_read_RLE_fragment: we read more "
258                         "bytes than the segment size.");
259          return false;
260       }
261    }
262    return true;
263 }
264
265 /**
266  * \brief     Reads from disk the Pixel Data of 'Run Length Encoded'
267  *            Dicom encapsulated file and uncompress it.
268  * @param     fp already open File Pointer
269  * @param     image_buffer destination Address (in caller's memory space)
270  *            at which the pixel data should be copied
271  * @return    Boolean
272  */
273 bool gdcmPixelConvert::gdcm_read_RLE_file( void* image_buffer,
274                                    int XSize,
275                                    int YSize,
276                                    int ZSize,
277                                    int BitsAllocated,
278                                    gdcmRLEFramesInfo* RLEInfo,
279                                    FILE* fp )
280 {
281    uint8_t* im = (uint8_t*)image_buffer;
282    long uncompressedSegmentSize = XSize * YSize;
283                                                                                 
284                                                                                 
285    // Loop on the frame[s]
286    for( gdcmRLEFramesInfo::RLEFrameList::iterator
287         it  = RLEInfo->Frames.begin();
288         it != RLEInfo->Frames.end();
289       ++it )
290    {
291       // Loop on the fragments
292       for( unsigned int k = 1; k <= (*it)->NumberFragments; k++ )
293       {
294          fseek( fp, (*it)->Offset[k] ,SEEK_SET);
295          (void)gdcmPixelConvert::ReadAndUncompressRLEFragment(
296                                  (uint8_t*) im, (*it)->Length[k],
297                                  uncompressedSegmentSize, fp );
298          im += uncompressedSegmentSize;
299       }
300    }
301                                                                                 
302    if ( BitsAllocated == 16 )
303    {
304       // Try to deal with RLE 16 Bits
305       (void)gdcmPixelConvert::UncompressRLE16BitsFromRLE8Bits(
306                                              XSize,
307                                              YSize,
308                                              ZSize,
309                                              (uint8_t*) image_buffer);
310    }
311                                                                                 
312    return true;
313 }
314
315 /**
316  * \brief   Swap the bytes, according to swap code.
317  * \warning not end user intended
318  * @param   im area to deal with
319  * @param   swap swap code
320  * @param   lgr Area Length
321  * @param   nb Pixels Bit number
322  */
323 void gdcmPixelConvert::SwapZone(void* im, int swap, int lgr, int nb)
324 {
325    int i;
326                                                                                 
327    if( nb == 16 )
328    {
329       uint16_t* im16 = (uint16_t*)im;
330       switch( swap )
331       {
332          case 0:
333          case 12:
334          case 1234:
335             break;
336          case 21:
337          case 3412:
338          case 2143:
339          case 4321:
340             for(i=0; i < lgr/2; i++)
341             {
342                im16[i]= (im16[i] >> 8) | (im16[i] << 8 );
343             }
344             break;
345          default:
346             std::cout << "SWAP value (16 bits) not allowed :i" << swap <<
347             std::endl;
348       }
349    }
350    else if( nb == 32 )
351    {
352       uint32_t s32;
353       uint16_t fort, faible;
354       uint32_t* im32 = (uint32_t*)im;
355       switch ( swap )
356       {
357          case 0:
358          case 1234:
359             break;
360          case 4321:
361             for(i = 0; i < lgr/4; i++)
362             {
363                faible  = im32[i] & 0x0000ffff;  // 4321
364                fort    = im32[i] >> 16;
365                fort    = ( fort >> 8   ) | ( fort << 8 );
366                faible  = ( faible >> 8 ) | ( faible << 8);
367                s32     = faible;
368                im32[i] = ( s32 << 16 ) | fort;
369             }
370             break;
371          case 2143:
372             for(i = 0; i < lgr/4; i++)
373             {
374                faible  = im32[i] & 0x0000ffff;   // 2143
375                fort    = im32[i] >> 16;
376                fort    = ( fort >> 8 ) | ( fort << 8 );
377                faible  = ( faible >> 8) | ( faible << 8);
378                s32     = fort;
379                im32[i] = ( s32 << 16 ) | faible;
380             }
381             break;
382          case 3412:
383             for(i = 0; i < lgr/4; i++)
384             {
385                faible  = im32[i] & 0x0000ffff; // 3412
386                fort    = im32[i] >> 16;
387                s32     = faible;
388                im32[i] = ( s32 << 16 ) | fort;
389             }
390             break;
391          default:
392             std::cout << "SWAP value (32 bits) not allowed : " << swap <<
393             std::endl;
394       }
395    }
396 }
397
398
399
400 /**
401  * \brief Deal with endianity i.e. re-arange bytes inside the integer
402  */
403 void gdcmPixelConvert::ConvertReorderEndianity( uint8_t* pixelZone,
404                                         size_t imageDataSize,
405                                         int numberBitsStored,
406                                         int numberBitsAllocated,
407                                         int swapCode,
408                                         bool signedPixel)
409 {
410    if ( numberBitsAllocated != 8 )
411    {
412       SwapZone( pixelZone, swapCode, imageDataSize, numberBitsAllocated );
413    }
414                                                                                 
415    // Special kludge in order to deal with xmedcon broken images:
416    if (  ( numberBitsAllocated == 16 )
417       && ( numberBitsStored < numberBitsAllocated )
418       && ( ! signedPixel ) )
419    {
420       int l = (int)(imageDataSize / (numberBitsAllocated/8));
421       uint16_t *deb = (uint16_t *)pixelZone;
422       for(int i = 0; i<l; i++)
423       {
424          if( *deb == 0xffff )
425          {
426            *deb = 0;
427          }
428          deb++;
429       }
430    }
431 }
432