Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | 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/02/05 01:37:09 $
00007   Version:   $Revision: 1.49 $
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 "gdcmDebug.h"
00020 #include "gdcmFile.h"
00021 #include "gdcmGlobal.h"
00022 #include "gdcmTS.h"
00023 #include "gdcmPixelReadConvert.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 #define str2num(str, typeNum) *((typeNum *)(str))
00035 
00036 //-----------------------------------------------------------------------------
00037 // Constructor / Destructor
00039 PixelReadConvert::PixelReadConvert() 
00040 {
00041    RGB          = 0;
00042    RGBSize      = 0;
00043    Raw          = 0;
00044    RawSize      = 0;
00045    LutRGBA      = 0;
00046    LutRedData   = 0;
00047    LutGreenData = 0;
00048    LutBlueData  = 0;
00049 }
00050 
00052 PixelReadConvert::~PixelReadConvert() 
00053 {
00054    Squeeze();
00055 }
00056 
00057 //-----------------------------------------------------------------------------
00058 // Public
00063 bool PixelReadConvert::IsRawRGB()
00064 {
00065    if (   IsMonochrome
00066        || PlanarConfiguration == 2
00067        || IsPaletteColor )
00068    {
00069       return false;
00070    }
00071    return true;
00072 }
00077 void PixelReadConvert::GrabInformationsFromFile( File *file )
00078 {
00079    // Number of Bits Allocated for storing a Pixel is defaulted to 16
00080    // when absent from the file.
00081    BitsAllocated = file->GetBitsAllocated();
00082    if ( BitsAllocated == 0 )
00083    {
00084       BitsAllocated = 16;
00085    }
00086 
00087    // Number of "Bits Stored", defaulted to number of "Bits Allocated"
00088    // when absent from the file.
00089    BitsStored = file->GetBitsStored();
00090    if ( BitsStored == 0 )
00091    {
00092       BitsStored = BitsAllocated;
00093    }
00094 
00095    // High Bit Position, defaulted to "Bits Allocated" - 1
00096    HighBitPosition = file->GetHighBitPosition();
00097    if ( HighBitPosition == 0 )
00098    {
00099       HighBitPosition = BitsAllocated - 1;
00100    }
00101 
00102    XSize           = file->GetXSize();
00103    YSize           = file->GetYSize();
00104    ZSize           = file->GetZSize();
00105    SamplesPerPixel = file->GetSamplesPerPixel();
00106    PixelSize       = file->GetPixelSize();
00107    PixelSign       = file->IsSignedPixelData();
00108    SwapCode        = file->GetSwapCode();
00109    std::string ts  = file->GetTransferSyntax();
00110    IsRaw =
00111         ( ! file->IsDicomV3() )
00112      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndian
00113      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndianDLXGE
00114      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRLittleEndian
00115      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian
00116      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::DeflatedExplicitVRLittleEndian;
00117 
00118    IsJPEG2000      = Global::GetTS()->IsJPEG2000(ts);
00119    IsJPEGLS        = Global::GetTS()->IsJPEGLS(ts);
00120    IsJPEGLossy     = Global::GetTS()->IsJPEGLossy(ts);
00121    IsJPEGLossless  = Global::GetTS()->IsJPEGLossless(ts);
00122    IsRLELossless   = Global::GetTS()->IsRLELossless(ts);
00123 
00124    PixelOffset     = file->GetPixelOffset();
00125    PixelDataLength = file->GetPixelAreaLength();
00126    RLEInfo  = file->GetRLEInfo();
00127    JPEGInfo = file->GetJPEGInfo();
00128 
00129    PlanarConfiguration = file->GetPlanarConfiguration();
00130    IsMonochrome = file->IsMonochrome();
00131    IsPaletteColor = file->IsPaletteColor();
00132    IsYBRFull = file->IsYBRFull();
00133 
00135    // LUT section:
00136    HasLUT = file->HasLUT();
00137    if ( HasLUT )
00138    {
00139       // Just in case some access to a File element requires disk access.
00140       LutRedDescriptor   = file->GetEntryValue( 0x0028, 0x1101 );
00141       LutGreenDescriptor = file->GetEntryValue( 0x0028, 0x1102 );
00142       LutBlueDescriptor  = file->GetEntryValue( 0x0028, 0x1103 );
00143    
00144       // Depending on the value of Document::MAX_SIZE_LOAD_ELEMENT_VALUE
00145       // [ refer to invocation of Document::SetMaxSizeLoadEntry() in
00146       // Document::Document() ], the loading of the value (content) of a
00147       // [Bin|Val]Entry occurence migth have been hindered (read simply NOT
00148       // loaded). Hence, we first try to obtain the LUTs data from the file
00149       // and when this fails we read the LUTs data directly from disk.
00150       // \TODO Reading a [Bin|Val]Entry directly from disk is a kludge.
00151       //       We should NOT bypass the [Bin|Val]Entry class. Instead
00152       //       an access to an UNLOADED content of a [Bin|Val]Entry occurence
00153       //       (e.g. BinEntry::GetBinArea()) should force disk access from
00154       //       within the [Bin|Val]Entry class itself. The only problem
00155       //       is that the [Bin|Val]Entry is unaware of the FILE* is was
00156       //       parsed from. Fix that. FIXME.
00157    
00158       // //// Red round
00159       file->LoadEntryBinArea(0x0028, 0x1201);
00160       LutRedData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1201 );
00161       if ( ! LutRedData )
00162       {
00163          gdcmWarningMacro( "Unable to read Red LUT data" );
00164       }
00165 
00166       // //// Green round:
00167       file->LoadEntryBinArea(0x0028, 0x1202);
00168       LutGreenData = (uint8_t*)file->GetEntryBinArea(0x0028, 0x1202 );
00169       if ( ! LutGreenData)
00170       {
00171          gdcmWarningMacro( "Unable to read Green LUT data" );
00172       }
00173 
00174       // //// Blue round:
00175       file->LoadEntryBinArea(0x0028, 0x1203);
00176       LutBlueData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1203 );
00177       if ( ! LutBlueData )
00178       {
00179          gdcmWarningMacro( "Unable to read Blue LUT data" );
00180       }
00181    }
00182 
00183    ComputeRawAndRGBSizes();
00184 }
00185 
00187 bool PixelReadConvert::ReadAndDecompressPixelData( std::ifstream *fp )
00188 {
00189    // ComputeRawAndRGBSizes is already made by 
00190    // ::GrabInformationsFromfile. So, the structure sizes are
00191    // correct
00192    Squeeze();
00193 
00196    if ( !fp )
00197    {
00198       gdcmWarningMacro( "Unavailable file pointer." );
00199       return false;
00200    }
00201 
00202    fp->seekg( PixelOffset, std::ios::beg );
00203    if( fp->fail() || fp->eof())
00204    {
00205       gdcmWarningMacro( "Unable to find PixelOffset in file." );
00206       return false;
00207    }
00208 
00209    AllocateRaw();
00210 
00213    if ( BitsAllocated == 12 )
00214    {
00215       ReadAndDecompress12BitsTo16Bits( fp);
00216    }
00217    else if ( IsRaw )
00218    {
00219       // This problem can be found when some obvious informations are found
00220       // after the field containing the image data. In this case, these
00221       // bad data are added to the size of the image (in the PixelDataLength
00222       // variable). But RawSize is the right size of the image !
00223       if( PixelDataLength != RawSize)
00224       {
00225          gdcmWarningMacro( "Mismatch between PixelReadConvert : "
00226                             << PixelDataLength << " and RawSize : " << RawSize );
00227       }
00228       if( PixelDataLength > RawSize)
00229       {
00230          fp->read( (char*)Raw, RawSize);
00231       }
00232       else
00233       {
00234          fp->read( (char*)Raw, PixelDataLength);
00235       }
00236 
00237       if ( fp->fail() || fp->eof())
00238       {
00239          gdcmWarningMacro( "Reading of Raw pixel data failed." );
00240          return false;
00241       }
00242    } 
00243    else if ( IsRLELossless )
00244    {
00245       if ( ! RLEInfo->DecompressRLEFile( fp, Raw, XSize, YSize, ZSize, BitsAllocated ) )
00246       {
00247          gdcmWarningMacro( "RLE decompressor failed." );
00248          return false;
00249       }
00250    }
00251    else
00252    {
00253       // Default case concerns JPEG family
00254       if ( ! ReadAndDecompressJPEGFile( fp ) )
00255       {
00256          gdcmWarningMacro( "JPEG decompressor failed." );
00257          return false;
00258       }
00259    }
00260 
00263    ConvertReorderEndianity();
00264    ConvertReArrangeBits();
00265    ConvertHandleColor();
00266 
00267    return true;
00268 }
00269 
00271 void PixelReadConvert::Squeeze() 
00272 {
00273    if ( RGB )
00274       delete [] RGB;
00275    RGB = 0;
00276 
00277    if ( Raw )
00278       delete [] Raw;
00279    Raw = 0;
00280 
00281    if ( LutRGBA )
00282       delete [] LutRGBA;
00283    LutRGBA = 0;
00284 }
00285 
00289 bool PixelReadConvert::BuildRGBImage()
00290 {
00291    if ( RGB )
00292    {
00293       // The job is already done.
00294       return true;
00295    }
00296 
00297    if ( ! Raw )
00298    {
00299       // The job can't be done
00300       return false;
00301    }
00302 
00303    BuildLUTRGBA();
00304    if ( ! LutRGBA )
00305    {
00306       // The job can't be done
00307       return false;
00308    }
00309                                                                                 
00310    // Build RGB Pixels
00311    AllocateRGB();
00312    uint8_t *localRGB = RGB;
00313    for (size_t i = 0; i < RawSize; ++i )
00314    {
00315       int j  = Raw[i] * 4;
00316       *localRGB++ = LutRGBA[j];
00317       *localRGB++ = LutRGBA[j+1];
00318       *localRGB++ = LutRGBA[j+2];
00319    }
00320    return true;
00321 }
00322 
00323 //-----------------------------------------------------------------------------
00324 // Protected
00325 
00326 //-----------------------------------------------------------------------------
00327 // Private
00332 void PixelReadConvert::ReadAndDecompress12BitsTo16Bits( std::ifstream *fp )
00333                throw ( FormatError )
00334 {
00335    int nbPixels = XSize * YSize;
00336    uint16_t *localDecompres = (uint16_t*)Raw;
00337 
00338    for( int p = 0; p < nbPixels; p += 2 )
00339    {
00340       uint8_t b0, b1, b2;
00341 
00342       fp->read( (char*)&b0, 1);
00343       if ( fp->fail() || fp->eof() )
00344       {
00345          throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
00346                                 "Unfound first block" );
00347       }
00348 
00349       fp->read( (char*)&b1, 1 );
00350       if ( fp->fail() || fp->eof())
00351       {
00352          throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
00353                                 "Unfound second block" );
00354       }
00355 
00356       fp->read( (char*)&b2, 1 );
00357       if ( fp->fail() || fp->eof())
00358       {
00359          throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
00360                                 "Unfound second block" );
00361       }
00362 
00363       // Two steps are necessary to please VC++
00364       //
00365       // 2 pixels 12bit =     [0xABCDEF]
00366       // 2 pixels 16bit = [0x0ABD] + [0x0FCE]
00367       //                        A                     B                 D
00368       *localDecompres++ =  ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f);
00369       //                        F                     C                 E
00370       *localDecompres++ =  ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4);
00371 
00373    }
00374 }
00375 
00382 bool PixelReadConvert::ReadAndDecompressJPEGFile( std::ifstream *fp )
00383 {
00384    if ( IsJPEG2000 )
00385    {
00386       gdcmWarningMacro( "Sorry, JPEG2000 not yet taken into account" );
00387       fp->seekg( JPEGInfo->GetFirstFragment()->GetOffset(), std::ios::beg);
00388 //    if ( ! gdcm_read_JPEG2000_file( fp,Raw ) )
00389           return false;
00390    }
00391 
00392    if ( IsJPEGLS )
00393    {
00394       gdcmWarningMacro( "Sorry, JPEG-LS not yet taken into account" );
00395       fp->seekg( JPEGInfo->GetFirstFragment()->GetOffset(), std::ios::beg);
00396 //    if ( ! gdcm_read_JPEGLS_file( fp,Raw ) )
00397          return false;
00398    }
00399 
00400    // else ??
00401    // Precompute the offset localRaw will be shifted with
00402    int length = XSize * YSize * SamplesPerPixel;
00403    int numberBytes = BitsAllocated / 8;
00404 
00405    JPEGInfo->DecompressFromFile(fp, Raw, BitsStored, numberBytes, length );
00406    return true;
00407 }
00408 
00424 void PixelReadConvert::BuildLUTRGBA()
00425 {
00426    if ( LutRGBA )
00427    {
00428       return;
00429    }
00430    // Not so easy : see
00431    // http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables
00432                                                                                 
00433    if ( ! IsPaletteColor )
00434    {
00435       return;
00436    }
00437                                                                                 
00438    if (   LutRedDescriptor   == GDCM_UNFOUND
00439        || LutGreenDescriptor == GDCM_UNFOUND
00440        || LutBlueDescriptor  == GDCM_UNFOUND )
00441    {
00442       return;
00443    }
00444 
00446    // Extract the info from the LUT descriptors
00447    int lengthR;   // Red LUT length in Bytes
00448    int debR;      // Subscript of the first Lut Value
00449    int nbitsR;    // Lut item size (in Bits)
00450    int nbRead = sscanf( LutRedDescriptor.c_str(),
00451                         "%d\\%d\\%d",
00452                         &lengthR, &debR, &nbitsR );
00453    if( nbRead != 3 )
00454    {
00455       gdcmWarningMacro( "Wrong Red LUT descriptor" );
00456    }
00457                                                                                 
00458    int lengthG;  // Green LUT length in Bytes
00459    int debG;     // Subscript of the first Lut Value
00460    int nbitsG;   // Lut item size (in Bits)
00461    nbRead = sscanf( LutGreenDescriptor.c_str(),
00462                     "%d\\%d\\%d",
00463                     &lengthG, &debG, &nbitsG );
00464    if( nbRead != 3 )
00465    {
00466       gdcmWarningMacro( "Wrong Green LUT descriptor" );
00467    }
00468                                                                                 
00469    int lengthB;  // Blue LUT length in Bytes
00470    int debB;     // Subscript of the first Lut Value
00471    int nbitsB;   // Lut item size (in Bits)
00472    nbRead = sscanf( LutRedDescriptor.c_str(),
00473                     "%d\\%d\\%d",
00474                     &lengthB, &debB, &nbitsB );
00475    if( nbRead != 3 )
00476    {
00477       gdcmWarningMacro( "Wrong Blue LUT descriptor" );
00478    }
00479                                                                                 
00481    if ( ( ! LutRedData ) || ( ! LutGreenData ) || ( ! LutBlueData ) )
00482    {
00483       return;
00484    }
00485 
00487    // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT
00488    LutRGBA = new uint8_t[ 1024 ]; // 256 * 4 (R, G, B, Alpha)
00489    if ( !LutRGBA )
00490       return;
00491 
00492    memset( LutRGBA, 0, 1024 );
00493                                                                                 
00494    int mult;
00495    if ( ( nbitsR == 16 ) && ( BitsAllocated == 8 ) )
00496    {
00497       // when LUT item size is different than pixel size
00498       mult = 2; // high byte must be = low byte
00499    }
00500    else
00501    {
00502       // See PS 3.3-2003 C.11.1.1.2 p 619
00503       mult = 1;
00504    }
00505                                                                                 
00506    // if we get a black image, let's just remove the '+1'
00507    // from 'i*mult+1' and check again
00508    // if it works, we shall have to check the 3 Palettes
00509    // to see which byte is ==0 (first one, or second one)
00510    // and fix the code
00511    // We give up the checking to avoid some (useless ?) overhead
00512    // (optimistic asumption)
00513    int i;
00514    uint8_t *a = LutRGBA + 0;
00515    for( i=0; i < lengthR; ++i )
00516    {
00517       *a = LutRedData[i*mult+1];
00518       a += 4;
00519    }
00520                                                                                 
00521    a = LutRGBA + 1;
00522    for( i=0; i < lengthG; ++i)
00523    {
00524       *a = LutGreenData[i*mult+1];
00525       a += 4;
00526    }
00527                                                                                 
00528    a = LutRGBA + 2;
00529    for(i=0; i < lengthB; ++i)
00530    {
00531       *a = LutBlueData[i*mult+1];
00532       a += 4;
00533    }
00534                                                                                 
00535    a = LutRGBA + 3;
00536    for(i=0; i < 256; ++i)
00537    {
00538       *a = 1; // Alpha component
00539       a += 4;
00540    }
00541 }
00542 
00546 void PixelReadConvert::ConvertSwapZone()
00547 {
00548    unsigned int i;
00549 
00550    if( BitsAllocated == 16 )
00551    {
00552       uint16_t *im16 = (uint16_t*)Raw;
00553       switch( SwapCode )
00554       {
00555          case 1234:
00556             break;
00557          case 3412:
00558          case 2143:
00559          case 4321:
00560             for( i = 0; i < RawSize / 2; i++ )
00561             {
00562                im16[i]= (im16[i] >> 8) | (im16[i] << 8 );
00563             }
00564             break;
00565          default:
00566             gdcmWarningMacro("SwapCode value (16 bits) not allowed.");
00567       }
00568    }
00569    else if( BitsAllocated == 32 )
00570    {
00571       uint32_t s32;
00572       uint16_t high;
00573       uint16_t low;
00574       uint32_t *im32 = (uint32_t*)Raw;
00575       switch ( SwapCode )
00576       {
00577          case 1234:
00578             break;
00579          case 4321:
00580             for( i = 0; i < RawSize / 4; i++ )
00581             {
00582                low     = im32[i] & 0x0000ffff;  // 4321
00583                high    = im32[i] >> 16;
00584                high    = ( high >> 8 ) | ( high << 8 );
00585                low     = ( low  >> 8 ) | ( low  << 8 );
00586                s32     = low;
00587                im32[i] = ( s32 << 16 ) | high;
00588             }
00589             break;
00590          case 2143:
00591             for( i = 0; i < RawSize / 4; i++ )
00592             {
00593                low     = im32[i] & 0x0000ffff;   // 2143
00594                high    = im32[i] >> 16;
00595                high    = ( high >> 8 ) | ( high << 8 );
00596                low     = ( low  >> 8 ) | ( low  << 8 );
00597                s32     = high;
00598                im32[i] = ( s32 << 16 ) | low;
00599             }
00600             break;
00601          case 3412:
00602             for( i = 0; i < RawSize / 4; i++ )
00603             {
00604                low     = im32[i] & 0x0000ffff; // 3412
00605                high    = im32[i] >> 16;
00606                s32     = low;
00607                im32[i] = ( s32 << 16 ) | high;
00608             }
00609             break;
00610          default:
00611             gdcmWarningMacro("SwapCode value (32 bits) not allowed." );
00612       }
00613    }
00614 }
00615 
00619 void PixelReadConvert::ConvertReorderEndianity()
00620 {
00621    if ( BitsAllocated != 8 )
00622    {
00623       ConvertSwapZone();
00624    }
00625 
00626    // Special kludge in order to deal with xmedcon broken images:
00627    if ( BitsAllocated == 16
00628      && BitsStored < BitsAllocated
00629      && !PixelSign )
00630    {
00631       int l = (int)( RawSize / ( BitsAllocated / 8 ) );
00632       uint16_t *deb = (uint16_t *)Raw;
00633       for(int i = 0; i<l; i++)
00634       {
00635          if( *deb == 0xffff )
00636          {
00637            *deb = 0;
00638          }
00639          deb++;
00640       }
00641    }
00642 }
00643 
00648 bool PixelReadConvert::ConvertReArrangeBits() throw ( FormatError )
00649 {
00650    if ( BitsStored != BitsAllocated )
00651    {
00652       int l = (int)( RawSize / ( BitsAllocated / 8 ) );
00653       if ( BitsAllocated == 16 )
00654       {
00655          uint16_t mask = 0xffff;
00656          mask = mask >> ( BitsAllocated - BitsStored );
00657          uint16_t *deb = (uint16_t*)Raw;
00658          for(int i = 0; i<l; i++)
00659          {
00660             *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & mask;
00661             deb++;
00662          }
00663       }
00664       else if ( BitsAllocated == 32 )
00665       {
00666          uint32_t mask = 0xffffffff;
00667          mask = mask >> ( BitsAllocated - BitsStored );
00668          uint32_t *deb = (uint32_t*)Raw;
00669          for(int i = 0; i<l; i++)
00670          {
00671             *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & mask;
00672             deb++;
00673          }
00674       }
00675       else
00676       {
00677          gdcmWarningMacro("Weird image");
00678          throw FormatError( "Weird image !?" );
00679       }
00680    }
00681    return true;
00682 }
00683 
00688 void PixelReadConvert::ConvertRGBPlanesToRGBPixels()
00689 {
00690    uint8_t *localRaw = Raw;
00691    uint8_t *copyRaw = new uint8_t[ RawSize ];
00692    memmove( copyRaw, localRaw, RawSize );
00693 
00694    int l = XSize * YSize * ZSize;
00695 
00696    uint8_t *a = copyRaw;
00697    uint8_t *b = copyRaw + l;
00698    uint8_t *c = copyRaw + l + l;
00699 
00700    for (int j = 0; j < l; j++)
00701    {
00702       *(localRaw++) = *(a++);
00703       *(localRaw++) = *(b++);
00704       *(localRaw++) = *(c++);
00705    }
00706    delete[] copyRaw;
00707 }
00708 
00713 void PixelReadConvert::ConvertYcBcRPlanesToRGBPixels()
00714 {
00715    uint8_t *localRaw = Raw;
00716    uint8_t *copyRaw = new uint8_t[ RawSize ];
00717    memmove( copyRaw, localRaw, RawSize );
00718 
00719    // to see the tricks about YBR_FULL, YBR_FULL_422,
00720    // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at :
00721    // ftp://medical.nema.org/medical/dicom/final/sup61_ft.pdf
00722    // and be *very* affraid
00723    //
00724    int l        = XSize * YSize;
00725    int nbFrames = ZSize;
00726 
00727    uint8_t *a = copyRaw;
00728    uint8_t *b = copyRaw + l;
00729    uint8_t *c = copyRaw + l + l;
00730    double R, G, B;
00731 
00736 
00737    for ( int i = 0; i < nbFrames; i++ )
00738    {
00739       for ( int j = 0; j < l; j++ )
00740       {
00741          R = 1.164 *(*a-16) + 1.596 *(*c -128) + 0.5;
00742          G = 1.164 *(*a-16) - 0.813 *(*c -128) - 0.392 *(*b -128) + 0.5;
00743          B = 1.164 *(*a-16) + 2.017 *(*b -128) + 0.5;
00744 
00745          if (R < 0.0)   R = 0.0;
00746          if (G < 0.0)   G = 0.0;
00747          if (B < 0.0)   B = 0.0;
00748          if (R > 255.0) R = 255.0;
00749          if (G > 255.0) G = 255.0;
00750          if (B > 255.0) B = 255.0;
00751 
00752          *(localRaw++) = (uint8_t)R;
00753          *(localRaw++) = (uint8_t)G;
00754          *(localRaw++) = (uint8_t)B;
00755          a++;
00756          b++;
00757          c++;
00758       }
00759    }
00760    delete[] copyRaw;
00761 }
00762 
00767 
00768 void PixelReadConvert::ConvertHandleColor()
00769 {
00771    // Deal with the color decoding i.e. handle:
00772    //   - R, G, B planes (as opposed to RGB pixels)
00773    //   - YBR (various) encodings.
00774    //   - LUT[s] (or "PALETTE COLOR").
00775    //
00776    // The classification in the color decoding schema is based on the blending
00777    // of two Dicom tags values:
00778    // * "Photometric Interpretation" for which we have the cases:
00779    //  - [Photo A] MONOCHROME[1|2] pictures,
00780    //  - [Photo B] RGB or YBR_FULL_422 (which acts as RGB),
00781    //  - [Photo C] YBR_* (with the above exception of YBR_FULL_422)
00782    //  - [Photo D] "PALETTE COLOR" which indicates the presence of LUT[s].
00783    // * "Planar Configuration" for which we have the cases:
00784    //  - [Planar 0] 0 then Pixels are already RGB
00785    //  - [Planar 1] 1 then we have 3 planes : R, G, B,
00786    //  - [Planar 2] 2 then we have 1 gray Plane and 3 LUTs
00787    //
00788    // Now in theory, one could expect some coherence when blending the above
00789    // cases. For example we should not encounter files belonging at the
00790    // time to case [Planar 0] and case [Photo D].
00791    // Alas, this was only theory ! Because in practice some odd (read ill
00792    // formated Dicom) files (e.g. gdcmData/US-PAL-8-10x-echo.dcm) we encounter:
00793    //     - "Planar Configuration" = 0,
00794    //     - "Photometric Interpretation" = "PALETTE COLOR".
00795    // Hence gdcm will use the folowing "heuristic" in order to be tolerant
00796    // towards Dicom-non-conformance files:
00797    //   << whatever the "Planar Configuration" value might be, a
00798    //      "Photometric Interpretation" set to "PALETTE COLOR" forces
00799    //      a LUT intervention >>
00800    //
00801    // Now we are left with the following handling of the cases:
00802    // - [Planar 0] OR  [Photo A] no color decoding (since respectively
00803    //       Pixels are already RGB and monochrome pictures have no color :),
00804    // - [Planar 1] AND [Photo B] handled with ConvertRGBPlanesToRGBPixels()
00805    // - [Planar 1] AND [Photo C] handled with ConvertYcBcRPlanesToRGBPixels()
00806    // - [Planar 2] OR  [Photo D] requires LUT intervention.
00807 
00808    if ( ! IsRawRGB() )
00809    {
00810       // [Planar 2] OR  [Photo D]: LUT intervention done outside
00811       return;
00812    }
00813                                                                                 
00814    if ( PlanarConfiguration == 1 )
00815    {
00816       if ( IsYBRFull )
00817       {
00818          // [Planar 1] AND [Photo C] (remember YBR_FULL_422 acts as RGB)
00819          ConvertYcBcRPlanesToRGBPixels();
00820       }
00821       else
00822       {
00823          // [Planar 1] AND [Photo C]
00824          ConvertRGBPlanesToRGBPixels();
00825       }
00826       return;
00827    }
00828                                                                                 
00829    // When planarConf is 0, and RLELossless (forbidden by Dicom norm)
00830    // pixels need to be RGB-fied anyway
00831    if (IsRLELossless)
00832    {
00833      ConvertRGBPlanesToRGBPixels();
00834    }
00835    // In *normal *case, when planarConf is 0, pixels are already in RGB
00836 }
00837 
00839 void PixelReadConvert::ComputeRawAndRGBSizes()
00840 {
00841    int bitsAllocated = BitsAllocated;
00842    // Number of "Bits Allocated" is fixed to 16 when it's 12, since
00843    // in this case we will expand the image to 16 bits (see
00844    //    \ref ReadAndDecompress12BitsTo16Bits() )
00845    if (  BitsAllocated == 12 )
00846    {
00847       bitsAllocated = 16;
00848    }
00849                                                                                 
00850    RawSize =  XSize * YSize * ZSize
00851                      * ( bitsAllocated / 8 )
00852                      * SamplesPerPixel;
00853    if ( HasLUT )
00854    {
00855       RGBSize = 3 * RawSize;
00856    }
00857    else
00858    {
00859       RGBSize = RawSize;
00860    }
00861 }
00862 
00864 void PixelReadConvert::AllocateRGB()
00865 {
00866   if ( RGB )
00867      delete [] RGB;
00868   RGB = new uint8_t[RGBSize];
00869 }
00870 
00872 void PixelReadConvert::AllocateRaw()
00873 {
00874   if ( Raw )
00875      delete [] Raw;
00876   Raw = new uint8_t[RawSize];
00877 }
00878 
00879 //-----------------------------------------------------------------------------
00880 // Print
00886 void PixelReadConvert::Print( std::ostream &os, std::string const &indent )
00887 {
00888    os << indent
00889       << "--- Pixel information -------------------------"
00890       << std::endl;
00891    os << indent
00892       << "Pixel Data: offset " << PixelOffset
00893       << " x(" << std::hex << PixelOffset << std::dec
00894       << ")   length " << PixelDataLength
00895       << " x(" << std::hex << PixelDataLength << std::dec
00896       << ")" << std::endl;
00897 
00898    if ( IsRLELossless )
00899    {
00900       if ( RLEInfo )
00901       {
00902          RLEInfo->Print( os, indent );
00903       }
00904       else
00905       {
00906          gdcmWarningMacro("Set as RLE file but NO RLEinfo present.");
00907       }
00908    }
00909 
00910    if ( IsJPEG2000 || IsJPEGLossless || IsJPEGLossy || IsJPEGLS )
00911    {
00912       if ( JPEGInfo )
00913       {
00914          JPEGInfo->Print( os, indent );
00915       }
00916       else
00917       {
00918          gdcmWarningMacro("Set as JPEG file but NO JPEGinfo present.");
00919       }
00920    }
00921 }
00922 
00923 //-----------------------------------------------------------------------------
00924 } // end namespace gdcm
00925 
00926 // NOTES on File internal calls
00927 // User
00928 // ---> GetImageData
00929 //     ---> GetImageDataIntoVector
00930 //        |---> GetImageDataIntoVectorRaw
00931 //        | lut intervention
00932 // User
00933 // ---> GetImageDataRaw
00934 //     ---> GetImageDataIntoVectorRaw
00935 

Generated on Thu Feb 10 22:17:59 2005 for gdcm by doxygen 1.3.6