/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef GDCMSTREAMIMAGEWRITER_H #define GDCMSTREAMIMAGEWRITER_H #include "gdcmWriter.h" #include #include "gdcmDataSet.h" namespace gdcm { class MediaStorage; class RAWCodec; /** * \brief StreamImageReader * \note its role is to convert the DICOM DataSet into a Image * representation via an ITK streaming (ie, multithreaded) interface * Image is different from Pixmap has it has a position and a direction in * Space. * Currently, this class is threadsafe in that it can read a single extent * in a single thread. Multiple versions can be used for multiple extents/threads. * * \see Image */ class GDCM_EXPORT StreamImageWriter { public: StreamImageWriter(); virtual ~StreamImageWriter(); /// One of either SetFileName or SetStream must be called prior /// to any other functions. These initialize an internal Reader class /// to be able to get non-pixel image information. void SetFileName(const char* inFileName); void SetStream(std::ostream& inStream); /// Defines an image extent for the Read function. /// DICOM states that an image can have no more than 2^16 pixels per edge (as of 2009) /// In this case, the pixel extents ignore the direction cosines entirely, and /// assumes that the origin of the image is at location 0,0 (regardless of the definition /// in space per the tags). So, if the first 100 pixels of the first row are to be read in, /// this function should be called with DefinePixelExtent(0, 100, 0, 1), regardless /// of pixel size or orientation. /// 15 nov 2010: added z dimension, defaults to being 1 plane large void DefinePixelExtent(uint16_t inXMin, uint16_t inXMax, uint16_t inYMin, uint16_t inYMax, uint16_t inZMin = 0, uint16_t inZMax = 1); /// Paying attention to the pixel format and so forth, define the proper buffer length for the user. /// The return amount is in bytes. /// If the return is 0, then that means that the pixel extent was not defined prior /// this return is for RAW inputs which are then encoded by the writer, but are used /// to ensure that the writer gets the proper buffer size uint32_t DefineProperBufferLength(); /// Read the DICOM image. There are three reasons for failure: /// 1. The extent is not set /// 2. the conversion from void* to std::ostream (internally) fails /// 3. the given buffer isn't large enough to accommodate the desired pixel extent. /// This method has been implemented to look similar to the metaimageio in itk /// MUST have an extent defined, or else Read will return false. /// If no particular extent is required, use ImageReader instead. bool Write(void* inWriteBuffer, const std::size_t& inBufferLength); /// Write the header information to disk, and a bunch of zeros for the actual pixel information /// Of course, if we're doing a non-compressed format, that works /// but if it's compressed, we have to force the ordering of chunks that are written. virtual bool WriteImageInformation(); /// This function determines if a file can even be written using the streaming writer /// unlike the reader, can be called before WriteImageInformation, but must be called /// after SetFile. bool CanWriteFile() const; /// Set the image information to be written to disk that is everything but /// the pixel information: (7fe0,0010) PixelData void SetFile(const File& inFile); protected: //contains the PrepareWrite function, which will get the given dataset ready //for writing to disk by manufacturing the header information. //note that if there is a pixel element in the given dataset, that will be removed //during the copy, so that the imagewriter can write everything else out Writer mWriter; //is the offset necessary if we always append? //std::streamoff mFileOffset; //the fileoffset for getting header information SmartPointer mspFile; //all the non-pixel information //for thread safety, these should not be stored here, but should be used //for every read subregion operation. uint16_t mXMin, mYMin, mXMax, mYMax, mZMin, mZMax; /// Using the min, max, etc set by DefinePixelExtent, this will fill the given buffer /// Make sure to call DefinePixelExtent and to initialize the buffer with the /// amount given by DefineProperBufferLength prior to calling this. /// reads by the RAW codec; other codecs are added once implemented //virtual bool ReadImageSubregionRAW(std::ostream& os); virtual bool WriteImageSubregionRAW(char* inWriteBuffer, const std::size_t& inBufferLength); /// when writing a raw file, we know the full extent, and can just write the first /// 12 bytes out (the tag, the VR, and the size) /// when we do compressed files, we'll do it in chunks, as described in /// 2009-3, part 5, Annex A, section 4. /// Pass the raw codec so that in the rare case of a bigendian explicit raw, /// the first 12 bytes written out should still be kosher. /// returns -1 if there's any failure, or the complete offset (12 bytes) /// if it works. Those 12 bytes are then added to the position in order to determine /// where to write. int WriteRawHeader(RAWCodec* inCodec, std::ostream* inStream); /// The result of WriteRawHeader (or another header, when that's implemented) /// This result is saved so that the first N bytes aren't constantly being /// rewritten for each chunk that's passed in. /// For compressed data, the offset table will require rewrites of data. int mElementOffsets; int mElementOffsets1; }; } // end namespace gdcm #endif //GDCMSTREAMIMAGEWRITER_H