Skip to content

Commit

Permalink
Implementation of strict scanner
Browse files Browse the repository at this point in the history
This new class will work around a low level implementation issue with the legacy gdcm.Scanner class.
It is now possible to compile gdcm using the relaxed DICOM parser while at the same time acccess the very strict DICOM parser.
This commit uses a complex build system which will hide a gdcmstrict namespace away from the user but allow developer to use it.
  • Loading branch information
malaterre committed Feb 25, 2015
1 parent eeb5f56 commit 1a46e1f
Show file tree
Hide file tree
Showing 60 changed files with 1,250 additions and 186 deletions.
41 changes: 34 additions & 7 deletions Examples/Csharp/ScanDirectory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,59 @@ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR

/*
* Usage:
* $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin
* $ mono bin/ScanDirectory.exe /path/to/gdcmData/
* $ bin/ScanDirectory.exe /path/to/gdcmData/
*/
using System;
using gdcm;

// We will print each filename being processed
public class MyWatcher : SimpleSubjectWatcher
{
public MyWatcher(Subject s):base(s,"Override String"){}
protected override void ShowFileName(Subject caller, Event evt){
FileNameEvent fne = FileNameEvent.Cast(evt);
if( fne != null )
{
string fn = fne.GetFileName();
System.Console.WriteLine( "This is my Scanner. Processing FileName: " + fn );
}
else
{
System.Console.WriteLine( "This is my Anonymization. Unhandled Event type: " + evt.GetEventName() );
}
}
}

