Extracting Tag Data using Borland C++ Builder

All other questions regarding DCMTK

Moderator: Moderator Team

Post Reply
Message
Author
dave
Posts: 67
Joined: Fri, 2004-11-05, 18:20
Location: Houston, Texas, USA

Extracting Tag Data using Borland C++ Builder

#1 Post by dave »

We are writing a program (using Borland C++ Builder 6) to calculate Dose per Monitor Unit in proton therapy treatment, and we need to extract programmatically about 30 non-image related tag values from a treatment plan file. How reasonable is it to "port" the necessary code from DCMTK to C++Builder? Is all the necesary code in the DCMDATA module?

Any and all help or guidance is much appreciated.

Thanks in advance.

David

dave
Posts: 67
Joined: Fri, 2004-11-05, 18:20
Location: Houston, Texas, USA

Re: Extracting Tag Data using Borland C++ Builder

#2 Post by dave »

dave wrote:We are writing a program (using Borland C++ Builder 6) to calculate Dose per Monitor Unit in proton therapy treatment, and we need to extract programmatically about 30 non-image related tag values from a treatment plan file. How reasonable is it to "port" the necessary code from DCMTK to C++Builder? Is all the necesary code in the DCMDATA module?
I guess we are looking for suggestions about an approach as much as anything more specific, although specific is good, too. For example, would it be best to try to compile the whole toolkit under C++Builder, then make our program a dependency of the toolkit? Or can we select out - obviously with much appreciation and acknowledgement - just the sections of code needed to extract the data?

dave

Michael Onken
DCMTK Developer
Posts: 2049
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

#3 Post by Michael Onken »

Hi Dave,

Borland C++ Compiler is not actively supported by the DCMTK. However it should be possible to compile the toolkit using this compiler, too.

The necessary code to extract tags from a DICOM file is contained in the module "dcmdata", which itself needs classes from module "ofstd". Using these two modules, you can read and write DICOM files and work with tags, sequences, items etc.

Take a look at the doxygen documentation included in the toolkit (and published on the DCMTK-website), how to access tags. The dcmdata-documentation should be a good point to start with:
http://support.dcmtk.org/docs/mod_dcmdata.html

Regards
Michael Onken

roydobbins
Posts: 25
Joined: Wed, 2005-07-20, 22:42
Location: Payson, Arizona

Borland C++

#4 Post by roydobbins »

There has already been a discussion in the installation forum regarding Borland C++. You should look at this. Also, since I have now compiled DCMTK using Borland C++ 5.5, I would be prepared to answer any questions about getting the DCMTK compiled, in case you have any difficulties. In short, apart from a couple of tweaks, everything was reasonably painless. This is of course the command line implementation. Personally, if you need some kind of GUI environment, I would advocate the separate process approach, ie, run the dcmtk command line tools as child processes of your GUI app, supplying either parameters or query files, and redirecting the results for extraction.
Extracting the tags from specific dicom formatted files is also easy. There are some other tools and samples available, besides the dcmtk itself, eg look at ezdicom from Chris Riorden, implemented in Delphi, but should be easy to port to C++.

Hope this helps, and I would be happy to assist any way I can. Also I did promise to post all of my Borland patches, if there is any interest.

Regards,
Roy Dobbins

AndreasKnopke
Posts: 49
Joined: Wed, 2005-02-16, 16:27

#5 Post by AndreasKnopke »

Hi Roy,

please post your Borland patches. I tried to compile with Builder 6 myself and failed. That's why I currently have to use MS Visual Studio which feels very uncomfortably for a Borland user like me.

regards,
Andreas

roydobbins
Posts: 25
Joined: Wed, 2005-07-20, 22:42
Location: Payson, Arizona

Borland c++ 5.5 patches to compile dcmtk

#6 Post by roydobbins »

These are the changes I have made to get the dcmtk to compile and run:-
I have not exhaustively tested the effect of these changes, but I have tested, and used several of the major tools, such as findscu,movescu,storescu, and they are working great so far.
Some of these patches are ugly, eg those in the files dcdict.cxx, and storescp.cxx, which have borland specific patches. These have to do with the strchr() and strrchr() function prototypes, and whether the parameters are const or non const.
I am sure there is a cleaner way to get the right function prototypes to be defined in a compatible way. However, these are #ifdef'd with __BORLANDC__ sections, so at least wont affect other compilers.
If I have time to investigate this further, I will try to propose a better solution.

