Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

gdcmPixelReadConvert.cxx

Go to the documentation of this file.
00001 /*=========================================================================
00002  
00003   Program:   gdcm
00004   Module:    $RCSfile: gdcmPixelReadConvert.cxx,v $
00005   Language:  C++
00006   Date:      $Date: 2005/11/30 11:44:38 $
00007   Version:   $Revision: 1.107 $
00008                                                                                 
00009   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
00010   l'Image). All rights reserved. See Doc/License.txt or
00011   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
00012                                                                                 
00013      This software is distributed WITHOUT ANY WARRANTY; without even
00014      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00015      PURPOSE.  See the above copyright notices for more information.
00016                                                                                 
00017 =========================================================================*/
00018 
00019 #include "gdcmPixelReadConvert.h"
00020 #include "gdcmDebug.h"
00021 #include "gdcmFile.h"
00022 #include "gdcmGlobal.h"
00023 #include "gdcmTS.h"
00024 #include "gdcmDocEntry.h"
00025 #include "gdcmRLEFramesInfo.h"
00026 #include "gdcmJPEGFragmentsInfo.h"
00027 
00028 #include <fstream>
00029 #include <stdio.h> //for sscanf
00030 
00031 namespace gdcm
00032 {
00033 
00034 //bool ReadMPEGFile (std::ifstream *fp, char *inputdata, size_t lenght); 
00035 bool gdcm_read_JPEG2000_file (void* raw, 
00036                               char *inputdata, size_t inputlength);
00037 //-----------------------------------------------------------------------------
00038 #define str2num(str, typeNum) *((typeNum *)(str))
00039 
00040 //-----------------------------------------------------------------------------
00041 // Constructor / Destructor
00043 PixelReadConvert::PixelReadConvert() 
00044 {
00045    RGB          = 0;
00046    RGBSize      = 0;
00047    Raw          = 0;
00048    RawSize      = 0;
00049    LutRGBA      = 0;
00050    LutRedData   = 0;
00051    LutGreenData = 0;
00052    LutBlueData  = 0;
00053    RLEInfo      = 0;
00054    JPEGInfo     = 0;
00055    UserFunction = 0;
00056    FileInternal = 0;
00057 }
00058 
00060 PixelReadConvert::~PixelReadConvert() 
00061 {
00062    Squeeze();
00063 }
00064 
00065 //-----------------------------------------------------------------------------
00066 // Public
00071 bool PixelReadConvert::IsRawRGB()
00072 {
00073    if (   IsMonochrome
00074        || PlanarConfiguration == 2
00075        || IsPaletteColor )
00076    {
00077       return false;
00078    }
00079    return true;
00080 }
00085 void PixelReadConvert::GrabInformationsFromFile( File *file, 
00086                                                  FileHelper *fileHelper )
00087 {
00088    // Number of Bits Allocated for storing a Pixel is defaulted to 16
00089    // when absent from the file.
00090    BitsAllocated = file->GetBitsAllocated();
00091    if ( BitsAllocated == 0 )
00092    {
00093       BitsAllocated = 16;
00094    }
00095 
00096    // Number of "Bits Stored", defaulted to number of "Bits Allocated"
00097    // when absent from the file.
00098    BitsStored = file->GetBitsStored();
00099    if ( BitsStored == 0 )
00100    {
00101       BitsStored = BitsAllocated;
00102    }
00103 
00104    // High Bit Position, defaulted to "Bits Allocated" - 1
00105    HighBitPosition = file->GetHighBitPosition();
00106    if ( HighBitPosition == 0 )
00107    {
00108       HighBitPosition = BitsAllocated - 1;
00109    }
00110 
00111    XSize           = file->GetXSize();
00112    YSize           = file->GetYSize();
00113    ZSize           = file->GetZSize();
00114    SamplesPerPixel = file->GetSamplesPerPixel();
00115    //PixelSize       = file->GetPixelSize();  Useless
00116    PixelSign       = file->IsSignedPixelData();
00117    SwapCode        = file->GetSwapCode();
00118  
00119    IsPrivateGETransferSyntax = IsMPEG
00120              = IsJPEG2000 = IsJPEGLS = IsJPEGLossy  
00121              = IsJPEGLossless = IsRLELossless 
00122              = false;
00123      
00124    if (! file->IsDicomV3() )  // Should be ACR-NEMA file
00125    {
00126       IsRaw = true;
00127    }
00128    else
00129    {
00130       std::string ts = file->GetTransferSyntax();
00131 
00132       IsRaw = false;
00133       while (true) // short to write than if elseif elseif elseif ...
00134       {
00135          // mind the order : check the most usual first.
00136          if( IsRaw = Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRLittleEndian)         break;
00137          if( IsRaw = Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndian )        break;
00138          if( IsRaw = Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian)            break;
00139          if( IsRaw = Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRBigEndianPrivateGE)   break;
00140          if( IsRaw = Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::DeflatedExplicitVRLittleEndian) break;
00141          break;
00142       }
00143       // cache whether this is a strange GE transfer syntax (which uses
00144       // a little endian transfer syntax for the header and a big endian
00145       // transfer syntax for the pixel data). 
00146       IsPrivateGETransferSyntax = 
00147                 ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRBigEndianPrivateGE );
00148 
00149       IsMPEG =  IsJPEG2000 =  IsJPEGLS =  IsJPEGLossy =  IsJPEGLossless = IsRLELossless = false;  
00150       if (!IsRaw)
00151       {     
00152          while(true)
00153          {
00154             // mind the order : check the most usual first.
00155             if( IsJPEGLossy     = Global::GetTS()->IsJPEGLossy(ts) )    break;
00156             if( IsJPEGLossless  = Global::GetTS()->IsJPEGLossless(ts) ) break;
00157             if( IsRLELossless   = Global::GetTS()->IsRLELossless(ts) )  break;
00158             if( IsJPEG2000      = Global::GetTS()->IsJPEG2000(ts) )     break;
00159             if( IsMPEG          = Global::GetTS()->IsMPEG(ts) )         break;
00160             if( IsJPEGLS        = Global::GetTS()->IsJPEGLS(ts) )       break;
00161             gdcmWarningMacro("Unexpected Transfer Syntax :[" << ts << "]");
00162             break;
00163          } 
00164       }
00165    }
00166 
00167    PixelOffset     = file->GetPixelOffset();
00168    PixelDataLength = file->GetPixelAreaLength();
00169    RLEInfo         = file->GetRLEInfo();
00170    JPEGInfo        = file->GetJPEGInfo();
00171 
00172    IsMonochrome    = file->IsMonochrome();
00173    IsMonochrome1   = file->IsMonochrome1();
00174    IsPaletteColor  = file->IsPaletteColor();
00175    IsYBRFull       = file->IsYBRFull();
00176 
00177    PlanarConfiguration = file->GetPlanarConfiguration();
00178 
00180    // LUT section:
00181    HasLUT = file->HasLUT();
00182    if ( HasLUT )
00183    {
00184       // Just in case some access to a File element requires disk access.
00185       LutRedDescriptor   = file->GetEntryString( 0x0028, 0x1101 );
00186       LutGreenDescriptor = file->GetEntryString( 0x0028, 0x1102 );
00187       LutBlueDescriptor  = file->GetEntryString( 0x0028, 0x1103 );
00188    
00189       // FIXME : The following comment is probabely meaningless, since LUT are *always*
00190       // loaded at parsing time, whatever their length is.
00191          
00192       // Depending on the value of Document::MAX_SIZE_LOAD_ELEMENT_VALUE
00193       // [ refer to invocation of Document::SetMaxSizeLoadEntry() in
00194       // Document::Document() ], the loading of the value (content) of a
00195       // [Bin|Val]Entry occurence migth have been hindered (read simply NOT
00196       // loaded). Hence, we first try to obtain the LUTs data from the file
00197       // and when this fails we read the LUTs data directly from disk.
00198       // \TODO Reading a [Bin|Val]Entry directly from disk is a kludge.
00199       //       We should NOT bypass the [Bin|Val]Entry class. Instead
00200       //       an access to an UNLOADED content of a [Bin|Val]Entry occurence
00201       //       (e.g. DataEntry::GetBinArea()) should force disk access from
00202       //       within the [Bin|Val]Entry class itself. The only problem
00203       //       is that the [Bin|Val]Entry is unaware of the FILE* is was
00204       //       parsed from. Fix that. FIXME.
00205    
00206       // //// Red round
00207       file->LoadEntryBinArea(0x0028, 0x1201);
00208       LutRedData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1201 );
00209       if ( ! LutRedData )
00210       {
00211          gdcmWarningMacro("Unable to read Red Palette Color Lookup Table data");
00212       }
00213 
00214       // //// Green round:
00215       file->LoadEntryBinArea(0x0028, 0x1202);
00216       LutGreenData = (uint8_t*)file->GetEntryBinArea(0x0028, 0x1202 );
00217       if ( ! LutGreenData)
00218       {
00219          gdcmWarningMacro("Unable to read Green Palette Color Lookup Table data");
00220       }
00221 
00222       // //// Blue round:
00223       file->LoadEntryBinArea(0x0028, 0x1203);
00224       LutBlueData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1203 );
00225       if ( ! LutBlueData )
00226       {
00227          gdcmWarningMacro("Unable to read Blue Palette Color Lookup Table data");
00228       }
00229    }
00230    FileInternal = file;   
00231    FH = fileHelper;
00232    ComputeRawAndRGBSizes();
00233 }
00234 
00236 bool PixelReadConvert::ReadAndDecompressPixelData( std::ifstream *fp )
00237 {
00238    // ComputeRawAndRGBSizes is already made by 
00239    // ::GrabInformationsFromfile. So, the structure sizes are
00240    // correct
00241    Squeeze();
00242 
00245    if ( !fp )
00246    {
00247       gdcmWarningMacro( "Unavailable file pointer." );
00248       return false;
00249    }
00250 
00251    fp->seekg( PixelOffset, std::ios::beg );
00252    if ( fp->fail() || fp->eof() )
00253    {
00254       gdcmWarningMacro( "Unable to find PixelOffset in file." );
00255       return false;
00256    }
00257 
00258    AllocateRaw();
00259 
00261    
00262    CallStartMethod(); // for progress bar
00263    unsigned int count = 0;
00264    unsigned int frameSize;
00265    unsigned int bitsAllocated = BitsAllocated;
00266    if(bitsAllocated == 12)
00267       bitsAllocated = 16;
00268    frameSize = XSize*YSize*SamplesPerPixel*bitsAllocated/8;
00269    
00271    
00272    if ( BitsAllocated == 12 ) // We suppose 'BitsAllocated' = 12 only exist for uncompressed files
00273    {
00274       ReadAndDecompress12BitsTo16Bits( fp);
00275    }
00276    else if ( IsRaw )
00277    {
00278       // This problem can be found when some obvious informations are found
00279       // after the field containing the image data. In this case, these
00280       // bad data are added to the size of the image (in the PixelDataLength
00281       // variable). But RawSize is the right size of the image !
00282       if ( PixelDataLength != RawSize )
00283       {
00284          gdcmWarningMacro( "Mismatch between PixelReadConvert : "
00285                               << PixelDataLength << " and RawSize : " << RawSize );
00286       }
00287       
00288       //todo : is it the right patch?
00289       char *raw = (char*)Raw;
00290       uint32_t remainingLength;
00291       unsigned int i; 
00292       unsigned int lengthToRead;
00293        
00294       if ( PixelDataLength > RawSize )
00295         lengthToRead =  RawSize;
00296       else
00297         lengthToRead = PixelDataLength;
00298  
00299       // perform a frame by frame reading
00300       remainingLength = lengthToRead;
00301       unsigned int nbFrames = lengthToRead / frameSize;
00302       for (i=0;i<nbFrames; i++)
00303       {
00304          Progress = (float)(count+1)/(float)nbFrames;
00305          fp->read( raw, frameSize);
00306          raw +=  frameSize;
00307          remainingLength -=  frameSize;
00308          count++;
00309       }
00310       if (remainingLength !=0 )
00311         fp->read( raw, remainingLength);
00312                  
00313       //if ( PixelDataLength > RawSize )
00314       //{
00315       //   fp->read( (char*)Raw, RawSize); // Read all the frames with a single fread    
00316       //}
00317       //else
00318       //{
00319       //   fp->read( (char*)Raw, PixelDataLength); // Read all the frames with a single fread
00320       //}
00321 
00322       if ( fp->fail() || fp->eof())
00323       {
00324          gdcmWarningMacro( "Reading of Raw pixel data failed." );
00325          return false;
00326       }
00327    } 
00328    else if ( IsRLELossless )
00329    {
00330       if ( ! RLEInfo->DecompressRLEFile
00331                                ( fp, Raw, XSize, YSize, ZSize, BitsAllocated ) )
00332       {
00333          gdcmWarningMacro( "RLE decompressor failed." );
00334          return false;
00335       }
00336    }
00337    else if ( IsMPEG )
00338    {
00339       //gdcmWarningMacro( "Sorry, MPEG not yet taken into account" );
00340       //return false;
00341       // fp has already been seek to start of mpeg
00342       //ReadMPEGFile(fp, (char*)Raw, PixelDataLength); 
00343       return true;
00344    }
00345    else
00346    {
00347       // Default case concerns JPEG family
00348       if ( ! ReadAndDecompressJPEGFile( fp ) )
00349       {
00350          gdcmWarningMacro( "JPEG decompressor ( ReadAndDecompressJPEGFile()"
00351                               << " method ) failed." );
00352          return false;
00353       }
00354    }
00355 
00358    ConvertReorderEndianity();
00359    ConvertReArrangeBits();
00360    ConvertFixGreyLevels();
00361    if (UserFunction) // user is allowed to Mirror, TopDown, Rotate,...the image
00362       UserFunction( Raw, FileInternal);
00363    ConvertHandleColor();
00364 
00365    return true;
00366 }
00367 
00369 void PixelReadConvert::Squeeze() 
00370 {
00371    if ( RGB )
00372       delete [] RGB;
00373    RGB = 0;
00374 
00375    if ( Raw )
00376       delete [] Raw;
00377    Raw = 0;
00378 
00379    if ( LutRGBA )
00380       delete [] LutRGBA;
00381    LutRGBA = 0;
00382 }
00383 
00387 bool PixelReadConvert::BuildRGBImage()
00388 {
00389    if ( RGB )
00390    {
00391       // The job is already done.
00392       return true;
00393    }
00394 
00395    if ( ! Raw )
00396    {
00397       // The job can't be done
00398       return false;
00399    }
00400 
00401    BuildLUTRGBA();
00402    if ( ! LutRGBA )
00403    {
00404       // The job can't be done
00405       return false;
00406    }
00407 
00408    gdcmDebugMacro( "--> BuildRGBImage" );
00409                                                                                 
00410    // Build RGB Pixels
00411    AllocateRGB();
00412    
00413    int j;
00414    if ( BitsAllocated <= 8 )
00415    {
00416       uint8_t *localRGB = RGB;
00417       for (size_t i = 0; i < RawSize; ++i )
00418       {
00419          j  = Raw[i] * 4;
00420          *localRGB++ = LutRGBA[j];
00421          *localRGB++ = LutRGBA[j+1];
00422          *localRGB++ = LutRGBA[j+2];
00423       }
00424     }
00425  
00426     else  // deal with 16 bits pixels and 16 bits Palette color
00427     {
00428       uint16_t *localRGB = (uint16_t *)RGB;
00429       for (size_t i = 0; i < RawSize/2; ++i )
00430       {
00431          j  = ((uint16_t *)Raw)[i] * 4;
00432          *localRGB++ = ((uint16_t *)LutRGBA)[j];
00433          *localRGB++ = ((uint16_t *)LutRGBA)[j+1];
00434          *localRGB++ = ((uint16_t *)LutRGBA)[j+2];
00435       } 
00436     }
00437  
00438    return true;
00439 }
00440 
00441 //-----------------------------------------------------------------------------
00442 // Protected
00443 
00444 //-----------------------------------------------------------------------------
00445 // Private
00450 void PixelReadConvert::ReadAndDecompress12BitsTo16Bits( std::ifstream *fp )
00451                throw ( FormatError )
00452 {
00453    int nbPixels = XSize * YSize;
00454    uint16_t *localDecompres = (uint16_t*)Raw;
00455 
00456    for( int p = 0; p < nbPixels; p += 2 )
00457    {
00458       uint8_t b0, b1, b2;
00459 
00460       fp->read( (char*)&b0, 1);
00461       if ( fp->fail() || fp->eof() )
00462       {
00463          throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
00464                                 "Unfound first block" );
00465       }
00466 
00467       fp->read( (char*)&b1, 1 );
00468       if ( fp->fail() || fp->eof())
00469       {
00470          throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
00471                                 "Unfound second block" );
00472       }
00473 
00474       fp->read( (char*)&b2, 1 );
00475       if ( fp->fail() || fp->eof())
00476       {
00477          throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
00478                                 "Unfound second block" );
00479       }
00480 
00481       // Two steps are necessary to please VC++
00482       //
00483       // 2 pixels 12bit =     [0xABCDEF]
00484       // 2 pixels 16bit = [0x0ABD] + [0x0FCE]
00485       //                        A                     B                 D
00486       *localDecompres++ =  ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f);
00487       //                        F                     C                 E
00488       *localDecompres++ =  ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4);
00489 
00491    }
00492 }
00493 
00500 bool PixelReadConvert::ReadAndDecompressJPEGFile( std::ifstream *fp )
00501 {
00502    if ( IsJPEG2000 )
00503    {
00504      // make sure this is the right JPEG compression
00505      assert( !IsJPEGLossless || !IsJPEGLossy || !IsJPEGLS );
00506      // FIXME this is really ugly but it seems I have to load the complete
00507      // jpeg2000 stream to use jasper:
00508      // I don't think we'll ever be able to deal with multiple fragments properly
00509 
00510       unsigned long inputlength = 0;
00511       JPEGFragment *jpegfrag = JPEGInfo->GetFirstFragment();
00512       while( jpegfrag )
00513       {
00514          inputlength += jpegfrag->GetLength();
00515          jpegfrag = JPEGInfo->GetNextFragment();
00516       }
00517       gdcmAssertMacro( inputlength != 0);
00518       uint8_t *inputdata = new uint8_t[inputlength];
00519       char *pinputdata = (char*)inputdata;
00520       jpegfrag = JPEGInfo->GetFirstFragment();
00521       while( jpegfrag )
00522       {
00523          fp->seekg( jpegfrag->GetOffset(), std::ios::beg);
00524          fp->read(pinputdata, jpegfrag->GetLength());
00525          pinputdata += jpegfrag->GetLength();
00526          jpegfrag = JPEGInfo->GetNextFragment();
00527       }
00528       // Warning the inputdata buffer is delete in the function
00529       if ( ! gdcm_read_JPEG2000_file( Raw, 
00530           (char*)inputdata, inputlength ) )
00531       {
00532          return true;
00533       }
00534       // wow what happen, must be an error
00535       gdcmWarningMacro( "gdcm_read_JPEG2000_file() failed "); 
00536       return false;
00537    }
00538    else if ( IsJPEGLS )
00539    {
00540      // make sure this is the right JPEG compression
00541      assert( !IsJPEGLossless || !IsJPEGLossy || !IsJPEG2000 );
00542    // WARNING : JPEG-LS is NOT the 'classical' Jpeg Lossless : 
00543    // [JPEG-LS is the basis for new lossless/near-lossless compression
00544    // standard for continuous-tone images intended for JPEG2000. The standard
00545    // is based on the LOCO-I algorithm (LOw COmplexity LOssless COmpression
00546    // for Images) developed at Hewlett-Packard Laboratories]
00547    //
00548    // see http://datacompression.info/JPEGLS.shtml
00549    //
00550 #if 0
00551    std::cerr << "count:" << JPEGInfo->GetFragmentCount() << std::endl;
00552       unsigned long inputlength = 0;
00553       JPEGFragment *jpegfrag = JPEGInfo->GetFirstFragment();
00554       while( jpegfrag )
00555       {
00556          inputlength += jpegfrag->GetLength();
00557          jpegfrag = JPEGInfo->GetNextFragment();
00558       }
00559       gdcmAssertMacro( inputlength != 0);
00560       uint8_t *inputdata = new uint8_t[inputlength];
00561       char *pinputdata = (char*)inputdata;
00562       jpegfrag = JPEGInfo->GetFirstFragment();
00563       while( jpegfrag )
00564       {
00565          fp->seekg( jpegfrag->GetOffset(), std::ios::beg);
00566          fp->read(pinputdata, jpegfrag->GetLength());
00567          pinputdata += jpegfrag->GetLength();
00568          jpegfrag = JPEGInfo->GetNextFragment();
00569       }  
00570       
00571   //fp->read((char*)Raw, PixelDataLength);
00572 
00573   std::ofstream out("/tmp/jpegls.jpg");
00574   out.write((char*)inputdata, inputlength);
00575   out.close();
00576   delete[] inputdata;
00577 #endif
00578 
00579       gdcmWarningMacro( "Sorry, JPEG-LS not yet taken into account" );
00580       fp->seekg( JPEGInfo->GetFirstFragment()->GetOffset(), std::ios::beg);
00581 //    if ( ! gdcm_read_JPEGLS_file( fp,Raw ) )
00582          return false;
00583    }
00584    else
00585    {
00586      // make sure this is the right JPEG compression
00587      assert( !IsJPEGLS || !IsJPEG2000 );
00588      // Precompute the offset localRaw will be shifted with
00589      int length = XSize * YSize * SamplesPerPixel;
00590      int numberBytes = BitsAllocated / 8;
00591 
00592      JPEGInfo->DecompressFromFile(fp, Raw, BitsStored, numberBytes, length );
00593      return true;
00594    }
00595 }
00596 
00614 void PixelReadConvert::BuildLUTRGBA()
00615 {
00616 
00617    // Note to code reviewers :
00618    // The problem is *much more* complicated, since a lot of manufacturers
00619    // Don't follow the norm :
00620    // have a look at David Clunie's remark at the end of this .cxx file.
00621    if ( LutRGBA )
00622    
00623    {
00624       return;
00625    }
00626    // Not so easy : see
00627    // http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables
00628                                                                                 
00629    if ( ! IsPaletteColor )
00630    {
00631       return;
00632    }
00633                                                                                 
00634    if (   LutRedDescriptor   == GDCM_UNFOUND
00635        || LutGreenDescriptor == GDCM_UNFOUND
00636        || LutBlueDescriptor  == GDCM_UNFOUND )
00637    {
00638       gdcmWarningMacro( "(At least) a LUT Descriptor is missing" );
00639       return;
00640    }
00641 
00643    // Extract the info from the LUT descriptors
00644    int lengthR;   // Red LUT length in Bytes
00645    int debR;      // Subscript of the first Lut Value
00646    int nbitsR;    // Lut item size (in Bits)
00647    int nbRead;    // nb of items in LUT descriptor (must be = 3)
00648 
00649    nbRead = sscanf( LutRedDescriptor.c_str(),
00650                         "%d\\%d\\%d",
00651                         &lengthR, &debR, &nbitsR );
00652    if ( nbRead != 3 )
00653    {
00654       gdcmWarningMacro( "Wrong Red LUT descriptor" );
00655    }                                                                                
00656    int lengthG;  // Green LUT length in Bytes
00657    int debG;     // Subscript of the first Lut Value
00658    int nbitsG;   // Lut item size (in Bits)
00659 
00660    nbRead = sscanf( LutGreenDescriptor.c_str(),
00661                     "%d\\%d\\%d",
00662                     &lengthG, &debG, &nbitsG );  
00663    if ( nbRead != 3 )
00664    {
00665       gdcmWarningMacro( "Wrong Green LUT descriptor" );
00666    }
00667                                                                                 
00668    int lengthB;  // Blue LUT length in Bytes
00669    int debB;     // Subscript of the first Lut Value
00670    int nbitsB;   // Lut item size (in Bits)
00671    nbRead = sscanf( LutRedDescriptor.c_str(),
00672                     "%d\\%d\\%d",
00673                     &lengthB, &debB, &nbitsB );
00674    if ( nbRead != 3 )
00675    {
00676       gdcmWarningMacro( "Wrong Blue LUT descriptor" );
00677    }
00678  
00679    gdcmDebugMacro(" lengthR " << lengthR << " debR " 
00680                 << debR << " nbitsR " << nbitsR);
00681    gdcmDebugMacro(" lengthG " << lengthG << " debG " 
00682                 << debG << " nbitsG " << nbitsG);
00683    gdcmDebugMacro(" lengthB " << lengthB << " debB " 
00684                 << debB << " nbitsB " << nbitsB);
00685 
00686    if ( !lengthR ) // if = 2^16, this shall be 0 see : CP-143
00687       lengthR=65536;
00688    if ( !lengthG ) // if = 2^16, this shall be 0
00689       lengthG=65536;
00690    if ( !lengthB ) // if = 2^16, this shall be 0
00691       lengthB=65536; 
00692                                                                                 
00694 
00695    if ( ( ! LutRedData ) || ( ! LutGreenData ) || ( ! LutBlueData ) )
00696    {
00697       gdcmWarningMacro( "(At least) a LUT is missing" );
00698       return;
00699    }
00700 
00701    // -------------------------------------------------------------
00702    
00703    if ( BitsAllocated <= 8 )
00704    {
00705       // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT
00706       LutRGBA = new uint8_t[ 1024 ]; // 256 * 4 (R, G, B, Alpha)
00707       if ( !LutRGBA )
00708          return;
00709       LutItemNumber = 256;
00710       LutItemSize   = 8;
00711       memset( LutRGBA, 0, 1024 );
00712                                                                                 
00713       int mult;
00714       if ( ( nbitsR == 16 ) && ( BitsAllocated == 8 ) )
00715       {
00716          // when LUT item size is different than pixel size
00717          mult = 2; // high byte must be = low byte
00718       }
00719       else
00720       {
00721          // See PS 3.3-2003 C.11.1.1.2 p 619
00722          mult = 1;
00723       }
00724                                                                                 
00725       // if we get a black image, let's just remove the '+1'
00726       // from 'i*mult+1' and check again
00727       // if it works, we shall have to check the 3 Palettes
00728       // to see which byte is ==0 (first one, or second one)
00729       // and fix the code
00730       // We give up the checking to avoid some (useless ?) overhead
00731       // (optimistic asumption)
00732       int i;
00733       uint8_t *a;
00734 
00735       //take "Subscript of the first Lut Value" (debR,debG,debB) into account!
00736 
00737       //FIXME :  +1 : to get 'low value' byte
00738       //         Trouble expected on Big Endian Processors ?
00739       //         16 BIts Per Pixel Palette Color to be swapped?
00740 
00741       a = LutRGBA + 0 + debR;
00742       for( i=0; i < lengthR; ++i )
00743       {
00744          *a = LutRedData[i*mult+1]; 
00745          a += 4;
00746       }
00747                                                                                 
00748       a = LutRGBA + 1 + debG;
00749       for( i=0; i < lengthG; ++i)
00750       {
00751          *a = LutGreenData[i*mult+1];
00752          a += 4;
00753       }
00754                                                                                 
00755       a = LutRGBA + 2 + debB;
00756       for(i=0; i < lengthB; ++i)
00757       {
00758          *a = LutBlueData[i*mult+1];
00759          a += 4;
00760       }
00761                                     
00762       a = LutRGBA + 3 ;
00763       for(i=0; i < 256; ++i)
00764       {
00765          *a = 1; // Alpha component
00766          a += 4;
00767       }
00768    }
00769    else
00770    {
00771       // Probabely the same stuff is to be done for 16 Bits Pixels
00772       // with 65536 entries LUT ?!?
00773       // Still looking for accurate info on the web :-(
00774 
00775       gdcmWarningMacro( "Sorry Palette Color Lookup Tables not yet dealt with"
00776                          << " for 16 Bits Per Pixel images" );
00777 
00778       // forge the 4 * 16 Bits Red/Green/Blue/Alpha LUT
00779 
00780       LutRGBA = (uint8_t *)new uint16_t[ 65536*4 ]; // 2^16 * 4 (R, G, B, Alpha)
00781       if ( !LutRGBA )
00782          return;
00783       memset( LutRGBA, 0, 65536*4*2 );  // 16 bits = 2 bytes ;-)
00784 
00785       LutItemNumber = 65536;
00786       LutItemSize   = 16;
00787 
00788       int i;
00789       uint16_t *a16;
00790 
00791       //take "Subscript of the first Lut Value" (debR,debG,debB) into account!
00792 
00793       a16 = (uint16_t*)LutRGBA + 0 + debR;
00794       for( i=0; i < lengthR; ++i )
00795       {
00796          *a16 = ((uint16_t*)LutRedData)[i];
00797          a16 += 4;
00798       }
00799                                                                               
00800       a16 = (uint16_t*)LutRGBA + 1 + debG;
00801       for( i=0; i < lengthG; ++i)
00802       {
00803          *a16 = ((uint16_t*)LutGreenData)[i];
00804          a16 += 4;
00805       }
00806                                                                                 
00807       a16 = (uint16_t*)LutRGBA + 2 + debB;
00808       for(i=0; i < lengthB; ++i)
00809       {
00810          *a16 = ((uint16_t*)LutBlueData)[i];
00811          a16 += 4;
00812       }
00813                                                                              
00814       a16 = (uint16_t*)LutRGBA + 3 ;
00815       for(i=0; i < 65536; ++i)
00816       {
00817          *a16 = 1; // Alpha component
00818          a16 += 4;
00819       }
00820 /* Just to 'see' the LUT, at debug time
00821 // Don't remove this commented out code.
00822 
00823       a16=(uint16_t*)LutRGBA;
00824       for (int j=0;j<65536;j++)
00825       {
00826          std::cout << *a16     << " " << *(a16+1) << " "
00827                    << *(a16+2) << " " << *(a16+3) << std::endl;
00828          a16+=4;
00829       }
00830 */
00831    }
00832 }
00833 
00837 void PixelReadConvert::ConvertSwapZone()
00838 {
00839    unsigned int i;
00840    
00841    // If this file is 'ImplicitVR BigEndian PrivateGE Transfer Syntax', 
00842    // then the header is in little endian format and the pixel data is in 
00843    // big endian format.  When reading the header, GDCM has already established
00844    // a byte swapping code suitable for this machine to read the
00845    // header. In TS::ImplicitVRBigEndianPrivateGE, this code will need
00846    // to be switched in order to read the pixel data.  This must be
00847    // done REGARDLESS of the processor endianess!
00848    //
00849    // Example:  Assume we are on a little endian machine.  When
00850    // GDCM reads the header, the header will match the machine
00851    // endianess and the swap code will be established as a no-op.
00852    // When GDCM reaches the pixel data, it will need to switch the
00853    // swap code to do big endian to little endian conversion.
00854    //
00855    // Now, assume we are on a big endian machine.  When GDCM reads the
00856    // header, the header will be recognized as a different endianess
00857    // than the machine endianess, and a swap code will be established
00858    // to convert from little endian to big endian.  When GDCM readers
00859    // the pixel data, the pixel data endianess will now match the
00860    // machine endianess.  But we currently have a swap code that
00861    // converts from little endian to big endian.  In this case, we
00862    // need to switch the swap code to a no-op.
00863    //
00864    // Therefore, in either case, if the file is in
00865    // 'ImplicitVR BigEndian PrivateGE Transfer Syntax', then GDCM needs to switch
00866    // the byte swapping code when entering the pixel data.
00867    
00868    int tempSwapCode = SwapCode;
00869    if ( IsPrivateGETransferSyntax )
00870    {
00871       gdcmWarningMacro(" IsPrivateGETransferSyntax found; turn the SwapCode"); 
00872       // PrivateGETransferSyntax only exists for 'true' Dicom images
00873       // we assume there is no 'exotic' 32 bits endianess!
00874       if (SwapCode == 1234) 
00875       {
00876          tempSwapCode = 4321;
00877       }
00878       else if (SwapCode == 4321)
00879       {
00880          tempSwapCode = 1234;
00881       }
00882    }
00883     
00884    if ( BitsAllocated == 16 )
00885    {
00886       uint16_t *im16 = (uint16_t*)Raw;
00887       switch( tempSwapCode )
00888       {
00889          case 1234:
00890             break;
00891          case 3412:
00892          case 2143:
00893          case 4321:
00894             for( i = 0; i < RawSize / 2; i++ )
00895             {
00896                im16[i]= (im16[i] >> 8) | (im16[i] << 8 );
00897             }
00898             break;
00899          default:
00900             gdcmWarningMacro("SwapCode value (16 bits) not allowed." 
00901                         << tempSwapCode);
00902       }
00903    }
00904    else if ( BitsAllocated == 32 )
00905    {
00906       uint32_t s32;
00907       uint16_t high;
00908       uint16_t low;
00909       uint32_t *im32 = (uint32_t*)Raw;
00910       switch ( tempSwapCode )
00911       {
00912          case 1234:
00913             break;
00914          case 4321:
00915             for( i = 0; i < RawSize / 4; i++ )
00916             {
00917                low     = im32[i] & 0x0000ffff;  // 4321
00918                high    = im32[i] >> 16;
00919                high    = ( high >> 8 ) | ( high << 8 );
00920                low     = ( low  >> 8 ) | ( low  << 8 );
00921                s32     = low;
00922                im32[i] = ( s32 << 16 ) | high;
00923             }
00924             break;
00925          case 2143:
00926             for( i = 0; i < RawSize / 4; i++ )
00927             {
00928                low     = im32[i] & 0x0000ffff;   // 2143
00929                high    = im32[i] >> 16;
00930                high    = ( high >> 8 ) | ( high << 8 );
00931                low     = ( low  >> 8 ) | ( low  << 8 );
00932                s32     = high;
00933                im32[i] = ( s32 << 16 ) | low;
00934             }
00935             break;
00936          case 3412:
00937             for( i = 0; i < RawSize / 4; i++ )
00938             {
00939                low     = im32[i] & 0x0000ffff; // 3412
00940                high    = im32[i] >> 16;
00941                s32     = low;
00942                im32[i] = ( s32 << 16 ) | high;
00943             }
00944             break;
00945          default:
00946             gdcmWarningMacro("SwapCode value (32 bits) not allowed." << tempSwapCode );
00947       }
00948    }
00949 }
00950 
00954 void PixelReadConvert::ConvertReorderEndianity()
00955 {
00956    if ( BitsAllocated != 8 )
00957    {
00958       ConvertSwapZone();
00959    }
00960 
00961    // Special kludge in order to deal with xmedcon broken images:
00962    if ( BitsAllocated == 16
00963      && BitsStored < BitsAllocated
00964      && !PixelSign )
00965    {
00966       int l = (int)( RawSize / ( BitsAllocated / 8 ) );
00967       uint16_t *deb = (uint16_t *)Raw;
00968       for(int i = 0; i<l; i++)
00969       {
00970          if ( *deb == 0xffff )
00971          {
00972            *deb = 0;
00973          }
00974          deb++;
00975       }
00976    }
00977 }
00978 
00983 void PixelReadConvert::ConvertFixGreyLevels()
00984 {
00985    if (!IsMonochrome1)
00986       return;
00987 
00988    uint32_t i; // to please M$VC6
00989    int16_t j;
00990 
00991    if (!PixelSign)
00992    {
00993       if ( BitsAllocated == 8 )
00994       {
00995          uint8_t *deb = (uint8_t *)Raw;
00996          for (i=0; i<RawSize; i++)      
00997          {
00998             *deb = 255 - *deb;
00999             deb++;
01000          }
01001          return;
01002       }
01003 
01004       if ( BitsAllocated == 16 )
01005       {
01006          uint16_t mask =1;
01007          for (j=0; j<BitsStored-1; j++)
01008          {
01009             mask = (mask << 1) +1; // will be fff when BitsStored=12
01010          }
01011 
01012          uint16_t *deb = (uint16_t *)Raw;
01013          for (i=0; i<RawSize/2; i++)      
01014          {
01015             *deb = mask - *deb;
01016             deb++;
01017          }
01018          return;
01019        }
01020    }
01021    else
01022    {
01023       if ( BitsAllocated == 8 )
01024       {
01025          uint8_t smask8 = 255;
01026          uint8_t *deb = (uint8_t *)Raw;
01027          for (i=0; i<RawSize; i++)      
01028          {
01029             *deb = smask8 - *deb;
01030             deb++;
01031          }
01032          return;
01033       }
01034       if ( BitsAllocated == 16 )
01035       {
01036          uint16_t smask16 = 65535;
01037          uint16_t *deb = (uint16_t *)Raw;
01038          for (i=0; i<RawSize/2; i++)      
01039          {
01040             *deb = smask16 - *deb;
01041             deb++;
01042          }
01043          return;
01044       }
01045    }
01046 }
01047 
01052 bool PixelReadConvert::ConvertReArrangeBits() throw ( FormatError )
01053 {
01054 
01055    if ( BitsStored != BitsAllocated )
01056    {
01057       int l = (int)( RawSize / ( BitsAllocated / 8 ) );
01058       if ( BitsAllocated == 16 )
01059       {
01060          // pmask : to mask the 'unused bits' (may contain overlays)
01061          uint16_t pmask = 0xffff;
01062          pmask = pmask >> ( BitsAllocated - BitsStored );
01063 
01064          uint16_t *deb = (uint16_t*)Raw;
01065 
01066          if ( !PixelSign )  // Pixels are unsigned
01067          {
01068             for(int i = 0; i<l; i++)
01069             {   
01070                *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & pmask;
01071                deb++;
01072             }
01073          }
01074          else // Pixels are signed
01075          {
01076             // smask : to check the 'sign' when BitsStored != BitsAllocated
01077             uint16_t smask = 0x0001;
01078             smask = smask << ( 16 - (BitsAllocated - BitsStored + 1) );
01079             // nmask : to propagate sign bit on negative values
01080             int16_t nmask = (int16_t)0x8000;  
01081             nmask = nmask >> ( BitsAllocated - BitsStored - 1 );
01082  
01083             for(int i = 0; i<l; i++)
01084             {
01085                *deb = *deb >> (BitsStored - HighBitPosition - 1);
01086                if ( *deb & smask )
01087                {
01088                   *deb = *deb | nmask;
01089                }
01090                else
01091                {
01092                   *deb = *deb & pmask;
01093                }
01094                deb++;
01095             }
01096          }
01097       }
01098       else if ( BitsAllocated == 32 )
01099       {
01100          // pmask : to mask the 'unused bits' (may contain overlays)
01101          uint32_t pmask = 0xffffffff;
01102          pmask = pmask >> ( BitsAllocated - BitsStored );
01103 
01104          uint32_t *deb = (uint32_t*)Raw;
01105 
01106          if ( !PixelSign )
01107          {
01108             for(int i = 0; i<l; i++)
01109             {             
01110                *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & pmask;
01111                deb++;
01112             }
01113          }
01114          else
01115          {
01116             // smask : to check the 'sign' when BitsStored != BitsAllocated
01117             uint32_t smask = 0x00000001;
01118             smask = smask >> ( 32 - (BitsAllocated - BitsStored +1 ));
01119             // nmask : to propagate sign bit on negative values
01120             int32_t nmask = 0x80000000;   
01121             nmask = nmask >> ( BitsAllocated - BitsStored -1 );
01122 
01123             for(int i = 0; i<l; i++)
01124             {
01125                *deb = *deb >> (BitsStored - HighBitPosition - 1);
01126                if ( *deb & smask )
01127                   *deb = *deb | nmask;
01128                else
01129                   *deb = *deb & pmask;
01130                deb++;
01131             }
01132          }
01133       }
01134       else
01135       {
01136          gdcmWarningMacro("Weird image (BitsAllocated !=8, 12, 16, 32)");
01137          throw FormatError( "Weird image !?" );
01138       }
01139    }
01140    return true;
01141 }
01142 
01147 void PixelReadConvert::ConvertRGBPlanesToRGBPixels()
01148 {
01149    gdcmWarningMacro("--> ConvertRGBPlanesToRGBPixels");
01150 
01151    uint8_t *localRaw = Raw;
01152    uint8_t *copyRaw = new uint8_t[ RawSize ];
01153    memmove( copyRaw, localRaw, RawSize );
01154 
01155    int l = XSize * YSize * ZSize;
01156 
01157    uint8_t *a = copyRaw;
01158    uint8_t *b = copyRaw + l;
01159    uint8_t *c = copyRaw + l + l;
01160 
01161    for (int j = 0; j < l; j++)
01162    {
01163       *(localRaw++) = *(a++);
01164       *(localRaw++) = *(b++);
01165       *(localRaw++) = *(c++);
01166    }
01167    delete[] copyRaw;
01168 }
01169 
01174 void PixelReadConvert::ConvertYcBcRPlanesToRGBPixels()
01175 {
01176   // Remarks for YBR newbees :
01177   // YBR_FULL works very much like RGB, i.e. three samples per pixel, 
01178   // just the color space is YCbCr instead of RGB. This is particularly useful
01179   // for doppler ultrasound where most of the image is grayscale 
01180   // (i.e. only populates the Y components) and Cb and Cr are mostly zero,
01181   // except for the few patches of color on the image.
01182   // On such images, RLE achieves a compression ratio that is much better 
01183   // than the compression ratio on an equivalent RGB image. 
01184  
01185    gdcmWarningMacro("--> ConvertYcBcRPlanesToRGBPixels");
01186    
01187    uint8_t *localRaw = Raw;
01188    uint8_t *copyRaw = new uint8_t[ RawSize ];
01189    memmove( copyRaw, localRaw, RawSize );
01190 
01191    // to see the tricks about YBR_FULL, YBR_FULL_422,
01192    // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at :
01193    // ftp://medical.nema.org/medical/dicom/final/sup61_ft.pdf
01194    // and be *very* affraid
01195    //
01196    int l        = XSize * YSize;
01197    int nbFrames = ZSize;
01198 
01199    uint8_t *a = copyRaw + 0;
01200    uint8_t *b = copyRaw + l;
01201    uint8_t *c = copyRaw + l+ l;
01202    int32_t R, G, B;
01203 
01209 
01210    for ( int i = 0; i < nbFrames; i++ )
01211    {
01212       for ( int j = 0; j < l; j++ )
01213       {
01214          R = 38142 *(*a-16) + 52298 *(*c -128);
01215          G = 38142 *(*a-16) - 26640 *(*c -128) - 12845 *(*b -128);
01216          B = 38142 *(*a-16) + 66093 *(*b -128);
01217 
01218          R = (R+16384)>>15;
01219          G = (G+16384)>>15;
01220          B = (B+16384)>>15;
01221 
01222          if (R < 0)   R = 0;
01223          if (G < 0)   G = 0;
01224          if (B < 0)   B = 0;
01225          if (R > 255) R = 255;
01226          if (G > 255) G = 255;
01227          if (B > 255) B = 255;
01228 
01229          *(localRaw++) = (uint8_t)R;
01230          *(localRaw++) = (uint8_t)G;
01231          *(localRaw++) = (uint8_t)B;
01232          a++;
01233          b++;
01234          c++;
01235       }
01236    }
01237    delete[] copyRaw;
01238 }
01239 
01244 
01245 void PixelReadConvert::ConvertHandleColor()
01246 {
01248    // Deal with the color decoding i.e. handle:
01249    //   - R, G, B planes (as opposed to RGB pixels)
01250    //   - YBR (various) encodings.
01251    //   - LUT[s] (or "PALETTE COLOR").
01252    //
01253    // The classification in the color decoding schema is based on the blending
01254    // of two Dicom tags values:
01255    // * "Photometric Interpretation" for which we have the cases:
01256    //  - [Photo A] MONOCHROME[1|2] pictures,
01257    //  - [Photo B] RGB or YBR_FULL_422 (which acts as RGB),
01258    //  - [Photo C] YBR_* (with the above exception of YBR_FULL_422)
01259    //  - [Photo D] "PALETTE COLOR" which indicates the presence of LUT[s].
01260    // * "Planar Configuration" for which we have the cases:
01261    //  - [Planar 0] 0 then Pixels are already RGB
01262    //  - [Planar 1] 1 then we have 3 planes : R, G, B,
01263    //  - [Planar 2] 2 then we have 1 gray Plane and 3 LUTs
01264    //
01265    // Now in theory, one could expect some coherence when blending the above
01266    // cases. For example we should not encounter files belonging at the
01267    // time to case [Planar 0] and case [Photo D].
01268    // Alas, this was only theory ! Because in practice some odd (read ill
01269    // formated Dicom) files (e.g. gdcmData/US-PAL-8-10x-echo.dcm) we encounter:
01270    //     - "Planar Configuration" = 0,
01271    //     - "Photometric Interpretation" = "PALETTE COLOR".
01272    // Hence gdcm will use the folowing "heuristic" in order to be tolerant
01273    // towards Dicom-non-conformant files:
01274    //   << whatever the "Planar Configuration" value might be, a
01275    //      "Photometric Interpretation" set to "PALETTE COLOR" forces
01276    //      a LUT intervention >>
01277    //
01278    // Now we are left with the following handling of the cases:
01279    // - [Planar 0] OR  [Photo A] no color decoding (since respectively
01280    //       Pixels are already RGB and monochrome pictures have no color :),
01281    // - [Planar 1] AND [Photo B] handled with ConvertRGBPlanesToRGBPixels()
01282    // - [Planar 1] AND [Photo C] handled with ConvertYcBcRPlanesToRGBPixels()
01283    // - [Planar 2] OR  [Photo D] requires LUT intervention.
01284 
01285    gdcmDebugMacro("--> ConvertHandleColor "
01286                      << "Planar Configuration " << PlanarConfiguration );
01287 
01288    if ( ! IsRawRGB() )
01289    {
01290       // [Planar 2] OR  [Photo D]: LUT intervention done outside
01291       gdcmDebugMacro("--> RawRGB : LUT intervention done outside");
01292       return;
01293    }
01294                                                                                 
01295    if ( PlanarConfiguration == 1 )
01296    {
01297       if ( IsYBRFull )
01298       {
01299          // [Planar 1] AND [Photo C] (remember YBR_FULL_422 acts as RGB)
01300          gdcmDebugMacro("--> YBRFull");
01301          ConvertYcBcRPlanesToRGBPixels();
01302       }
01303       else
01304       {
01305          // [Planar 1] AND [Photo C]
01306          gdcmDebugMacro("--> YBRFull");
01307          ConvertRGBPlanesToRGBPixels();
01308       }
01309       return;
01310    }
01311                                                                                 
01312    // When planarConf is 0, and RLELossless (forbidden by Dicom norm)
01313    // pixels need to be RGB-fyied anyway
01314 
01315    if (IsRLELossless)
01316    { 
01317      gdcmDebugMacro("--> RLE Lossless");
01318      ConvertRGBPlanesToRGBPixels();
01319    }
01320 
01321    // In *normal *case, when planarConf is 0, pixels are already in RGB
01322 }
01323 
01325 void PixelReadConvert::ComputeRawAndRGBSizes()
01326 {
01327    int bitsAllocated = BitsAllocated;
01328    // Number of "Bits Allocated" is fixed to 16 when it's 12, since
01329    // in this case we will expand the image to 16 bits (see
01330    //    \ref ReadAndDecompress12BitsTo16Bits() )
01331    if (  BitsAllocated == 12 )
01332    {
01333       bitsAllocated = 16;
01334    }
01335                                                                                 
01336    RawSize =  XSize * YSize * ZSize
01337                      * ( bitsAllocated / 8 )
01338                      * SamplesPerPixel;
01339    if ( HasLUT )
01340    {
01341       RGBSize = 3 * RawSize; // works for 8 and 16 bits per Pixel
01342    }
01343    else
01344    {
01345       RGBSize = RawSize;
01346    }
01347 }
01348 
01350 void PixelReadConvert::AllocateRGB()
01351 {
01352   if ( RGB )
01353      delete [] RGB;
01354   RGB = new uint8_t[RGBSize];
01355 }
01356 
01358 void PixelReadConvert::AllocateRaw()
01359 {
01360   if ( Raw )
01361      delete [] Raw;
01362   Raw = new uint8_t[RawSize];
01363 }
01364 
01365 //-----------------------------------------------------------------------------
01366 // Print
01372 void PixelReadConvert::Print( std::ostream &os, std::string const &indent )
01373 {
01374    os << indent
01375       << "--- Pixel information -------------------------"
01376       << std::endl;
01377    os << indent
01378       << "Pixel Data: offset " << PixelOffset
01379       << " x(" << std::hex << PixelOffset << std::dec
01380       << ")   length " << PixelDataLength
01381       << " x(" << std::hex << PixelDataLength << std::dec
01382       << ")" << std::endl;
01383 
01384    if ( IsRLELossless )
01385    {
01386       if ( RLEInfo )
01387       {
01388          RLEInfo->Print( os, indent );
01389       }
01390       else
01391       {
01392          gdcmWarningMacro("Set as RLE file but NO RLEinfo present.");
01393       }
01394    }
01395 
01396    if ( IsJPEG2000 || IsJPEGLossless || IsJPEGLossy || IsJPEGLS )
01397    {
01398       if ( JPEGInfo )
01399       {
01400          JPEGInfo->Print( os, indent );
01401       }
01402       else
01403       {
01404          gdcmWarningMacro("Set as JPEG file but NO JPEGinfo present.");
01405       }
01406    }
01407 }
01408 
01412 void PixelReadConvert::CallStartMethod()
01413 {
01414    Progress = 0.0f;
01415    Abort    = false;
01416    CommandManager::ExecuteCommand(FH,CMD_STARTPROGRESS);
01417 }
01418 
01422 void PixelReadConvert::CallProgressMethod()
01423 {
01424    CommandManager::ExecuteCommand(FH,CMD_PROGRESS);
01425 }
01426 
01430 void PixelReadConvert::CallEndMethod()
01431 {
01432    Progress = 1.0f;
01433    CommandManager::ExecuteCommand(FH,CMD_ENDPROGRESS);
01434 }
01435 
01436 
01437 //-----------------------------------------------------------------------------
01438 } // end namespace gdcm
01439 
01440 // Note to developpers :
01441 // Here is a very detailled post from David Clunie, on the troubles caused 
01442 // 'non standard' LUT and LUT description
01443 // We shall have to take it into accound in our code.
01444 // Some day ...
01445 
01446 
01447 /*
01448 Subject: Problem with VOI LUTs in Agfa and Fuji CR and GE DX images, was Re: VOI LUT issues
01449 Date: Sun, 06 Feb 2005 17:13:40 GMT
01450 From: David Clunie <dclunie@dclunie.com>
01451 Reply-To: dclunie@dclunie.com
01452 Newsgroups: comp.protocols.dicom
01453 References: <1107553502.040221.189550@o13g2000cwo.googlegroups.com>
01454 
01455 > THE LUT that comes with [my] image claims to be 16-bit, but none of the
01456 > values goes higher than 4095.  That being said, though, none of my
01457 > original pixel values goes higher than that, either.  I have read
01458 > elsewhere on this group that when that happens you are supposed to
01459 > adjust the LUT.  Can someone be more specific?  There was a thread from
01460 > 2002 where Marco and David were mentioning doing precisely that.
01461 >
01462 > Thanks
01463 >
01464 > -carlos rodriguez
01465 
01466 
01467 You have encountered the well known "we know what the standard says but
01468 we are going to ignore it and do what we have been doing for almost
01469 a decade regardless" CR vendor bug. Agfa started this, but they are not
01470 the only vendor doing this now; GE and Fuji may have joined the club.
01471 
01472 Sadly, one needs to look at the LUT Data, figure out what the maximum
01473 value actually encoded is, and find the next highest power of 2 (e.g.
01474 212 in this case), to figure out what the range of the data is
01475 supposed to be. I have assumed that if the maximum value in the LUT
01476 data is less than a power of 2 minus 1 (e.g. 0xebc) then the intent
01477 of the vendor was not to use the maximum available grayscale range
01478 of the display (e.g. the maximum is 0xfff in this case). An alternative
01479 would be to scale to the actual maximum rather than a power of two.
01480 
01481 Very irritating, and in theory not totally reliable if one really
01482 intended the full 16 bits and only used, say 15, but that is extremely
01483 unlikely since everything would be too dark, and this heuristic
01484 seems to work OK.
01485 
01486 There has never been anything in the standard that describes having
01487 to go through these convolutions. Since the only value in the
01488 standard that describes the bit depth of the LUT values is LUT
01489 Descriptor value 3 and that is (usually) always required to be
01490 either 8 or 16, it mystifies me how the creators' of these images
01491 imagine that the receiver is going to divine the range that is intended. Further, the standard is quite explicit that this 3rd
01492 value defines the range of LUT values, but as far as I am aware, all
01493 the vendors are ignoring the standard and indeed sending a third value
01494 of 16 in all cases.
01495 
01496 This problem is not confined to CR, and is also seen with DX products.
01497 
01498 Typically I have seen:
01499 
01500 - Agfa CR, which usually (always ?) sends LUTs, values up to 0x0fff
01501 - Fuji CR, which occasionally send LUTs, values up to 0x03ff
01502 - GE DX, for presentation, which always have LUTs, up to 0x3fff
01503 
01504 Swissray, Siemens, Philips, Canon and Kodak never seem to send VOI LUTs
01505 at this point (which is a whole other problem). Note that the presence
01506 or absence of a VOI LUT as opposed to window values may be configurable
01507 on the modality in some cases, and I have just looked at what I happen
01508 to have received from a myriad of sites over whose configuration I have
01509 no control. This may be why the majority of Fuji images have no VOI LUTs,
01510 but a few do (or it may be the Siemens system that these Fuji images went
01511 through that perhaps added it). I do have some test Hologic DX images that
01512 are not from a clinical site that do actually get this right (a value
01513 of 12 for the third value and a max of 0xfff).
01514 
01515 Since almost every vendor that I have encountered that encodes LUTs
01516 makes this mistake, perhaps it is time to amend the standard to warn
01517 implementor's of receivers and/or sanction this bad behavior. We have
01518 talked about this in the past in WG 6 but so far everyone has been
01519 reluctant to write into the standard such a comment. Maybe it is time
01520 to try again, since if one is not aware of this problem, one cannot
01521 effectively implement display using VOI LUTs, and there is a vast
01522 installed base to contend with.
01523 
01524 I did not check presentation states, in which VOI LUTs could also be
01525 encountered, for the prevalence of this mistake, nor did I look at the
01526 encoding of Modality LUT's, which are unusual. Nor did I check digital
01527 mammography images. I would be interested to hear from anyone who has.
01528 
01529 David
01530 
01531 PS. The following older thread in this newsgroup discusses this:
01532 
01533 "http://groups-beta.google.com/group/comp.protocols.dicom/browse_frm/t hread/6a033444802a35fc/0f0a9a1e35c1468e?q=voi+lut&_done=%2Fgroup%2Fcom p.protocols.dicom%2Fsearch%3Fgroup%3Dcomp.protocols.dicom%26q%3Dvoi+lu t%26qt_g%3D1%26searchnow%3DSearch+this+group%26&_doneTitle=Back+to+Sea rch&&d#0f0a9a1e35c1468e"
01534 
01535 PPS. From a historical perspective, the following may be of interest.
01536 
01537 In the original standard in 1993, all that was said about this was a
01538 reference to the corresponding such where Modality LUTs are described
01539 that said:
01540 
01541 "The third value specifies the number of bits for each entry in the
01542 LUT Data. It shall take the value 8 or 16. The LUT Data shall be stored
01543 in a format equivalent to 8 or 16 bits allocated and high bit equal
01544 1-bits allocated."
01545 
01546 Since the high bit hint was not apparently explicit enough, a very
01547 early CP, CP 15 (submitted by Agfa as it happens), replaced this with:
01548 
01549 "The third value conveys the range of LUT entry values. It shall take
01550 the value 8 or 16, corresponding with the LUT entry value range of
01551 256 or 65536.
01552 
01553 Note:    The third value is not required for describing the
01554     LUT data and is only included for informational usage
01555     and for maintaining compatibility with ACRNEMA 2.0.
01556 
01557 The LUT Data contains the LUT entry values."
01558 
01559 That is how it read in the 1996, 1998 and 1999 editions.
01560 
01561 By the 2000 edition, Supplement 33 that introduced presentation states
01562 extensively reworked this entire section and tried to explain this in
01563 different words:
01564 
01565 "The output range is from 0 to 2^n-1 where n is the third value of LUT
01566 Descriptor. This range is always unsigned."
01567 
01568 and also added a note to spell out what the output range meant in the
01569 VOI LUT section:
01570 
01571 "9. The output of the Window Center/Width or VOI LUT transformation
01572 is either implicitly scaled to the full range of the display device
01573 if there is no succeeding transformation defined, or implicitly scaled
01574 to the full input range of the succeeding transformation step (such as
01575 the Presentation LUT), if present. See C.11.6.1."
01576 
01577 It still reads this way in the 2004 edition.
01578 
01579 Note that LUTs in other applications than the general VOI LUT allow for
01580 values other than 8 or 16 in the third value of LUT descriptor to permit
01581 ranges other than 0 to 255 or 65535.
01582 
01583 In addition, the DX Image Module specializes the VOI LUT
01584 attributes as follows, in PS 3.3 section C.8.11.3.1.5 (added in Sup 32):
01585 
01586 "The third value specifies the number of bits for each entry in the LUT
01587 Data (analogous to ìbits storedî). It shall be between 10-16. The LUT
01588 Data shall be stored in a format equivalent to 16 ìbits allocatedî and
01589 ìhigh bitî equal to ìbits storedî - 1. The third value conveys the range
01590 of LUT entry values. These unsigned LUT entry values shall range between
01591 0 and 2^n-1, where n is the third value of the LUT Descriptor."
01592 
01593 So in the case of the GE DX for presentation images, the third value of
01594 LUT descriptor is allowed to be and probably should be 14 rather than 16.
01595 
01596 */

Generated on Fri Jan 20 10:14:25 2006 for gdcm by  doxygen 1.4.4