]> Creatis software - gdcm.git/blob - src/gdcmPixelConvert.cxx
* CLEANUP_ROUND (10) for gdcmPixelConvert (Xanax is my friend stage)
[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 16:44:00 $
7   Version:   $Revision: 1.6 $
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 //
23 // grep PIXELCONVERT everywhere and clean up !
24
25
26 #define str2num(str, typeNum) *((typeNum *)(str))
27
28 #include "gdcmDebug.h"
29 #include "gdcmPixelConvert.h"
30
31 // External JPEG decompression
32
33 // for JPEGLosslessDecodeImage
34 #include "jpeg/ljpg/jpegless.h"
35
36 // For JPEG 2000, body in file gdcmJpeg2000.cxx
37 bool gdcm_read_JPEG2000_file (FILE* fp, void* image_buffer);
38
39 // For JPEG 8 Bits, body in file gdcmJpeg8.cxx
40 bool gdcm_read_JPEG_file     (FILE* fp, void* image_buffer);
41
42 // For JPEG 12 Bits, body in file gdcmJpeg12.cxx
43 bool gdcm_read_JPEG_file12   (FILE* fp, void* image_buffer);
44
45
46
47 //-----------------------------------------------------------------------------
48 // Constructor / Destructor
49 gdcmPixelConvert::gdcmPixelConvert() 
50 {
51    RGB = 0;
52    RGBSize = 0;
53    Uncompressed = 0;
54    UncompressedSize = 0;
55 }
56
57 void gdcmPixelConvert::Squeeze() 
58 {
59    if ( RGB ) {
60       delete [] RGB;
61    } 
62    if ( Uncompressed ) {
63       delete [] Uncompressed;
64    }
65 }
66
67 gdcmPixelConvert::~gdcmPixelConvert() 
68 {
69    Squeeze();
70 }
71
72 void gdcmPixelConvert::AllocateRGB()
73 {
74   if ( RGB ) {
75      delete [] RGB;
76   }
77   RGB = new uint8_t[RGBSize];
78 }
79
80 void gdcmPixelConvert::AllocateUncompressed()
81 {
82   if ( Uncompressed ) {
83      delete [] Uncompressed;
84   }
85   Uncompressed = new uint8_t[ UncompressedSize ];
86 }
87
88 /**
89  * \brief Read from file a 12 bits per pixel image and uncompress it
90  *        into a 16 bits per pixel image.
91  */
92 void gdcmPixelConvert::ConvertDecompress12BitsTo16Bits(
93                   uint8_t* pixelZone,
94                   int sizeX,
95                   int sizeY,
96                   FILE* filePtr)
97                throw ( gdcmFormatError )
98 {
99    int nbPixels = sizeX * sizeY;
100    uint16_t* destination = (uint16_t*)pixelZone;
101                                                                                 
102    for( int p = 0; p < nbPixels; p += 2 )
103    {
104       uint8_t b0, b1, b2;
105       size_t ItemRead;
106                                                                                 
107       ItemRead = fread( &b0, 1, 1, filePtr);
108       if ( ItemRead != 1 )
109       {
110          throw gdcmFormatError( "gdcmFile::ConvertDecompress12BitsTo16Bits()",
111                                 "Unfound first block" );
112       }
113                                                                                 
114       ItemRead = fread( &b1, 1, 1, filePtr);
115       if ( ItemRead != 1 )
116       {
117          throw gdcmFormatError( "gdcmFile::ConvertDecompress12BitsTo16Bits()",
118                                 "Unfound second block" );
119       }
120                                                                                 
121       ItemRead = fread( &b2, 1, 1, filePtr);
122       if ( ItemRead != 1 )
123       {
124          throw gdcmFormatError( "gdcmFile::ConvertDecompress12BitsTo16Bits()",
125                                 "Unfound second block" );
126       }
127                                                                                 
128       // Two steps are necessary to please VC++
129       //
130       // 2 pixels 12bit =     [0xABCDEF]
131       // 2 pixels 16bit = [0x0ABD] + [0x0FCE]
132       //                     A                     B                 D
133       *destination++ =  ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f);
134       //                     F                     C                 E
135       *destination++ =  ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4);
136                                                                                 
137       /// \todo JPR Troubles expected on Big-Endian processors ?
138    }
139 }
140
141 /**
142  * \brief     Try to deal with RLE 16 Bits. 
143  *            We assume the RLE has allready been parsed and loaded in
144  *            Uncompressed (through \ref ReadAndDecompressJPEGFile ).
145  *            We here need to make 16 Bits Pixels from Low Byte and
146  *            High Byte 'Planes'...(for what it may mean)
147  * @return    Boolean
148  */
149 bool gdcmPixelConvert::UncompressRLE16BitsFromRLE8Bits(
150                        int XSize,
151                        int YSize,
152                        int NumberOfFrames,
153                        uint8_t* fixMemUncompressed )
154 {
155    size_t PixelNumber = XSize * YSize;
156    size_t fixMemUncompressedSize = XSize * YSize * NumberOfFrames;
157
158    // We assumed Uncompressed contains the decoded RLE pixels but as
159    // 8 bits per pixel. In order to convert those pixels to 16 bits
160    // per pixel we cannot work in place within Uncompressed and hence
161    // we copy Uncompressed in a safe place, say OldUncompressed.
162
163    uint8_t* OldUncompressed = new uint8_t[ fixMemUncompressedSize * 2 ];
164    memmove( OldUncompressed, fixMemUncompressed, fixMemUncompressedSize * 2);
165
166    uint8_t* x = fixMemUncompressed;
167    uint8_t* a = OldUncompressed;
168    uint8_t* b = a + PixelNumber;
169
170    for ( int i = 0; i < NumberOfFrames; i++ )
171    {
172       for ( unsigned int j = 0; j < PixelNumber; j++ )
173       {
174          *(x++) = *(a++);
175          *(x++) = *(b++);
176       }
177    }
178
179    delete[] OldUncompressed;
180       
181    /// \todo check that operator new []didn't fail, and sometimes return false
182    return true;
183 }
184
185 /**
186  * \brief Implementation of the RLE decoding algorithm for uncompressing
187  *        a RLE fragment. [refer to PS 3.5-2003, section G.3.2 p 86]
188  */
189 bool gdcmPixelConvert::ReadAndUncompressRLEFragment( uint8_t* decodedZone,
190                                                long fragmentSize,
191                                                long uncompressedSegmentSize,
192                                                FILE* fp )
193 {
194    int8_t count;
195    long numberOfOutputBytes = 0;
196    long numberOfReadBytes = 0;
197                                                                                 
198    while( numberOfOutputBytes < uncompressedSegmentSize )
199    {
200       fread( &count, 1, 1, fp );
201       numberOfReadBytes += 1;
202       if ( count >= 0 )
203       // Note: count <= 127 comparison is always true due to limited range
204       //       of data type int8_t [since the maximum of an exact width
205       //       signed integer of width N is 2^(N-1) - 1, which for int8_t
206       //       is 127].
207       {
208          fread( decodedZone, count + 1, 1, fp);
209          numberOfReadBytes += count + 1;
210          decodedZone         += count + 1;
211          numberOfOutputBytes += count + 1;
212       }
213       else
214       {
215          if ( ( count <= -1 ) && ( count >= -127 ) )
216          {
217             int8_t newByte;
218             fread( &newByte, 1, 1, fp);
219             numberOfReadBytes += 1;
220             for( int i = 0; i < -count + 1; i++ )
221             {
222                decodedZone[i] = newByte;
223             }
224             decodedZone         += -count + 1;
225             numberOfOutputBytes += -count + 1;
226          }
227       }
228       // if count = 128 output nothing
229                                                                                 
230       if ( numberOfReadBytes > fragmentSize )
231       {
232          dbg.Verbose(0, "gdcmFile::gdcm_read_RLE_fragment: we read more "
233                         "bytes than the segment size.");
234          return false;
235       }
236    }
237    return true;
238 }
239
240 /**
241  * \brief     Reads from disk the Pixel Data of 'Run Length Encoded'
242  *            Dicom encapsulated file and uncompress it.
243  * @param     fp already open File Pointer
244  * @param     image_buffer destination Address (in caller's memory space)
245  *            at which the pixel data should be copied
246  * @return    Boolean
247  */
248 bool gdcmPixelConvert::ReadAndDecompressRLEFile( void* image_buffer,
249                                    int XSize,
250                                    int YSize,
251                                    int ZSize,
252                                    int BitsAllocated,
253                                    gdcmRLEFramesInfo* RLEInfo,
254                                    FILE* fp )
255 {
256    uint8_t* im = (uint8_t*)image_buffer;
257    long uncompressedSegmentSize = XSize * YSize;
258                                                                                 
259                                                                                 
260    // Loop on the frame[s]
261    for( gdcmRLEFramesInfo::RLEFrameList::iterator
262         it  = RLEInfo->Frames.begin();
263         it != RLEInfo->Frames.end();
264       ++it )
265    {
266       // Loop on the fragments
267       for( unsigned int k = 1; k <= (*it)->NumberFragments; k++ )
268       {
269          fseek( fp, (*it)->Offset[k] ,SEEK_SET );
270          (void)gdcmPixelConvert::ReadAndUncompressRLEFragment(
271                                  (uint8_t*) im, (*it)->Length[k],
272                                  uncompressedSegmentSize, fp );
273          im += uncompressedSegmentSize;
274       }
275    }
276                                                                                 
277    if ( BitsAllocated == 16 )
278    {
279       // Try to deal with RLE 16 Bits
280       (void)gdcmPixelConvert::UncompressRLE16BitsFromRLE8Bits(
281                                              XSize,
282                                              YSize,
283                                              ZSize,
284                                              (uint8_t*) image_buffer);
285    }
286                                                                                 
287    return true;
288 }
289
290 /**
291  * \brief   Swap the bytes, according to swap code.
292  * \warning not end user intended
293  * @param   im area to deal with
294  * @param   swap swap code
295  * @param   lgr Area Length
296  * @param   nb Pixels Bit number
297  */
298 void gdcmPixelConvert::SwapZone(void* im, int swap, int lgr, int nb)
299 {
300    int i;
301                                                                                 
302    if( nb == 16 )
303    {
304       uint16_t* im16 = (uint16_t*)im;
305       switch( swap )
306       {
307          case 0:
308          case 12:
309          case 1234:
310             break;
311          case 21:
312          case 3412:
313          case 2143:
314          case 4321:
315             for(i=0; i < lgr/2; i++)
316             {
317                im16[i]= (im16[i] >> 8) | (im16[i] << 8 );
318             }
319             break;
320          default:
321             std::cout << "SWAP value (16 bits) not allowed :i" << swap <<
322             std::endl;
323       }
324    }
325    else if( nb == 32 )
326    {
327       uint32_t s32;
328       uint16_t fort, faible;
329       uint32_t* im32 = (uint32_t*)im;
330       switch ( swap )
331       {
332          case 0:
333          case 1234:
334             break;
335          case 4321:
336             for(i = 0; i < lgr/4; i++)
337             {
338                faible  = im32[i] & 0x0000ffff;  // 4321
339                fort    = im32[i] >> 16;
340                fort    = ( fort >> 8   ) | ( fort << 8 );
341                faible  = ( faible >> 8 ) | ( faible << 8);
342                s32     = faible;
343                im32[i] = ( s32 << 16 ) | fort;
344             }
345             break;
346          case 2143:
347             for(i = 0; i < lgr/4; i++)
348             {
349                faible  = im32[i] & 0x0000ffff;   // 2143
350                fort    = im32[i] >> 16;
351                fort    = ( fort >> 8 ) | ( fort << 8 );
352                faible  = ( faible >> 8) | ( faible << 8);
353                s32     = fort;
354                im32[i] = ( s32 << 16 ) | faible;
355             }
356             break;
357          case 3412:
358             for(i = 0; i < lgr/4; i++)
359             {
360                faible  = im32[i] & 0x0000ffff; // 3412
361                fort    = im32[i] >> 16;
362                s32     = faible;
363                im32[i] = ( s32 << 16 ) | fort;
364             }
365             break;
366          default:
367             std::cout << "SWAP value (32 bits) not allowed : " << swap <<
368             std::endl;
369       }
370    }
371 }
372
373
374
375 /**
376  * \brief Deal with endianity i.e. re-arange bytes inside the integer
377  */
378 void gdcmPixelConvert::ConvertReorderEndianity( uint8_t* pixelZone,
379                                         size_t imageDataSize,
380                                         int numberBitsStored,
381                                         int numberBitsAllocated,
382                                         int swapCode,
383                                         bool signedPixel)
384 {
385    if ( numberBitsAllocated != 8 )
386    {
387       SwapZone( pixelZone, swapCode, imageDataSize, numberBitsAllocated );
388    }
389                                                                                 
390    // Special kludge in order to deal with xmedcon broken images:
391    if (  ( numberBitsAllocated == 16 )
392       && ( numberBitsStored < numberBitsAllocated )
393       && ( ! signedPixel ) )
394    {
395       int l = (int)(imageDataSize / (numberBitsAllocated/8));
396       uint16_t *deb = (uint16_t *)pixelZone;
397       for(int i = 0; i<l; i++)
398       {
399          if( *deb == 0xffff )
400          {
401            *deb = 0;
402          }
403          deb++;
404       }
405    }
406 }
407
408 /**
409  * \brief     Reads from disk the Pixel Data of JPEG Dicom encapsulated
410  &            file and uncompress it.
411  * @param     fp already open File Pointer
412  * @param     destination Where decompressed fragments should end up
413  * @return    Boolean
414  */
415 bool gdcmPixelConvert::ReadAndDecompressJPEGFile( uint8_t* destination,
416                                    int XSize,
417                                    int YSize,
418                                    int BitsAllocated,
419                                    int BitsStored,
420                                    int SamplesPerPixel,
421                                    int PixelSize,
422                                    bool isJPEG2000,
423                                    bool isJPEGLossless,
424                                    gdcmJPEGFragmentsInfo* JPEGInfo,
425                                    FILE* fp )
426 {
427    // Loop on the fragment[s]
428    for( gdcmJPEGFragmentsInfo::JPEGFragmentsList::iterator
429         it  = JPEGInfo->Fragments.begin();
430         it != JPEGInfo->Fragments.end();
431       ++it )
432    {
433       fseek( fp, (*it)->Offset, SEEK_SET );
434                                                                                 
435       if ( isJPEG2000 )
436       {
437          if ( ! gdcm_read_JPEG2000_file( fp, destination ) )
438          {
439             return false;
440          }
441       }
442       else if ( isJPEGLossless )
443       {
444          // JPEG LossLess : call to xmedcom Lossless JPEG
445          JPEGLosslessDecodeImage( fp,
446                                   (uint16_t*)destination,
447                                   PixelSize * 8 * SamplesPerPixel,
448                                   (*it)->Length );
449       }
450       else if ( BitsStored == 8)
451       {
452          // JPEG Lossy : call to IJG 6b
453          if ( ! gdcm_read_JPEG_file ( fp, destination ) )
454          {
455             return false;
456          }
457       }
458       else if ( BitsStored == 12)
459       {
460          // Reading Fragment pixels
461          if ( ! gdcm_read_JPEG_file12 ( fp, destination ) )
462          {
463             return false;
464          }
465       }
466       else
467       {
468          // other JPEG lossy not supported
469          dbg.Error(" gdcmFile::ReadPixelData : unknown jpeg lossy "
470                    " compression ");
471          return false;
472       }
473                                                                                 
474       // Advance to next free location in destination 
475       // for next fragment decompression (if any)
476       int length = XSize * YSize * SamplesPerPixel;
477       int numberBytes = BitsAllocated / 8;
478                                                                                 
479       destination = (uint8_t*)destination + length * numberBytes;
480                                                                                 
481    }
482    return true;
483 }
484
485 /**
486  * \brief  Re-arrange the bits within the bytes.
487  * @param  fp already open File Pointer
488  * @param  destination Where decompressed fragments should end up
489  * @return Boolean
490  */
491 bool gdcmPixelConvert::ConvertReArrangeBits(
492                           uint8_t* pixelZone,
493                           size_t imageDataSize,
494                           int numberBitsStored,
495                           int numberBitsAllocated,
496                           int highBitPosition )
497      throw ( gdcmFormatError )
498 {
499    if ( numberBitsStored != numberBitsAllocated )
500    {
501       int l = (int)(imageDataSize / (numberBitsAllocated/8));
502       if ( numberBitsAllocated == 16 )
503       {
504          uint16_t mask = 0xffff;
505          mask = mask >> ( numberBitsAllocated - numberBitsStored );
506          uint16_t* deb = (uint16_t*)pixelZone;
507          for(int i = 0; i<l; i++)
508          {
509             *deb = (*deb >> (numberBitsStored - highBitPosition - 1)) & mask;
510             deb++;
511          }
512       }
513       else if ( numberBitsAllocated == 32 )
514       {
515          uint32_t mask = 0xffffffff;
516          mask = mask >> ( numberBitsAllocated - numberBitsStored );
517          uint32_t* deb = (uint32_t*)pixelZone;
518          for(int i = 0; i<l; i++)
519          {
520             *deb = (*deb >> (numberBitsStored - highBitPosition - 1)) & mask;
521             deb++;
522          }
523       }
524       else
525       {
526          dbg.Verbose(0, "gdcmPixelConvert::ConvertReArrangeBits: weird image");
527          throw gdcmFormatError( "gdcmFile::ConvertReArrangeBits()",
528                                 "weird image !?" );
529       }
530    }
531 }
532