public class ScanDirectory
{
public static int Main(string[] args)
{
string directory = args[0];
Tag t = new Tag(0x8,0x8);
Tag t = new Tag(0x8,0x80);

Directory d = new Directory();
uint nfiles = d.Load( directory );
if(nfiles == 0) return 1;
//System.Console.WriteLine( "Files:\n" + d.toString() );

//Scanner s = new Scanner();
SmartPtrScan sscan = Scanner.New();
Scanner s = sscan.__ref__();
SimpleSubjectWatcher watcher = new SimpleSubjectWatcher(s, "MySimple");
// Use a StrictScanner, need to use a reference to pass the C++ pointer to
// MyWatcher implementation
SmartPtrStrictScan sscan = StrictScanner.New();
StrictScanner s = sscan.__ref__();
MyWatcher watcher = new MyWatcher(s);

s.AddTag( t );
bool b = s.Scan( d.GetFilenames() );
if(!b) return 1;

for(int i = 0; i < (int)nfiles; ++i)
{
if( !s.IsKey( d.GetFilenames()[i] ) )
{
System.Console.WriteLine( "File is not DICOM or could not be read: " + d.GetFilenames()[i] );
}
}

System.Console.WriteLine( "Scan:\n" + s.toString() );

System.Console.WriteLine( "success" );
Expand Down
29 changes: 17 additions & 12 deletions Examples/Cxx/SimpleScanner.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* ./SimpleScanner gdcmData/012345.002.050.dcm
*/

#include "gdcmScanner.h"
#include "gdcmStrictScanner.h"
#include "gdcmSimpleSubjectWatcher.h"
#include "gdcmFileNameEvent.h"

Expand All @@ -53,19 +53,21 @@ int main(int argc, char *argv[])
const char filename_invalid[] = "this is a file that may not exist on this disk.dcm";


gdcm::SmartPointer<gdcm::Scanner> sp = new gdcm::Scanner;
gdcm::Scanner &s = *sp;
gdcm::SmartPointer<gdcm::StrictScanner> sp = new gdcm::StrictScanner;
gdcm::StrictScanner &s = *sp;
//gdcm::SimpleSubjectWatcher w(&s, "TestFileName" );
MyFileWatcher w(&s, "TestFileName" );

const gdcm::Tag tag_array[] = {
gdcm::Tag(0x8,0x50),
gdcm::Tag(0x8,0x51),
gdcm::Tag(0x8,0x60),
gdcm::Tag(0x8,0x80),
};
s.AddTag( tag_array[0] );
s.AddTag( tag_array[1] );
s.AddTag( tag_array[2] );
s.AddTag( tag_array[3] );

gdcm::Directory::FilenamesType filenames;
filenames.push_back( filename );
Expand All @@ -79,22 +81,25 @@ int main(int argc, char *argv[])
//s.Print( std::cout );


if( s.IsKey( filename ) )
gdcm::Directory::FilenamesType::const_iterator it = filenames.begin();
for( ; it != filenames.end(); ++it )
{
std::cout << "INFO:" << filename << " is a proper Key for the Scanner (this is a DICOM file)" << std::endl;
}

if( !s.IsKey( filename_invalid ) )
{
std::cout << "INFO:" << filename_invalid << " is not a proper Key for the Scanner (this is either not a DICOM file or file does not exist)" << std::endl;
if( s.IsKey( it->c_str() ) )
{
std::cout << "INFO:" << it->c_str() << " is a proper Key for the Scanner (this is a DICOM file)" << std::endl;
}
else
{
std::cout << "INFO:" << it->c_str() << " is not a proper Key for the Scanner (this is either not a DICOM file or file does not exist)" << std::endl;
}
}

gdcm::Scanner::TagToValue const &ttv = s.GetMapping(filename);
gdcm::StrictScanner::TagToValue const &ttv = s.GetMapping(filename);

const gdcm::Tag *ptag = tag_array;
for( ; ptag != tag_array + 3; ++ptag )
{
gdcm::Scanner::TagToValue::const_iterator it = ttv.find( *ptag );
gdcm::StrictScanner::TagToValue::const_iterator it = ttv.find( *ptag );
if( it != ttv.end() )
{
std::cout << *ptag << " was properly found in this file" << std::endl;
Expand Down
6 changes: 6 additions & 0 deletions PACKAGER
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,9 @@ Examples:
GDCM comes with some examples for user, but setting the following:
GDCM_BUILD_EXAMPLES:BOOL=ON
will not do anything since there is no install rule for examples...

The library attempts to provide a clean API, therefore it is highly suggested that you compile GDCM using:

$ CFLAGS=-fvisibility=hidden CXXFLAGS=-fvisibility=hidden cmake /path/to/gdcm/sources

This make sure that on UNIX, the API is actually identical at what is found on Windows.
5 changes: 5 additions & 0 deletions Source/Common/gdcmConfigure.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,15 @@

#cmakedefine GDCM_FORCE_BIGENDIAN_EMULATION

#ifndef GDCM_OVERRIDE_BROKEN_IMPLEMENTATION
/* To Remove code that support broken DICOM implementation and therefore
* add some over head. Turn Off at your own risk
*/
#cmakedefine GDCM_SUPPORT_BROKEN_IMPLEMENTATION
#endif
#ifndef gdcm_ns
#define gdcm_ns gdcm
#endif

#define GDCM_PVRG_JPEG_EXECUTABLE "@PVRGJPEG_EXECUTABLE@"
#define GDCM_KAKADU_EXPAND_EXECUTABLE "@KDU_EXPAND_EXECUTABLE@"
Expand Down
5 changes: 5 additions & 0 deletions Source/Common/gdcmWin32.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
#endif
#endif

#if defined(GDCM_OVERRIDE_BROKEN_IMPLEMENTATION) && !defined(GDCM_FORCE_EXPORT)
#undef GDCM_EXPORT
#define GDCM_EXPORT
#endif

// In VTK 4.2 vtkWrapPython does not like anything other than VTK_*EXPORT
// [ 86%] Generating vtkGDCMImageReaderPython.cxx
// syntax error
Expand Down
60 changes: 43 additions & 17 deletions Source/DataStructureAndEncodingDefinition/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,36 +1,63 @@
# Define the srcs for Data Structure and Encoding Definitions
# DSED
set(DSED_SRCS
gdcmTag.cxx
gdcmTagToVR.cxx
gdcmPrivateTag.cxx
gdcmCodeString.cxx

# dual compilation (namespace gdcm_ns), all the following either directly
# reference code using GDCM_SUPPORT_BROKEN_IMPLEMENTATION or indirectly
set(DSED2_SRCS
gdcmByteValue.cxx
gdcmValue.cxx
gdcmFileSet.cxx
gdcmDataElement.cxx
gdcmDataSet.cxx
gdcmByteSwapFilter.cxx
gdcmUNExplicitImplicitDataElement.cxx
gdcmExplicitDataElement.cxx
gdcmFileMetaInformation.cxx
gdcmFile.cxx # FileMeta is class member
gdcmFileMetaInformation.cxx # subclass of DataSet
gdcmFragment.cxx
gdcmImplicitDataElement.cxx
gdcmItem.cxx
gdcmMediaStorage.cxx # SetFromModality takes a DataSet
gdcmPrivateTag.cxx
gdcmReader.cxx
gdcmSequenceOfFragments.cxx
gdcmSequenceOfItems.cxx
gdcmValue.cxx # friend decl
)
# need to prepare duplicate files to help cmake handle setting compile
# definitions (cmake cannot handle duplicate source file in same target).
# this trick allows us to avoid a static compilation which may not be portable
foreach(src ${DSED2_SRCS})
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/${src}
${CMAKE_CURRENT_SOURCE_DIR}/strict_${src}
COPYONLY
)
list(APPEND DSED3_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/strict_${src}
)
set_property(
SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/strict_${src}
PROPERTY COMPILE_DEFINITIONS "GDCM_OVERRIDE_BROKEN_IMPLEMENTATION" "gdcm_ns=gdcmstrict"
)
endforeach()

# the following source code do not need a duplicate compilation to handle
# GDCM_SUPPORT_BROKEN_IMPLEMENTATION
set(DSED_SRCS
${DSED2_SRCS}
gdcmReader.strict.cxx # hook to call gdcmstrict API
gdcmTag.cxx
gdcmTagToVR.cxx
gdcmCodeString.cxx
gdcmFileSet.cxx
gdcmByteSwapFilter.cxx
gdcmUNExplicitImplicitDataElement.cxx
gdcmWriter.cxx
#gdcmParser.cxx
gdcmCSAHeader.cxx
gdcmPDBHeader.cxx
gdcmSequenceOfFragments.cxx
gdcmSequenceOfItems.cxx
gdcmTransferSyntax.cxx
gdcmMediaStorage.cxx
gdcmVM.cxx
gdcmVR.cxx
gdcmFile.cxx
gdcmPreamble.cxx
gdcmParseException.cxx
gdcmDataElement.cxx
gdcmUNExplicitDataElement.cxx
gdcmCP246ExplicitDataElement.cxx
gdcmExplicitImplicitDataElement.cxx
Expand All @@ -56,8 +83,7 @@ if(NOT GDCM_USE_SYSTEM_ZLIB)
)
endif()


add_library(gdcmDSED ${DSED_SRCS})
add_library(gdcmDSED ${DSED_SRCS} ${DSED3_SRCS})
target_link_libraries(gdcmDSED gdcmCommon)
# zlib stuff are actually included (template) so we need to link them here.
target_link_libraries(gdcmDSED ${GDCM_ZLIB_LIBRARIES})
Expand Down
4 changes: 2 additions & 2 deletions Source/DataStructureAndEncodingDefinition/gdcmAttribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#include <vector>
#include <sstream>

namespace gdcm
namespace gdcm_ns
{

struct void_;
Expand Down Expand Up @@ -1045,6 +1045,6 @@ class Attribute<Group,Element, VR::SQ, VM::VM1, SQA>
* This is a C++ example on how to use gdcm::Attribute
*/

} // namespace gdcm
} // namespace gdcm_ns

#endif //GDCMATTRIBUTE_H
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

#include "gdcmFragment.h"

namespace gdcm
namespace gdcm_ns
{
/**
* \brief Class to represent a BasicOffsetTable
Expand Down Expand Up @@ -121,6 +121,6 @@ inline std::ostream &operator<<(std::ostream &os, const BasicOffsetTable &val)
}


} // end namespace gdcm
} // end namespace gdcm_ns

#endif //GDCMBASICOFFSETTABLE_H
37 changes: 35 additions & 2 deletions Source/DataStructureAndEncodingDefinition/gdcmByteValue.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,42 @@
#include <algorithm> // req C++11
#include <cstring> // memcpy

namespace gdcm
namespace gdcm_ns
{

void ByteValue::SetLength(VL vl) {
VL l(vl);
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
// CompressedLossy.dcm
if( l.IsUndefined() ) throw Exception( "Impossible" );
if ( l.IsOdd() ) {
gdcmDebugMacro(
"BUGGY HEADER: Your dicom contain odd length value field." );
++l;
}
#else
assert( !l.IsUndefined() && !l.IsOdd() );
#endif
// I cannot use reserve for now. I need to implement:
// STL - vector<> and istream
// http://groups.google.com/group/comp.lang.c++/msg/37ec052ed8283e74
//#define SHORT_READ_HACK
try
{
#ifdef SHORT_READ_HACK
if( l <= 0xff )
#endif
Internal.resize(l);
//Internal.reserve(l);
}
catch(...)
{
//throw Exception("Impossible to allocate: " << l << " bytes." );
throw Exception("Impossible to allocate" );
}
// Keep the exact length
Length = vl;
}
void ByteValue::PrintASCII(std::ostream &os, VL maxlength ) const {
VL length = std::min(maxlength, Length);
// Special case for VR::UI, do not print the trailing \0
Expand Down Expand Up @@ -295,4 +328,4 @@ namespace gdcm
assert( Internal.size() % 2 == 0 && Internal.size() == Length );
}

}
} // end namespace gdcm_ns
Loading

0 comments on commit 1a46e1f

Please sign in to comment.