+
+/**
+ * \brief Points the internal Pixel_Data pointer to the callers inData
+ * image representation, BUT WITHOUT COPYING THE DATA.
+ * 'image' Pixels are presented as C-like 2D arrays : line per line.
+ * 'volume'Pixels are presented as C-like 3D arrays : plane per plane
+ * \warning Since the pixels are not copied, it is the caller's responsability
+ * not to deallocate it's data before gdcm uses them (e.g. with
+ * the Write() method.
+ * @param inData user supplied pixel area
+ * @param expectedSize total image size, in Bytes
+ *
+ * @return boolean
+ */
+bool File::SetImageData(uint8_t* inData, size_t expectedSize)
+{
+// FIXME : if already allocated, memory leak !
+ Pixel_Data = inData;
+ ImageDataSize = expectedSize;
+// FIXME : 7fe0, 0010 IS NOT set ...
+ return true;
+}
+
+/**
+ * \brief Writes on disk A SINGLE Dicom file
+ * NO test is performed on processor "Endiannity".
+ * It's up to the user to call his Reader properly
+ * @param fileName name of the file to be created
+ * (any already existing file is over written)
+ * @return false if write fails
+ */
+
+bool File::WriteRawData(std::string const & fileName)
+{
+ std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary );
+ if (!fp1)
+ {
+ dbg.Verbose(2, "Fail to open (write) file:", fileName.c_str());
+ return false;
+ }
+ fp1.write((char*)Pixel_Data, ImageDataSize);
+ fp1.close();
+
+ return true;
+}
+
+/**
+ * \brief Writes on disk A SINGLE Dicom file,
+ * using the Implicit Value Representation convention
+ * NO test is performed on processor "Endiannity".
+ * @param fileName name of the file to be created
+ * (any already existing file is overwritten)
+ * @return false if write fails
+ */
+
+bool File::WriteDcmImplVR (std::string const & fileName)
+{
+ SetWriteTypeToDcmImplVR();
+ return Write(fileName);
+}
+
+/**
+* \brief Writes on disk A SINGLE Dicom file,
+ * using the Explicit Value Representation convention
+ * NO test is performed on processor "Endiannity". * @param fileName name of the file to be created
+ * (any already existing file is overwritten)
+ * @return false if write fails
+ */
+
+bool File::WriteDcmExplVR (std::string const & fileName)
+{
+ SetWriteTypeToDcmExplVR();
+ return Write(fileName);
+}
+
+/**
+ * \brief Writes on disk A SINGLE Dicom file,
+ * using the ACR-NEMA convention
+ * NO test is performed on processor "Endiannity".
+ * (a l'attention des logiciels cliniques
+ * qui ne prennent en entrée QUE des images ACR ...
+ * \warning if a DICOM_V3 header is supplied,
+ * groups < 0x0008 and shadow groups are ignored
+ * \warning NO TEST is performed on processor "Endiannity".
+ * @param fileName name of the file to be created
+ * (any already existing file is overwritten)
+ * @return false if write fails
+ */
+
+bool File::WriteAcr (std::string const & fileName)
+{
+ SetWriteTypeToAcr();
+ return Write(fileName);
+}
+
+bool File::Write(std::string const& fileName)
+{
+ switch(WriteType)
+ {
+ case WTYPE_IMPL_VR:
+ return WriteBase(fileName,ImplicitVR);
+ case WTYPE_EXPL_VR:
+ return WriteBase(fileName,ExplicitVR);
+ case WTYPE_ACR:
+ return WriteBase(fileName,ACR);
+ }
+ return(false);
+}
+
+/**
+ * \brief Access to the underlying \ref PixelConverter RGBA LUT
+ */
+uint8_t* File::GetLutRGBA()
+{
+ return PixelConverter->GetLutRGBA();
+}
+
+//-----------------------------------------------------------------------------
+// Protected
+/**
+ * \brief NOT a end user inteded function
+ * (used by WriteDcmExplVR, WriteDcmImplVR, WriteAcr, etc)
+ * @param fileName name of the file to be created
+ * (any already existing file is overwritten)
+ * @param type file type (ExplicitVR, ImplicitVR, ...)
+ * @return false if write fails
+ */
+bool File::WriteBase (std::string const & fileName, FileType type)
+{
+ switch(type)
+ {
+ case ImplicitVR:
+ SetWriteFileTypeToImplicitVR();
+ break;
+ case ExplicitVR:
+ SetWriteFileTypeToExplicitVR();
+ break;
+ case ACR:
+ case ACR_LIBIDO:
+ SetWriteFileTypeToACR();
+ break;
+ default:
+ SetWriteFileTypeToExplicitVR();
+ }
+
+ if( type == ACR_LIBIDO )
+ {
+ SetWriteToLibido();
+ }
+ else
+ {
+ SetWriteToNoLibido();
+ }
+
+ switch(WriteMode)
+ {
+ case WMODE_NATIVE :
+ SetWriteToNative();
+ break;
+ case WMODE_DECOMPRESSED :
+ SetWriteToDecompressed();
+ break;
+ case WMODE_RGB :
+ SetWriteToRGB();
+ break;
+ }
+
+ // --------------------------------------------------------------
+ // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
+ //
+ // if recognition code tells us we dealt with a LibIDO image
+ // we reproduce on disk the switch between lineNumber and columnNumber
+ // just before writting ...
+ /// \todo the best trick would be *change* the recognition code
+ /// but pb expected if user deals with, e.g. COMPLEX images
+/* if ( HeaderInternal->GetFileType() == ACR_LIBIDO)
+ {
+ SetWriteToLibido();
+ }*/
+ // ----------------- End of Special Patch ----------------
+
+ bool check = CheckWriteIntegrity();
+ if(check)
+ {
+ check = HeaderInternal->Write(fileName,type);
+ }
+
+ // --------------------------------------------------------------
+ // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
+ //
+ // ...and we restore the Header to be Dicom Compliant again
+ // just after writting
+/* if ( HeaderInternal->GetFileType() == ACR_LIBIDO )
+ {
+ RestoreWriteFromLibido();
+ }*/
+ // ----------------- End of Special Patch ----------------
+
+ RestoreWrite();
+ RestoreWriteFileType();
+ RestoreWriteOfLibido();
+
+ return check;
+}
+
+/**
+ * \brief Check the write integrity
+ *
+ * The tests made are :
+ * - verify the size of the image to write with the possible write
+ * when the user set an image data
+ * @return true if the check successfulls
+ */
+bool File::CheckWriteIntegrity()
+{
+ if(Pixel_Data)
+ {
+ int numberBitsAllocated = HeaderInternal->GetBitsAllocated();
+ if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
+ {
+ numberBitsAllocated = 16;
+ }
+
+ size_t decSize = HeaderInternal->GetXSize()
+ * HeaderInternal->GetYSize()
+ * HeaderInternal->GetZSize()
+ * ( numberBitsAllocated / 8 )
+ * HeaderInternal->GetSamplesPerPixel();
+ size_t rgbSize = decSize;
+ if( HeaderInternal->HasLUT() )
+ rgbSize = decSize * 3;
+
+ switch(WriteMode)
+ {
+ case WMODE_NATIVE :
+ break;
+ case WMODE_DECOMPRESSED :
+ if( decSize!=ImageDataSize )
+ {
+ dbg.Verbose(0, "File::CheckWriteIntegrity: Data size is incorrect");
+ //std::cerr<<"Dec : "<<decSize<<" | "<<ImageDataSize<<std::endl;
+ return false;
+ }
+ break;
+ case WMODE_RGB :
+ if( rgbSize!=ImageDataSize )
+ {
+ dbg.Verbose(0, "File::CheckWriteIntegrity: Data size is incorrect");
+ //std::cerr<<"RGB : "<<decSize<<" | "<<ImageDataSize<<std::endl;
+ return false;
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
+void File::SetWriteToNative()
+{
+ if(Pixel_Data)
+ {
+ BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
+ pixel->SetValue(GDCM_BINLOADED);
+ pixel->SetBinArea(Pixel_Data,false);
+ pixel->SetLength(ImageDataSize);
+
+ Archive->Push(pixel);
+ }
+}
+
+void File::SetWriteToDecompressed()
+{
+ if(HeaderInternal->GetNumberOfScalarComponents()==3 && !HeaderInternal->HasLUT())
+ {
+ SetWriteToRGB();
+ }
+ else
+ {
+ ValEntry* photInt = CopyValEntry(0x0028,0x0004);
+ if(HeaderInternal->HasLUT())
+ {
+ photInt->SetValue("PALETTE COLOR ");
+ photInt->SetLength(14);
+ }
+ else
+ {
+ photInt->SetValue("MONOCHROME1 ");
+ photInt->SetLength(12);
+ }
+
+ BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
+ pixel->SetValue(GDCM_BINLOADED);
+ if(Pixel_Data)
+ {
+ pixel->SetBinArea(Pixel_Data,false);
+ pixel->SetLength(ImageDataSize);
+ }
+ else
+ {
+ pixel->SetBinArea(PixelConverter->GetDecompressed(),false);
+ pixel->SetLength(PixelConverter->GetDecompressedSize());
+ }
+
+ Archive->Push(photInt);
+ Archive->Push(pixel);
+ }
+}
+
+void File::SetWriteToRGB()
+{
+ if(HeaderInternal->GetNumberOfScalarComponents()==3)
+ {
+ PixelConverter->BuildRGBImage();
+
+ ValEntry* spp = CopyValEntry(0x0028,0x0002);
+ spp->SetValue("3 ");
+ spp->SetLength(2);
+
+ ValEntry* planConfig = CopyValEntry(0x0028,0x0006);
+ planConfig->SetValue("0 ");
+ planConfig->SetLength(2);
+
+ ValEntry* photInt = CopyValEntry(0x0028,0x0004);
+ photInt->SetValue("RGB ");
+ photInt->SetLength(4);
+
+ BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
+ pixel->SetValue(GDCM_BINLOADED);
+ if(Pixel_Data)
+ {
+ pixel->SetBinArea(Pixel_Data,false);
+ pixel->SetLength(ImageDataSize);
+ }
+ else if(PixelConverter->GetRGB())
+ {
+ pixel->SetBinArea(PixelConverter->GetRGB(),false);
+ pixel->SetLength(PixelConverter->GetRGBSize());
+ }
+ else // Decompressed data
+ {
+ pixel->SetBinArea(PixelConverter->GetDecompressed(),false);
+ pixel->SetLength(PixelConverter->GetDecompressedSize());
+ }
+
+ Archive->Push(spp);
+ Archive->Push(planConfig);
+ Archive->Push(photInt);
+ Archive->Push(pixel);
+
+ // Remove any LUT
+ Archive->Push(0x0028,0x1101);
+ Archive->Push(0x0028,0x1102);
+ Archive->Push(0x0028,0x1103);
+ Archive->Push(0x0028,0x1201);
+ Archive->Push(0x0028,0x1202);
+ Archive->Push(0x0028,0x1203);
+
+ // For old ACR-NEMA
+ // Thus, we have a RGB image and the bits allocated = 24 and
+ // samples per pixels = 1 (in the read file)
+ if(HeaderInternal->GetBitsAllocated()==24)
+ {
+ ValEntry* bitsAlloc = CopyValEntry(0x0028,0x0100);
+ bitsAlloc->SetValue("8 ");
+ bitsAlloc->SetLength(2);
+
+ ValEntry* bitsStored = CopyValEntry(0x0028,0x0101);
+ bitsStored->SetValue("8 ");
+ bitsStored->SetLength(2);
+
+ ValEntry* highBit = CopyValEntry(0x0028,0x0102);
+ highBit->SetValue("7 ");
+ highBit->SetLength(2);
+
+ Archive->Push(bitsAlloc);
+ Archive->Push(bitsStored);
+ Archive->Push(highBit);
+ }
+ }
+ else
+ {
+ SetWriteToDecompressed();
+ }
+}
+
+void File::RestoreWrite()
+{
+ Archive->Restore(0x0028,0x0002);
+ Archive->Restore(0x0028,0x0004);
+ Archive->Restore(0x0028,0x0006);
+ Archive->Restore(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
+
+ // For old ACR-NEMA (24 bits problem)
+ Archive->Restore(0x0028,0x0100);
+ Archive->Restore(0x0028,0x0101);
+ Archive->Restore(0x0028,0x0102);
+
+ // For the LUT
+ Archive->Restore(0x0028,0x1101);
+ Archive->Restore(0x0028,0x1102);
+ Archive->Restore(0x0028,0x1103);
+ Archive->Restore(0x0028,0x1201);
+ Archive->Restore(0x0028,0x1202);
+ Archive->Restore(0x0028,0x1203);
+}
+
+void File::SetWriteFileTypeToACR()
+{
+ Archive->Push(0x0002,0x0010);
+}
+
+void File::SetWriteFileTypeToExplicitVR()
+{
+ std::string ts = Util::DicomString(
+ Document::GetTransferSyntaxValue(ExplicitVRLittleEndian).c_str() );
+
+ ValEntry* tss = CopyValEntry(0x0002,0x0010);
+ tss->SetValue(ts);
+ tss->SetLength(ts.length());
+
+ Archive->Push(tss);
+}
+
+void File::SetWriteFileTypeToImplicitVR()
+{
+ std::string ts = Util::DicomString(
+ Document::GetTransferSyntaxValue(ImplicitVRLittleEndian).c_str() );
+
+ ValEntry* tss = CopyValEntry(0x0002,0x0010);
+ tss->SetValue(ts);
+ tss->SetLength(ts.length());
+}
+
+void File::RestoreWriteFileType()
+{
+ Archive->Restore(0x0002,0x0010);
+}
+
+void File::SetWriteToLibido()
+{
+ ValEntry *oldRow = dynamic_cast<ValEntry *>(HeaderInternal->GetDocEntryByNumber(0x0028, 0x0010));
+ ValEntry *oldCol = dynamic_cast<ValEntry *>(HeaderInternal->GetDocEntryByNumber(0x0028, 0x0011));
+
+ if( oldRow && oldCol )
+ {
+ std::string rows, columns;
+
+ ValEntry *newRow=new ValEntry(oldRow->GetDictEntry());
+ ValEntry *newCol=new ValEntry(oldCol->GetDictEntry());
+
+ newRow->Copy(oldCol);
+ newCol->Copy(oldRow);
+
+ newRow->SetValue(oldCol->GetValue());
+ newCol->SetValue(oldRow->GetValue());
+
+ Archive->Push(newRow);
+ Archive->Push(newCol);
+ }
+
+ ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
+ libidoCode->SetValue("ACRNEMA_LIBIDO_1.1");
+ libidoCode->SetLength(10);
+ Archive->Push(libidoCode);
+}
+
+void File::SetWriteToNoLibido()
+{
+ ValEntry *recCode = dynamic_cast<ValEntry *>(HeaderInternal->GetDocEntryByNumber(0x0008,0x0010));
+ if( recCode )
+ {
+ if( recCode->GetValue() == "ACRNEMA_LIBIDO_1.1" )
+ {
+ ValEntry *libidoCode = CopyValEntry(0x0008,0x0010);
+ libidoCode->SetValue("");
+ libidoCode->SetLength(0);
+ Archive->Push(libidoCode);
+ }
+ }
+}
+
+void File::RestoreWriteOfLibido()
+{
+ Archive->Restore(0x0028,0x0010);
+ Archive->Restore(0x0028,0x0011);
+ Archive->Restore(0x0008,0x0010);
+}
+
+ValEntry* File::CopyValEntry(uint16_t group,uint16_t element)
+{
+ DocEntry* oldE = HeaderInternal->GetDocEntryByNumber(group, element);
+ ValEntry* newE;
+
+ if(oldE)
+ {
+ newE = new ValEntry(oldE->GetDictEntry());
+ newE->Copy(oldE);
+ }
+ else
+ {
+ newE = GetHeader()->NewValEntryByNumber(group,element);
+ }
+
+ return(newE);
+}
+
+BinEntry* File::CopyBinEntry(uint16_t group,uint16_t element)
+{
+ DocEntry* oldE = HeaderInternal->GetDocEntryByNumber(group, element);
+ BinEntry* newE;
+
+ if(oldE)
+ {
+ newE = new BinEntry(oldE->GetDictEntry());
+ newE->Copy(oldE);
+ }
+ else
+ {
+ newE = GetHeader()->NewBinEntryByNumber(group,element);
+ }
+
+
+ return(newE);
+}
+
+//-----------------------------------------------------------------------------
+// Private
+
+//-----------------------------------------------------------------------------
+} // end namespace gdcm
+