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

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: 2006/01/19 11:46:45 $
00008   Version:   $Revision: 1.88 $
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 "gdcmFile.h"
00030 #include "gdcmPixelReadConvert.h"
00031 #include "gdcmPixelWriteConvert.h"
00032 #include "gdcmDocEntryArchive.h"
00033 #include "gdcmDictSet.h"
00034 #include "gdcmOrientation.h"
00035 
00036 #include <fstream>
00037 
00038 /*
00039 // ----------------------------- WARNING -------------------------
00040 
00041 These lines will be moved to the document-to-be 'User's Guide'
00042 
00043 // To read an image, user needs a gdcm::File
00044 gdcm::File *f = new gdcm::File(fileName);
00045 // or (advanced) :
00046 // user may also decide he doesn't want to load some parts of the header
00047 gdcm::File *f = new gdcm::File();
00048 f->SetFileName(fileName);
00049    f->SetLoadMode(LD_NOSEQ);             // or      
00050    f->SetLoadMode(LD_NOSHADOW);          // or
00051    f->SetLoadMode(LD_NOSEQ | LD_NOSHADOW); // or
00052    f->SetLoadMode(LD_NOSHADOWSEQ);
00053 f->Load();
00054 
00055 // user can now check some values
00056 std::string v = f->GetEntryValue(groupNb,ElementNb);
00057 
00058 // to get the pixels, user needs a gdcm::FileHelper
00059 gdcm::FileHelper *fh = new gdcm::FileHelper(f);
00060 // user may ask not to convert Palette to RGB
00061 uint8_t *pixels = fh->GetImageDataRaw();
00062 int imageLength = fh->GetImageDataRawSize();
00063 // He can now use the pixels, create a new image, ...
00064 uint8_t *userPixels = ...
00065 
00066 To re-write the image, user re-uses the gdcm::FileHelper
00067 
00068 fh->SetImageData( userPixels, userPixelsLength);
00069 fh->SetTypeToRaw(); // Even if it was possible to convert Palette to RGB
00070                      // (WriteMode is set)
00071  
00072 fh->SetWriteTypeToDcmExpl(); // he wants Explicit Value Representation
00073                               // Little Endian is the default
00074                               // no other value is allowed
00075                                 (-->SetWriteType(ExplicitVR);)
00076                                    -->WriteType = ExplicitVR;
00077 fh->Write(newFileName);      // overwrites the file, if any
00078 
00079 // or :
00080 fh->WriteDcmExplVR(newFileName);
00081 
00082 
00083 // ----------------------------- WARNING -------------------------
00084 
00085 These lines will be moved to the document-to-be 'Developer's Guide'
00086 
00087 WriteMode : WMODE_RAW / WMODE_RGB
00088 WriteType : ImplicitVR, ExplicitVR, ACR, ACR_LIBIDO
00089 
00090 fh1->Write(newFileName);
00091    SetWriteFileTypeToImplicitVR() / SetWriteFileTypeToExplicitVR();
00092    (modifies TransferSyntax)
00093    SetWriteToRaw(); / SetWriteToRGB();
00094       (modifies, when necessary : photochromatic interpretation, 
00095          samples per pixel, Planar configuration, 
00096          bits allocated, bits stored, high bit -ACR 24 bits-
00097          Pixels element VR, pushes out the LUT )
00098    CheckWriteIntegrity();
00099       (checks user given pixels length)
00100    FileInternal->Write(fileName,WriteType)
00101    fp = opens file(fileName);
00102    ComputeGroup0002Length( );
00103    BitsAllocated 12->16
00104       RemoveEntry(palettes, etc)
00105       Document::WriteContent(fp, writetype);
00106    RestoreWrite();
00107       (moves back to the File all the archived elements)
00108    RestoreWriteFileType();
00109       (pushes back group 0002, with TransferSyntax)
00110 */
00111 
00112 
00113 
00114 
00115 namespace gdcm 
00116 {
00117 typedef std::map<uint16_t, int> GroupHT;    //  Hash Table
00118 //-------------------------------------------------------------------------
00119 // Constructor / Destructor
00133 FileHelper::FileHelper( )
00134 { 
00135    FileInternal = File::New( );
00136    Initialize();
00137 }
00138 
00153 FileHelper::FileHelper(File *header)
00154 {
00155    gdcmAssertMacro(header);
00156 
00157    FileInternal = header;
00158    FileInternal->Register();
00159    Initialize();
00160    if ( FileInternal->IsReadable() )
00161    {
00162       PixelReadConverter->GrabInformationsFromFile( FileInternal, this );
00163    }
00164 }
00165 
00171 FileHelper::~FileHelper()
00172 { 
00173    if ( PixelReadConverter )
00174    {
00175       delete PixelReadConverter;
00176    }
00177    if ( PixelWriteConverter )
00178    {
00179       delete PixelWriteConverter;
00180    }
00181    if ( Archive )
00182    {
00183       delete Archive;
00184    }
00185 
00186    FileInternal->Unregister();
00187 }
00188 
00189 //-----------------------------------------------------------------------------
00190 // Public
00191 
00200 void FileHelper::SetLoadMode(int loadMode) 
00201 { 
00202    GetFile()->SetLoadMode( loadMode ); 
00203 }
00208 void FileHelper::SetFileName(std::string const &fileName)
00209 {
00210    FileInternal->SetFileName( fileName );
00211 }
00212 
00218 bool FileHelper::Load()
00219 { 
00220    if ( !FileInternal->Load() )
00221       return false;
00222 
00223    PixelReadConverter->GrabInformationsFromFile( FileInternal, this );
00224    return true;
00225 }
00226 
00235 bool FileHelper::SetEntryString(std::string const &content,
00236                                     uint16_t group, uint16_t elem)
00237 { 
00238    return FileInternal->SetEntryString(content, group, elem);
00239 }
00240 
00241 
00251 bool FileHelper::SetEntryBinArea(uint8_t *content, int lgth,
00252                                      uint16_t group, uint16_t elem)
00253 {
00254    return FileInternal->SetEntryBinArea(content, lgth, group, elem);
00255 }
00256 
00266 DataEntry *FileHelper::InsertEntryString(std::string const &content,
00267                                                 uint16_t group, uint16_t elem)
00268 {
00269    return FileInternal->InsertEntryString(content, group, elem);
00270 }
00271 
00283 DataEntry *FileHelper::InsertEntryBinArea(uint8_t *binArea, int lgth,
00284                                                  uint16_t group, uint16_t elem)
00285 {
00286    return FileInternal->InsertEntryBinArea(binArea, lgth, group, elem);
00287 }
00288 
00297 SeqEntry *FileHelper::InsertSeqEntry(uint16_t group, uint16_t elem)
00298 {
00299    return FileInternal->InsertSeqEntry(group, elem);
00300 }
00301 
00310 size_t FileHelper::GetImageDataSize()
00311 {
00312    if ( PixelWriteConverter->GetUserData() )
00313    {
00314       return PixelWriteConverter->GetUserDataSize();
00315    }
00316    return PixelReadConverter->GetRGBSize();
00317 }
00318 
00326 size_t FileHelper::GetImageDataRawSize()
00327 {
00328    if ( PixelWriteConverter->GetUserData() )
00329    {
00330       return PixelWriteConverter->GetUserDataSize();
00331    }
00332    return PixelReadConverter->GetRawSize();
00333 }
00334 
00347 uint8_t *FileHelper::GetImageData()
00348 {
00349    if ( PixelWriteConverter->GetUserData() )
00350    {
00351       return PixelWriteConverter->GetUserData();
00352    }
00353 
00354    if ( ! GetRaw() )
00355    {
00356       // If the decompression failed nothing can be done.
00357       return 0;
00358    }
00359 
00360    if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
00361    {
00362       return PixelReadConverter->GetRGB();
00363    }
00364    else
00365    {
00366       // When no LUT or LUT conversion fails, return the Raw
00367       return PixelReadConverter->GetRaw();
00368    }
00369 }
00370 
00382 uint8_t *FileHelper::GetImageDataRaw ()
00383 {
00384    return GetRaw();
00385 }
00386 
00387 #ifndef GDCM_LEGACY_REMOVE
00388 /*
00389  * \ brief   Useless function, since PixelReadConverter forces us 
00390  *          copy the Pixels anyway.  
00391  *          Reads the pixels from disk (uncompress if necessary),
00392  *          Transforms YBR pixels, if any, into RGB pixels
00393  *          Transforms 3 planes R, G, B, if any, into a single RGB Plane
00394  *          Transforms single Grey plane + 3 Palettes into a RGB Plane   
00395  *          Copies at most MaxSize bytes of pixel data to caller allocated
00396  *          memory space.
00397  * \ warning This function allows people that want to build a volume
00398  *          from an image stack *not to* have, first to get the image pixels, 
00399  *          and then move them to the volume area.
00400  *          It's absolutely useless for any VTK user since vtk chooses 
00401  *          to invert the lines of an image, that is the last line comes first
00402  *          (for some axis related reasons?). Hence he will have 
00403  *          to load the image line by line, starting from the end.
00404  *          VTK users have to call GetImageData
00405  *     
00406  * @ param   destination Address (in caller's memory space) at which the
00407  *          pixel data should be copied
00408  * @ param   maxSize Maximum number of bytes to be copied. When MaxSize
00409  *          is not sufficient to hold the pixel data the copy is not
00410  *          executed (i.e. no partial copy).
00411  * @ return  On success, the number of bytes actually copied. Zero on
00412  *          failure e.g. MaxSize is lower than necessary.
00413  */
00414 size_t FileHelper::GetImageDataIntoVector (void *destination, size_t maxSize)
00415 {
00416    if ( ! GetRaw() )
00417    {
00418       // If the decompression failed nothing can be done.
00419       return 0;
00420    }
00421 
00422    if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() )
00423    {
00424       if ( PixelReadConverter->GetRGBSize() > maxSize )
00425       {
00426          gdcmWarningMacro( "Pixel data bigger than caller's expected MaxSize");
00427          return 0;
00428       }
00429       memcpy( destination,
00430               (void*)PixelReadConverter->GetRGB(),
00431               PixelReadConverter->GetRGBSize() );
00432       return PixelReadConverter->GetRGBSize();
00433    }
00434 
00435    // Either no LUT conversion necessary or LUT conversion failed
00436    if ( PixelReadConverter->GetRawSize() > maxSize )
00437    {
00438       gdcmWarningMacro( "Pixel data bigger than caller's expected MaxSize");
00439       return 0;
00440    }
00441    memcpy( destination,
00442            (void *)PixelReadConverter->GetRaw(),
00443            PixelReadConverter->GetRawSize() );
00444    return PixelReadConverter->GetRawSize();
00445 }
00446 #endif
00447 
00461 void FileHelper::SetImageData(uint8_t *inData, size_t expectedSize)
00462 {
00463    SetUserData(inData, expectedSize);
00464 }
00465 
00474 void FileHelper::SetUserData(uint8_t *inData, size_t expectedSize)
00475 {
00476    PixelWriteConverter->SetUserData(inData, expectedSize);
00477 }
00478 
00483 uint8_t *FileHelper::GetUserData()
00484 {
00485    return PixelWriteConverter->GetUserData();
00486 }
00487 
00492 size_t FileHelper::GetUserDataSize()
00493 {
00494    return PixelWriteConverter->GetUserDataSize();
00495 }
00496 
00501 uint8_t *FileHelper::GetRGBData()
00502 {
00503    return PixelReadConverter->GetRGB();
00504 }
00505 
00510 size_t FileHelper::GetRGBDataSize()
00511 {
00512    return PixelReadConverter->GetRGBSize();
00513 }
00514 
00519 uint8_t *FileHelper::GetRawData()
00520 {
00521    return PixelReadConverter->GetRaw();
00522 }
00523 
00528 size_t FileHelper::GetRawDataSize()
00529 {
00530    return PixelReadConverter->GetRawSize();
00531 }
00532 
00536 uint8_t* FileHelper::GetLutRGBA()
00537 {
00538    if ( PixelReadConverter->GetLutRGBA() ==0 )
00539       PixelReadConverter->BuildLUTRGBA();
00540    return PixelReadConverter->GetLutRGBA();
00541 }
00542 
00546 int FileHelper::GetLutItemNumber()
00547 {
00548    return PixelReadConverter->GetLutItemNumber();
00549 }
00550 
00554 int FileHelper::GetLutItemSize()
00555 {
00556    return PixelReadConverter->GetLutItemSize();
00557 }
00558 
00567 bool FileHelper::WriteRawData(std::string const &fileName)
00568 {
00569    std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary );
00570    if (!fp1)
00571    {
00572       gdcmWarningMacro( "Fail to open (write) file:" << fileName.c_str());
00573       return false;
00574    }
00575 
00576    if ( PixelWriteConverter->GetUserData() )
00577    {
00578       fp1.write( (char *)PixelWriteConverter->GetUserData(), 
00579                  PixelWriteConverter->GetUserDataSize() );
00580    }
00581    else if ( PixelReadConverter->GetRGB() )
00582    {
00583       fp1.write( (char *)PixelReadConverter->GetRGB(), 
00584                  PixelReadConverter->GetRGBSize());
00585    }
00586    else if ( PixelReadConverter->GetRaw() )
00587    {
00588       fp1.write( (char *)PixelReadConverter->GetRaw(), 
00589                  PixelReadConverter->GetRawSize());
00590    }
00591    else
00592    {
00593       gdcmErrorMacro( "Nothing written." );
00594    }
00595 
00596    fp1.close();
00597 
00598    return true;
00599 }
00600 
00610 bool FileHelper::WriteDcmImplVR (std::string const &fileName)
00611 {
00612    SetWriteTypeToDcmImplVR();
00613    return Write(fileName);
00614 }
00615 
00625 bool FileHelper::WriteDcmExplVR (std::string const &fileName)
00626 {
00627    SetWriteTypeToDcmExplVR();
00628    return Write(fileName);
00629 }
00630 
00645 bool FileHelper::WriteAcr (std::string const &fileName)
00646 {
00647    SetWriteTypeToAcr();
00648    return Write(fileName);
00649 }
00650 
00657 bool FileHelper::Write(std::string const &fileName)
00658 {
00659    switch(WriteType)
00660    {
00661       case ImplicitVR:
00662          SetWriteFileTypeToImplicitVR();
00663          break;
00664       case Unknown:  // should never happen; ExplicitVR is the default value
00665       case ExplicitVR:
00666          SetWriteFileTypeToExplicitVR();
00667          break;
00668       case ACR:
00669       case ACR_LIBIDO:
00670       // NOTHING is done here just for LibIDO.
00671       // Just to avoid further trouble if user creates a file ex-nihilo,
00672       // wants to write it as an ACR-NEMA file,
00673       // and forgets to create any Entry belonging to group 0008
00674       // (shame on him !)
00675       // We add Recognition Code (RET)
00676         if ( ! FileInternal->GetDataEntry(0x0008, 0x0010) )
00677             FileInternal->InsertEntryString("ACR-NEMA V1.0 ", 0x0008, 0x0010);
00678          SetWriteFileTypeToACR();
00679         // SetWriteFileTypeToImplicitVR(); // ACR IS implicit VR !
00680          break;
00681       case JPEG:
00682          SetWriteFileTypeToJPEG();
00683          std::cerr << "Writting as JPEG" << std::endl;
00684          break;
00685    }
00686    CheckMandatoryElements();
00687 
00688    // --------------------------------------------------------------
00689    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
00690    //
00691    // if recognition code tells us we dealt with a LibIDO image
00692    // we reproduce on disk the switch between lineNumber and columnNumber
00693    // just before writting ...
00696    
00697    if ( WriteType == ACR_LIBIDO )
00698    {
00699       SetWriteToLibido();
00700    }
00701    else
00702    {
00703       SetWriteToNoLibido();
00704    }
00705    // ----------------- End of Special Patch ----------------
00706   
00707    switch(WriteMode)
00708    {
00709       case WMODE_RAW :
00710          SetWriteToRaw(); // modifies and pushes to the archive, when necessary
00711          break;
00712       case WMODE_RGB :
00713          SetWriteToRGB(); // modifies and pushes to the archive, when necessary
00714          break;
00715    }
00716 
00717    bool check = CheckWriteIntegrity(); // verifies length
00718    if (WriteType == JPEG ) check = true;
00719    if (check)
00720    {
00721       check = FileInternal->Write(fileName,WriteType);
00722    }
00723 
00724    RestoreWrite();
00725    RestoreWriteFileType();
00726    RestoreWriteMandatory();
00727 
00728    // --------------------------------------------------------------
00729    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
00730    // 
00731    // ...and we restore the header to be Dicom Compliant again 
00732    // just after writting
00733    RestoreWriteOfLibido();
00734    // ----------------- End of Special Patch ----------------
00735 
00736    return check;
00737 }
00738 
00739 //-----------------------------------------------------------------------------
00740 // Protected
00749 bool FileHelper::CheckWriteIntegrity()
00750 {
00751    if ( PixelWriteConverter->GetUserData() )
00752    {
00753       int numberBitsAllocated = FileInternal->GetBitsAllocated();
00754       if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
00755       {
00756          gdcmWarningMacro( "numberBitsAllocated changed from " 
00757                           << numberBitsAllocated << " to 16 " 
00758                           << " for consistency purpose" );
00759          numberBitsAllocated = 16;
00760       }
00761 
00762       size_t decSize = FileInternal->GetXSize()
00763                      * FileInternal->GetYSize() 
00764                      * FileInternal->GetZSize()
00765                      * FileInternal->GetSamplesPerPixel()
00766                      * ( numberBitsAllocated / 8 );
00767       size_t rgbSize = decSize;
00768       if ( FileInternal->HasLUT() )
00769          rgbSize = decSize * 3;
00770 
00771       switch(WriteMode)
00772       {
00773          case WMODE_RAW :
00774             if ( decSize!=PixelWriteConverter->GetUserDataSize() )
00775             {
00776                gdcmWarningMacro( "Data size (Raw) is incorrect. Should be " 
00777                            << decSize << " / Found :" 
00778                            << PixelWriteConverter->GetUserDataSize() );
00779                return false;
00780             }
00781             break;
00782          case WMODE_RGB :
00783             if ( rgbSize!=PixelWriteConverter->GetUserDataSize() )
00784             {
00785                gdcmWarningMacro( "Data size (RGB) is incorrect. Should be " 
00786                           << decSize << " / Found " 
00787                           << PixelWriteConverter->GetUserDataSize() );
00788                return false;
00789             }
00790             break;
00791       }
00792    }
00793 
00794    return true;
00795 }
00796 
00802 void FileHelper::SetWriteToRaw()
00803 {
00804    if ( FileInternal->GetNumberOfScalarComponents() == 3 
00805     && !FileInternal->HasLUT() )
00806    {
00807       SetWriteToRGB();
00808    } 
00809    else
00810    {
00811       DataEntry *photInt = CopyDataEntry(0x0028,0x0004);
00812       if (FileInternal->HasLUT() )
00813       {
00814          photInt->SetString("PALETTE COLOR ");
00815       }
00816       else
00817       {
00818          photInt->SetString("MONOCHROME2 ");
00819       }
00820 
00821       PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
00822                                        PixelReadConverter->GetRawSize());
00823 
00824       std::string vr = "OB";
00825       if ( FileInternal->GetBitsAllocated()>8 )
00826          vr = "OW";
00827       if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files 
00828          vr = "OB";
00829       DataEntry *pixel = 
00830          CopyDataEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr);
00831       pixel->SetFlag(DataEntry::FLAG_PIXELDATA);
00832       pixel->SetBinArea(PixelWriteConverter->GetData(),false);
00833       pixel->SetLength(PixelWriteConverter->GetDataSize());
00834 
00835       Archive->Push(photInt);
00836       Archive->Push(pixel);
00837 
00838       photInt->Delete();
00839       pixel->Delete();
00840    }
00841 }
00842 
00850 void FileHelper::SetWriteToRGB()
00851 {
00852    if ( FileInternal->GetNumberOfScalarComponents()==3 )
00853    {
00854       PixelReadConverter->BuildRGBImage();
00855       
00856       DataEntry *spp = CopyDataEntry(0x0028,0x0002);
00857       spp->SetString("3 ");
00858 
00859       DataEntry *planConfig = CopyDataEntry(0x0028,0x0006);
00860       planConfig->SetString("0 ");
00861 
00862       DataEntry *photInt = CopyDataEntry(0x0028,0x0004);
00863       photInt->SetString("RGB ");
00864 
00865       if ( PixelReadConverter->GetRGB() )
00866       {
00867          PixelWriteConverter->SetReadData(PixelReadConverter->GetRGB(),
00868                                           PixelReadConverter->GetRGBSize());
00869       }
00870       else // Raw data
00871       {
00872          PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(),
00873                                           PixelReadConverter->GetRawSize());
00874       }
00875 
00876       std::string vr = "OB";
00877       if ( FileInternal->GetBitsAllocated()>8 )
00878          vr = "OW";
00879       if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files 
00880          vr = "OB";
00881       DataEntry *pixel = 
00882          CopyDataEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr);
00883       pixel->SetFlag(DataEntry::FLAG_PIXELDATA);
00884       pixel->SetBinArea(PixelWriteConverter->GetData(),false);
00885       pixel->SetLength(PixelWriteConverter->GetDataSize());
00886 
00887       Archive->Push(spp);
00888       Archive->Push(planConfig);
00889       Archive->Push(photInt);
00890       Archive->Push(pixel);
00891 
00892       spp->Delete();
00893       planConfig->Delete();
00894       photInt->Delete();
00895       pixel->Delete();
00896 
00897       // Remove any LUT
00898       Archive->Push(0x0028,0x1101);
00899       Archive->Push(0x0028,0x1102);
00900       Archive->Push(0x0028,0x1103);
00901       Archive->Push(0x0028,0x1201);
00902       Archive->Push(0x0028,0x1202);
00903       Archive->Push(0x0028,0x1203);
00904 
00905       // push out Palette Color Lookup Table UID, if any
00906       Archive->Push(0x0028,0x1199);
00907 
00908       // For old '24 Bits' ACR-NEMA
00909       // Thus, we have a RGB image and the bits allocated = 24 and 
00910       // samples per pixels = 1 (in the read file)
00911       if ( FileInternal->GetBitsAllocated()==24 ) 
00912       {
00913          DataEntry *bitsAlloc = CopyDataEntry(0x0028,0x0100);
00914          bitsAlloc->SetString("8 ");
00915 
00916          DataEntry *bitsStored = CopyDataEntry(0x0028,0x0101);
00917          bitsStored->SetString("8 ");
00918 
00919          DataEntry *highBit = CopyDataEntry(0x0028,0x0102);
00920          highBit->SetString("7 ");
00921 
00922          Archive->Push(bitsAlloc);
00923          Archive->Push(bitsStored);
00924          Archive->Push(highBit);
00925 
00926          bitsAlloc->Delete();
00927          bitsStored->Delete();
00928          highBit->Delete();
00929       }
00930    }
00931    else
00932    {
00933       SetWriteToRaw();
00934    }
00935 }
00936 
00940 void FileHelper::RestoreWrite()
00941 {
00942    Archive->Restore(0x0028,0x0002);
00943    Archive->Restore(0x0028,0x0004);
00944    Archive->Restore(0x0028,0x0006);
00945    Archive->Restore(GetFile()->GetGrPixel(),GetFile()->GetNumPixel());
00946 
00947    // For old ACR-NEMA (24 bits problem)
00948    Archive->Restore(0x0028,0x0100);
00949    Archive->Restore(0x0028,0x0101);
00950    Archive->Restore(0x0028,0x0102);
00951 
00952    // For the LUT
00953    Archive->Restore(0x0028,0x1101);
00954    Archive->Restore(0x0028,0x1102);
00955    Archive->Restore(0x0028,0x1103);
00956    Archive->Restore(0x0028,0x1201);
00957    Archive->Restore(0x0028,0x1202);
00958    Archive->Restore(0x0028,0x1203);
00959 
00960    // For the Palette Color Lookup Table UID
00961    Archive->Restore(0x0028,0x1203); 
00962 
00963 
00964    // group 0002 may be pushed out for ACR-NEMA writting purposes 
00965    Archive->Restore(0x0002,0x0000);
00966    Archive->Restore(0x0002,0x0001);
00967    Archive->Restore(0x0002,0x0002);
00968    Archive->Restore(0x0002,0x0003);
00969    Archive->Restore(0x0002,0x0010);
00970    Archive->Restore(0x0002,0x0012);
00971    Archive->Restore(0x0002,0x0013);
00972    Archive->Restore(0x0002,0x0016);
00973    Archive->Restore(0x0002,0x0100);
00974    Archive->Restore(0x0002,0x0102);
00975 }
00976 
00984 void FileHelper::SetWriteFileTypeToACR()
00985 {
00986    Archive->Push(0x0002,0x0000);
00987    Archive->Push(0x0002,0x0001);
00988    Archive->Push(0x0002,0x0002);
00989    Archive->Push(0x0002,0x0003);
00990    Archive->Push(0x0002,0x0010);
00991    Archive->Push(0x0002,0x0012);
00992    Archive->Push(0x0002,0x0013);
00993    Archive->Push(0x0002,0x0016);
00994    Archive->Push(0x0002,0x0100);
00995    Archive->Push(0x0002,0x0102);
00996 }
00997 
01001 void FileHelper::SetWriteFileTypeToJPEG()
01002 {
01003    std::string ts = Util::DicomString( 
01004       Global::GetTS()->GetSpecialTransferSyntax(TS::JPEGBaselineProcess1) );
01005 
01006    DataEntry *tss = CopyDataEntry(0x0002,0x0010);
01007    tss->SetString(ts);
01008 
01009    Archive->Push(tss);
01010    tss->Delete();
01011 }
01012 
01013 void FileHelper::SetWriteFileTypeToExplicitVR()
01014 {
01015    std::string ts = Util::DicomString( 
01016       Global::GetTS()->GetSpecialTransferSyntax(TS::ExplicitVRLittleEndian) );
01017 
01018    DataEntry *tss = CopyDataEntry(0x0002,0x0010);
01019    tss->SetString(ts);
01020 
01021    Archive->Push(tss);
01022    tss->Delete();
01023 }
01024 
01028 void FileHelper::SetWriteFileTypeToImplicitVR()
01029 {
01030    std::string ts = Util::DicomString(
01031       Global::GetTS()->GetSpecialTransferSyntax(TS::ImplicitVRLittleEndian) );
01032 
01033    DataEntry *tss = CopyDataEntry(0x0002,0x0010);
01034    tss->SetString(ts);
01035 
01036    Archive->Push(tss);
01037    tss->Delete();
01038 }
01039 
01040 
01044 void FileHelper::RestoreWriteFileType()
01045 {
01046 }
01047 
01051 void FileHelper::SetWriteToLibido()
01052 {
01053    DataEntry *oldRow = FileInternal->GetDataEntry(0x0028, 0x0010);
01054    DataEntry *oldCol = FileInternal->GetDataEntry(0x0028, 0x0011);
01055    
01056    if ( oldRow && oldCol )
01057    {
01058       std::string rows, columns; 
01059 
01060       DataEntry *newRow=DataEntry::New(oldRow->GetDictEntry());
01061       DataEntry *newCol=DataEntry::New(oldCol->GetDictEntry());
01062 
01063       newRow->Copy(oldCol);
01064       newCol->Copy(oldRow);
01065 
01066       newRow->SetString(oldCol->GetString());
01067       newCol->SetString(oldRow->GetString());
01068 
01069       Archive->Push(newRow);
01070       Archive->Push(newCol);
01071 
01072       newRow->Delete();
01073       newCol->Delete();
01074    }
01075 
01076    DataEntry *libidoCode = CopyDataEntry(0x0008,0x0010);
01077    libidoCode->SetString("ACRNEMA_LIBIDO_1.1");
01078    Archive->Push(libidoCode);
01079    libidoCode->Delete();
01080 }
01081 
01085 void FileHelper::SetWriteToNoLibido()
01086 {
01087    DataEntry *recCode = FileInternal->GetDataEntry(0x0008,0x0010);
01088    if ( recCode )
01089    {
01090       if ( recCode->GetString() == "ACRNEMA_LIBIDO_1.1" )
01091       {
01092          DataEntry *libidoCode = CopyDataEntry(0x0008,0x0010);
01093          libidoCode->SetString("");
01094          Archive->Push(libidoCode);
01095          libidoCode->Delete();
01096       }
01097    }
01098 }
01099 
01103 void FileHelper::RestoreWriteOfLibido()
01104 {
01105    Archive->Restore(0x0028,0x0010);
01106    Archive->Restore(0x0028,0x0011);
01107    Archive->Restore(0x0008,0x0010);
01108 
01109    // Restore 'LibIDO-special' entries, if any
01110    Archive->Restore(0x0028,0x0015);
01111    Archive->Restore(0x0028,0x0016);
01112    Archive->Restore(0x0028,0x0017);
01113    Archive->Restore(0x0028,0x00199);
01114 }
01115 
01124 DataEntry *FileHelper::CopyDataEntry(uint16_t group, uint16_t elem,
01125                                    const TagName &vr)
01126 {
01127    DocEntry *oldE = FileInternal->GetDocEntry(group, elem);
01128    DataEntry *newE;
01129 
01130    if ( oldE && vr != GDCM_VRUNKNOWN ) 
01131       if ( oldE->GetVR() != vr )
01132          oldE = NULL;
01133 
01134    if ( oldE )
01135    {
01136       newE = DataEntry::New(oldE->GetDictEntry());
01137       newE->Copy(oldE);
01138    }
01139    else
01140    {
01141       newE = GetFile()->NewDataEntry(group, elem, vr);
01142    }
01143 
01144    return newE;
01145 }
01146 
01183 /* -------------------------------------------------------------------------------------
01184 To be moved to User's guide / WIKI  ?
01185 
01186 We have to deal with 4 *very* different cases :
01187 -1) user created ex nihilo his own image  and wants to write it as a Dicom image.
01188 -2) user modified the pixels of an existing image.
01189 -3) user created a new image, using existing images (eg MIP, MPR, cartography image)
01190 -4) user anonymized an image without processing the pixels.
01191 
01192 gdcm::FileHelper::CheckMandatoryElements() deals automatically with these cases.
01193 
01194 1)2)3)4)
01195 0008 0012 Instance Creation Date
01196 0008 0013 Instance Creation Time
01197 0008 0018 SOP Instance UID
01198 are *always* created with the current values; user has *no* possible intervention on
01199 them.
01200 
01201 'Serie Instance UID'(0x0020,0x000e)
01202 'Study Instance UID'(0x0020,0x000d) are kept as is if already exist,
01203                                     created  if it doesn't.
01204  The user is allowed to create his own Series/Studies, 
01205      keeping the same 'Serie Instance UID' / 'Study Instance UID' for various images
01206  Warning :     
01207  The user shouldn't add any image to a 'Manufacturer Serie'
01208      but there is no way no to allowed him to do that
01209      
01210  None of the 'shadow elements' are droped out.
01211      
01212 
01213 1)
01214 'Modality' (0x0008,0x0060)       is defaulted to "OT" (other) if missing.
01215 'Conversion Type (0x0008,0x0064) is forced to 'SYN' (Synthetic Image).
01216 'Study Date', 'Study Time' are defaulted to current Date and Time.
01217  
01218 1)2)3)
01219 'Media Storage SOP Class UID' (0x0002,0x0002)
01220 'SOP Class UID'               (0x0008,0x0016) are set to 
01221                                                [Secondary Capture Image Storage]
01222 'Image Type'                  (0x0008,0x0008) is forced to  "DERIVED\PRIMARY"
01223 Conversion Type               (0x0008,0x0064) is forced to 'SYN' (Synthetic Image)
01224 
01225 2)4)
01226 If 'SOP Class UID' exists in the native image  ('true DICOM' image)
01227     we create the 'Source Image Sequence' SeqEntry (0x0008, 0x2112)    
01228     --> 'Referenced SOP Class UID' (0x0008, 0x1150)
01229          whose value is the original 'SOP Class UID'
01230     --> 'Referenced SOP Instance UID' (0x0008, 0x1155)
01231          whose value is the original 'SOP Class UID'
01232 
01233 3) TODO : find a trick to allow user to pass to the writter the list of the Dicom images 
01234           or the Series, (or the Study ?) he used to created his image 
01235           (MIP, MPR, cartography image, ...)
01236            These info should be stored (?)
01237           0008 1110 SQ 1 Referenced Study Sequence
01238           0008 1115 SQ 1 Referenced Series Sequence
01239           0008 1140 SQ 1 Referenced Image Sequence
01240        
01241 4) When user *knows* he didn't modified the pixels, he may ask the writer to keep some
01242 informations unchanged :
01243 'Media Storage SOP Class UID' (0x0002,0x0002)
01244 'SOP Class UID'               (0x0008,0x0016)
01245 'Image Type'                  (0x0008,0x0008)
01246 'Conversion Type'             (0x0008,0x0064)
01247 He has to use gdcm::FileHelper::SetKeepMediaStorageSOPClassUID(true)
01248 (probabely name has to be changed)
01249 
01250 
01251 Bellow follows the full description (hope so !) of the consistency checks performed 
01252 by gdcm::FileHelper::CheckMandatoryElements()
01253 
01254 
01255 -->'Media Storage SOP Class UID' (0x0002,0x0002)
01256 -->'SOP Class UID'               (0x0008,0x0016) are set to 
01257                                                [Secondary Capture Image Storage]
01258    (Potentialy, the image was modified by user, and post-processed; 
01259     it's no longer a 'native' image)
01260   Except if user told he wants to keep MediaStorageSOPClassUID,
01261   when *he* knows he didn't modify the image (e.g. : he just anonymized the file)
01262 
01263 --> 'Image Type'  (0x0008,0x0008)
01264      is forced to  "DERIVED\PRIMARY"
01265      (The written image is no longer an 'ORIGINAL' one)
01266   Except if user told he wants to keep MediaStorageSOPClassUID,
01267   when *he* knows he didn't modify the image (e.g. : he just anonymized the file)
01268    
01269  -->  Conversion Type (0x0008,0x0064)
01270      is forced to 'SYN' (Synthetic Image)
01271   Except if user told he wants to keep MediaStorageSOPClassUID,
01272   when *he* knows he didn't modify the image (e.g. : he just anonymized the file)
01273             
01274 --> 'Modality' (0x0008,0x0060)   
01275     is defaulted to "OT" (other) if missing.   
01276     (a fully user created image belongs to *no* modality)
01277       
01278 --> 'Media Storage SOP Instance UID' (0x0002,0x0003)
01279 --> 'Implementation Class UID'       (0x0002,0x0012)
01280     are automatically generated; no user intervention possible
01281 
01282 --> 'Serie Instance UID'(0x0020,0x000e)
01283 --> 'Study Instance UID'(0x0020,0x000d) are kept as is if already exist
01284                                              created  if it doesn't.
01285      The user is allowed to create his own Series/Studies, 
01286      keeping the same 'Serie Instance UID' / 'Study Instance UID' 
01287      for various images
01288      Warning :     
01289      The user shouldn't add any image to a 'Manufacturer Serie'
01290      but there is no way no to allowed him to do that 
01291              
01292 --> If 'SOP Class UID' exists in the native image  ('true DICOM' image)
01293     we create the 'Source Image Sequence' SeqEntry (0x0008, 0x2112)
01294     
01295     --> 'Referenced SOP Class UID' (0x0008, 0x1150)
01296          whose value is the original 'SOP Class UID'
01297     --> 'Referenced SOP Instance UID' (0x0008, 0x1155)
01298          whose value is the original 'SOP Class UID'
01299     
01300 --> Bits Stored, Bits Allocated, Hight Bit Position are checked for consistency
01301 --> Pixel Spacing     (0x0028,0x0030) is defaulted to "1.0\1.0"
01302 --> Samples Per Pixel (0x0028,0x0002) is defaulted to 1 (grayscale)
01303 
01304 --> Imager Pixel Spacing (0x0018,0x1164) : defaulted to Pixel Spacing value
01305 
01306 --> Instance Creation Date, Instance Creation Time are forced to current Date and Time
01307 
01308 --> Study Date, Study Time are defaulted to current Date and Time
01309    (they remain unchanged if they exist)
01310 
01311 --> Patient Orientation : (0x0020,0x0020), if not present, is deduced from 
01312     Image Orientation (Patient) : (0020|0037) or from
01313     Image Orientation (RET)     : (0020 0035)
01314    
01315 --> Study ID, Series Number, Instance Number, Patient Orientation (Type 2)
01316     are created, with empty value if there are missing.
01317 
01318 --> Manufacturer, Institution Name, Patient's Name, (Type 2)
01319     are defaulted with a 'gdcm' value.
01320     
01321 --> Patient ID, Patient's Birth Date, Patient's Sex, (Type 2)
01322 --> Referring Physician's Name  (Type 2)
01323     are created, with empty value if there are missing.  
01324 
01325  -------------------------------------------------------------------------------------*/
01326  
01327 void FileHelper::CheckMandatoryElements()
01328 {
01329    std::string sop =  Util::CreateUniqueUID();
01330    
01331    // just to remember : 'official' 0002 group
01332    if ( WriteType != ACR && WriteType != ACR_LIBIDO )
01333    {
01334      // Group 000002 (Meta Elements) already pushed out
01335   
01336    //0002 0000 UL 1 Meta Group Length
01337    //0002 0001 OB 1 File Meta Information Version
01338    //0002 0002 UI 1 Media Stored SOP Class UID
01339    //0002 0003 UI 1 Media Stored SOP Instance UID
01340    //0002 0010 UI 1 Transfer Syntax UID
01341    //0002 0012 UI 1 Implementation Class UID
01342    //0002 0013 SH 1 Implementation Version Name
01343    //0002 0016 AE 1 Source Application Entity Title
01344    //0002 0100 UI 1 Private Information Creator
01345    //0002 0102 OB 1 Private Information
01346   
01347    // Create them if not found
01348    // Always modify the value
01349    // Push the entries to the archive.
01350       CopyMandatoryEntry(0x0002,0x0000,"0");
01351  
01352       DataEntry *e_0002_0001 = CopyDataEntry(0x0002,0x0001, "OB");
01353       e_0002_0001->SetBinArea((uint8_t*)Util::GetFileMetaInformationVersion(),
01354                                false);
01355       e_0002_0001->SetLength(2);
01356       Archive->Push(e_0002_0001);
01357       e_0002_0001->Delete(); 
01358 
01359       if ( KeepMediaStorageSOPClassUID)      
01360    // It up to the use to *know* whether he modified the pixels or not.
01361    // he is allowed to keep the original 'Media Storage SOP Class UID'
01362          CheckMandatoryEntry(0x0002,0x0002,"1.2.840.10008.5.1.4.1.1.7");    
01363       else
01364    // Potentialy this is a post-processed image 
01365    // 'Media Storage SOP Class UID'  --> [Secondary Capture Image Storage]
01366          CopyMandatoryEntry(0x0002,0x0002,"1.2.840.10008.5.1.4.1.1.7");    
01367        
01368    // 'Media Storage SOP Instance UID'   
01369       CopyMandatoryEntry(0x0002,0x0003,sop);
01370       
01371    // 'Implementation Class UID'
01372    // FIXME : in all examples we have, 0x0002,0x0012 is not so long :
01373    //         semms to be Root UID + 4 digits (?)
01374       CopyMandatoryEntry(0x0002,0x0012,Util::CreateUniqueUID());
01375 
01376    // 'Implementation Version Name'
01377       std::string version = "GDCM ";
01378       version += Util::GetVersion();
01379       CopyMandatoryEntry(0x0002,0x0013,version);
01380    }
01381 
01382    // Push out 'LibIDO-special' entries, if any
01383    Archive->Push(0x0028,0x0015);
01384    Archive->Push(0x0028,0x0016);
01385    Archive->Push(0x0028,0x0017);
01386    Archive->Push(0x0028,0x00199);
01387 
01388    // Deal with the pb of (Bits Stored = 12)
01389    // - we're gonna write the image as Bits Stored = 16
01390    if ( FileInternal->GetEntryString(0x0028,0x0100) ==  "12")
01391    {
01392       CopyMandatoryEntry(0x0028,0x0100,"16");
01393    }
01394 
01395    // Check if user wasn't drunk ;-)
01396 
01397    std::ostringstream s;
01398    // check 'Bits Allocated' vs decent values
01399    int nbBitsAllocated = FileInternal->GetBitsAllocated();
01400    if ( nbBitsAllocated == 0 || nbBitsAllocated > 32)
01401    {
01402       CopyMandatoryEntry(0x0028,0x0100,"16");
01403       gdcmWarningMacro("(0028,0100) changed from "
01404          << nbBitsAllocated << " to 16 for consistency purpose");
01405       nbBitsAllocated = 16; 
01406    }
01407    // check 'Bits Stored' vs 'Bits Allocated'   
01408    int nbBitsStored = FileInternal->GetBitsStored();
01409    if ( nbBitsStored == 0 || nbBitsStored > nbBitsAllocated )
01410    {
01411       s.str("");
01412       s << nbBitsAllocated;
01413       CopyMandatoryEntry(0x0028,0x0101,s.str());
01414       gdcmWarningMacro("(0028,0101) changed from "
01415                        << nbBitsStored << " to " << nbBitsAllocated
01416                        << " for consistency purpose" );
01417       nbBitsStored = nbBitsAllocated; 
01418     }
01419    // check 'Hight Bit Position' vs 'Bits Allocated' and 'Bits Stored'
01420    int highBitPosition = FileInternal->GetHighBitPosition();
01421    if ( highBitPosition == 0 || 
01422         highBitPosition > nbBitsAllocated-1 ||
01423         highBitPosition < nbBitsStored-1  )
01424    {
01425       s.str("");
01426       s << nbBitsStored - 1; 
01427       CopyMandatoryEntry(0x0028,0x0102,s.str());
01428       gdcmWarningMacro("(0028,0102) changed from "
01429                        << highBitPosition << " to " << nbBitsAllocated-1
01430                        << " for consistency purpose");
01431    }
01432 
01433    std::string pixelSpacing = FileInternal->GetEntryString(0x0028,0x0030);
01434    if ( pixelSpacing == GDCM_UNFOUND )
01435    {
01436       pixelSpacing = "1.0\\1.0";
01437        // if missing, Pixel Spacing forced to "1.0\1.0"
01438       CopyMandatoryEntry(0x0028,0x0030,pixelSpacing);
01439    }
01440    
01441    // 'Imager Pixel Spacing' : defaulted to 'Pixel Spacing'
01442    // --> This one is the *legal* one !
01443    // FIXME : we should write it only when we are *sure* the image comes from
01444    //         an imager (see also 0008,0x0064)          
01445    CheckMandatoryEntry(0x0018,0x1164,pixelSpacing);
01446    
01447    // Samples Per Pixel (type 1) : default to grayscale 
01448    CheckMandatoryEntry(0x0028,0x0002,"1");
01449    
01450    // --- Check UID-related Entries ---
01451 
01452    // If 'SOP Class UID' exists ('true DICOM' image)
01453    // we create the 'Source Image Sequence' SeqEntry
01454    // to hold informations about the Source Image
01455 
01456    DataEntry *e_0008_0016 = FileInternal->GetDataEntry(0x0008, 0x0016);
01457    if ( e_0008_0016 )
01458    {
01459       // Create 'Source Image Sequence' SeqEntry
01460       SeqEntry *sis = SeqEntry::New (
01461             Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x2112) );
01462       SQItem *sqi = SQItem::New(1);
01463       // (we assume 'SOP Instance UID' exists too) 
01464       // create 'Referenced SOP Class UID'
01465       DataEntry *e_0008_1150 = DataEntry::New(
01466             Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1150) );
01467       e_0008_1150->SetString( e_0008_0016->GetString());
01468       sqi->AddEntry(e_0008_1150);
01469       e_0008_1150->Delete();
01470       
01471       // create 'Referenced SOP Instance UID'
01472       DataEntry *e_0008_0018 = FileInternal->GetDataEntry(0x0008, 0x0018);
01473       DataEntry *e_0008_1155 = DataEntry::New(
01474             Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1155) );
01475       e_0008_1155->SetString( e_0008_0018->GetString());
01476       sqi->AddEntry(e_0008_1155);
01477       e_0008_1155->Delete();
01478 
01479       sis->AddSQItem(sqi,1);
01480       sqi->Delete();
01481 
01482       // temporarily replaces any previous 'Source Image Sequence' 
01483       Archive->Push(sis);
01484       sis->Delete();
01485  
01486       // FIXME : is 'Image Type' *really* depending on the presence of'SOP Class UID'?
01487        if ( KeepMediaStorageSOPClassUID)      
01488    // It up to the use to *know* whether he modified the pixels or not.
01489    // he is allowed to keep the original 'Media Storage SOP Class UID'
01490    // and 'Image Type' as well
01491          CheckMandatoryEntry(0x0008,0x0008,"DERIVED\\PRIMARY");    
01492       else
01493    // Potentialy this is a post-processed image 
01494    // (The written image is no longer an 'ORIGINAL' one)
01495       CopyMandatoryEntry(0x0008,0x0008,"DERIVED\\PRIMARY");
01496 
01497    }
01498 
01499    // At the end, not to overwrite the original ones,
01500    // needed by 'Referenced SOP Instance UID', 'Referenced SOP Class UID'   
01501    // 'SOP Instance UID'  
01502    CopyMandatoryEntry(0x0008,0x0018,sop);
01503    
01504    // the gdcm written image is a [Secondary Capture Image Storage]
01505    // except if user told us he dind't modify the pixels, and, therefore
01506    // he want to keep the 'Media Storage SOP Class UID'
01507    
01508       // 'Media Storage SOP Class UID' : [Secondary Capture Image Storage]
01509    if ( KeepMediaStorageSOPClassUID)
01510    {      
01511       // It up to the use to *know* whether he modified the pixels or not.
01512       // he is allowed to keep the original 'Media Storage SOP Class UID'
01513       CheckMandatoryEntry(0x0008,0x0016,"1.2.840.10008.5.1.4.1.1.7");    
01514    }
01515    else
01516    {
01517        // Potentialy this is a post-processed image 
01518        // 'Media Storage SOP Class UID'  --> [Secondary Capture Image Storage]
01519       CopyMandatoryEntry(0x0008,0x0016,"1.2.840.10008.5.1.4.1.1.7");    
01520 
01521        // FIXME : Must we Force Value, or Default value ?
01522        // Is it Type 1 for any Modality ?
01523        //    --> Answer seems to be NO :-(
01524        // FIXME : we should write it only when we are *sure* the image 
01525        //         *does not* come from an imager (see also 0018,0x1164)
01526 
01527        // Conversion Type.
01528        // Other possible values are :
01529        // See PS 3.3, Page 408
01530    
01531        // DV = Digitized Video
01532        // DI = Digital Interface   
01533        // DF = Digitized Film
01534        // WSD = Workstation
01535        // SD = Scanned Document
01536        // SI = Scanned Image
01537        // DRW = Drawing
01538        // SYN = Synthetic Image
01539      
01540       CheckMandatoryEntry(0x0008,0x0064,"SYN");
01541    }   
01542            
01543    // ---- The user will never have to take any action on the following ----
01544    
01545    // new value for 'SOP Instance UID'
01546    //SetMandatoryEntry(0x0008,0x0018,Util::CreateUniqueUID());
01547 
01548    // Instance Creation Date
01549    const std::string &date = Util::GetCurrentDate();
01550    CopyMandatoryEntry(0x0008,0x0012,date);
01551  
01552    // Instance Creation Time
01553    const std::string &time = Util::GetCurrentTime();
01554    CopyMandatoryEntry(0x0008,0x0013,time);
01555 
01556    // Study Date
01557    CheckMandatoryEntry(0x0008,0x0020,date);
01558    // Study Time
01559    CheckMandatoryEntry(0x0008,0x0030,time);
01560 
01561    // Accession Number
01562    //CopyMandatoryEntry(0x0008,0x0050,"");
01563    CheckMandatoryEntry(0x0008,0x0050,"");
01564    
01565 
01566    // ----- Add Mandatory Entries if missing ---
01567    // Entries whose type is 1 are mandatory, with a mandatory value
01568    // Entries whose type is 1c are mandatory-inside-a-Sequence,
01569    //                          with a mandatory value
01570    // Entries whose type is 2 are mandatory, with an optional value
01571    // Entries whose type is 2c are mandatory-inside-a-Sequence,
01572    //                          with an optional value
01573    // Entries whose type is 3 are optional
01574 
01575    // 'Study Instance UID'
01576    // Keep the value if exists
01577    // The user is allowed to create his own Study, 
01578    //          keeping the same 'Study Instance UID' for various images
01579    // The user may add images to a 'Manufacturer Study',
01580    //          adding new Series to an already existing Study 
01581    CheckMandatoryEntry(0x0020,0x000d,Util::CreateUniqueUID());
01582 
01583    // 'Serie Instance UID'
01584    // Keep the value if exists
01585    // The user is allowed to create his own Series, 
01586    // keeping the same 'Serie Instance UID' for various images
01587    // The user shouldn't add any image to a 'Manufacturer Serie'
01588    // but there is no way no to prevent him for doing that 
01589    CheckMandatoryEntry(0x0020,0x000e,Util::CreateUniqueUID());
01590 
01591    // Study ID
01592    CheckMandatoryEntry(0x0020,0x0010,"");
01593 
01594    // Series Number
01595    CheckMandatoryEntry(0x0020,0x0011,"");
01596 
01597    // Instance Number
01598    CheckMandatoryEntry(0x0020,0x0013,"");
01599    
01600    // Patient Orientation
01601    // Can be computed from (0020|0037) :  Image Orientation (Patient)
01602    gdcm::Orientation *o = gdcm::Orientation::New();
01603    std::string ori = o->GetOrientation ( FileInternal );
01604    o->Delete();
01605    if (ori != "\\" )
01606       CheckMandatoryEntry(0x0020,0x0020,ori);
01607    else   
01608       CheckMandatoryEntry(0x0020,0x0020,"");
01609    
01610    // Modality : if missing we set it to 'OTher'
01611    CheckMandatoryEntry(0x0008,0x0060,"OT");
01612 
01613    // Manufacturer : if missing we set it to 'GDCM Factory'
01614    CheckMandatoryEntry(0x0008,0x0070,"GDCM Factory");
01615 
01616    // Institution Name : if missing we set it to 'GDCM Hospital'
01617    CheckMandatoryEntry(0x0008,0x0080,"GDCM Hospital");
01618 
01619    // Patient's Name : if missing, we set it to 'GDCM^Patient'
01620    CheckMandatoryEntry(0x0010,0x0010,"GDCM^Patient");
01621 
01622    // Patient ID
01623    CheckMandatoryEntry(0x0010,0x0020,"");
01624 
01625    // Patient's Birth Date : 'type 2' entry -> must exist, value not mandatory
01626    CheckMandatoryEntry(0x0010,0x0030,"");
01627 
01628    // Patient's Sex :'type 2' entry -> must exist, value not mandatory
01629    CheckMandatoryEntry(0x0010,0x0040,"");
01630 
01631    // Referring Physician's Name :'type 2' entry -> must exist, value not mandatory
01632    CheckMandatoryEntry(0x0008,0x0090,"");
01633    
01634    // Remove some inconstencies (probably some more will be added)
01635 
01636    // if (0028 0008)Number of Frames exists
01637    //    Push out (0020 0052),Frame of Reference UID
01638    //    (only meaningfull within a Serie)
01639    DataEntry *e_0028_0008 = FileInternal->GetDataEntry(0x0028, 0x0008);
01640    if ( !e_0028_0008 )
01641    {
01642       Archive->Push(0x0020, 0x0052);
01643    }
01644  
01645    // Deal with element 0x0000 (group length) of each group.
01646    // First stage : get all the different Groups
01647  /*
01648   GroupHT grHT;
01649   DocEntry *d = FileInternal->GetFirstEntry();
01650   while(d)
01651   {
01652     grHT[d->GetGroup()] = 0;
01653     d=FileInternal->GetNextEntry();
01654   }
01655   // Second stage : add the missing ones (if any)
01656   for (GroupHT::iterator it = grHT.begin(); it != grHT.end(); ++it)  
01657   {
01658       CheckMandatoryEntry(it->first, 0x0000, "0"); 
01659   }    
01660   // Third stage : update all 'zero level' groups length
01661 */   
01662 } 
01663 
01664 void FileHelper::CheckMandatoryEntry(uint16_t group,uint16_t elem,std::string value)
01665 {
01666    DataEntry *entry = FileInternal->GetDataEntry(group,elem);
01667    if ( !entry )
01668    {
01669       entry = DataEntry::New(Global::GetDicts()->GetDefaultPubDict()->GetEntry(group,elem));
01670       entry->SetString(value);
01671       Archive->Push(entry);
01672       entry->Delete();
01673    }
01674 }
01675 
01676 void FileHelper::SetMandatoryEntry(uint16_t group,uint16_t elem,std::string value)
01677 {
01678    DataEntry *entry = DataEntry::New(Global::GetDicts()->GetDefaultPubDict()->GetEntry(group,elem));
01679    entry->SetString(value);
01680    Archive->Push(entry);
01681    entry->Delete();
01682 }
01683 
01684 void FileHelper::CopyMandatoryEntry(uint16_t group,uint16_t elem,std::string value)
01685 {
01686    DataEntry *entry = CopyDataEntry(group,elem);
01687    entry->SetString(value);
01688    Archive->Push(entry);
01689    entry->Delete();
01690 }
01691 
01695 void FileHelper::RestoreWriteMandatory()
01696 {
01697    // group 0002 may be pushed out for ACR-NEMA writting purposes 
01698    Archive->Restore(0x0002,0x0000);
01699    Archive->Restore(0x0002,0x0001);
01700    Archive->Restore(0x0002,0x0002);
01701    Archive->Restore(0x0002,0x0003);
01702    Archive->Restore(0x0002,0x0010);
01703    Archive->Restore(0x0002,0x0012);
01704    Archive->Restore(0x0002,0x0013);
01705    Archive->Restore(0x0002,0x0016);
01706    Archive->Restore(0x0002,0x0100);
01707    Archive->Restore(0x0002,0x0102);
01708 
01709    // FIXME : Check if none is missing !
01710    
01711    Archive->Restore(0x0008,0x0012);
01712    Archive->Restore(0x0008,0x0013);
01713    Archive->Restore(0x0008,0x0016);
01714    Archive->Restore(0x0008,0x0018);
01715    Archive->Restore(0x0008,0x0060);
01716    Archive->Restore(0x0008,0x0070);
01717    Archive->Restore(0x0008,0x0080);
01718    Archive->Restore(0x0008,0x0090);
01719    Archive->Restore(0x0008,0x2112);
01720 
01721    Archive->Restore(0x0010,0x0010);
01722    Archive->Restore(0x0010,0x0030);
01723    Archive->Restore(0x0010,0x0040);
01724 
01725    Archive->Restore(0x0020,0x000d);
01726    Archive->Restore(0x0020,0x000e);
01727 }
01728 
01729 
01733 void FileHelper::CallStartMethod()
01734 {
01735    Progress = 0.0f;
01736    Abort    = false;
01737    CommandManager::ExecuteCommand(this,CMD_STARTPROGRESS);
01738 }
01739 
01743 void FileHelper::CallProgressMethod()
01744 {
01745    CommandManager::ExecuteCommand(this,CMD_PROGRESS);
01746 }
01747 
01751 void FileHelper::CallEndMethod()
01752 {
01753    Progress = 1.0f;
01754    CommandManager::ExecuteCommand(this,CMD_ENDPROGRESS);
01755 }
01756 
01757 //-----------------------------------------------------------------------------
01758 // Private
01762 void FileHelper::Initialize()
01763 {
01764    UserFunction = 0;
01765    KeepMediaStorageSOPClassUID = false;
01766    
01767    WriteMode = WMODE_RAW;
01768    WriteType = ExplicitVR;
01769 
01770    PixelReadConverter  = new PixelReadConvert;
01771    PixelWriteConverter = new PixelWriteConvert;
01772    Archive = new DocEntryArchive( FileInternal );
01773 }
01774 
01781 uint8_t *FileHelper::GetRaw()
01782 {
01783    PixelReadConverter->SetUserFunction( UserFunction );
01784 
01785    uint8_t *raw = PixelReadConverter->GetRaw();
01786    if ( ! raw )
01787    {
01788       // The Raw image migth not be loaded yet:
01789       std::ifstream *fp = FileInternal->OpenFile();
01790       PixelReadConverter->ReadAndDecompressPixelData( fp );
01791       if ( fp ) 
01792          FileInternal->CloseFile();
01793 
01794       raw = PixelReadConverter->GetRaw();
01795       if ( ! raw )
01796       {
01797          gdcmWarningMacro( "Read/decompress of pixel data apparently went wrong.");
01798          return 0;
01799       }
01800    }
01801    return raw;
01802 }
01803 
01804 //-----------------------------------------------------------------------------
01810 void FileHelper::Print(std::ostream &os, std::string const &)
01811 {
01812    FileInternal->SetPrintLevel(PrintLevel);
01813    FileInternal->Print(os);
01814 
01815    if ( FileInternal->IsReadable() )
01816    {
01817       PixelReadConverter->SetPrintLevel(PrintLevel);
01818       PixelReadConverter->Print(os);
01819    }
01820 }
01821 
01822 //-----------------------------------------------------------------------------
01823 } // end namespace gdcm

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