Let me know if this works, or if you discover other problems,

Regards,
--roy

Here are the changes:-

Patches to dcmtk to allow compiling the source using Borland C++ 5.5

options in cmakecache.txt:
These are not specific to BCC5.5, however they may cause problems in initially getting everything compiled and linked:

--turn off support for zlib, jpeg, tiff, png depending on your requirements, if you have problems linking to these libraries.


other compile,link errors which you may encounter:

if you get the linker error:-

netapi32.lib not found

then add c:\borland\bcc32\lib\psdk to the bcc32.cfg
(found in the borland\bin directory)
you should have something like:-

-L"c:\Borland\Bcc55\lib;c:\Borland\Bcc55\lib\psdk"


-if you get the compiler error:-

_errno not found

in \dcmtk\config\include\cfwin32.h, in the _BORLANDC section,
ie after:-

/* Additional settings for Borland C++ Builder */
#ifdef __BORLANDC__

add:
#define _MT

(to kick in the multithreading library defs, including for errno,
which is what the compiler is complaining about here)

***you must run cmake at this point***
something like:-
cmake -G"Borland Makefiles"


provisional (working) patches, to be investigated further:-

File ..\..\dcmdata\libsrc\dcdict.cxx:

inside the function def:-

static int
splitFields(const char* line, char* fields[], int maxFields, char splitChar)

change:-
p = strchr(line, splitChar);
to:-
#ifdef __BORLANDC__
/* borland c++ builder strchr() expects non const line, so...
* force char * line typecast
* roy todo: is there a cleaner way?
*/
p = strchr((char *)line, splitChar);
#else
p = strchr(line, splitChar);
#endif

File ..\..\dcmnet\apps\storescp.cxx:

inside the function def:-

