dcm2xml and dcmj2pnm stream file to stdin

Compilation and installation of DCMTK

Moderator: Moderator Team

Post Reply
Message
Author
Tetraib
Posts: 1
Joined: Fri, 2015-09-25, 08:32

dcm2xml and dcmj2pnm stream file to stdin

#1 Post by Tetraib » Wed, 2015-10-21, 09:34

Hi,
I would like to stream files to dcm2xml and dcmj2pnm, by streaming the dicom file to the stdin instead of using a file linker. I don't think it is possible out of the box (correct me if I am wrong).
Is this possible to achieve by editing the source code ? I looked at the source code, but I feel a little bit stuck, can you help me by pointing me the right direction ?
Many Thanks.

Marco Eichelberg
OFFIS DICOM Team
OFFIS DICOM Team
Posts: 1280
Joined: Tue, 2004-11-02, 17:22
Location: Oldenburg, Germany
Contact:

Re: dcm2xml and dcmj2pnm stream file to stdin

#2 Post by Marco Eichelberg » Mon, 2016-01-25, 18:27

I don't think this will be possible without major changes in the dcmdata module. The DcmFileFormat::loadFile() routine, which loads the DICOM file in most DCMTK command line tools, is based on the DcmInputFileStream class, which opens the file with fopen() and expects a file that has a known size and can be seek()ed. For reading a DICOM file from stdin one would have to rather use (or adapt) DcmInputBufferStream, write a routine that implements loadFile() based on such a stream class, and then implement code perhaps in DcmFileFormat::loadFile() that selects the stream-based loading code based on a special filename (the classical Un*x convention would be to use "-" to indicate stdin). Possible, but not trivial.

Marco Eichelberg
OFFIS DICOM Team
OFFIS DICOM Team
Posts: 1280
Joined: Tue, 2004-11-02, 17:22
Location: Oldenburg, Germany
Contact:

Re: dcm2xml and dcmj2pnm stream file to stdin

#3 Post by Marco Eichelberg » Mon, 2020-07-06, 10:22

In case anybody wants to implement that, here's some brief instructions.

Modify the following four methods such that they recognize "-" as a special filename indicating stdin or stdout, respectively, and then use a different stream class to read or write the DICOM object:

Code: Select all

DcmFileFormat::loadFileUntilTag()
DcmFileFormat::saveFile()
DcmDataset::loadFileUntilTag()
DcmDataset::saveFile()
As you will see, the four methods are rather simple. They all create a DcmInputFileStream or DcmOutputFileStream instance and call three methods:

Code: Select all

transferInit(); readUntilTag(); transferEnd();  // read
or

Code: Select all

transferInit(); write(); transferEnd(); // write
The DcmInputFileStream/DcmOutputFileStream classes are not suitable for stdin/stdout because they assume that the fseek() operation can be used on the underlying file, which is not the case for stdin and stdout. So you would have to implement two new classes, let's call them DcmStdinStream and DcmStdoutStream that are derived from the abstract classes DcmInputStream and DcmOutputStream. These classes are almost trivial because they offload almost all of the work to instances derived from the abstract classes DcmProducer and DcmConsumer, which is where the real implementation takes place.

A DcmStdinStream object would contain a DcmStdinProducer instance and use that to read from stdin, implementing the API of DcmProducer, and vice versa for the output side. Most methods will be trivial, but some, such as avail() and putback() might be somewhat tricky in a stdin/stdout stream setting.

Once that is done, it should be down to testing the whole thing. When you can read and write normal DICOM files from/to stdin/stdout, try with the Deflated transfer syntax (such files can be produced with dcmconv +td). This encoding is the reason for the rather convoluted structure of the streams, because it requires that at some point within the file the remaining content is passed through a ZIP (Deflate) compressor/decompressor, which is implemented as a "filter" in DCMTK that is plugged into the stream object.

In the implementation of the consumer/producer, do not directly use read()/write() or fread()/fwrite()/fdopen(). Instead use class OFFile (declared in the ofstd module), which is a thin layer encapsulating the C FILE * API that provides support for some special cases such as systems needing fopen64() for files larger than 2 GBytes. There is an OFFile::fdopen() method, which should be what you need to open stdin or stdout as a stream.

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest