gdcmFileHelper.cxx

Go to the documentation of this file.
00001 /*=========================================================================
00002                                                                                 
00003   Program:   gdcm
00004   Module:    $RCSfile: gdcmFileHelper.cxx,v $
00005   Language:  C++
00006 
00007   Date:      $Date: 2007/08/24 10:45:18 $
00008   Version:   $Revision: 1.121 $
00009                                                                                 
00010   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
00011   l'Image). All rights reserved. See Doc/License.txt or
00012   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
00013                                                                                 
00014      This software is distributed WITHOUT ANY WARRANTY; without even
00015      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00016      PURPOSE.  See the above copyright notices for more information.
00017                                                                                 
00018 =========================================================================*/
00019 
00020 #include "gdcmFileHelper.h"
00021 #include "gdcmGlobal.h"
00022 #include "gdcmTS.h"
00023 #include "gdcmDocument.h"
00024 #include "gdcmDebug.h"
00025 #include "gdcmUtil.h"
00026 #include "gdcmSeqEntry.h"
00027 #include "gdcmSQItem.h"
00028 #include "gdcmDataEntry.h"
00029 #include "gdcmDocEntry.h"
00030 #include "gdcmFile.h"
00031 #include "gdcmPixelReadConvert.h"
00032 #include "gdcmPixelWriteConvert.h"
00033 #include "gdcmDocEntryArchive.h"
00034 #include "gdcmDictSet.h"
00035 #include "gdcmOrientation.h"
00036  
00037 #if defined(__BORLANDC__)
00038    #include <mem.h> // for memset
00039 #endif 
00040 
00041 #include <fstream>
00042 
00043 /*
00044 // ----------------------------- WARNING -------------------------
00045 
00046 These lines will be moved to the document-to-be 'User's Guide'
00047 
00048 // To read an image, user needs a gdcm::File
00049 gdcm::File *f = new gdcm::File(fileName);
00050 // or (advanced) :
00051 // user may also decide he doesn't want to load some parts of the header
00052 gdcm::File *f = new gdcm::File();
00053 f->SetFileName(fileName);
00054    f->SetLoadMode(LD_NOSEQ);               // or      
00055    f->SetLoadMode(LD_NOSHADOW);            // or
00056    f->SetLoadMode(LD_NOSEQ | LD_NOSHADOW); // or
00057    f->SetLoadMode(LD_NOSHADOWSEQ);
00058 f->Load();
00059 
00060 // To decide whether it's an 'image of interest for him, or not,
00061 // user can now check some values
00062 std::string v = f->GetEntryValue(groupNb,ElementNb);
00063 
00064 // to get the pixels, user needs a gdcm::FileHelper
00065 gdcm::FileHelper *fh = new gdcm::FileHelper(f);
00066 
00067 // user may ask not to convert Palette (if any) to RGB
00068 uint8_t *pixels = fh->GetImageDataRaw();
00069 int imageLength = fh->GetImageDataRawSize();
00070 
00071 // He can now use the pixels, create a new image, ...
00072 uint8_t *userPixels = ...
00073 
00074 //To re-write the image, user re-uses the gdcm::FileHelper
00075 gdcm::File *fh = new gdcm::FileHelper();
00076 
00077 fh->SetTypeToRaw(); // Even if it was possible to convert Palette to RGB
00078                     // (WriteMode is set)
00079 
00080 // If user wants to write the file as MONOCHROME1 (0=white)
00081 fh->SetPhotometricInterpretationToMonochrome1();
00082 
00083 fh->SetWriteTypeToDcmExpl();  // he wants Explicit Value Representation
00084                               // Little Endian is the default,
00085                               // bigendian not supported for writting
00086                                 (-->SetWriteType(ExplicitVR);)
00087                                    -->WriteType = ExplicitVR;
00088 fh->SetWriteTypeToJPEG();     // lossless compression   
00089 fh->SetWriteTypeToJPEG2000(); // lossless compression   
00090 
00091 fh->SetImageData( userPixels, userPixelsLength);
00092 or
00093 fh->SetUserData( userPixels, userPixelsLength); // this one performs compression, when required
00094    
00095 fh->Write(newFileName);      // overwrites the file, if any
00096 
00097 
00098 
00099 
00100 // ----------------------------- WARNING -------------------------
00101 
00102 These lines will be moved to the document-to-be 'Developer's Guide'
00103 
00104 WriteMode : WMODE_RAW / WMODE_RGB
00105 WriteType : ImplicitVR, ExplicitVR, ACR, ACR_LIBIDO
00106 PhotometricInterpretation : MONOCHROME2 (0=black), MONOCHROME2 (0=white)
00107 
00108 
00109 fh->SetWriteMode(WMODE_RAW / WMODE_RGB)
00110 
00111 fh->SetWriteType( ImplicitVR/ExplicitVR/ACR/ACR_LIBIDO/JPEG/JPEG2000)
00112       
00113 fh->Write(newFileName);
00114    CheckMandatoryElements(); // Checks existing ones / Add missing ones
00115    Fix VR if unknown elements
00116    SetWriteFileTypeToImplicitVR() / SetWriteFileTypeToExplicitVR(); /
00117    SetWriteFileTypeToACR() / SetWriteFileTypeToJPEG() / SetWriteFileTypeToJ2K()
00118       (Modifies TransferSyntax if any; Pushes to the Archives old one)
00119    SetWriteToRaw(); / SetWriteToRGB();
00120       (Modifies and pushes to the Archive, when necessary : photochr. interp., 
00121        samples per pixel, Planar configuration, 
00122        bits allocated, bits stored, high bit -ACR 24 bits-
00123        Pixels element VR, pushes out the LUT )
00124           SetWriteToRaw()
00125              Sets Photometric Interpretation
00126              DataEntry *pixel =CopyDataEntry(7fe0,0010,VR)
00127              Sets VR, BinArea, Length for PixelData
00128              if MONOCHROME1
00129                 ConvertFixGreyLevels
00130              Archive->Push(photInt);
00131              Archive->Push(pixel);
00132              photInt->Delete();
00133              pixel->Delete();
00134         SetWriteToRGB()
00135            if NumberOfScalarComponents==1
00136               SetWriteToRaw(); return;
00137            PixelReadConverter->BuildRGBImage()
00138            DataEntry *pixel =CopyDataEntry(7fe0,0010,VR)
00139            Archives spp, planConfig,photInt, pixel
00140            Pushes out any LUT               
00141    CheckWriteIntegrity();
00142       (checks user given pixels length)
00143    FileInternal->Write(fileName,WriteType)
00144       fp = opens file(fileName); // out|binary
00145       ComputeGroup0002Length( );
00146       Document::WriteContent(fp, writetype);
00147          writes Dicom File Preamble not ACR-NEMA
00148          ElementSet::WriteContent(fp, writetype);
00149             writes recursively all DataElements    
00150    RestoreWrite();
00151          (moves back to the gdcm::File all the archived elements)
00152 */
00153 
00154 
00155 
00156 
00157 namespace GDCM_NAME_SPACE 
00158 {
00159 typedef std::map<uint16_t, int> GroupHT;    //  Hash Table
00160 //-------------------------------------------------------------------------
00161 // Constructor / Destructor
00175 FileHelper::FileHelper( )
00176 { 
00177    FileInternal = File::New( );
00178    Initialize();
00179 }
00180 
00195 FileHelper::FileHelper(File *header)
00196 {
00197    gdcmAssertMacro(header);
00198 
00199    FileInternal = header;
00200    FileInternal->Register();
00201    Initialize();
00202    if ( FileInternal->IsReadable() )
00203    {
00204       PixelReadConverter->GrabInformationsFromFile( FileInternal, this );
00205    }
00206 }
00207 
00213 FileHelper::~FileHelper()
00214 { 
00215    if ( PixelReadConverter )
00216    {
00217       delete PixelReadConverter;
00218    }
00219    if ( PixelWriteConverter )
00220    {
00221       delete PixelWriteConverter;
00222    }
00223    if ( Archive )
00224    {
00225       delete Archive;
00226    }
00227 
00228    FileInternal->Unregister();
00229 }
00230 
00231 //-----------------------------------------------------------------------------
00232 // Public
00233 
00242 void FileHelper::SetLoadMode(int loadMode) 
00243 { 
00244    GetFile()->SetLoadMode( loadMode ); 
00245 }
00250 void FileHelper::SetFileName(std::string const &fileName)
00251 {
00252    FileInternal->SetFileName( fileName );
00253 }
00254 
00260 bool FileHelper::Load()
00261 { 
00262    if ( !FileInternal->Load() )
00263       return false;
00264 
00265    PixelReadConverter->GrabInformationsFromFile( FileInternal, this );
00266    return true;
00267 }
00268 
00277 bool FileHelper::SetEntryString(std::string const &content,
00278                                 uint16_t group, uint16_t elem)
00279 { 
00280    return FileInternal->SetEntryString(content, group, elem);
00281 }
00282 
00283 
00293 bool FileHelper::SetEntryBinArea(uint8_t *content, int lgth,
00294                                  uint16_t group, uint16_t elem)
00295 {
00296    return FileInternal->SetEntryBinArea(content, lgth, group, elem);
00297 }
00298 
00309 DataEntry *FileHelper::InsertEntryString(std::string const &content,
00310                                          uint16_t group, uint16_t elem,
00311                                          VRKey const &vr )
00312 {
00313    return FileInternal->InsertEntryString(content, group, elem, vr);
00314 }
00315 
00328 DataEntry *FileHelper::InsertEntryBinArea(uint8_t *binArea, int lgth,
00329                                           uint16_t group, uint16_t elem,
00330                                           VRKey const &vr )
00331 {
00332    return FileInternal->InsertEntryBinArea(binArea, lgth, group, elem, vr);
00333 }
00334 
00343 SeqEntry *FileHelper::InsertSeqEntry(uint16_t group, uint16_t elem)
00344 {
00345    return FileInternal->InsertSeqEntry(group, elem);
00346 }
00347 
00356 size_t FileHelper::GetImageDataSize()
00357 {
00358    if ( PixelWriteConverter->GetUserData() )
00359    {
00360       return PixelWriteConverter->GetUserDataSize();
00361    }
00362    return PixelReadConverter->GetRGBSize();
00363 }
00364 
00372 size_t FileHelper::GetImageDataRawSize()
00373 {
00374    if ( PixelWriteConverter->GetUserData() )
00375    {
00376       return PixelWriteConverter->GetUserDataSize();
00377    }
00378    return PixelReadConverter->GetRawSize();
00379 }
00380 
00393 uint8_t *FileHelper::GetImageData()
00394 {
00395    if ( PixelWriteConverter->GetUserData() )
00396    {
00397       return PixelWriteConverter->GetUserData();
00398    }
00399 
00400    if ( ! GetRaw() )
00401    {
00402       // If the decompression failed nothing can be done.
00403       return 0;
00404    }
00405 
00406    if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
00407    {
00408       return PixelReadConverter->GetRGB();
00409    }
00410    else
00411    {
00412       // When no LUT or LUT conversion fails, return the Raw
00413       return PixelReadConverter->GetRaw();
00414    }
00415 }
00416 
00428 uint8_t *FileHelper::GetImageDataRaw ()
00429 {
00430    return GetRaw();
00431 }
00432 
00433 //#ifndef GDCM_LEGACY_REMOVE
00434 /*
00435  * \brief   Useless function, since PixelReadConverter forces us 
00436  *          copy the Pixels anyway.  
00437  *          Reads the pixels from disk (uncompress if necessary),
00438  *          Transforms YBR pixels, if any, into RGB pixels
00439  *          Transforms 3 planes R, G, B, if any, into a single RGB Plane
00440  *          Transforms single Grey plane + 3 Palettes into a RGB Plane   
00441  *          Copies at most MaxSize bytes of pixel data to caller allocated
00442  *          memory space.
00443  * \warning This function allows people that want to build a volume
00444  *          from an image stack *not to* have, first to get the image pixels, 
00445  *          and then move them to the volume area.
00446  *          It's absolutely useless for any VTK user since vtk chooses 
00447  *          to invert the lines of an image, that is the last line comes first
00448  *          (for some axis related reasons?). Hence he will have 
00449  *          to load the image line by line, starting from the end.
00450  *          VTK users have to call GetImageData
00451  *     
00452  * @param   destination Address (in caller's memory space) at which the
00453  *          pixel data should be copied
00454  * @param   maxSize Maximum number of bytes to be copied. When MaxSize
00455  *          is not sufficient to hold the pixel data the copy is not
00456  *          executed (i.e. no partial copy).
00457  * @return  On success, the number of bytes actually copied. Zero on
00458  *          failure e.g. MaxSize is lower than necessary.
00459  */
00460  /*
00461 size_t FileHelper::GetImageDataIntoVector (void *destination, size_t maxSize)
00462 {
00463    if ( ! GetRaw() )
00464    {
00465       // If the decompression failed nothing can be done.
00466       return 0;
00467    }
00468 
00469    if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
00470    {
00471       if ( PixelReadConverter->GetRGBSize() > maxSize )
00472       {
00473          gdcmWarningMacro( "Pixel data bigger than caller's expected MaxSize");
00474          return 0;
00475       }
00476       memcpy( destination,
00477               (void*)PixelReadConverter->GetRGB(),
00478               PixelReadConverter->GetRGBSize() );
00479       return PixelReadConverter->GetRGBSize();
00480    }
00481 
00482    // Either no LUT conversion necessary or LUT conversion failed
00483    if ( PixelReadConverter->GetRawSize() > maxSize )
00484    {
00485       gdcmWarningMacro( "Pixel data bigger than caller's expected MaxSize");
00486       return 0;
00487    }
00488    memcpy( destination,
00489            (void *)PixelReadConverter->GetRaw(),
00490            PixelReadConverter->GetRawSize() );
00491    return PixelReadConverter->GetRawSize();
00492 }
00493 */
00494 //#endif
00495 
00509 void FileHelper::SetImageData(uint8_t *inData, size_t expectedSize)
00510 {
00511    PixelWriteConverter->SetUserData(inData, expectedSize);
00512 }
00513 
00522 void FileHelper::SetUserData(uint8_t *inData, size_t expectedSize)
00523 {
00524    if( WriteType == JPEG2000 )
00525    {
00526       PixelWriteConverter->SetCompressJPEG2000UserData(inData, expectedSize, FileInternal);
00527    }
00528    else if( WriteType == JPEG )
00529    {
00530       PixelWriteConverter->SetCompressJPEGUserData(inData, expectedSize, FileInternal);
00531    }
00532    else
00533    {
00534       PixelWriteConverter->SetUserData(inData, expectedSize);
00535    }
00536 }
00537 
00542 uint8_t *FileHelper::GetUserData()
00543 {
00544    return PixelWriteConverter->GetUserData();
00545 }
00546 
00551 size_t FileHelper::GetUserDataSize()
00552 {
00553    return PixelWriteConverter->GetUserDataSize();
00554 }
00555 
00560 uint8_t *FileHelper::GetRGBData()
00561 {
00562    return PixelReadConverter->GetRGB();
00563 }
00564 
00569 size_t FileHelper::GetRGBDataSize()
00570 {
00571    return PixelReadConverter->GetRGBSize();
00572 }
00573 
00578 uint8_t *FileHelper::GetRawData()
00579 {
00580    return PixelReadConverter->GetRaw();
00581 }
00582 
00587 size_t FileHelper::GetRawDataSize()
00588 {
00589    return PixelReadConverter->GetRawSize();
00590 }
00591 
00595 uint8_t* FileHelper::GetLutRGBA()
00596 {
00597    if ( PixelReadConverter->GetLutRGBA() ==0 )
00598       PixelReadConverter->BuildLUTRGBA();
00599    return PixelReadConverter->GetLutRGBA();
00600 }
00601 
00605 int FileHelper::GetLutItemNumber()
00606 {
00607    return PixelReadConverter->GetLutItemNumber();
00608 }
00609 
00613 int FileHelper::GetLutItemSize()
00614 {
00615    return PixelReadConverter->GetLutItemSize();
00616 }
00617 
00626 bool FileHelper::WriteRawData(std::string const &fileName)
00627 {
00628    std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary );
00629    if (!fp1)
00630    {
00631       gdcmWarningMacro( "Fail to open (write) file:" << fileName.c_str());
00632       return false;
00633    }
00634 
00635    if ( PixelWriteConverter->GetUserData() )
00636    {
00637       fp1.write( (char *)PixelWriteConverter->GetUserData(), 
00638                  PixelWriteConverter->GetUserDataSize() );
00639    }
00640    else if ( PixelReadConverter->GetRGB() )
00641    {
00642       fp1.write( (char *)PixelReadConverter->GetRGB(), 
00643                  PixelReadConverter->GetRGBSize());
00644    }
00645    else if ( PixelReadConverter->GetRaw() )
00646    {
00647       fp1.write( (char *)PixelReadConverter->GetRaw(), 
00648                  PixelReadConverter->GetRawSize());
00649    }
00650    else
00651    {
00652       gdcmErrorMacro( "Nothing written." );
00653    }
00654 
00655    fp1.close();
00656 
00657    return true;
00658 }
00659 
00669 bool FileHelper::WriteDcmImplVR (std::string const &fileName)
00670 {
00671    SetWriteTypeToDcmImplVR();
00672    return Write(fileName);
00673 }
00674 
00684 bool FileHelper::WriteDcmExplVR (std::string const &fileName)
00685 {
00686    SetWriteTypeToDcmExplVR();
00687    return Write(fileName);
00688 }
00689 
00704 bool FileHelper::WriteAcr (std::string const &fileName)
00705 {
00706    SetWriteTypeToAcr();
00707    return Write(fileName);
00708 }
00709 
00716 bool FileHelper::Write(std::string const &fileName)
00717 { 
00718    CheckMandatoryElements(); //called once, here !
00719    
00720    bool flag = false;
00721    DocEntry *e;   
00722    switch(WriteType)
00723    {
00724       case ImplicitVR:
00725          SetWriteFileTypeToImplicitVR();
00726          break;
00727  
00728       case Unknown:  // should never happen; ExplicitVR is the default value
00729       case ExplicitVR:
00730 
00731    // User should ask gdcm to write an image in Explicit VR mode
00732    // only when he is sure *all* the VR of *all* the DataElements is known.
00733    // i.e : when there are *only* Public Groups
00734    // or *all* the Shadow Groups are fully described in the relevant Shadow
00735    // Dictionnary
00736    // Let's just *dream* about it; *never* trust a user !
00737    // We turn to Implicit VR if at least the VR of one element is unknown.
00738    
00739    // Better we let DocEntry::WriteContent to put vr=UN for undocumented Shadow Groups !
00740 
00741 /*
00742          e = FileInternal->GetFirstEntry();
00743          while (e != 0)
00744          {
00745             if (e->GetVR() == "  ")  
00746             {
00747                SetWriteTypeToDcmImplVR();
00748                SetWriteFileTypeToImplicitVR();
00749                flag = true;
00750                break;         
00751             } 
00752             e = FileInternal->GetNextEntry();
00753          }        
00754 
00755          if (!flag)
00756          {
00757             SetWriteFileTypeToExplicitVR();
00758          }
00759          break;
00760 */
00761 
00762          SetWriteFileTypeToExplicitVR();
00763 
00764   break;
00765       case ACR:
00766       case ACR_LIBIDO:
00767       // NOTHING is done here just for LibIDO.
00768       // Just to avoid further trouble if user creates a file ex-nihilo,
00769       // wants to write it as an ACR-NEMA file,
00770       // and forgets to create any Entry belonging to group 0008
00771       // (shame on him !)
00772       // We add Recognition Code (RET)
00773         if ( ! FileInternal->GetDataEntry(0x0008, 0x0010) )
00774             FileInternal->InsertEntryString("ACR-NEMA V1.0 ", 
00775                                              0x0008, 0x0010, "LO");
00776          SetWriteFileTypeToACR();
00777         // SetWriteFileTypeToImplicitVR(); // ACR IS implicit VR !
00778          break;
00779  
00781       case JPEG:
00782          SetWriteFileTypeToJPEG();
00783          break;
00784 
00785       case JPEG2000:
00786          SetWriteFileTypeToJPEG2000();
00787          break;
00788    }
00789 
00790    // --------------------------------------------------------------
00791    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
00792    //
00793    // if recognition code tells us we dealt with a LibIDO image
00794    // we reproduce on disk the switch between lineNumber and columnNumber
00795    // just before writting ...
00798    
00799    if ( WriteType == ACR_LIBIDO )
00800    {
00801       SetWriteToLibido();
00802    }
00803    else
00804    {
00805       SetWriteToNoLibido();
00806    }
00807    // ----------------- End of Special Patch ----------------
00808   
00809    switch(WriteMode)
00810    {
00811       case WMODE_RAW :
00812          SetWriteToRaw(); // modifies and pushes to the archive, when necessary
00813          break;
00814       case WMODE_RGB :
00815          SetWriteToRGB(); // modifies and pushes to the archive, when necessary
00816          break;
00817    }
00818 
00819    bool check;
00820    if (WriteType == JPEG || WriteType == JPEG2000)
00821       check = true;
00822    else
00823       check = CheckWriteIntegrity(); // verifies length
00824 
00825    if (check)
00826    {
00827       check = FileInternal->Write(fileName,WriteType);
00828    }
00829 
00830    RestoreWrite();
00831   // RestoreWriteFileType();
00832   // RestoreWriteMandatory();
00833 
00834    // --------------------------------------------------------------
00835    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
00836    // 
00837    // ...and we restore the header to be Dicom Compliant again 
00838    // just after writting
00839    RestoreWriteOfLibido();
00840    // ----------------- End of Special Patch ----------------
00841 
00842    return check;
00843 }
00844 
00845 //-----------------------------------------------------------------------------
00846 // Protected
00851 bool FileHelper::CheckWriteIntegrity()
00852 {
00853    if ( PixelWriteConverter->GetUserData() )
00854    {
00855       int numberBitsAllocated = FileInternal->GetBitsAllocated();
00856       if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
00857       {
00858          gdcmWarningMacro( "numberBitsAllocated changed from " 
00859                           << numberBitsAllocated << " to 16 " 
00860                           << " for consistency purpose" );
00861          numberBitsAllocated = 16;
00862       }
00863 
00864       size_t decSize = FileInternal->GetXSize()
00865                      * FileInternal->GetYSize() 
00866                      * FileInternal->GetZSize()
00867                      * FileInternal->GetTSize()     
00868                      * FileInternal->GetSamplesPerPixel()
00869                      * ( numberBitsAllocated / 8 );
00870       size_t rgbSize = decSize;
00871       if ( FileInternal->HasLUT() )
00872          rgbSize = decSize * 3;
00873 
00874       switch(WriteMode)
00875       {
00876          case WMODE_RAW :
00877             if ( decSize!=PixelWriteConverter->GetUserDataSize() )
00878             {
00879                gdcmWarningMacro( "Data size (Raw) is incorrect. Should be " 
00880                            << decSize << " / Found :" 
00881                            << PixelWriteConverter->GetUserDataSize() );
00882                return false;
00883             }
00884             break;
00885          case WMODE_RGB :
00886             if ( rgbSize!=PixelWriteConverter->GetUserDataSize() )
00887             {
00888                gdcmWarningMacro( "Data size (RGB) is incorrect. Should be " 
00889                           << decSize << " / Found " 
00890                           << PixelWriteConverter->GetUserDataSize() );
00891                return false;
00892             }
00893             break;
00894       }
00895    }
00896    return true;
00897 }
00898 
00906 void FileHelper::SetWriteToRaw()
00907 {
00908    if ( FileInternal->GetNumberOfScalarComponents() == 3 
00909     && !FileInternal->HasLUT() )
00910    {
00911       SetWriteToRGB();
00912    } 
00913    else
00914    {
00915       // 0x0028,0x0004 : Photometric Interpretation
00916       DataEntry *photInt = CopyDataEntry(0x0028,0x0004,"CS");
00917       if (FileInternal->HasLUT() )
00918       {
00919          photInt->SetString("PALETTE COLOR ");
00920       }
00921       else
00922       {
00923          if (GetPhotometricInterpretation() == 2)
00924             photInt->SetString("MONOCHROME2 ");  // 0 = Black
00925          else
00926             photInt->SetString("MONOCHROME1 ");  // 0 = White !
00927       }
00928 
00929       PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
00930                                        PixelReadConverter->GetRawSize());
00931 
00932       std::string vr = "OB";
00933       if ( FileInternal->GetBitsAllocated()>8 )
00934          vr = "OW";
00935       if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files 
00936          vr = "OB";
00937        // For non RAW data. Mainly JPEG
00938       if( WriteType == JPEG || WriteType == JPEG2000)
00939       {
00940          vr = "OW";
00941       }
00942 
00943       DataEntry *pixel = 
00944          CopyDataEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr);
00945       pixel->SetFlag(DataEntry::FLAG_PIXELDATA);
00946       pixel->SetBinArea(PixelWriteConverter->GetData(),false);
00947       pixel->SetLength(
00948          static_cast< uint32_t >(PixelWriteConverter->GetDataSize()) );
00949 
00950       if (!FileInternal->HasLUT() && GetPhotometricInterpretation() == 1)
00951       {
00952           ConvertFixGreyLevels( pixel->GetBinArea(), pixel->GetLength() );
00953       }
00954 
00955       Archive->Push(photInt);
00956       Archive->Push(pixel);
00957 
00958       photInt->Delete();
00959       pixel->Delete();
00960    }
00961 }
00962 
00970 void FileHelper::SetWriteToRGB()
00971 {
00972    if ( FileInternal->GetNumberOfScalarComponents()==3 )
00973    {
00974       PixelReadConverter->BuildRGBImage();
00975       
00976       DataEntry *spp = CopyDataEntry(0x0028,0x0002,"US");
00977       spp->SetString("3 ");
00978 
00979       DataEntry *planConfig = CopyDataEntry(0x0028,0x0006,"US");
00980       planConfig->SetString("0 ");
00981 
00982       DataEntry *photInt = CopyDataEntry(0x0028,0x0004,"CS");
00983       photInt->SetString("RGB ");
00984 
00985       if ( PixelReadConverter->GetRGB() )
00986       {
00987          PixelWriteConverter->SetReadData(PixelReadConverter->GetRGB(),
00988                                           PixelReadConverter->GetRGBSize());
00989       }
00990       else // Raw data
00991       {
00992          PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
00993                                           PixelReadConverter->GetRawSize());
00994       }
00995 
00996       std::string vr = "OB";
00997       if ( FileInternal->GetBitsAllocated()>8 )
00998          vr = "OW";
00999       if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files 
01000          vr = "OB";
01001       DataEntry *pixel = 
01002          CopyDataEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr);
01003       pixel->SetFlag(DataEntry::FLAG_PIXELDATA);
01004       pixel->SetBinArea(PixelWriteConverter->GetData(),false);
01005       pixel->SetLength(PixelWriteConverter->GetDataSize());
01006 
01007       Archive->Push(spp);
01008       Archive->Push(planConfig);
01009       Archive->Push(photInt);
01010       Archive->Push(pixel);
01011 
01012       spp->Delete();
01013       planConfig->Delete();
01014       photInt->Delete();
01015       pixel->Delete();
01016 
01017       // Remove any LUT
01018       Archive->Push(0x0028,0x1101);
01019       Archive->Push(0x0028,0x1102);
01020       Archive->Push(0x0028,0x1103);
01021       Archive->Push(0x0028,0x1201);
01022       Archive->Push(0x0028,0x1202);
01023       Archive->Push(0x0028,0x1203);
01024 
01025       // push out Palette Color Lookup Table UID, if any
01026       Archive->Push(0x0028,0x1199);
01027 
01028       // For old '24 Bits' ACR-NEMA
01029       // Thus, we have a RGB image and the bits allocated = 24 and 
01030       // samples per pixels = 1 (in the read file)
01031       if ( FileInternal->GetBitsAllocated()==24 ) 
01032       {
01033          DataEntry *bitsAlloc = CopyDataEntry(0x0028,0x0100,"US");
01034          bitsAlloc->SetString("8 ");
01035 
01036          DataEntry *bitsStored = CopyDataEntry(0x0028,0x0101,"US");
01037          bitsStored->SetString("8 ");
01038 
01039          DataEntry *highBit = CopyDataEntry(0x0028,0x0102,"US");
01040          highBit->SetString("7 ");
01041 
01042          Archive->Push(bitsAlloc);
01043          Archive->Push(bitsStored);
01044          Archive->Push(highBit);
01045 
01046          bitsAlloc->Delete();
01047          bitsStored->Delete();
01048          highBit->Delete();
01049       }
01050    }
01051    else
01052    {
01053       SetWriteToRaw();
01054    }
01055 }
01056 
01060 void FileHelper::RestoreWrite()
01061 {
01062    Archive->Restore(0x0028,0x0002);
01063    Archive->Restore(0x0028,0x0004);
01064    
01065    Archive->Restore(0x0028,0x0006);
01066    Archive->Restore(GetFile()->GetGrPixel(),GetFile()->GetNumPixel());
01067 
01068    // For old ACR-NEMA (24 bits problem)
01069    Archive->Restore(0x0028,0x0100);
01070    Archive->Restore(0x0028,0x0101);
01071    Archive->Restore(0x0028,0x0102);
01072 
01073    // For the LUT
01074    Archive->Restore(0x0028,0x1101);
01075    Archive->Restore(0x0028,0x1102);
01076    Archive->Restore(0x0028,0x1103);
01077    Archive->Restore(0x0028,0x1201);
01078    Archive->Restore(0x0028,0x1202);
01079    Archive->Restore(0x0028,0x1203);
01080 
01081    // For the Palette Color Lookup Table UID
01082    Archive->Restore(0x0028,0x1203); 
01083 
01084    // group 0002 may be pushed out for ACR-NEMA writting purposes 
01085    Archive->Restore(0x0002,0x0000);
01086    Archive->Restore(0x0002,0x0001);
01087    Archive->Restore(0x0002,0x0002);
01088    Archive->Restore(0x0002,0x0003);
01089    Archive->Restore(0x0002,0x0010);
01090    Archive->Restore(0x0002,0x0012);
01091    Archive->Restore(0x0002,0x0013);
01092    Archive->Restore(0x0002,0x0016);
01093    Archive->Restore(0x0002,0x0100);
01094    Archive->Restore(0x0002,0x0102);
01095 
01096 }
01097 
01105 void FileHelper::SetWriteFileTypeToACR()
01106 {
01107    Archive->Push(0x0002,0x0000);
01108    Archive->Push(0x0002,0x0001);
01109    Archive->Push(0x0002,0x0002);
01110    Archive->Push(0x0002,0x0003);
01111    Archive->Push(0x0002,0x0010);
01112    Archive->Push(0x0002,0x0012);
01113    Archive->Push(0x0002,0x0013);
01114    Archive->Push(0x0002,0x0016);
01115    Archive->Push(0x0002,0x0100);
01116    Archive->Push(0x0002,0x0102);
01117 }
01118 
01122 void FileHelper::SetWriteFileTypeToJPEG2000()
01123 {
01124    std::string ts = Util::DicomString(
01125    Global::GetTS()->GetSpecialTransferSyntax(TS::JPEG2000Lossless) );
01126 
01127    DataEntry *tss = CopyDataEntry(0x0002,0x0010,"UI");
01128    tss->SetString(ts);
01129 
01130    Archive->Push(tss);
01131    tss->Delete();   
01132 }
01133 
01137 void FileHelper::SetWriteFileTypeToJPEG()
01138 {
01139    std::string ts = Util::DicomString(
01140       Global::GetTS()->GetSpecialTransferSyntax(TS::JPEGLosslessProcess14_1) );
01141 
01142    DataEntry *tss = CopyDataEntry(0x0002,0x0010,"UI");
01143    tss->SetString(ts);
01144 
01145    Archive->Push(tss);
01146    tss->Delete();
01147 }
01148 
01152 void FileHelper::SetWriteFileTypeToExplicitVR()
01153 {
01154    std::string ts = Util::DicomString( 
01155       Global::GetTS()->GetSpecialTransferSyntax(TS::ExplicitVRLittleEndian) );
01156 
01157    DataEntry *tss = CopyDataEntry(0x0002,0x0010,"UI");
01158    tss->SetString(ts);
01159    Archive->Push(tss);
01160    tss->Delete();
01161 }
01162 
01166 void FileHelper::SetWriteFileTypeToImplicitVR()
01167 {
01168    std::string ts = Util::DicomString(
01169       Global::GetTS()->GetSpecialTransferSyntax(TS::ImplicitVRLittleEndian) );
01170 
01171    DataEntry *tss = CopyDataEntry(0x0002,0x0010,"UI");
01172    tss->SetString(ts);
01173    Archive->Push(tss);
01174    tss->Delete();
01175 }
01176 
01180 void FileHelper::SetWriteToLibido()
01181 {
01182    DataEntry *oldRow = FileInternal->GetDataEntry(0x0028, 0x0010);
01183    DataEntry *oldCol = FileInternal->GetDataEntry(0x0028, 0x0011);
01184    
01185    if ( oldRow && oldCol )
01186    {
01187       std::string rows, columns; 
01188 
01189       DataEntry *newRow=DataEntry::New(0x0028, 0x0010, "US");
01190       DataEntry *newCol=DataEntry::New(0x0028, 0x0011, "US");
01191 
01192       newRow->Copy(oldCol);
01193       newCol->Copy(oldRow);
01194 
01195       newRow->SetString(oldCol->GetString());
01196       newCol->SetString(oldRow->GetString());
01197 
01198       Archive->Push(newRow);
01199       Archive->Push(newCol);
01200 
01201       newRow->Delete();
01202       newCol->Delete();
01203    }
01204 
01205    DataEntry *libidoCode = CopyDataEntry(0x0008,0x0010,"LO");
01206    libidoCode->SetString("ACRNEMA_LIBIDO_1.1");
01207    Archive->Push(libidoCode);
01208    libidoCode->Delete();
01209 }
01210 
01214 void FileHelper::SetWriteToNoLibido()
01215 {
01216    DataEntry *recCode = FileInternal->GetDataEntry(0x0008,0x0010);
01217    if ( recCode )
01218    {
01219       if ( recCode->GetString() == "ACRNEMA_LIBIDO_1.1" )
01220       {
01221          DataEntry *libidoCode = CopyDataEntry(0x0008,0x0010,"LO");
01222          libidoCode->SetString("");
01223          Archive->Push(libidoCode);
01224          libidoCode->Delete();
01225       }
01226    }
01227 }
01228 
01232 void FileHelper::RestoreWriteOfLibido()
01233 {
01234    Archive->Restore(0x0028,0x0010);
01235    Archive->Restore(0x0028,0x0011);
01236    Archive->Restore(0x0008,0x0010);
01237 
01238    // Restore 'LibIDO-special' entries, if any
01239    Archive->Restore(0x0028,0x0015);
01240    Archive->Restore(0x0028,0x0016);
01241    Archive->Restore(0x0028,0x0017);
01242    Archive->Restore(0x0028,0x00199);
01243 }
01244 
01252 DataEntry *FileHelper::CopyDataEntry(uint16_t group, uint16_t elem,
01253                                    const VRKey &vr)
01254 {
01255    DocEntry *oldE = FileInternal->GetDocEntry(group, elem);
01256    DataEntry *newE;
01257 
01258    if ( oldE && vr != GDCM_VRUNKNOWN ) 
01259       if ( oldE->GetVR() != vr )
01260          oldE = NULL;
01261 
01262    if ( oldE )
01263    {
01264       newE = DataEntry::New(group, elem, vr);
01265       newE->Copy(oldE);
01266    }
01267    else
01268    {
01269       newE = GetFile()->NewDataEntry(group, elem, vr);
01270    }
01271 
01272    return newE;
01273 }
01274 
01311 /* -------------------------------------------------------------------------------------
01312 To be moved to User's guide / WIKI  ?
01313 
01314 We have to deal with 4 *very* different cases :
01315 -1) user created ex nihilo his own image and wants to write it as a Dicom image.
01316     USER_OWN_IMAGE
01317 -2) user modified the pixels of an existing image.
01318    FILTERED_IMAGE
01319 -3) user created a new image, using a set of existing images (eg MIP, MPR, cartography image)
01320    CREATED_IMAGE
01321 -4) user modified/added some tags *without processing* the pixels (anonymization...)
01322    UNMODIFIED_PIXELS_IMAGE
01323 -Probabely some more to be added.
01324  
01325 gdcm::FileHelper::CheckMandatoryElements() deals automatically with these cases.
01326 
01327 1)2)3)4)
01328 0008 0012 Instance Creation Date
01329 0008 0013 Instance Creation Time
01330 0008 0018 SOP Instance UID
01331 are *always* created with the current values; user has *no* possible intervention on
01332 them.
01333 
01334 'Serie Instance UID'(0x0020,0x000e)
01335 'Study Instance UID'(0x0020,0x000d) are kept as is if already exist,
01336                                     created  if it doesn't.
01337  The user is allowed to create his own Series/Studies, 
01338      keeping the same 'Serie Instance UID' / 'Study Instance UID' for various images
01339  Warning :     
01340  The user shouldn't add any image to a 'Manufacturer Serie'
01341      but there is no way no to allow him to do that
01342      
01343  None of the 'shadow elements' are droped out.
01344      
01345 
01346 1)
01347 'Conversion Type (0x0008,0x0064) is forced to 'SYN' (Synthetic Image).
01348  
01349 1)3)
01350 'Media Storage SOP Class UID' (0x0002,0x0002)
01351 'SOP Class UID'               (0x0008,0x0016) are set to 
01352                                                [Secondary Capture Image Storage]
01353 'Image Type'                  (0x0008,0x0008) is forced to  "DERIVED\PRIMARY"
01354 Conversion Type               (0x0008,0x0064) is forced to 'SYN' (Synthetic Image)
01355 
01356 2)4)
01357 If 'SOP Class UID' exists in the native image  ('true DICOM' image)
01358     we create the 'Source Image Sequence' SeqEntry (0x0008, 0x2112)    
01359     --> 'Referenced SOP Class UID' (0x0008, 0x1150)
01360          whose value is the original 'SOP Class UID'
01361     --> 'Referenced SOP Instance UID' (0x0008, 0x1155)
01362          whose value is the original 'SOP Class UID'
01363 
01364 3) TODO : find a trick to allow user to pass to the writter the list of the Dicom images 
01365           or the Series, (or the Study ?) he used to created his image 
01366           (MIP, MPR, cartography image, ...)
01367            These info should be stored (?)
01368           0008 1110 SQ 1 Referenced Study Sequence
01369           0008 1115 SQ 1 Referenced Series Sequence
01370           0008 1140 SQ 1 Referenced Image Sequence
01371        
01372 4) When user *knows* he didn't modified the pixels, we keep some informations unchanged :
01373 'Media Storage SOP Class UID' (0x0002,0x0002)
01374 'SOP Class UID'               (0x0008,0x0016)
01375 'Image Type'                  (0x0008,0x0008)
01376 'Conversion Type'             (0x0008,0x0064)
01377 
01378 
01379 Bellow follows the full description (hope so !) of the consistency checks performed 
01380 by gdcm::FileHelper::CheckMandatoryElements()
01381 
01382 
01383 -->'Media Storage SOP Class UID' (0x0002,0x0002)
01384 -->'SOP Class UID'               (0x0008,0x0016) are defaulted to 
01385                                                [Secondary Capture Image Storage]
01386 --> 'Image Type'  (0x0008,0x0008)
01387      is forced to  "DERIVED\PRIMARY"
01388      (The written image is no longer an 'ORIGINAL' one)
01389   Except if user knows he didn't modify the image (e.g. : he just anonymized the file)
01390    
01391  -->  Conversion Type (0x0008,0x0064)
01392      is defaulted to 'SYN' (Synthetic Image)
01393   when *he* knows he created his own image ex nihilo
01394             
01395 --> 'Modality' (0x0008,0x0060)   
01396     is defaulted to "OT" (other) if missing.   
01397     (a fully user created image belongs to *no* modality)
01398       
01399 --> 'Media Storage SOP Instance UID' (0x0002,0x0003)
01400 --> 'Implementation Class UID'       (0x0002,0x0012)
01401     are automatically generated; no user intervention possible
01402 
01403 --> 'Serie Instance UID'(0x0020,0x000e)
01404 --> 'Study Instance UID'(0x0020,0x000d) are kept as is if already exist
01405                                              created  if it doesn't.
01406      The user is allowed to create his own Series/Studies, 
01407      keeping the same 'Serie Instance UID' / 'Study Instance UID' 
01408      for various images
01409      Warning :     
01410      The user shouldn't add any image to a 'Manufacturer Serie'
01411      but there is no way no to allowed him to do that 
01412              
01413 --> If 'SOP Class UID' exists in the native image  ('true DICOM' image)
01414     we create the 'Source Image Sequence' SeqEntry (0x0008, 0x2112)
01415     
01416     --> 'Referenced SOP Class UID' (0x0008, 0x1150)
01417          whose value is the original 'SOP Class UID'
01418     --> 'Referenced SOP Instance UID' (0x0008, 0x1155)
01419          whose value is the original 'SOP Class UID'
01420     
01421 --> Bits Stored, Bits Allocated, Hight Bit Position are checked for consistency
01422 --> Pixel Spacing     (0x0028,0x0030) is defaulted to "1.0\1.0"
01423 --> Samples Per Pixel (0x0028,0x0002) is defaulted to 1 (grayscale)
01424 
01425 --> Imager Pixel Spacing (0x0018,0x1164) : defaulted to Pixel Spacing value
01426 
01427 --> Instance Creation Date, Instance Creation Time are forced to current Date and Time
01428 
01429 --> Study Date, Study Time are defaulted to current Date and Time
01430    (they remain unchanged if they exist)
01431 
01432 --> Patient Orientation : (0x0020,0x0020), if not present, is deduced from 
01433     Image Orientation (Patient) : (0020|0037) or from
01434     Image Orientation (RET)     : (0020 0035)
01435    
01436 --> Study ID, Series Number, Instance Number, Patient Orientation (Type 2)
01437     are created, with empty value if there are missing.
01438 
01439 --> Manufacturer, Institution Name, Patient's Name, (Type 2)
01440     are defaulted with a 'gdcm' value.
01441     
01442 --> Patient ID, Patient's Birth Date, Patient's Sex, (Type 2)
01443 --> Referring Physician's Name  (Type 2)
01444     are created, with empty value if there are missing.
01445 
01446  -------------------------------------------------------------------------------------*/
01447 
01448 void FileHelper::CheckMandatoryElements()
01449 {
01450    std::string sop =  Util::CreateUniqueUID();
01451 
01452    // --------------------- For Meta Elements ---------------------
01453    // just to remember : 'official' 0002 group
01454    if ( WriteType != ACR && WriteType != ACR_LIBIDO )
01455    {
01456      // Group 000002 (Meta Elements) already pushed out
01457   
01458    //0002 0000 UL 1 Meta Group Length
01459    //0002 0001 OB 1 File Meta Information Version
01460    //0002 0002 UI 1 Media Storage SOP Class UID
01461    //0002 0003 UI 1 Media Storage SOP Instance UID
01462    //0002 0010 UI 1 Transfer Syntax UID
01463    //0002 0012 UI 1 Implementation Class UID
01464    //0002 0013 SH 1 Implementation Version Name
01465    //0002 0016 AE 1 Source Application Entity Title
01466    //0002 0100 UI 1 Private Information Creator
01467    //0002 0102 OB 1 Private Information
01468 
01469    // Push out 'ACR-NEMA-special' entries, if any
01470       Archive->Push(0x0008,0x0001); // Length to End
01471       Archive->Push(0x0008,0x0010); // Recognition Code
01472       Archive->Push(0x0028,0x0005); // Image Dimension
01473 
01474    // Create them if not found
01475    // Always modify the value
01476    // Push the entries to the archive.
01477       CopyMandatoryEntry(0x0002,0x0000,"0","UL");
01478 
01479       DataEntry *e_0002_0001 = CopyDataEntry(0x0002,0x0001, "OB");
01480       e_0002_0001->SetBinArea((uint8_t*)Util::GetFileMetaInformationVersion(),
01481                                false);
01482       e_0002_0001->SetLength(2);
01483       Archive->Push(e_0002_0001);
01484       e_0002_0001->Delete(); 
01485 
01486       if ( ContentType == FILTERED_IMAGE || ContentType == UNMODIFIED_PIXELS_IMAGE)
01487       {      
01488    // we keep the original 'Media Storage SOP Class UID', we default it if missing
01489          CheckMandatoryEntry(0x0002,0x0002,"1.2.840.10008.5.1.4.1.1.7","UI"); 
01490       }
01491       else
01492       {
01493    // It's *not* an image comming straight from a source. We force
01494    // 'Media Storage SOP Class UID'  --> [Secondary Capture Image Storage]
01495          CopyMandatoryEntry(0x0002,0x0002,"1.2.840.10008.5.1.4.1.1.7","UI");
01496       }
01497 
01498    // 'Media Storage SOP Instance UID'
01499       CopyMandatoryEntry(0x0002,0x0003,sop,"UI");
01500 
01501    // 'Implementation Class UID'
01502    // FIXME : in all examples we have, 0x0002,0x0012 is not so long :
01503    //         seems to be Root UID + 4 digits (?)
01504       CopyMandatoryEntry(0x0002,0x0012,Util::CreateUniqueUID(),"UI");
01505 
01506    // 'Implementation Version Name'
01507       std::string version = "GDCM ";
01508       version += Util::GetVersion();
01509       CopyMandatoryEntry(0x0002,0x0013,version,"SH");
01510    }
01511 
01512    // --------------------- For DataSet ---------------------
01513 
01514    if ( ContentType != USER_OWN_IMAGE) // when it's not a user made image
01515    { 
01516 
01517       gdcmDebugMacro( "USER_OWN_IMAGE (1)");
01518    // If 'SOP Class UID' exists ('true DICOM' image)
01519    // we create the 'Source Image Sequence' SeqEntry
01520    // to hold informations about the Source Image
01521   
01522       DataEntry *e_0008_0016 = FileInternal->GetDataEntry(0x0008, 0x0016);
01523       if ( e_0008_0016 )
01524       {
01525       // Create 'Source Image Sequence' SeqEntry
01526 //     SeqEntry *sis = SeqEntry::New (
01527 //            Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x2112) );
01528       SeqEntry *sis = SeqEntry::New (0x0008, 0x2112);
01529       SQItem *sqi = SQItem::New(1);
01530       // (we assume 'SOP Instance UID' exists too) 
01531       // create 'Referenced SOP Class UID'
01532 //     DataEntry *e_0008_1150 = DataEntry::New(
01533 //            Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1150) );
01534       DataEntry *e_0008_1150 = DataEntry::New(0x0008, 0x1150, "UI");
01535       e_0008_1150->SetString( e_0008_0016->GetString());
01536       sqi->AddEntry(e_0008_1150);
01537       e_0008_1150->Delete();
01538       
01539       // create 'Referenced SOP Instance UID'
01540       DataEntry *e_0008_0018 = FileInternal->GetDataEntry(0x0008, 0x0018);
01541 //      DataEntry *e_0008_1155 = DataEntry::New(
01542 //            Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1155) );
01543       DataEntry *e_0008_1155 = DataEntry::New(0x0008, 0x1155, "UI");
01544       e_0008_1155->SetString( e_0008_0018->GetString());
01545       sqi->AddEntry(e_0008_1155);
01546       e_0008_1155->Delete();
01547 
01548       sis->AddSQItem(sqi,1);
01549       sqi->Delete();
01550 
01551       // temporarily replaces any previous 'Source Image Sequence' 
01552       Archive->Push(sis);
01553       sis->Delete();
01554  
01555       // FIXME : is 'Image Type' *really* depending on the presence of 'SOP Class UID'?
01556        if ( ContentType == FILTERED_IMAGE)      
01557       // the user *knows* he just modified the pixels
01558       // the image is no longer an 'Original' one
01559          CopyMandatoryEntry(0x0008,0x0008,"DERIVED\\PRIMARY","CS");    
01560       }
01561    }
01562       
01563    if ( ContentType == FILTERED_IMAGE || ContentType == UNMODIFIED_PIXELS_IMAGE)
01564    {      
01565    // we keep the original 'Media Storage SOP Class UID', we default it if missing (it should be present !)
01566          CheckMandatoryEntry(0x0008,0x0016,"1.2.840.10008.5.1.4.1.1.7","UI");      
01567    }
01568    else
01569    {
01570    // It's *not* an image comming straight from a source. We force
01571    // 'Media Storage SOP Class UID'  --> [Secondary Capture Image Storage]
01572          CopyMandatoryEntry(0x0008,0x0016,"1.2.840.10008.5.1.4.1.1.7", "UI");      
01573    }
01574      
01575    Archive->Push(0x0028,0x005); // [Image Dimensions (RET)
01576    // Push out 'LibIDO-special' entries, if any
01577    Archive->Push(0x0028,0x0015);
01578    Archive->Push(0x0028,0x0016);
01579    Archive->Push(0x0028,0x0017);
01580    Archive->Push(0x0028,0x0198);  // very old versions
01581    Archive->Push(0x0028,0x0199);
01582 
01583    // Replace deprecated 0028 0012 US Planes   
01584    // by new             0028 0008 IS Number of Frames
01585 
01587    DataEntry *e_0028_0012 = FileInternal->GetDataEntry(0x0028, 0x0012);
01588    if ( e_0028_0012 )
01589    {
01590       CopyMandatoryEntry(0x0028, 0x0008,e_0028_0012->GetString(),"IS");
01591       Archive->Push(0x0028,0x0012);      
01592    }
01593 
01594    // Deal with the pb of (Bits Stored = 12)
01595    // - we're gonna write the image as Bits Stored = 16
01596    if ( FileInternal->GetEntryString(0x0028,0x0100) ==  "12")
01597    {
01598       CopyMandatoryEntry(0x0028,0x0100,"16","US");
01599    }
01600 
01601    // Check if user wasn't drunk ;-)
01602 
01603    std::ostringstream s;
01604    // check 'Bits Allocated' vs decent values
01605    int nbBitsAllocated = FileInternal->GetBitsAllocated();
01606    if ( (nbBitsAllocated == 0 || nbBitsAllocated > 32)
01607      || ( nbBitsAllocated > 8 && nbBitsAllocated <16) )
01608    {
01609       CopyMandatoryEntry(0x0028,0x0100,"16","US");
01610       gdcmWarningMacro("(0028,0100) changed from "
01611          << nbBitsAllocated << " to 16 for consistency purpose");
01612       nbBitsAllocated = 16; 
01613    }
01614    // check 'Bits Stored' vs 'Bits Allocated'   
01615    int nbBitsStored = FileInternal->GetBitsStored();
01616    if ( nbBitsStored == 0 || nbBitsStored > nbBitsAllocated )
01617    {
01618       s.str("");
01619       s << nbBitsAllocated;
01620       CopyMandatoryEntry(0x0028,0x0101,s.str(),"US");
01621       gdcmWarningMacro("(0028,0101) changed from "
01622                        << nbBitsStored << " to " << nbBitsAllocated
01623                        << " for consistency purpose" );
01624       nbBitsStored = nbBitsAllocated; 
01625     }
01626    // check 'Hight Bit Position' vs 'Bits Allocated' and 'Bits Stored'
01627    int highBitPosition = FileInternal->GetHighBitPosition();
01628    if ( highBitPosition == 0 || 
01629         highBitPosition > nbBitsAllocated-1 ||
01630         highBitPosition < nbBitsStored-1  )
01631    {
01632       s.str("");
01633       s << nbBitsStored - 1; 
01634       CopyMandatoryEntry(0x0028,0x0102,s.str(),"US");
01635       gdcmWarningMacro("(0028,0102) changed from "
01636                        << highBitPosition << " to " << nbBitsAllocated-1
01637                        << " for consistency purpose");
01638    }
01639 
01640    // check Pixel Representation (default it as 0 -unsigned-)
01641 
01642    DataEntry *e_0028_0103 = FileInternal->GetDataEntry(0x0028, 0x0103);
01643    if ( !e_0028_0103 )
01644    {
01645       gdcmWarningMacro("PixelRepresentation (0028,0103) is supposed to be mandatory");
01646       CopyMandatoryEntry(0x0028, 0x0103,"0","US"); 
01647    }
01648    else
01649    {
01650       int sign = (int)e_0028_0103->GetValue(0);
01651       if (sign !=1 && sign !=0)
01652       {
01653          gdcmWarningMacro("PixelRepresentation (0028,0103) is supposed to be =1 or =0");
01654          CopyMandatoryEntry(0x0028, 0x0103,"0","US");
01655       }
01656    }
01657 
01658    std::string pixelSpacing = FileInternal->GetEntryString(0x0028,0x0030);
01659    if ( pixelSpacing == GDCM_UNFOUND )
01660    {
01661       pixelSpacing = "1.0\\1.0";
01662        // if missing, Pixel Spacing forced to "1.0\1.0"
01663       CopyMandatoryEntry(0x0028,0x0030,pixelSpacing,"DS");
01664    }
01665    
01666    // 'Imager Pixel Spacing' : defaulted to 'Pixel Spacing'
01667    // --> This one is the *legal* one !
01668    if ( ContentType != USER_OWN_IMAGE)
01669    //  we write it only when we are *sure* the image comes from
01670    //         an imager (see also 0008,0x0064)
01671       CheckMandatoryEntry(0x0018,0x1164,pixelSpacing,"DS");
01672 
01673 /*
01675 
01676 // See page 73 of ACR-NEMA_300-1988.pdf !
01677 
01678 // 0020,0020 : Patient Orientation :
01679 Patient direction of the first row and
01680 column of the images. The first entry id the direction of the raws, given by the
01681 direction of the last pixel in the first row from the first pixel in tha row.
01682 the second entry is the direction of the columns, given by the direction of the
01683 last pixel in the first column from the first pixel in that column.
01684 L : Left, F : Feet, A : Anterior, P : Posterior.
01685 Up to 3 letters can be used in combination to indicate oblique planes.
01686 
01687 //0020,0030 Image Position (RET)
01688 x,y,z coordinates im mm of the first pixel in the image
01689 
01690 // 0020,0035 Image Orientation (RET)
01691 Direction cosines of the R axis of the image system with respect to the
01692 equipment coordinate axes x,y,z, followed by direction cosines of the C axis of
01693 the image system with respect to the same axes
01694 
01695 //0020,0050 Location
01696 An image location reference, standard for the modality (such as CT bed position),
01697 used to indicate position. Calculation of position for other purposes
01698 is only from (0020,0030) and (0020,0035)
01699 */
01700 
01701 /*
01702 // if imagePositionPatient    not found, default it with imagePositionRet,    if any
01703 // if imageOrientationPatient not found, default it with imageOrientationRet, if any
01704 
01705    std::string imagePositionRet        = FileInternal->GetEntryString(0x0020,0x0030);
01706    std::string imageOrientationRet     = FileInternal->GetEntryString(0x0020,0x0035);
01707    std::string imagePositionPatient    = FileInternal->GetEntryString(0x0020,0x0032);
01708    std::string imageOrientationPatient = FileInternal->GetEntryString(0x0020,0x0037);
01709 
01710    if(  imagePositionPatient == GDCM_UNFOUND && imageOrientationPatient == GDCM_UNFOUND
01711      && imagePositionRet     != GDCM_UNFOUND && imageOrientationRet     != GDCM_UNFOUND)
01712    {
01713       CopyMandatoryEntry(0x0020, 0x0032,imagePositionRet,"DS");
01714       Archive->Push(0x0020,0x0030); 
01715       CopyMandatoryEntry(0x0020, 0x0037,imageOrientationRet,"DS");
01716       Archive->Push(0x0020,0x0035);
01717    }
01718 */
01719 
01720    // Samples Per Pixel (type 1) : default to grayscale
01721    CheckMandatoryEntry(0x0028,0x0002,"1","US");
01722 
01723    // --- Check UID-related Entries ---
01724  
01725    // At the end, not to overwrite the original ones,
01726    // needed by 'Referenced SOP Instance UID', 'Referenced SOP Class UID'
01727    // 'SOP Instance UID'  
01728    CopyMandatoryEntry(0x0008,0x0018,sop,"UI");
01729 
01730    if ( ContentType == USER_OWN_IMAGE)
01731    {
01732       gdcmDebugMacro( "USER_OWN_IMAGE (2)");
01733        // Conversion Type.
01734        // Other possible values are :
01735        // See PS 3.3, Page 408
01736 
01737        // DV = Digitized Video
01738        // DI = Digital Interface 
01739        // DF = Digitized Film
01740        // WSD = Workstation
01741        // SD = Scanned Document
01742        // SI = Scanned Image
01743        // DRW = Drawing
01744        // SYN = Synthetic Image
01745 
01746       CheckMandatoryEntry(0x0008,0x0064,"SYN","CS"); // Why not?
01747    } 
01748 /*
01749    if ( ContentType == CREATED_IMAGE)
01750    {
01752    
01753    }
01754 */
01755 
01756    // ---- The user will never have to take any action on the following ----
01757 
01758    // new value for 'SOP Instance UID'
01759    //SetMandatoryEntry(0x0008,0x0018,Util::CreateUniqueUID());
01760 
01761    // Instance Creation Date
01762    const std::string &date = Util::GetCurrentDate();
01763    CopyMandatoryEntry(0x0008,0x0012,date,"DA");
01764 
01765    // Instance Creation Time
01766    const std::string &time = Util::GetCurrentTime();
01767    CopyMandatoryEntry(0x0008,0x0013,time,"TM");
01768 
01769    // Study Date
01770    CheckMandatoryEntry(0x0008,0x0020,date,"DA");
01771    // Study Time
01772    CheckMandatoryEntry(0x0008,0x0030,time,"TM");
01773 
01774    // Accession Number
01775    //CopyMandatoryEntry(0x0008,0x0050,"");
01776    CheckMandatoryEntry(0x0008,0x0050,"","SH");
01777    
01778 
01779    // ----- Add Mandatory Entries if missing ---
01780    // Entries whose type is 1 are mandatory, with a mandatory value
01781    // Entries whose type is 1c are mandatory-inside-a-Sequence,
01782    //                          with a mandatory value
01783    // Entries whose type is 2 are mandatory, with an optional value
01784    // Entries whose type is 2c are mandatory-inside-a-Sequence,
01785    //                          with an optional value
01786    // Entries whose type is 3 are optional
01787 
01788    // 'Study Instance UID'
01789    // Keep the value if exists
01790    // The user is allowed to create his own Study, 
01791    //          keeping the same 'Study Instance UID' for various images
01792    // The user may add images to a 'Manufacturer Study',
01793    //          adding new Series to an already existing Study 
01794    CheckMandatoryEntry(0x0020,0x000d,Util::CreateUniqueUID(),"UI");
01795 
01796    // 'Serie Instance UID'
01797    // Keep the value if exists
01798    // The user is allowed to create his own Series, 
01799    // keeping the same 'Serie Instance UID' for various images
01800    // The user shouldn't add any image to a 'Manufacturer Serie'
01801    // but there is no way no to prevent him for doing that 
01802    CheckMandatoryEntry(0x0020,0x000e,Util::CreateUniqueUID(),"UI");
01803 
01804    // Study ID
01805    CheckMandatoryEntry(0x0020,0x0010,"","SH");
01806 
01807    // Series Number
01808    CheckMandatoryEntry(0x0020,0x0011,"","IS");
01809 
01810    // Instance Number
01811    CheckMandatoryEntry(0x0020,0x0013,"","IS");
01812 
01813    // Patient Orientation
01814    // Can be computed from (0020|0037) :  Image Orientation (Patient)
01815    GDCM_NAME_SPACE::Orientation *o = GDCM_NAME_SPACE::Orientation::New();
01816    std::string ori = o->GetOrientation ( FileInternal );
01817    o->Delete();
01818    if (ori != "\\" && ori != GDCM_UNFOUND)
01819       CheckMandatoryEntry(0x0020,0x0020,ori,"CS");
01820    else
01821       CheckMandatoryEntry(0x0020,0x0020,"","CS");
01822 
01823    // Default Patient Position to HFS
01824    CheckMandatoryEntry(0x0018,0x5100,"HFS","CS");
01825 
01826    // Modality : if missing we set it to 'OTher'
01827    CheckMandatoryEntry(0x0008,0x0060,"OT","CS");
01828 
01829    // Manufacturer : if missing we set it to 'GDCM Factory'
01830    CheckMandatoryEntry(0x0008,0x0070,"GDCM Factory","LO");
01831 
01832    // Institution Name : if missing we set it to 'GDCM Hospital'
01833    CheckMandatoryEntry(0x0008,0x0080,"GDCM Hospital","LO");
01834 
01835    // Patient's Name : if missing, we set it to 'GDCM^Patient'
01836    CheckMandatoryEntry(0x0010,0x0010,"GDCM^Patient","PN");
01837 
01838    // Patient ID : some clinical softwares *demand* it although it's a 'type 2' entry.
01839    CheckMandatoryEntry(0x0010,0x0020,"gdcm ID","LO");
01840 
01841    // Patient's Birth Date : 'type 2' entry -> must exist, value not mandatory
01842    CheckMandatoryEntry(0x0010,0x0030,"","DA");
01843 
01844    // Patient's Sex :'type 2' entry -> must exist, value not mandatory
01845    CheckMandatoryEntry(0x0010,0x0040,"","CS");
01846 
01847    // Referring Physician's Name :'type 2' entry -> must exist, value not mandatory
01848    CheckMandatoryEntry(0x0008,0x0090,"","PN");
01849 
01850  /*
01851    // Deal with element 0x0000 (group length) of each group.
01852    // First stage : get all the different Groups
01853 
01854   GroupHT grHT;
01855   DocEntry *d = FileInternal->GetFirstEntry();
01856   while(d)
01857   {
01858     grHT[d->GetGroup()] = 0;
01859     d=FileInternal->GetNextEntry();
01860   }
01861   // Second stage : add the missing ones (if any)
01862   for (GroupHT::iterator it = grHT.begin(); it != grHT.end(); ++it)  
01863   {
01864       CheckMandatoryEntry(it->first, 0x0000, "0"); 
01865   }    
01866   // Third stage : update all 'zero level' groups length
01867 */
01868 
01869 
01870    if (PhotometricInterpretation == 1)
01871    {
01872    }
01873 } 
01874 
01875 void FileHelper::CheckMandatoryEntry(uint16_t group,uint16_t elem,std::string value,const VRKey &vr )
01876 {
01877    DataEntry *entry = FileInternal->GetDataEntry(group,elem);
01878    if ( !entry )
01879    {
01880       //entry = DataEntry::New(Global::GetDicts()->GetDefaultPubDict()->GetEntry(group,elem));
01881       entry = DataEntry::New(group,elem,vr);
01882       entry->SetString(value);
01883       Archive->Push(entry);
01884       entry->Delete();
01885    }    
01886 }
01887 
01889 void FileHelper::SetMandatoryEntry(uint16_t group,uint16_t elem,std::string value,const VRKey &vr)
01890 {
01891    //DataEntry *entry = DataEntry::New(Global::GetDicts()->GetDefaultPubDict()->GetEntry(group,elem));
01892    DataEntry *entry = DataEntry::New(group,elem,vr);
01893    entry->SetString(value);
01894    Archive->Push(entry);
01895    entry->Delete();
01896 }
01897 
01898 void FileHelper::CopyMandatoryEntry(uint16_t group,uint16_t elem,std::string value,const VRKey &vr)
01899 {
01900    DataEntry *entry = CopyDataEntry(group,elem,vr);
01901    entry->SetString(value);
01902    Archive->Push(entry);
01903    entry->Delete();
01904 }
01905 
01909 void FileHelper::RestoreWriteMandatory()
01910 {
01911    // group 0002 may be pushed out for ACR-NEMA writting purposes 
01912    Archive->Restore(0x0002,0x0000);
01913    Archive->Restore(0x0002,0x0001);
01914    Archive->Restore(0x0002,0x0002);
01915    Archive->Restore(0x0002,0x0003);
01916    Archive->Restore(0x0002,0x0010);
01917    Archive->Restore(0x0002,0x0012);
01918    Archive->Restore(0x0002,0x0013);
01919    Archive->Restore(0x0002,0x0016);
01920    Archive->Restore(0x0002,0x0100);
01921    Archive->Restore(0x0002,0x0102);
01922 
01923    // FIXME : Check if none is missing !
01924    
01925    Archive->Restore(0x0008,0x0012);
01926    Archive->Restore(0x0008,0x0013);
01927    Archive->Restore(0x0008,0x0016);
01928    Archive->Restore(0x0008,0x0018);
01929    Archive->Restore(0x0008,0x0060);
01930    Archive->Restore(0x0008,0x0070);
01931    Archive->Restore(0x0008,0x0080);
01932    Archive->Restore(0x0008,0x0090);
01933    Archive->Restore(0x0008,0x2112);
01934 
01935    Archive->Restore(0x0010,0x0010);
01936    Archive->Restore(0x0010,0x0030);
01937    Archive->Restore(0x0010,0x0040);
01938 
01939    Archive->Restore(0x0020,0x000d);
01940    Archive->Restore(0x0020,0x000e);
01941 }
01942 
01946 void FileHelper::CallStartMethod()
01947 {
01948    Progress = 0.0f;
01949    Abort    = false;
01950    CommandManager::ExecuteCommand(this,CMD_STARTPROGRESS);
01951 }
01952 
01956 void FileHelper::CallProgressMethod()
01957 {
01958    CommandManager::ExecuteCommand(this,CMD_PROGRESS);
01959 }
01960 
01964 void FileHelper::CallEndMethod()
01965 {
01966    Progress = 1.0f;
01967    CommandManager::ExecuteCommand(this,CMD_ENDPROGRESS);
01968 }
01969 
01970 //-----------------------------------------------------------------------------
01971 // Private
01975 void FileHelper::Initialize()
01976 {
01977    UserFunction = 0;
01978    ContentType = USER_OWN_IMAGE;
01979 
01980    WriteMode = WMODE_RAW;
01981    WriteType = ExplicitVR;
01982    
01983    PhotometricInterpretation = 2; // Black = 0
01984 
01985    PixelReadConverter  = new PixelReadConvert;
01986    PixelWriteConverter = new PixelWriteConvert;
01987    Archive = new DocEntryArchive( FileInternal );
01988 }
01989 
01996 uint8_t *FileHelper::GetRaw()
01997 {
01998    PixelReadConverter->SetUserFunction( UserFunction );
01999 
02000    uint8_t *raw = PixelReadConverter->GetRaw();
02001    if ( ! raw )
02002    {
02003       // The Raw image migth not be loaded yet:
02004       std::ifstream *fp = FileInternal->OpenFile();
02005       PixelReadConverter->ReadAndDecompressPixelData( fp );
02006       if ( fp ) 
02007          FileInternal->CloseFile();
02008 
02009       raw = PixelReadConverter->GetRaw();
02010       if ( ! raw )
02011       {
02012          gdcmWarningMacro( "Read/decompress of pixel data apparently went wrong.");
02013          return 0;
02014       }
02015    }
02016    return raw;
02017 }
02018 
02023 void FileHelper::ConvertFixGreyLevels(uint8_t *raw, size_t rawSize)
02024 {
02025    uint32_t i; // to please M$VC6
02026    int16_t j;
02027 
02028    // Number of Bits Allocated for storing a Pixel is defaulted to 16
02029    // when absent from the file.
02030    int bitsAllocated = FileInternal->GetBitsAllocated();
02031    if ( bitsAllocated == 0 )
02032    {
02033       bitsAllocated = 16;
02034    }
02035 
02036    else if (bitsAllocated > 8 && bitsAllocated < 16 && bitsAllocated != 12)
02037    {
02038       bitsAllocated = 16;
02039    }   
02040    // Number of "Bits Stored", defaulted to number of "Bits Allocated"
02041    // when absent from the file.
02042    int bitsStored = FileInternal->GetBitsStored();
02043    if ( bitsStored == 0 )
02044    {
02045       bitsStored = bitsAllocated;
02046    }
02047 
02048    if (!FileInternal->IsSignedPixelData())
02049    {
02050       if ( bitsAllocated == 8 )
02051       {
02052          uint8_t *deb = (uint8_t *)raw;
02053          for (i=0; i<rawSize; i++)      
02054          {
02055             *deb = 255 - *deb;
02056             deb++;
02057          }
02058          return;
02059       }
02060 
02061       if ( bitsAllocated == 16 )
02062       {
02063          uint16_t mask =1;
02064          for (j=0; j<bitsStored-1; j++)
02065          {
02066             mask = (mask << 1) +1; // will be fff when BitsStored=12
02067          }
02068 
02069          uint16_t *deb = (uint16_t *)raw;
02070          for (i=0; i<rawSize/2; i++)      
02071          {
02072             *deb = mask - *deb;
02073             deb++;
02074          }
02075          return;
02076        }
02077    }
02078    else
02079    {
02080       if ( bitsAllocated == 8 )
02081       {
02082          uint8_t smask8 = 255;
02083          uint8_t *deb = (uint8_t *)raw;
02084          for (i=0; i<rawSize; i++)      
02085          {
02086             *deb = smask8 - *deb;
02087             deb++;
02088          }
02089          return;
02090       }
02091       if ( bitsAllocated == 16 )
02092       {
02093          uint16_t smask16 = 65535;
02094          uint16_t *deb = (uint16_t *)raw;
02095          for (i=0; i<rawSize/2; i++)      
02096          {
02097             *deb = smask16 - *deb;
02098             deb++;
02099          }
02100          return;
02101       }
02102    }
02103 }
02104 
02105 //-----------------------------------------------------------------------------
02111 void FileHelper::Print(std::ostream &os, std::string const &)
02112 {
02113    FileInternal->SetPrintLevel(PrintLevel);
02114    FileInternal->Print(os);
02115 
02116    if ( FileInternal->IsReadable() )
02117    {
02118       PixelReadConverter->SetPrintLevel(PrintLevel);
02119       PixelReadConverter->Print(os);
02120    }
02121 }
02122 
02123 //-----------------------------------------------------------------------------
02124 } // end namespace gdcm
02125 
02126 
02127 /* Probabely something to be added to use Rescale Slope/Intercept
02128 Have a look ,at ITK code !
02129 
02130 // Internal function to rescale pixel according to Rescale Slope/Intercept
02131 template<class TBuffer, class TSource>
02132 void RescaleFunction(TBuffer* buffer, TSource *source,
02133                      double slope, double intercept, size_t size)
02134 {
02135   size /= sizeof(TSource);
02136 
02137   if (slope != 1.0 && intercept != 0.0)
02138     {
02139     // Duff's device.  Instead of this code:
02140     //
02141     //   for(unsigned int i=0; i<size; i++)
02142     //    {
02143     //    buffer[i] = (TBuffer)(source[i]*slope + intercept);
02144     //    }
02145     //
02146     // use Duff's device which exploits "fall through"
02147     register size_t n = (size + 7) / 8;
02148     switch ( size % 8)
02149       {
02150       case 0: do { *buffer++ = (TBuffer)((*source++)*slope + intercept);
02151       case 7:      *buffer++ = (TBuffer)((*source++)*slope + intercept);
02152       case 6:      *buffer++ = (TBuffer)((*source++)*slope + intercept);
02153       case 5:      *buffer++ = (TBuffer)((*source++)*slope + intercept);
02154       case 4:      *buffer++ = (TBuffer)((*source++)*slope + intercept);
02155       case 3:      *buffer++ = (TBuffer)((*source++)*slope + intercept);
02156       case 2:      *buffer++ = (TBuffer)((*source++)*slope + intercept);
02157       case 1:      *buffer++ = (TBuffer)((*source++)*slope + intercept);
02158                  }  while (--n > 0);
02159       }
02160     }
02161   else if (slope == 1.0 && intercept != 0.0)
02162     {
02163     // Duff's device.  Instead of this code:
02164     //
02165     //   for(unsigned int i=0; i<size; i++)
02166     //    {
02167     //    buffer[i] = (TBuffer)(source[i] + intercept);
02168     //    }
02169     //
02170     // use Duff's device which exploits "fall through"
02171     register size_t n = (size + 7) / 8;
02172     switch ( size % 8)
02173       {
02174       case 0: do { *buffer++ = (TBuffer)(*source++ + intercept);
02175       case 7:      *buffer++ = (TBuffer)(*source++ + intercept);
02176       case 6:      *buffer++ = (TBuffer)(*source++ + intercept);
02177       case 5:      *buffer++ = (TBuffer)(*source++ + intercept);
02178       case 4:      *buffer++ = (TBuffer)(*source++ + intercept);
02179       case 3:      *buffer++ = (TBuffer)(*source++ + intercept);
02180       case 2:      *buffer++ = (TBuffer)(*source++ + intercept);
02181       case 1:      *buffer++ = (TBuffer)(*source++ + intercept);
02182                  }  while (--n > 0);
02183       }
02184     }
02185   else if (slope != 1.0 && intercept == 0.0)
02186     {
02187     // Duff's device.  Instead of this code:
02188     //
02189     //   for(unsigned int i=0; i<size; i++)
02190     //    {
02191     //    buffer[i] = (TBuffer)(source[i]*slope);
02192     //    }
02193     //
02194     // use Duff's device which exploits "fall through"
02195     register size_t n = (size + 7) / 8;
02196     switch ( size % 8)
02197       {
02198       case 0: do { *buffer++ = (TBuffer)((*source++)*slope);
02199       case 7:      *buffer++ = (TBuffer)((*source++)*slope);
02200       case 6:      *buffer++ = (TBuffer)((*source++)*slope);
02201       case 5:      *buffer++ = (TBuffer)((*source++)*slope);
02202       case 4:      *buffer++ = (TBuffer)((*source++)*slope);
02203       case 3:      *buffer++ = (TBuffer)((*source++)*slope);
02204       case 2:      *buffer++ = (TBuffer)((*source++)*slope);
02205       case 1:      *buffer++ = (TBuffer)((*source++)*slope);
02206                  }  while (--n > 0);
02207       }
02208     }
02209   else
02210     {
02211     // Duff's device.  Instead of this code:
02212     //
02213     //   for(unsigned int i=0; i<size; i++)
02214     //    {
02215     //    buffer[i] = (TBuffer)(source[i]);
02216     //    }
02217     //
02218     // use Duff's device which exploits "fall through"
02219     register size_t n = (size + 7) / 8;
02220     switch ( size % 8)
02221       {
02222       case 0: do { *buffer++ = (TBuffer)(*source++);
02223       case 7:      *buffer++ = (TBuffer)(*source++);
02224       case 6:      *buffer++ = (TBuffer)(*source++);
02225       case 5:      *buffer++ = (TBuffer)(*source++);
02226       case 4:      *buffer++ = (TBuffer)(*source++);
02227       case 3:      *buffer++ = (TBuffer)(*source++);
02228       case 2:      *buffer++ = (TBuffer)(*source++);
02229       case 1:      *buffer++ = (TBuffer)(*source++);
02230                  }  while (--n > 0);
02231       }
02232    }   
02233 }
02234 
02235 
02236 template<class TSource>
02237 void RescaleFunction(ImageIOBase::IOComponentType bufferType,
02238                      void* buffer, TSource *source,
02239                      double slope, double intercept, size_t size)
02240 {
02241   switch (bufferType)
02242     {
02243     case ImageIOBase::UCHAR:
02244       RescaleFunction( (unsigned char *)buffer, source, slope, intercept, size);
02245       break;
02246     case ImageIOBase::CHAR:
02247       RescaleFunction( (char *)buffer, source, slope, intercept, size);
02248       break;
02249     case ImageIOBase::USHORT:
02250       RescaleFunction( (unsigned short *)buffer, source, slope, intercept,size);
02251       break;
02252     case ImageIOBase::SHORT:
02253       RescaleFunction( (short *)buffer, source, slope, intercept, size);
02254       break;
02255     case ImageIOBase::UINT:
02256       RescaleFunction( (unsigned int *)buffer, source, slope, intercept, size);
02257       break;
02258     case ImageIOBase::INT:
02259       RescaleFunction( (int *)buffer, source, slope, intercept, size);
02260       break;
02261     case ImageIOBase::FLOAT:
02262       RescaleFunction( (float *)buffer, source, slope, intercept, size);
02263       break;
02264     case ImageIOBase::DOUBLE:
02265       RescaleFunction( (double *)buffer, source, slope, intercept, size);
02266       break;
02267     default:
02268       ::itk::OStringStream message;
02269       message << "itk::ERROR: GDCMImageIO: Unknown component type : " << bufferType;
02270       ::itk::ExceptionObject e(__FILE__, __LINE__, message.str().c_str(),ITK_LOCATION);
02271       throw e;
02272     }
02273 }
02274 */

Generated on Fri Aug 24 12:59:31 2007 for gdcm by  doxygen 1.4.6