]> Creatis software - gdcm.git/blob - src/gdcmPixelConvert.cxx
ENH: Fix various warnings
[gdcm.git] / src / gdcmPixelConvert.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmPixelConvert.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/10/10 03:03:10 $
7   Version:   $Revision: 1.5 $
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    (void)lutRGBA;
154    /// We assume Uncompressed contains the decompressed gray plane
155    /// and build the RGB image.
156    SetRGBSize( UncompressedSize );
157    AllocateRGB();
158
159 //aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
160 //AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
161 //COPY HERE THE CODE OF GetImageDataIntoVector
162       
163    /// \todo check that operator new []didn't fail, and sometimes return false
164    return true;
165 }
166
167 /**
168  * \brief     Try to deal with RLE 16 Bits. 
169  *            We assume the RLE has allready been parsed and loaded in
170  *            Uncompressed (through \ref ReadAndUncompressRLE8Bits ).
171  *            We here need to make 16 Bits Pixels from Low Byte and
172  *            High Byte 'Planes'...(for what it may mean)
173  * @return    Boolean
174  */
175 bool gdcmPixelConvert::UncompressRLE16BitsFromRLE8Bits(
176                        int XSize,
177                        int YSize,
178                        int NumberOfFrames,
179                        uint8_t* fixMemUncompressed )
180 {
181    size_t PixelNumber = XSize * YSize;
182    size_t fixMemUncompressedSize = XSize * YSize * NumberOfFrames;
183
184    // We assumed Uncompressed contains the decoded RLE pixels but as
185    // 8 bits per pixel. In order to convert those pixels to 16 bits
186    // per pixel we cannot work in place within Uncompressed and hence
187    // we copy Uncompressed in a safe place, say OldUncompressed.
188
189    uint8_t* OldUncompressed = new uint8_t[ fixMemUncompressedSize * 2 ];
190    memmove( OldUncompressed, fixMemUncompressed, fixMemUncompressedSize * 2);
191
192    uint8_t* x = fixMemUncompressed;
193    uint8_t* a = OldUncompressed;
194    uint8_t* b = a + PixelNumber;
195
196    for ( int i = 0; i < NumberOfFrames; i++ )
197    {
198       for ( unsigned int j = 0; j < PixelNumber; j++ )
199       {
200          *(x++) = *(a++);
201          *(x++) = *(b++);
202       }
203    }
204
205    delete[] OldUncompressed;
206       
207    /// \todo check that operator new []didn't fail, and sometimes return false
208    return true;
209 }
210
211 /**
212  * \brief Implementation of the RLE decoding algorithm for uncompressing
213  *        a RLE fragment. [refer to PS 3.5-2003, section G.3.2 p 86]
214  */
215 bool gdcmPixelConvert::ReadAndUncompressRLEFragment( uint8_t* decodedZone,
216                                                long fragmentSize,
217                                                long uncompressedSegmentSize,
218                                                FILE* fp )
219 {
220    int8_t count;
221    long numberOfOutputBytes = 0;
222    long numberOfReadBytes = 0;
223                                                                                 
224    while( numberOfOutputBytes < uncompressedSegmentSize )
225    {
226       fread( &count, 1, 1, fp );
227       numberOfReadBytes += 1;
228       if ( count >= 0 )
229       // Note: count <= 127 comparison is always true due to limited range
230       //       of data type int8_t [since the maximum of an exact width
231       //       signed integer of width N is 2^(N-1) - 1, which for int8_t
232       //       is 127].
233       {
234          fread( decodedZone, count + 1, 1, fp);
235          numberOfReadBytes += count + 1;
236          decodedZone         += count + 1;
237          numberOfOutputBytes += count + 1;
238       }
239       else
240       {
241          if ( ( count <= -1 ) && ( count >= -127 ) )
242          {
243             int8_t newByte;
244             fread( &newByte, 1, 1, fp);
245             numberOfReadBytes += 1;
246             for( int i = 0; i < -count + 1; i++ )
247             {
248                decodedZone[i] = newByte;
249             }
250             decodedZone         += -count + 1;
251             numberOfOutputBytes += -count + 1;
252          }
253       }
254       // if count = 128 output nothing
255                                                                                 
256       if ( numberOfReadBytes > fragmentSize )
257       {
258          dbg.Verbose(0, "gdcmFile::gdcm_read_RLE_fragment: we read more "
259                         "bytes than the segment size.");
260          return false;
261       }
262    }
263    return true;
264 }
265
266 /**
267  * \brief     Reads from disk the Pixel Data of 'Run Length Encoded'
268  *            Dicom encapsulated file and uncompress it.
269  * @param     fp already open File Pointer
270  * @param     image_buffer destination Address (in caller's memory space)
271  *            at which the pixel data should be copied
272  * @return    Boolean
273  */
274 bool gdcmPixelConvert::gdcm_read_RLE_file( void* image_buffer,
275                                    int XSize,
276                                    int YSize,
277                                    int ZSize,
278                                    int BitsAllocated,
279                                    gdcmRLEFramesInfo* RLEInfo,
280                                    FILE* fp )
281 {
282    uint8_t* im = (uint8_t*)image_buffer;
283    long uncompressedSegmentSize = XSize * YSize;
284                                                                                 
285                                                                                 
286    // Loop on the frame[s]
287    for( gdcmRLEFramesInfo::RLEFrameList::iterator
288         it  = RLEInfo->Frames.begin();
289         it != RLEInfo->Frames.end();
290       ++it )
291    {
292       // Loop on the fragments
293       for( int k = 1; k <= (*it)->NumberFragments; k++ )
294       {
295          fseek( fp, (*it)->Offset[k] ,SEEK_SET);
296          (void)gdcmPixelConvert::ReadAndUncompressRLEFragment(
297                                  (uint8_t*) im, (*it)->Length[k],
298                                  uncompressedSegmentSize, fp );
299          im += uncompressedSegmentSize;
300       }
301    }
302                                                                                 
303    if ( BitsAllocated == 16 )
304    {
305       // Try to deal with RLE 16 Bits
306       (void)gdcmPixelConvert::UncompressRLE16BitsFromRLE8Bits(
307                                              XSize,
308                                              YSize,
309                                              ZSize,
310                                              (uint8_t*) image_buffer);
311    }
312                                                                                 
313    return true;
314 }
315
316 /**
317  * \brief   Swap the bytes, according to swap code.
318  * \warning not end user intended
319  * @param   im area to deal with
320  * @param   swap swap code
321  * @param   lgr Area Length
322  * @param   nb Pixels Bit number
323  */
324 void gdcmPixelConvert::SwapZone(void* im, int swap, int lgr, int nb)
325 {
326    int i;
327                                                                                 
328    if( nb == 16 )
329    {
330       uint16_t* im16 = (uint16_t*)im;
331       switch( swap )
332       {
333          case 0:
334          case 12:
335          case 1234:
336             break;
337          case 21:
338          case 3412:
339          case 2143:
340          case 4321:
341             for(i=0; i < lgr/2; i++)
342             {
343                im16[i]= (im16[i] >> 8) | (im16[i] << 8 );
344             }
345             break;
346          default:
347             std::cout << "SWAP value (16 bits) not allowed :i" << swap <<
348             std::endl;
349       }
350    }
351    else if( nb == 32 )
352    {
353       uint32_t s32;
354       uint16_t fort, faible;
355       uint32_t* im32 = (uint32_t*)im;
356       switch ( swap )
357       {
358          case 0:
359          case 1234:
360             break;
361          case 4321:
362             for(i = 0; i < lgr/4; i++)
363             {
364                faible  = im32[i] & 0x0000ffff;  // 4321
365                fort    = im32[i] >> 16;
366                fort    = ( fort >> 8   ) | ( fort << 8 );
367                faible  = ( faible >> 8 ) | ( faible << 8);
368                s32     = faible;
369                im32[i] = ( s32 << 16 ) | fort;
370             }
371             break;
372          case 2143:
373             for(i = 0; i < lgr/4; i++)
374             {
375                faible  = im32[i] & 0x0000ffff;   // 2143
376                fort    = im32[i] >> 16;
377                fort    = ( fort >> 8 ) | ( fort << 8 );
378                faible  = ( faible >> 8) | ( faible << 8);
379                s32     = fort;
380                im32[i] = ( s32 << 16 ) | faible;
381             }
382             break;
383          case 3412:
384             for(i = 0; i < lgr/4; i++)
385             {
386                faible  = im32[i] & 0x0000ffff; // 3412
387                fort    = im32[i] >> 16;
388                s32     = faible;
389                im32[i] = ( s32 << 16 ) | fort;
390             }
391             break;
392          default:
393             std::cout << "SWAP value (32 bits) not allowed : " << swap <<
394             std::endl;
395       }
396    }
397 }
398
399
400
401 /**
402  * \brief Deal with endianity i.e. re-arange bytes inside the integer
403  */
404 void gdcmPixelConvert::ConvertReorderEndianity( uint8_t* pixelZone,
405                                         size_t imageDataSize,
406                                         int numberBitsStored,
407                                         int numberBitsAllocated,
408                                         int swapCode,
409                                         bool signedPixel)
410 {
411    if ( numberBitsAllocated != 8 )
412    {
413       SwapZone( pixelZone, swapCode, imageDataSize, numberBitsAllocated );
414    }
415                                                                                 
416    // Special kludge in order to deal with xmedcon broken images:
417    if (  ( numberBitsAllocated == 16 )
418       && ( numberBitsStored < numberBitsAllocated )
419       && ( ! signedPixel ) )
420    {
421       int l = (int)(imageDataSize / (numberBitsAllocated/8));
422       uint16_t *deb = (uint16_t *)pixelZone;
423       for(int i = 0; i<l; i++)
424       {
425          if( *deb == 0xffff )
426          {
427            *deb = 0;
428          }
429          deb++;
430       }
431    }
432 }
433