/*========================================================================= Program: GDCM (Grassroots DICOM). A DICOM library Copyright (c) 2006-2011 Mathieu Malaterre All rights reserved. See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "gdcmPixmapWriter.h" #include "gdcmImageHelper.h" #include "gdcmTrace.h" #include "gdcmDataSet.h" #include "gdcmDataElement.h" #include "gdcmAttribute.h" #include "gdcmUIDGenerator.h" #include "gdcmSystem.h" #include "gdcmPixmap.h" #include "gdcmLookupTable.h" #include "gdcmItem.h" #include "gdcmSequenceOfItems.h" namespace gdcm { PixmapWriter::PixmapWriter():PixelData(new Pixmap) { } PixmapWriter::~PixmapWriter() = default; void PixmapWriter::SetPixmap(Pixmap const &img) { PixelData = img; } void PixmapWriter::DoIconImage(DataSet & rootds, Pixmap const & image) { //const Tag ticonimage(0x0088,0x0200); const IconImage &icon = image.GetIconImage(); if( !icon.IsEmpty() ) { //DataElement iconimagesq = rootds.GetDataElement( ticonimage ); //iconimagesq.SetTag( ticonimage ); DataElement iconimagesq; iconimagesq.SetTag( Attribute<0x0088,0x0200>::GetTag() ); iconimagesq.SetVR( VR::SQ ); SmartPointer sq = new SequenceOfItems; sq->SetLengthToUndefined(); DataSet ds; //SequenceOfItems* sq = iconimagesq.GetSequenceOfItems(); //// Is SQ empty ? //if( !sq ) return; //SequenceOfItems::Iterator it = sq->Begin(); //DataSet &ds = it->GetNestedDataSet(); // col & rows: Attribute<0x0028, 0x0011> columns; columns.SetValue( (uint16_t)icon.GetDimension(0) ); ds.Insert( columns.GetAsDataElement() ); Attribute<0x0028, 0x0010> rows; rows.SetValue( (uint16_t)icon.GetDimension(1) ); ds.Insert( rows.GetAsDataElement() ); PixelFormat pf = icon.GetPixelFormat(); Attribute<0x0028, 0x0100> bitsallocated; bitsallocated.SetValue( pf.GetBitsAllocated() ); ds.Replace( bitsallocated.GetAsDataElement() ); Attribute<0x0028, 0x0101> bitsstored; bitsstored.SetValue( pf.GetBitsStored() ); ds.Replace( bitsstored.GetAsDataElement() ); Attribute<0x0028, 0x0102> highbit; highbit.SetValue( pf.GetHighBit() ); ds.Replace( highbit.GetAsDataElement() ); Attribute<0x0028, 0x0103> pixelrepresentation; pixelrepresentation.SetValue( pf.GetPixelRepresentation() ); ds.Replace( pixelrepresentation.GetAsDataElement() ); Attribute<0x0028, 0x0002> samplesperpixel; samplesperpixel.SetValue( pf.GetSamplesPerPixel() ); ds.Replace( samplesperpixel.GetAsDataElement() ); if( pf.GetSamplesPerPixel() != 1 ) { Attribute<0x0028, 0x0006> planarconf; planarconf.SetValue( (uint16_t)icon.GetPlanarConfiguration() ); ds.Replace( planarconf.GetAsDataElement() ); } PhotometricInterpretation pi = icon.GetPhotometricInterpretation(); Attribute<0x0028,0x0004> piat; const char *pistr = PhotometricInterpretation::GetPIString(pi); { DataElement de( Tag(0x0028, 0x0004 ) ); VL::Type strlenPistr = (VL::Type)strlen(pistr); de.SetByteValue( pistr, strlenPistr ); de.SetVR( piat.GetVR() ); ds.Replace( de ); } if ( pi == PhotometricInterpretation::PALETTE_COLOR ) { const LookupTable &lut = icon.GetLUT(); assert( (pf.GetBitsAllocated() == 8 && pf.GetPixelRepresentation() == 0) || (pf.GetBitsAllocated() == 16 && pf.GetPixelRepresentation() == 0) ); // lut descriptor: // (0028,1101) US 256\0\16 # 6, 3 RedPaletteColorLookupTableDescriptor // (0028,1102) US 256\0\16 # 6, 3 GreenPaletteColorLookupTableDescriptor // (0028,1103) US 256\0\16 # 6, 3 BluePaletteColorLookupTableDescriptor // lut data: unsigned short length, subscript, bitsize; //unsigned short rawlut8[256]; std::vector rawlut8; rawlut8.resize(256); //unsigned short rawlut16[65536]; std::vector rawlut16; unsigned short *rawlut = &rawlut8[0]; unsigned int lutlen = 256; if( pf.GetBitsAllocated() == 16 ) { rawlut16.resize(65536); rawlut = &rawlut16[0]; lutlen = 65536; } unsigned int l; // FIXME: should I really clear rawlut each time ? // RED memset(rawlut,0,lutlen*2); lut.GetLUT(LookupTable::RED, (unsigned char*)rawlut, l); DataElement redde( Tag(0x0028, 0x1201) ); redde.SetVR( VR::OW ); redde.SetByteValue( (char*)rawlut, l); ds.Replace( redde ); // descriptor: Attribute<0x0028, 0x1101, VR::US, VM::VM3> reddesc; lut.GetLUTDescriptor(LookupTable::RED, length, subscript, bitsize); reddesc.SetValue(length,0); reddesc.SetValue(subscript,1); reddesc.SetValue(bitsize,2); ds.Replace( reddesc.GetAsDataElement() ); // GREEN memset(rawlut,0,lutlen*2); lut.GetLUT(LookupTable::GREEN, (unsigned char*)rawlut, l); DataElement greende( Tag(0x0028, 0x1202) ); greende.SetVR( VR::OW ); greende.SetByteValue( (char*)rawlut, l); ds.Replace( greende ); // descriptor: Attribute<0x0028, 0x1102, VR::US, VM::VM3> greendesc; lut.GetLUTDescriptor(LookupTable::GREEN, length, subscript, bitsize); greendesc.SetValue(length,0); greendesc.SetValue(subscript,1); greendesc.SetValue(bitsize,2); ds.Replace( greendesc.GetAsDataElement() ); // BLUE memset(rawlut,0,lutlen*2); lut.GetLUT(LookupTable::BLUE, (unsigned char*)rawlut, l); DataElement bluede( Tag(0x0028, 0x1203) ); bluede.SetVR( VR::OW ); bluede.SetByteValue( (char*)rawlut, l); ds.Replace( bluede ); // descriptor: Attribute<0x0028, 0x1103, VR::US, VM::VM3> bluedesc; lut.GetLUTDescriptor(LookupTable::BLUE, length, subscript, bitsize); bluedesc.SetValue(length,0); bluedesc.SetValue(subscript,1); bluedesc.SetValue(bitsize,2); ds.Replace( bluedesc.GetAsDataElement() ); } { // Pixel Data DataElement de( Tag(0x7fe0,0x0010) ); const Value &v = icon.GetDataElement().GetValue(); de.SetValue( v ); const ByteValue *bv = de.GetByteValue(); const TransferSyntax &ts = icon.GetTransferSyntax(); assert( ts.IsExplicit() || ts.IsImplicit() ); VL vl; if( bv ) { // if ts is explicit -> set VR vl = bv->GetLength(); } else { // if ts is explicit -> set VR vl.SetToUndefined(); } if( ts.IsExplicit() ) { switch ( pf.GetBitsAllocated() ) { case 8: de.SetVR( VR::OB ); break; //case 12: case 16: case 32: de.SetVR( VR::OW ); break; default: assert( 0 && "should not happen" ); break; } } else { de.SetVR( VR::OB ); } de.SetVL( vl ); ds.Replace( de ); } Item item; item.SetNestedDataSet( ds ); sq->AddItem( item ); iconimagesq.SetValue( *sq ); rootds.Replace( iconimagesq ); } } bool PixmapWriter::PrepareWrite( MediaStorage const & ref_ms ) { File& file = GetFile(); DataSet& ds = file.GetDataSet(); FileMetaInformation &fmi_orig = file.GetHeader(); const TransferSyntax &ts_orig = fmi_orig.GetDataSetTransferSyntax(); const PhotometricInterpretation pi_orig = ImageHelper::GetPhotometricInterpretationValue(file); // col & rows: #if 0 Attribute<0x0028, 0x0011> columns; columns.SetValue( (uint16_t)PixelData->GetDimension(0) ); ds.Replace( columns.GetAsDataElement() ); Attribute<0x0028, 0x0010> rows; rows.SetValue( (uint16_t)PixelData->GetDimension(1) ); ds.Replace( rows.GetAsDataElement() ); // (0028,0008) IS [12] # 2, 1 NumberOfFrames const Tag tnumberofframes = Tag(0x0028, 0x0008); if( PixelData->GetNumberOfDimensions() == 3 ) { Attribute<0x0028, 0x0008> numberofframes; assert( PixelData->GetDimension(2) >= 1 ); numberofframes.SetValue( PixelData->GetDimension(2) ); ds.Replace( numberofframes.GetAsDataElement() ); } else if( ds.FindDataElement(tnumberofframes) ) // Remove Number Of Frames { assert( PixelData->GetNumberOfDimensions() == 2 ); assert( PixelData->GetDimension(2) == 1 ); ds.Remove( tnumberofframes ); } #endif PixelFormat pf = PixelData->GetPixelFormat(); if ( !pf.IsValid() ) { gdcmWarningMacro( "Pixel format is not valid: " << pf ); return false; } PhotometricInterpretation pi = PixelData->GetPhotometricInterpretation(); if( pi.GetSamplesPerPixel() != pf.GetSamplesPerPixel() ) { gdcmWarningMacro( "Photometric Interpretation and Pixel format are not compatible: " << pi.GetSamplesPerPixel() << " vs " << pf.GetSamplesPerPixel() ); return false; } { assert( pi != PhotometricInterpretation::UNKNOWN ); const char *pistr = PhotometricInterpretation::GetPIString(pi); DataElement de( Tag(0x0028, 0x0004 ) ); VL::Type strlenPistr = (VL::Type)strlen(pistr); de.SetByteValue( pistr, strlenPistr ); de.SetVR( Attribute<0x0028,0x0004>::GetVR() ); ds.Replace( de ); } // Pixel Format : // (0028,0100) US 8 # 2, 1 BitsAllocated // (0028,0101) US 8 # 2, 1 BitsStored // (0028,0102) US 7 # 2, 1 HighBit // (0028,0103) US 0 # 2, 1 PixelRepresentation Attribute<0x0028, 0x0100> bitsallocated; bitsallocated.SetValue( pf.GetBitsAllocated() ); ds.Replace( bitsallocated.GetAsDataElement() ); Attribute<0x0028, 0x0101> bitsstored; bitsstored.SetValue( pf.GetBitsStored() ); ds.Replace( bitsstored.GetAsDataElement() ); Attribute<0x0028, 0x0102> highbit; highbit.SetValue( pf.GetHighBit() ); ds.Replace( highbit.GetAsDataElement() ); Attribute<0x0028, 0x0103> pixelrepresentation; pixelrepresentation.SetValue( pf.GetPixelRepresentation() ); ds.Replace( pixelrepresentation.GetAsDataElement() ); Attribute<0x0028, 0x0002> samplesperpixel; samplesperpixel.SetValue( pf.GetSamplesPerPixel() ); ds.Replace( samplesperpixel.GetAsDataElement() ); if( pf.GetSamplesPerPixel() != 1 ) { Attribute<0x0028, 0x0006> planarconf; planarconf.SetValue( (uint16_t)PixelData->GetPlanarConfiguration() ); ds.Replace( planarconf.GetAsDataElement() ); } // PhotometricInterpretation // const Tag tphotometricinterpretation(0x0028, 0x0004); //if( !ds.FindDataElement( Tag(0x0028, 0x0004) ) ) { //if( pi == PhotometricInterpretation::RGB // || pi == PhotometricInterpretation::YBR_FULL ) // FIXME // { // Attribute<0x0028, 0x0006> planarconfiguration; // planarconfiguration.SetValue( PixelData->GetPlanarConfiguration() ); // ds.Replace( planarconfiguration.GetAsDataElement() ); // } //else if ( pi == PhotometricInterpretation::PALETTE_COLOR ) { const LookupTable &lut = PixelData->GetLUT(); assert( lut.Initialized() ); // assert( (pf.GetBitsAllocated() == 8 && pf.GetPixelRepresentation() == 0) // || (pf.GetBitsAllocated() == 16 && pf.GetPixelRepresentation() == 0) ); // lut descriptor: // (0028,1101) US 256\0\16 # 6, 3 RedPaletteColorLookupTableDescriptor // (0028,1102) US 256\0\16 # 6, 3 GreenPaletteColorLookupTableDescriptor // (0028,1103) US 256\0\16 # 6, 3 BluePaletteColorLookupTableDescriptor // lut data: unsigned short length, subscript, bitsize; unsigned short rawlut8[256]; unsigned short rawlut16[65536]; unsigned short *rawlut = rawlut8; unsigned int lutlen = 256; if( pf.GetBitsAllocated() == 16 ) { rawlut = rawlut16; lutlen = 65536; } unsigned int l; // FIXME: should I really clear rawlut each time ? // RED memset(rawlut,0,lutlen*2); lut.GetLUT(LookupTable::RED, (unsigned char*)rawlut, l); DataElement redde( Tag(0x0028, 0x1201) ); redde.SetVR( VR::OW ); redde.SetByteValue( (char*)rawlut, l); ds.Replace( redde ); // descriptor: Attribute<0x0028, 0x1101, VR::US, VM::VM3> reddesc; lut.GetLUTDescriptor(LookupTable::RED, length, subscript, bitsize); reddesc.SetValue(length,0); reddesc.SetValue(subscript,1); reddesc.SetValue(bitsize,2); ds.Replace( reddesc.GetAsDataElement() ); // GREEN memset(rawlut,0,lutlen*2); lut.GetLUT(LookupTable::GREEN, (unsigned char*)rawlut, l); DataElement greende( Tag(0x0028, 0x1202) ); greende.SetVR( VR::OW ); greende.SetByteValue( (char*)rawlut, l); ds.Replace( greende ); // descriptor: Attribute<0x0028, 0x1102, VR::US, VM::VM3> greendesc; lut.GetLUTDescriptor(LookupTable::GREEN, length, subscript, bitsize); greendesc.SetValue(length,0); greendesc.SetValue(subscript,1); greendesc.SetValue(bitsize,2); ds.Replace( greendesc.GetAsDataElement() ); // BLUE memset(rawlut,0,lutlen*2); lut.GetLUT(LookupTable::BLUE, (unsigned char*)rawlut, l); DataElement bluede( Tag(0x0028, 0x1203) ); bluede.SetVR( VR::OW ); bluede.SetByteValue( (char*)rawlut, l); ds.Replace( bluede ); // descriptor: Attribute<0x0028, 0x1103, VR::US, VM::VM3> bluedesc; lut.GetLUTDescriptor(LookupTable::BLUE, length, subscript, bitsize); bluedesc.SetValue(length,0); bluedesc.SetValue(subscript,1); bluedesc.SetValue(bitsize,2); ds.Replace( bluedesc.GetAsDataElement() ); } ds.Remove( Tag(0x0028, 0x1221) ); ds.Remove( Tag(0x0028, 0x1222) ); ds.Remove( Tag(0x0028, 0x1223) ); } // Cleanup LUT here since cannot be done within gdcm::ImageApplyLookupTable if( pi == PhotometricInterpretation::RGB ) { // usual tags: ds.Remove( Tag(0x0028, 0x1101) ); ds.Remove( Tag(0x0028, 0x1102) ); ds.Remove( Tag(0x0028, 0x1103) ); ds.Remove( Tag(0x0028, 0x1201) ); ds.Remove( Tag(0x0028, 0x1202) ); ds.Remove( Tag(0x0028, 0x1203) ); // Don't forget the segmented one: ds.Remove( Tag(0x0028, 0x1221) ); ds.Remove( Tag(0x0028, 0x1222) ); ds.Remove( Tag(0x0028, 0x1223) ); // PaletteColorLookupTableUID ?? ds.Remove( Tag(0x0028, 0x1199) ); } // Overlay Data 60xx SequenceOfItems::SizeType nOv = PixelData->GetNumberOfOverlays(); for(SequenceOfItems::SizeType ovidx = 0; ovidx < nOv; ++ovidx ) { // (6000,0010) US 484 # 2, 1 OverlayRows // (6000,0011) US 484 # 2, 1 OverlayColumns // (6000,0015) IS [1] # 2, 1 NumberOfFramesInOverlay // (6000,0022) LO [Siemens MedCom Object Graphics] # 30, 1 OverlayDescription // (6000,0040) CS [G] # 2, 1 OverlayType // (6000,0050) SS 1\1 # 4, 2 OverlayOrigin // (6000,0051) US 1 # 2, 1 ImageFrameOrigin // (6000,0100) US 1 # 2, 1 OverlayBitsAllocated // (6000,0102) US 0 # 2, 1 OverlayBitPosition // (6000,3000) OW 0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000\0000... # 29282, 1 OverlayData DataElement de; const Overlay &ov = PixelData->GetOverlay(ovidx); Attribute<0x6000,0x0010> overlayrows; overlayrows.SetValue( ov.GetRows() ); de = overlayrows.GetAsDataElement(); de.GetTag().SetGroup( ov.GetGroup() ); ds.Replace( de ); Attribute<0x6000,0x0011> overlaycolumns; overlaycolumns.SetValue( ov.GetColumns() ); de = overlaycolumns.GetAsDataElement(); de.GetTag().SetGroup( ov.GetGroup() ); ds.Replace( de ); if( ov.GetDescription() ) // Type 3 { Attribute<0x6000,0x0022> overlaydescription; overlaydescription.SetValue( ov.GetDescription() ); de = overlaydescription.GetAsDataElement(); de.GetTag().SetGroup( ov.GetGroup() ); ds.Replace( de ); } Attribute<0x6000,0x0040> overlaytype; // 'G' or 'R' overlaytype.SetValue( ov.GetType() ); de = overlaytype.GetAsDataElement(); de.GetTag().SetGroup( ov.GetGroup() ); ds.Replace( de ); Attribute<0x6000,0x0050> overlayorigin; overlayorigin.SetValues( ov.GetOrigin() ); de = overlayorigin.GetAsDataElement(); de.GetTag().SetGroup( ov.GetGroup() ); ds.Replace( de ); Attribute<0x6000,0x0100> overlaybitsallocated; overlaybitsallocated.SetValue( ov.GetBitsAllocated() ); de = overlaybitsallocated.GetAsDataElement(); de.GetTag().SetGroup( ov.GetGroup() ); ds.Replace( de ); Attribute<0x6000,0x0102> overlaybitposition; overlaybitposition.SetValue( ov.GetBitPosition() ); de = overlaybitposition.GetAsDataElement(); de.GetTag().SetGroup( ov.GetGroup() ); ds.Replace( de ); // FIXME: for now rewrite 'Overlay in pixel data' still in the pixel data element... //if( !ov.IsInPixelData() ) { const ByteValue & overlaydatabv = ov.GetOverlayData(); DataElement overlaydata( Tag(0x6000,0x3000) ); overlaydata.SetByteValue( overlaydatabv.GetPointer(), overlaydatabv.GetLength() ); overlaydata.SetVR( VR::OW ); // FIXME overlaydata.GetTag().SetGroup( ov.GetGroup() ); ds.Replace( overlaydata ); } } // Pixel Data DataElement depixdata( Tag(0x7fe0,0x0010) ); DataElement & pde = PixelData->GetDataElement(); const ByteValue *bvpixdata = nullptr; // Sometime advanced user may use a gdcm::ImageRegionReader to feed an empty gdcm::Image if( !pde.IsEmpty() ) { const Value &v = PixelData->GetDataElement().GetValue(); depixdata.SetValue( v ); bvpixdata = depixdata.GetByteValue(); } const TransferSyntax &ts = PixelData->GetTransferSyntax(); assert( ts.IsExplicit() || ts.IsImplicit() ); // It is perfectly ok to store a lossy image using a J2K (this is odd, but valid). // as long as your mark LossyImageCompression with value 1 #if 0 // if ts_orig is undefined we need to check ts of Pixel Data comply with itself if( ts_orig == TransferSyntax::TS_END ) { if( !ts.CanStoreLossy() && PixelData->IsLossy() ) { gdcmWarningMacro( "Sorry Pixel Data in encapsulated stream was found to be " "lossy while Transfer Syntax does not authorized that" ); return false; } // Obviously we could also be checking the contrary: trying to store a // lossless compressed JPEG file using a lossy JPEG (compatible) one. But I // do not believe this is an error in this case. } #endif if( /*ts.IsLossy() &&*/ PixelData->IsLossy() ) { Attribute<0x0028,0x2110> at1; Attribute<0x0028,0x2114> at3; if( ts_orig == TransferSyntax::TS_END ) { // Add the Lossy stuff: at1.SetValue( "01" ); ds.Replace( at1.GetAsDataElement() ); } else if( ts_orig.IsLossy() ) { // Add the Lossy stuff: at1.SetValue( "01" ); ds.Replace( at1.GetAsDataElement() ); /* The Defined Terms for Lossy Image Compression Method (0028,2114) are : ISO_10918_1 = JPEG Lossy Compression ISO_14495_1 = JPEG-LS Near-lossless Compression ISO_15444_1 = JPEG 2000 Irreversible Compression ISO_13818_2 = MPEG2 Compression */ if( ts_orig == TransferSyntax::JPEG2000 ) { static const CSComp newvalues2[] = {"ISO_15444_1"}; at3.SetValues( newvalues2, 1 ); } else if( ts_orig == TransferSyntax::JPEGLSNearLossless ) { static const CSComp newvalues2[] = {"ISO_14495_1"}; at3.SetValues( newvalues2, 1 ); } else if ( ts_orig == TransferSyntax::JPEGBaselineProcess1 || ts_orig == TransferSyntax::JPEGExtendedProcess2_4 || ts_orig == TransferSyntax::JPEGExtendedProcess3_5 || ts_orig == TransferSyntax::JPEGSpectralSelectionProcess6_8 || ts_orig == TransferSyntax::JPEGFullProgressionProcess10_12 ) { static const CSComp newvalues2[] = {"ISO_10918_1"}; at3.SetValues( newvalues2, 1 ); } else { gdcmErrorMacro( "Pixel Data is lossy but I cannot find the original transfer syntax" ); return false; } ds.Replace( at3.GetAsDataElement() ); } else { if( ds.FindDataElement( at1.GetTag() ) ) { at1.Set( ds ); if( atoi(at1.GetValue().c_str()) != 1 ) { gdcmDebugMacro( "Fixing invalid value for LossyImageCompression: " << at1.GetValue() ); at1.SetValue( "01" ); ds.Replace( at1.GetAsDataElement() ); } } else { if( pi_orig == PhotometricInterpretation::YBR_FULL_422 ) { at1.SetValue( "01" ); ds.Replace( at1.GetAsDataElement() ); static const CSComp newvalues2[] = {"ISO_10918_1"}; at3.SetValues( newvalues2, 1 ); ds.Replace( at3.GetAsDataElement() ); } else { gdcmErrorMacro( "Unhandled Lossy flag for Pixel Data" ); return false; } } } } VL vl; if( bvpixdata ) { // if ts is explicit -> set VR vl = bvpixdata->GetLength(); } else { // if ts is explicit -> set VR vl.SetToUndefined(); } if( ts.IsExplicit() ) { switch ( pf.GetBitsAllocated() ) { case 1: case 8: depixdata.SetVR( VR::OB ); break; case 12: case 16: case 32: if( depixdata.GetSequenceOfFragments() ) depixdata.SetVR( VR::OB ); else depixdata.SetVR( VR::OW ); break; default: assert( 0 && "should not happen" ); break; } } else { depixdata.SetVR( VR::OB ); } depixdata.SetVL( vl ); // Advanced user may have passed an empty image if( !pde.IsEmpty() ) { ds.Replace( depixdata ); } // Do Icon Image DoIconImage(ds, GetPixmap()); MediaStorage ms = ref_ms; // Most SOP Class support 2D, but let's make sure that 3D is ok: if( PixelData->GetNumberOfDimensions() > 2 ) { if( ms.GetModalityDimension() < PixelData->GetNumberOfDimensions() ) { // input was specified with SC, but the Number of Frame is > 1. Fix that: ms = ImageHelper::ComputeMediaStorageFromModality( ms.GetModality(), PixelData->GetNumberOfDimensions(), PixelData->GetPixelFormat(), PixelData->GetPhotometricInterpretation(), 0, 1 ); if( ms.GetModalityDimension() < PixelData->GetNumberOfDimensions() ) { gdcmErrorMacro( "Problem with NumberOfDimensions and MediaStorage" ); return false; } } } // if we reach here somethnig went really wrong in previous step. Let's make // it a hard failure gdcmAssertAlwaysMacro( ms != MediaStorage::MS_END ); const char* msstr = MediaStorage::GetMSString(ms); if( !ds.FindDataElement( Tag(0x0008, 0x0016) ) ) { DataElement de( Tag(0x0008, 0x0016 ) ); VL::Type strlenMsstr = (VL::Type)strlen(msstr); de.SetByteValue( msstr, strlenMsstr); de.SetVR( Attribute<0x0008, 0x0016>::GetVR() ); ds.Insert( de ); } else { const ByteValue *bv = ds.GetDataElement( Tag(0x0008,0x0016) ).GetByteValue(); if( !bv ) { gdcmErrorMacro( "Cannot be empty" ); return false; } if( strncmp( bv->GetPointer(), msstr, bv->GetLength() ) != 0 ) { DataElement de = ds.GetDataElement( Tag(0x0008,0x0016) ); VL::Type strlenMsstr = (VL::Type) strlen(msstr); de.SetByteValue( msstr, strlenMsstr ); ds.Replace( de ); } else { assert( bv->GetLength() == strlen( msstr ) || bv->GetLength() == strlen(msstr) + 1 ); } } ImageHelper::SetDimensionsValue(file, *PixelData); // UIDs: // (0008,0018) UI [1.3.6.1.4.1.5962.1.1.1.1.3.20040826185059.5457] # 46, 1 SOPInstanceUID // (0020,000d) UI [1.3.6.1.4.1.5962.1.2.1.20040826185059.5457] # 42, 1 StudyInstanceUID // (0020,000e) UI [1.3.6.1.4.1.5962.1.3.1.1.20040826185059.5457] # 44, 1 SeriesInstanceUID UIDGenerator uid; // Be careful with the SOP Instance UID: if( ds.FindDataElement( Tag(0x0008, 0x0018) ) && false ) { // We are coming from a real DICOM image, we need to reference it... const Tag tsourceImageSequence(0x0008,0x2112); SmartPointer sq; if( ds.FindDataElement( tsourceImageSequence ) ) { DataElement &de = const_cast(ds.GetDataElement( tsourceImageSequence )); de.SetVLToUndefined(); // For now if( de.IsEmpty() ) { sq = new SequenceOfItems; de.SetValue( *sq ); } sq = de.GetValueAsSQ(); } else { sq = new SequenceOfItems; } sq->SetLengthToUndefined(); Item item; //( /*Tag(0xfffe,0xe000)*/ ); //DataSet sourceimageds; // (0008,1150) UI =MRImageStorage # 26, 1 ReferencedSOPClassUID // (0008,1155) UI [1.3.6.1.4.17434.1.1.5.2.1160650698.1160650698.0] # 48, 1 ReferencedSOPInstanceUID DataElement referencedSOPClassUID = ds.GetDataElement( Tag(0x0008,0x0016) ); referencedSOPClassUID.SetTag( Tag(0x0008,0x1150 ) ); DataElement referencedSOPInstanceUID = ds.GetDataElement( Tag(0x0008,0x0018) ); referencedSOPInstanceUID.SetTag( Tag(0x0008,0x1155) ); //item.SetNestedDataSet( sourceimageds ); item.SetVLToUndefined(); item.InsertDataElement( referencedSOPClassUID ); item.InsertDataElement( referencedSOPInstanceUID ); sq->AddItem( item ); if( !ds.FindDataElement( tsourceImageSequence ) ) { DataElement de( tsourceImageSequence ); de.SetVR( VR::SQ ); de.SetValue( *sq ); de.SetVLToUndefined(); //std::cout << de << std::endl; ds.Insert( de ); } } { const char *sop = uid.Generate(); DataElement de( Tag(0x0008,0x0018) ); VL::Type strlenSOP = (VL::Type) strlen(sop); de.SetByteValue( sop, strlenSOP ); de.SetVR( Attribute<0x0008, 0x0018>::GetVR() ); ds.ReplaceEmpty( de ); } // Are we on a particular Study ? If not create a new UID if( !ds.FindDataElement( Tag(0x0020, 0x000d) ) ) { const char *study = uid.Generate(); DataElement de( Tag(0x0020,0x000d) ); VL::Type strlenStudy= (VL::Type)strlen(study); de.SetByteValue( study, strlenStudy ); de.SetVR( Attribute<0x0020, 0x000d>::GetVR() ); ds.ReplaceEmpty( de ); } // Are we on a particular Series ? If not create a new UID if( !ds.FindDataElement( Tag(0x0020, 0x000e) ) ) { const char *series = uid.Generate(); DataElement de( Tag(0x0020,0x000e) ); VL::Type strlenSeries= (VL::Type)strlen(series); de.SetByteValue( series, strlenSeries ); de.SetVR( Attribute<0x0020, 0x000e>::GetVR() ); ds.ReplaceEmpty( de ); } FileMetaInformation &fmi = file.GetHeader(); if( GetCheckFileMetaInformation() ) { fmi.Clear(); //assert( ts == TransferSyntax::ImplicitVRLittleEndian ); { const char *tsuid = TransferSyntax::GetTSString( ts ); DataElement de( Tag(0x0002,0x0010) ); VL::Type strlenTSUID = (VL::Type)strlen(tsuid); de.SetByteValue( tsuid, strlenTSUID ); de.SetVR( Attribute<0x0002, 0x0010>::GetVR() ); fmi.Replace( de ); fmi.SetDataSetTransferSyntax(ts); } fmi.FillFromDataSet( ds ); } else { Attribute<0x0002,0x0010> at; at.SetFromDataSet( fmi ); const char *tsuid = TransferSyntax::GetTSString( ts ); UIComp tsui = at.GetValue(); if( tsui != tsuid ) { gdcmErrorMacro( "Incompatible TransferSyntax." ); return false; } } return true; } bool PixmapWriter::Write() { MediaStorage ms; if( !ms.SetFromFile( GetFile() ) ) { // Let's fix some old ACR-NAME stuff: ms = ImageHelper::ComputeMediaStorageFromModality( ms.GetModality(), PixelData->GetNumberOfDimensions(), PixelData->GetPixelFormat(), PixelData->GetPhotometricInterpretation(), 0, 1 ); } if( !PrepareWrite( ms ) ) return false; assert( Stream ); if( !Writer::Write() ) { return false; } return true; } void PixmapWriter::SetImage(Pixmap const &img) { PixelData = img; } } // end namespace gdcm