static void
storeSCPCallback(

change:-

const char *tmpstr6 = strrchr( fileName.c_str(), PATH_SEPARATOR ); //roy TODO: changed to const for bcc32

to:-
#ifdef __BORLANDC__
/* borland c++ builder strchr() expects non const filename, so...
* force char * typecast
* roy todo: is there a cleaner way?
*/
char *tmpstr6 = strrchr( (char *)fileName.c_str(), PATH_SEPARATOR );
#else
char *tmpstr6 = strrchr( fileName.c_str(), PATH_SEPARATOR );
#endif

AndreasKnopke
Posts: 49
Joined: Wed, 2005-02-16, 16:27

#7 Post by AndreasKnopke »

thanks Roy,
I will try to compile DCMTK on Borland Builder 6 and report.

regards,
Andreas

dave
Posts: 67
Joined: Fri, 2004-11-05, 18:20
Location: Houston, Texas, USA

#8 Post by dave »

Roy,

In another thread on the installation list, you wrote

> you are compiling and linking with the VCL which is another
> environment altogether.

> another approach to take would be to compile your GUI application
> independently of the dcmtk, compile the (command line) dcmtk tools,
> then launch the tool(s) as separate processes, from your application to
> do the dicom work, and capture the results in your application.

Can you say more about the last part, about capturing the result in the application? We have called dcmdump from within a Borland VCL app, written the output to file, then parsed the file to get the data we needed. It was quick and dirty just to get the job done. The reason I started this thread was to learn how to avoid first writing to file to get the data.

David

AndreasKnopke
Posts: 49
Joined: Wed, 2005-02-16, 16:27

#9 Post by AndreasKnopke »

Hi Dave,

you have to pipe the output of the console to avoid saving the output to a file. I am more into Delphi than C++ but the following example should work with the Builder nevertheless.

function GetConsoleOutput(const Command: STRING;
var Output, Errors: TStringList): BOOLEAN;
var
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
SecurityAttr: TSecurityAttributes;
PipeOutputRead: THandle;
PipeOutputWrite: THandle;
PipeErrorsRead: THandle;
PipeErrorsWrite: THandle;
Succeed: BOOLEAN;
Buffer: array [0..255] of CHAR;
NumberOfBytesRead: DWORD;
Stream: TMemoryStream;
begin
//Initialize ProcessInfo
FillChar(ProcessInfo, SizeOf(TProcessInformation), 0);

//Initialize SecurityAttr
FillChar(SecurityAttr, SizeOf(TSecurityAttributes), 0);
SecurityAttr.nLength := SizeOf(SecurityAttr);
SecurityAttr.bInheritHandle := True;
SecurityAttr.lpSecurityDescriptor := nil;

//Create pipe
CreatePipe(PipeOutputRead, PipeOutputWrite, @SecurityAttr, 0);
CreatePipe(PipeErrorsRead, PipeErrorsWrite, @SecurityAttr, 0);

//Initialize startupInof
FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
StartupInfo.cb := SizeOf(StartupInfo);
StartupInfo.hStdInput := 0;
StartupInfo.hStdOutput := PipeOutputWrite;
StartupInfo.hStdError := PipeErrorsWrite;
StartupInfo.wShowWindow := sw_Hide;
StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;

if CreateProcess(nil, PChar(command), nil, nil, True,
CREATE_DEFAULT_ERROR_MODE or CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS,
nil, nil, StartupInfo, ProcessInfo) then
begin
Result := True;
//Write-Pipes schließen
CloseHandle(PipeOutputWrite);
CloseHandle(PipeErrorsWrite);

//Read read-pipe output
Stream := TMemoryStream.Create;
try
while True do
begin
succeed := ReadFile(PipeOutputRead, Buffer, 255, NumberOfBytesRead, nil);
if not succeed then
break;
Stream.Write(Buffer, NumberOfBytesRead);
end;
Stream.Position := 0;
Output.LoadFromStream(Stream);
finally
Stream.Free;
end;
CloseHandle(PipeOutputRead);

//error reading pipe output
Stream := TMemoryStream.Create;
try
while True do
begin
succeed := ReadFile(PipeErrorsRead, Buffer, 255, NumberOfBytesRead, nil);
if not succeed then
break;
Stream.Write(Buffer, NumberOfBytesRead);
end;
Stream.Position := 0;
Errors.LoadFromStream(Stream);
finally
Stream.Free;
end;
CloseHandle(PipeErrorsRead);

WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
CloseHandle(ProcessInfo.hProcess);
end
else
begin
Result := False;
CloseHandle(PipeOutputRead);
CloseHandle(PipeOutputWrite);
CloseHandle(PipeErrorsRead);
CloseHandle(PipeErrorsWrite);
end;
end;

found this code on the net and it works fine in my application

call it like:

GetConsoleOutput(dcmtkdir+ 'dcmdump.exe' +filename, output, errors)


hope I could help,

regards,
Andreas

dave
Posts: 67
Joined: Fri, 2004-11-05, 18:20
Location: Houston, Texas, USA

#10 Post by dave »

Thanks, Andreas. It looks interesting. I'll spend some time with the example today and post back.

David

reachmuraly
Posts: 8
Joined: Wed, 2006-05-31, 07:31

Re: Borland C++

#11 Post by reachmuraly »

Hi,

Currently i am working on running dcmtk with borland c++ compiler 5.5 (command line).Not able to compile now.I know that you have done this already. Can you tell me steps that are needed to run dcmtk with borland compiler.


Muraly


roydobbins wrote:There has already been a discussion in the installation forum regarding Borland C++. You should look at this. Also, since I have now compiled DCMTK using Borland C++ 5.5, I would be prepared to answer any questions about getting the DCMTK compiled, in case you have any difficulties. In short, apart from a couple of tweaks, everything was reasonably painless. This is of course the command line implementation. Personally, if you need some kind of GUI environment, I would advocate the separate process approach, ie, run the dcmtk command line tools as child processes of your GUI app, supplying either parameters or query files, and redirecting the results for extraction.
Extracting the tags from specific dicom formatted files is also easy. There are some other tools and samples available, besides the dcmtk itself, eg look at ezdicom from Chris Riorden, implemented in Delphi, but should be easy to port to C++.

Hope this helps, and I would be happy to assist any way I can. Also I did promise to post all of my Borland patches, if there is any interest.

Regards,
Roy Dobbins

roydobbins
Posts: 25
Joined: Wed, 2005-07-20, 22:42
Location: Payson, Arizona

#12 Post by roydobbins »

Did you already apply the patches as indicated in this thread (see my earlier post in which I gave all the patches in detail.

Double check that you have these all in place, and that you did follow all the instructions.

Post Reply

Who is online

Users browsing this forum: Bing [Bot], Majestic-12 [Bot] and 1 guest