1 /*=========================================================================
4 Module: $RCSfile: gdcmPixelWriteConvert.cxx,v $
6 Date: $Date: 2007/08/30 17:38:20 $
7 Version: $Revision: 1.21 $
9 Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10 l'Image). All rights reserved. See Doc/License.txt or
11 http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
13 This software is distributed WITHOUT ANY WARRANTY; without even
14 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 PURPOSE. See the above copyright notices for more information.
17 =========================================================================*/
19 #include "gdcmDebug.h"
20 #include "gdcmPixelWriteConvert.h"
26 #define WITHOFFSETTABLE 1
28 namespace GDCM_NAME_SPACE
30 //-----------------------------------------------------------------------------
33 //-----------------------------------------------------------------------------
36 //-----------------------------------------------------------------------------
39 // Constructor / Destructor
43 PixelWriteConvert::PixelWriteConvert()
56 PixelWriteConvert::~PixelWriteConvert()
58 gdcmDebugMacro("PixelWriteConvert::~PixelWriteConvert()" );
66 * \brief sets Read Data (and size)
67 * @param data data (uint8_t is for prototyping. if your data is not uint8_t
68 * just cast the pointer for calling the method)
69 * @param size data size, in bytes
71 void PixelWriteConvert::SetReadData(uint8_t *data, size_t size)
78 * \brief Sets the internal pointer to the caller's inData
79 * image representation, WITHOUT COPYING THE DATA.
80 * - 'image' Pixels are presented as C-like 2D arrays : line per line.
81 * - 'volume'Pixels are presented as C-like 3D arrays : plane per plane
82 * \warning Since the pixels are not copied, it is the caller's responsability
83 * not to deallocate its data before gdcm uses them (e.g. with
84 * the Write() method )
85 * @param data data (uint8_t is for prototyping. if your data is not uint8_t
86 * just cast the pointer for calling the method)
87 * @param size size, in bytes.
89 void PixelWriteConvert::SetUserData(uint8_t *data, size_t size)
96 * \brief Get Data (UserData or ReadData)
97 * @return data (uint8_t is for prototyping. if your data is *not* uint8_t
98 * just cast the returned pointer)
100 uint8_t *PixelWriteConvert::GetData()
113 * \brief Get Data Size (UserData or ReadData)
114 * @return size, in bytes.
116 size_t PixelWriteConvert::GetDataSize()
129 typedef std::pair<size_t, uint32_t> JpegPair; //offset, jpeg size
130 typedef std::vector<JpegPair> JpegVector;
132 bool gdcm_write_JPEG2000_file (std::ostream *of, char *inputdata, size_t inputlength,
133 int image_width, int image_height, int numZ, int sample_pixel, int bitsallocated,
134 int sign, int quality);
137 void WriteDICOMItems(std::ostream *fp, JpegVector &v)
140 uint16_t group = 0xfffe;
141 uint16_t elem = 0xe000;
142 GDCM_NAME_SPACE::binary_write(*fp, group);
143 GDCM_NAME_SPACE::binary_write(*fp, elem);
145 uint32_t dummy = 0x12345678;
146 size_t offset = fp->tellp();
150 GDCM_NAME_SPACE::binary_write(*fp, dummy);
154 void EncodeWithoutBasicOffsetTable(std::ostream *fp, int numFrag)// JpegVector& v) //, uint32_t length)
156 assert( numFrag == 1);
159 uint16_t group = 0xfffe;
160 uint16_t elem = 0xe000;
161 GDCM_NAME_SPACE::binary_write(*fp, group);
162 GDCM_NAME_SPACE::binary_write(*fp, elem);
164 uint32_t item_length = 0x0000;
165 GDCM_NAME_SPACE::binary_write(*fp, item_length);
170 void EncodeWithBasicOffsetTable(std::ostream *fp, int numFrag, size_t &start)
173 uint16_t group = 0xfffe;
174 uint16_t elem = 0xe000;
175 GDCM_NAME_SPACE::binary_write(*fp, group);
176 GDCM_NAME_SPACE::binary_write(*fp, elem);
178 uint32_t item_length = numFrag*4; // sizeof(uint32_t)
179 GDCM_NAME_SPACE::binary_write(*fp, item_length);
181 // Just prepare the space
182 start = fp->tellp(); //to be able to rewind
183 for(int i=0; i<numFrag;++i)
185 uint32_t dummy = 0x0000;
186 GDCM_NAME_SPACE::binary_write(*fp, dummy);
190 void UpdateBasicOffsetTable(std::ostream *fp, JpegVector const &v, size_t pos)
192 JpegVector::const_iterator i;
194 const JpegPair &first = v[0];
195 for(i=v.begin(); i!=v.end(); ++i)
197 const JpegPair &jp = *i;
198 if(i == v.begin() ){ assert( jp.first - first.first == 0); }
199 uint32_t offset = (uint32_t)(jp.first - first.first);
200 GDCM_NAME_SPACE::binary_write(*fp, offset);
201 //std::cerr << "Updating Table:" << jp.first - first.first << std::endl;
205 void UpdateJpegFragmentSize(std::ostream *fp, JpegVector const &v)
207 JpegVector::const_iterator i;
208 for(i= v.begin(); i!=v.end(); ++i)
210 const JpegPair &jp = *i;
211 fp->seekp( jp.first );
212 uint32_t length = jp.second;
213 GDCM_NAME_SPACE::binary_write(*fp, length);
214 //std::cerr << "Updating:" << jp.first << "," << jp.second << std::endl;
218 void CloseJpeg(std::ostream *fp, JpegVector &v)
220 // sequence terminator
221 uint16_t group = 0xfffe;
222 uint16_t elem = 0xe0dd;
223 GDCM_NAME_SPACE::binary_write(*fp, group);
224 GDCM_NAME_SPACE::binary_write(*fp, elem);
226 uint32_t length = 0x0;
227 GDCM_NAME_SPACE::binary_write(*fp, length);
229 // Jpeg is done, now update the frag length
230 UpdateJpegFragmentSize(fp, v);
233 // I need to pass the File*. I do not understand how PixelWriteConvert is supposed
234 // to access this information otherwise
235 // size can now be computed from File attributes (what an API...)
236 void PixelWriteConvert::SetCompressJPEG2000UserData(uint8_t *data, size_t size, File *image)
239 //char * userData = reinterpret_cast<char*>(UserData);
241 std::ostringstream *of = new std::ostringstream();
242 int xsize = image->GetXSize();
243 int ysize = image->GetYSize();
244 int zsize = image->GetZSize();
245 int samplesPerPixel = image->GetSamplesPerPixel();
246 //std::cout << "X: " << xsize << std::endl;
247 //std::cout << "Y: " << ysize << std::endl;
248 //std::cout << "Sample: " << samplesPerPixel << std::endl;
249 int bitsallocated = image->GetBitsAllocated();
250 int sign = image->IsSignedPixelData();
251 unsigned int fragment_size = xsize*ysize*samplesPerPixel * (bitsallocated / 8);
252 //assert( fragment_size*zsize == size );
254 gdcmDebugMacro("fragment_size " << fragment_size << " zsize " << zsize << " size " << size);
255 assert( abs(fragment_size*zsize-size) <=1 );
257 JpegVector JpegFragmentSize;
258 gdcmDebugMacro("Call Encode..BasicOffsetTable " );
260 size_t bots; //basic offset table start
261 EncodeWithBasicOffsetTable(of, zsize, bots);
263 EncodeWithoutBasicOffsetTable(of, 1);
266 gdcmDebugMacro("Out of Encode..BasicOffsetTable " );
268 uint8_t *pImageData = data;
269 for(int i=0; i<zsize;i++)
271 gdcmDebugMacro("Write fragment no " << i );
272 WriteDICOMItems(of, JpegFragmentSize);
273 size_t beg = of->tellp();
274 gdcm_write_JPEG2000_file(of, (char*)pImageData,size,
275 image->GetXSize(), image->GetYSize(), image->GetZSize(), image->GetSamplesPerPixel(),
276 image->GetBitsAllocated(), sign, 100);
277 //userData, UserDataSize);
278 // CreateOneFrame(of, pImageData, fragment_size, xsize, ysize, zsize,
279 // samplesPerPixel, quality, JpegFragmentSize);
280 //assert( !(fragment_size % 2) );
281 // Update the JpegVector with offset
282 size_t end = of->tellp();
284 JpegPair &jp = JpegFragmentSize[i];
285 jp.second = (uint32_t)(end-beg);
286 if( ((end-beg) % 2) )
291 assert( !(jp.second % 2) );
292 //std::cerr << "DIFF: " << i <<" -> " << jp.second << std::endl;
294 pImageData += fragment_size;
296 CloseJpeg(of, JpegFragmentSize);
298 UpdateBasicOffsetTable(of, JpegFragmentSize, bots);
302 size_t of_size = of->str().size();
303 UserData = new uint8_t[of_size];
304 memcpy(UserData, of->str().c_str(), of_size);
305 UserDataSize = of_size;
309 bool gdcm_write_JPEG_file8 (std::ostream *fp, char *inputdata, size_t inputlength,
310 int image_width, int image_height, int numZ,
311 int sample_pixel, int bitsallocated, int quality);
312 bool gdcm_write_JPEG_file12 (std::ostream *fp, char *inputdata, size_t inputlength,
313 int image_width, int image_height, int numZ,
314 int sample_pixel, int bitsallocated, int quality);
315 bool gdcm_write_JPEG_file16 (std::ostream *fp, char *inputdata, size_t inputlength,
316 int image_width, int image_height, int numZ,
317 int sample_pixel, int bitsallocated, int quality);
319 void PixelWriteConvert::SetCompressJPEGUserData(uint8_t *data, size_t size, File *image)
325 //char * userData = reinterpret_cast<char*>(UserData);
327 std::ostringstream *of = new std::ostringstream();
328 int xsize = image->GetXSize();
329 int ysize = image->GetYSize();
330 int zsize = image->GetZSize();
331 int samplesPerPixel = image->GetSamplesPerPixel();
332 //std::cout << "X: " << xsize << std::endl;
333 //std::cout << "Y: " << ysize << std::endl;
334 //std::cout << "Sample: " << samplesPerPixel << std::endl;
335 int bitsallocated = image->GetBitsAllocated();
336 unsigned int fragment_size = xsize*ysize*samplesPerPixel * (bitsallocated / 8);
337 gdcmDebugMacro("fragment_size " << fragment_size << " zsize " << zsize << " size " << size);
338 assert( abs(fragment_size*zsize-size) <=1 );
340 JpegVector JpegFragmentSize;
341 gdcmDebugMacro("Call Encode..BasicOffsetTable " );
343 size_t bots; //basic offset table start
344 EncodeWithBasicOffsetTable(of, zsize, bots);
346 EncodeWithoutBasicOffsetTable(of, 1);
348 gdcmDebugMacro("Out of Encode..BasicOffsetTable " );
349 uint8_t *pImageData = data;
350 for(int i=0; i<zsize;i++)
352 gdcmDebugMacro("Write fragment no " << i );
353 WriteDICOMItems(of, JpegFragmentSize);
354 size_t beg = of->tellp();
355 if( bitsallocated == 8 )
357 gdcm_write_JPEG_file8(of, (char*)pImageData,size,
358 image->GetXSize(), image->GetYSize(), image->GetZSize(), image->GetSamplesPerPixel(),
359 image->GetBitsAllocated(), 100 );
361 else if (bitsallocated <= 12)
363 assert( bitsallocated >= 8 );
364 gdcm_write_JPEG_file12(of, (char*)pImageData,size,
365 image->GetXSize(), image->GetYSize(), image->GetZSize(), image->GetSamplesPerPixel(),
366 image->GetBitsAllocated(), 100);
368 else if (bitsallocated <= 16)
370 assert( bitsallocated >= 12 );
371 gdcm_write_JPEG_file16(of, (char*)pImageData,size,
372 image->GetXSize(), image->GetYSize(), image->GetZSize(), image->GetSamplesPerPixel(),
373 image->GetBitsAllocated(), 100);
375 else if (bitsallocated <= 32) // if we are lucky (?), it will compress as a 2 bytes stream
376 { // (Actually it doesn't !)
377 // Just to allow ctest not to abort on 32bits per pixel image RTDOSE.dcm
378 assert( bitsallocated >= 16 );
379 gdcmDebugMacro( "Warning : bitsallocated>16 not supported by JPEG !" );
380 gdcm_write_JPEG_file16(of, (char*)pImageData, size,
381 image->GetXSize(), image->GetYSize(), image->GetZSize(), image->GetSamplesPerPixel(),
382 image->GetBitsAllocated(), 100);
386 std::cerr << "Major pb : bitsallocated =" << bitsallocated << std::endl;
389 size_t end = of->tellp();
391 JpegPair &jp = JpegFragmentSize[i];
392 jp.second = (uint32_t)(end-beg);
393 if( ((end-beg) % 2) )
398 assert( !(jp.second % 2) );
399 //std::cerr << "DIFF: " << i <<" -> " << jp.second << std::endl;
402 //JpegPair &jp = v[0];
405 //userData, UserDataSize);
406 // CreateOneFrame(of, pImageData, fragment_size, xsize, ysize, zsize,
407 // samplesPerPixel, quality, JpegFragmentSize);
408 //assert( !(fragment_size % 2) );
409 pImageData += fragment_size;
411 CloseJpeg(of, JpegFragmentSize);
413 UpdateBasicOffsetTable(of, JpegFragmentSize, bots);
416 size_t of_size = of->str().size();
417 UserData = new uint8_t[of_size];
418 memcpy(UserData, of->str().c_str(), of_size);
419 UserDataSize = of_size;
424 //-----------------------------------------------------------------------------
426 //bool PixelWriteConvert::CompressJPEG2000(uint8_t *data, size_t size)
430 //-----------------------------------------------------------------------------
433 //-----------------------------------------------------------------------------
436 //-----------------------------------------------------------------------------
437 } // end namespace gdcm