]> Creatis software - gdcm.git/blob - src/gdcmPixelWriteConvert.cxx
First step to sync with v 1.2.2
[gdcm.git] / src / gdcmPixelWriteConvert.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmPixelWriteConvert.cxx,v $
5   Language:  C++
6   Date:      $Date: 2007/07/13 08:17:21 $
7   Version:   $Revision: 1.14 $
8                                                                                 
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.
12                                                                                 
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.
16                                                                                 
17 =========================================================================*/
18
19 #include "gdcmDebug.h"
20 #include "gdcmPixelWriteConvert.h"
21 #include "gdcmFile.h"
22 #include "gdcmUtil.h"
23
24 #include <vector>
25
26 #define WITHOFFSETTABLE 1
27
28 namespace GDCM_NAME_SPACE
29 {
30 //-----------------------------------------------------------------------------
31 // Public
32
33 //-----------------------------------------------------------------------------
34 // Protected
35
36 //-----------------------------------------------------------------------------
37 // Private
38
39 // Constructor / Destructor
40 /**
41  * \brief Constructor
42  */
43 PixelWriteConvert::PixelWriteConvert() 
44 {
45    ReadData     = 0;
46    ReadDataSize = 0;
47
48    UserData     = 0;
49    UserDataSize = 0;
50    Compressed   = false;
51 }
52
53 /**
54  * \brief Destructor
55  */
56 PixelWriteConvert::~PixelWriteConvert() 
57 {
58    if( Compressed )
59      {
60      delete[] UserData;
61      }
62 }
63
64 /**
65  * \brief   sets Read Data (and size)
66  * @param   data data (uint8_t is for prototyping. if your data is not uint8_t
67  *                     just cast the pointer for calling the method)
68  * @param   size data size, in bytes
69  */
70 void PixelWriteConvert::SetReadData(uint8_t *data, size_t size)
71 {
72    ReadData = data;
73    ReadDataSize = size;
74 }
75
76 /**
77  * \brief   Sets the internal pointer to the caller's inData
78  *          image representation, WITHOUT COPYING THE DATA.
79  *          - 'image' Pixels are presented as C-like 2D arrays : line per line.
80  *          - 'volume'Pixels are presented as C-like 3D arrays : plane per plane 
81  * \warning Since the pixels are not copied, it is the caller's responsability
82  *          not to deallocate its data before gdcm uses them (e.g. with
83  *          the Write() method )
84  * @param   data data (uint8_t is for prototyping. if your data is not uint8_t
85  *                     just cast the pointer for calling the method)
86  * @param   size size, in bytes.
87  */
88 void PixelWriteConvert::SetUserData(uint8_t *data, size_t size)
89 {
90    UserData = data;
91    UserDataSize = size;
92 }
93
94 /**
95  * \brief   Get Data (UserData or ReadData)
96  * @return  data (uint8_t is for prototyping. if your data is *not* uint8_t
97  *                just cast the returned pointer)
98  */
99 uint8_t *PixelWriteConvert::GetData()
100 {
101    if ( UserData )
102    {
103       return UserData;
104    }
105    else
106    {
107       return ReadData;
108    }
109 }
110
111 /**
112  * \brief   Get Data Size (UserData or ReadData)
113  * @return  size, in bytes.
114  */
115 size_t PixelWriteConvert::GetDataSize()
116 {
117    if ( UserData )
118    {
119       return UserDataSize;
120    }
121    else
122    {
123       return ReadDataSize;
124    }
125 }
126
127
128 typedef std::pair<size_t, uint32_t> JpegPair; //offset, jpeg size
129 typedef std::vector<JpegPair> JpegVector;
130
131 bool gdcm_write_JPEG2000_file (std::ostream *of, char *inputdata, size_t inputlength, 
132   int image_width, int image_height, int numZ, int sample_pixel, int bitsallocated,
133   int sign, int quality);
134
135
136 void WriteDICOMItems(std::ostream *fp, JpegVector &v)
137 {
138   // Item tag:
139   uint16_t group = 0xfffe;
140   uint16_t elem  = 0xe000;
141   GDCM_NAME_SPACE::binary_write(*fp, group);
142   GDCM_NAME_SPACE::binary_write(*fp, elem);
143   // Item Length
144   uint32_t dummy = 0x12345678;
145   size_t offset = fp->tellp();
146   JpegPair jp;
147   jp.first = offset;
148   v.push_back(jp);
149   GDCM_NAME_SPACE::binary_write(*fp, dummy);
150 }
151
152 // PS 3.5, page 66
153 void EncodeWithoutBasicOffsetTable(std::ostream *fp, int numFrag)// JpegVector& v) //, uint32_t length)
154 {
155   assert( numFrag == 1);
156
157   // Item tag:
158   uint16_t group = 0xfffe;
159   uint16_t elem  = 0xe000;
160   GDCM_NAME_SPACE::binary_write(*fp, group);
161   GDCM_NAME_SPACE::binary_write(*fp, elem);
162   // Item Length
163   uint32_t item_length = 0x0000;
164   GDCM_NAME_SPACE::binary_write(*fp, item_length);
165
166 }
167
168 // PS 3.5, page 67
169 void EncodeWithBasicOffsetTable(std::ostream *fp, int numFrag, size_t &start)
170 {
171   // Item tag:
172   uint16_t group = 0xfffe;
173   uint16_t elem  = 0xe000;
174   GDCM_NAME_SPACE::binary_write(*fp, group);
175   GDCM_NAME_SPACE::binary_write(*fp, elem);
176   // Item Length
177   uint32_t item_length = numFrag*4; // sizeof(uint32_t)
178   GDCM_NAME_SPACE::binary_write(*fp, item_length);
179
180   // Just prepare the space
181   start = fp->tellp(); //to be able to rewind
182   for(int i=0; i<numFrag;++i)
183     {
184     uint32_t dummy = 0x0000;
185     GDCM_NAME_SPACE::binary_write(*fp, dummy);
186     }
187 }
188
189 void UpdateBasicOffsetTable(std::ostream *fp, JpegVector const &v, size_t pos)
190 {
191   JpegVector::const_iterator i;
192   fp->seekp( pos );
193   const JpegPair &first = v[0];
194   for(i=v.begin(); i!=v.end(); ++i)
195     {
196     const JpegPair &jp = *i;
197     if(i == v.begin() ){ assert( jp.first - first.first == 0); }
198     uint32_t offset = jp.first - first.first;
199     GDCM_NAME_SPACE::binary_write(*fp, offset);
200     //std::cerr << "Updating Table:" << jp.first - first.first << std::endl;
201     }
202 }
203
204 void UpdateJpegFragmentSize(std::ostream *fp, JpegVector const &v)
205 {
206   JpegVector::const_iterator i;
207   for(i= v.begin(); i!=v.end(); ++i)
208     {
209     const JpegPair &jp = *i;
210     fp->seekp( jp.first );
211     uint32_t length = jp.second;
212     GDCM_NAME_SPACE::binary_write(*fp, length);
213     //std::cerr << "Updating:" << jp.first << "," << jp.second << std::endl;
214     }
215 }
216
217 void CloseJpeg(std::ostream *fp, JpegVector &v)
218 {
219   // sequence terminator
220   uint16_t group = 0xfffe;
221   uint16_t elem  = 0xe0dd;
222   GDCM_NAME_SPACE::binary_write(*fp, group);
223   GDCM_NAME_SPACE::binary_write(*fp, elem);
224
225   uint32_t length = 0x0;
226   GDCM_NAME_SPACE::binary_write(*fp, length);
227
228   // Jpeg is done, now update the frag length
229   UpdateJpegFragmentSize(fp, v);
230 }
231
232 // I need to pass the File*. I do not understand how PixelWriteConvert is supposed
233 // to access this information otherwise
234 // size can now be computer from File attributes (what an API...)
235 void PixelWriteConvert::SetCompressJPEG2000UserData(uint8_t *data, size_t size, File *image)
236 {
237   Compressed = true;
238   //char * userData = reinterpret_cast<char*>(UserData);
239
240    std::ostringstream *of = new std::ostringstream();
241     int xsize = image->GetXSize();
242    int ysize = image->GetYSize();
243   int zsize =  image->GetZSize();
244     int samplesPerPixel = image->GetSamplesPerPixel();
245    //std::cout << "X: " << xsize << std::endl;
246    //std::cout << "Y: " << ysize << std::endl;
247    //std::cout << "Sample: " << samplesPerPixel << std::endl;
248     int bitsallocated = image->GetBitsAllocated();
249     int sign = image->IsSignedPixelData();
250    unsigned int fragment_size = xsize*ysize*samplesPerPixel * (bitsallocated / 8);
251     assert( fragment_size*zsize == size );
252
253    JpegVector JpegFragmentSize;
254 #if WITHOFFSETTABLE
255    size_t bots; //basic offset table start
256    EncodeWithBasicOffsetTable(of, zsize, bots);
257 #else
258    EncodeWithoutBasicOffsetTable(of, 1);
259 #endif
260    uint8_t *pImageData = data;
261    for(int i=0; i<zsize;i++)
262      {
263      WriteDICOMItems(of, JpegFragmentSize);
264      size_t beg = of->tellp();
265      gdcm_write_JPEG2000_file(of, (char*)pImageData,size, 
266        image->GetXSize(), image->GetYSize(), image->GetZSize(), image->GetSamplesPerPixel(),
267        image->GetBitsAllocated(), sign, 100);
268      //userData, UserDataSize);
269      //     CreateOneFrame(of, pImageData, fragment_size, xsize, ysize, zsize, 
270      //       samplesPerPixel, quality, JpegFragmentSize);
271      //assert( !(fragment_size % 2) );
272      // Update the JpegVector with offset
273      size_t end = of->tellp();
274      //static int i = 0;
275      JpegPair &jp = JpegFragmentSize[i];
276      jp.second = end-beg;
277      if( ((end-beg) % 2) )
278        {
279        of->put( '\0' );
280        jp.second += 1;
281        }
282      assert( !(jp.second % 2) );
283      //std::cerr << "DIFF: " << i <<" -> " << jp.second << std::endl;
284      //++i;
285      pImageData += fragment_size;
286      }
287    CloseJpeg(of, JpegFragmentSize);
288 #if WITHOFFSETTABLE
289    UpdateBasicOffsetTable(of, JpegFragmentSize, bots);
290 #endif
291
292
293    size_t of_size = of->str().size();
294    UserData = new uint8_t[of_size];
295    memcpy(UserData, of->str().c_str(), of_size);
296    UserDataSize = of_size;
297    
298 }
299
300 bool gdcm_write_JPEG_file8 (std::ostream *fp, char *inputdata, size_t inputlength,
301                            int image_width, int image_height, int numZ,
302                            int sample_pixel, int bitsallocated, int quality);
303 bool gdcm_write_JPEG_file12 (std::ostream *fp, char *inputdata, size_t inputlength,
304                            int image_width, int image_height, int numZ,
305                            int sample_pixel, int bitsallocated, int quality);
306 bool gdcm_write_JPEG_file16 (std::ostream *fp, char *inputdata, size_t inputlength,
307                            int image_width, int image_height, int numZ,
308                            int sample_pixel, int bitsallocated, int quality);
309
310 void PixelWriteConvert::SetCompressJPEGUserData(uint8_t *data, size_t size, File *image)
311 {
312
313  std::cerr << "entree ds PixelWriteConvert::SetCompressJPEGUserData" << std::endl; 
314  
315   (void)data;
316   (void)size;
317   (void)image;
318   Compressed = true;
319   //char * userData = reinterpret_cast<char*>(UserData);
320
321    std::ostringstream *of = new std::ostringstream();
322     int xsize = image->GetXSize();
323    int ysize = image->GetYSize();
324   int zsize =  image->GetZSize();
325     int samplesPerPixel = image->GetSamplesPerPixel();
326    //std::cout << "X: " << xsize << std::endl;
327    //std::cout << "Y: " << ysize << std::endl;
328    //std::cout << "Sample: " << samplesPerPixel << std::endl;
329     int bitsallocated = image->GetBitsAllocated();
330    unsigned int fragment_size = xsize*ysize*samplesPerPixel * (bitsallocated / 8);
331     assert( fragment_size*zsize == size );
332
333    JpegVector JpegFragmentSize;
334 #if WITHOFFSETTABLE
335    size_t bots; //basic offset table start
336    EncodeWithBasicOffsetTable(of, zsize, bots);
337 #else
338    EncodeWithoutBasicOffsetTable(of, 1);
339 #endif
340    uint8_t *pImageData = data;
341    for(int i=0; i<zsize;i++)
342      {
343      WriteDICOMItems(of, JpegFragmentSize);
344   size_t beg = of->tellp();
345      if( bitsallocated == 8 )
346        {
347        gdcm_write_JPEG_file8(of, (char*)pImageData,size, 
348          image->GetXSize(), image->GetYSize(), image->GetZSize(), image->GetSamplesPerPixel(),
349          image->GetBitsAllocated(), 100 );
350        }
351      else if (bitsallocated <= 12)
352        {
353        assert( bitsallocated >= 8 );
354        gdcm_write_JPEG_file12(of, (char*)pImageData,size, 
355          image->GetXSize(), image->GetYSize(), image->GetZSize(), image->GetSamplesPerPixel(),
356          image->GetBitsAllocated(), 100);
357        }
358      else if (bitsallocated <= 16)
359        {
360        assert( bitsallocated >= 12 );
361        gdcm_write_JPEG_file16(of, (char*)pImageData,size, 
362          image->GetXSize(), image->GetYSize(), image->GetZSize(), image->GetSamplesPerPixel(),
363          image->GetBitsAllocated(), 100);
364        }
365      else
366        {
367        abort();
368        }
369     size_t end = of->tellp();
370     //static int i = 0;
371     JpegPair &jp = JpegFragmentSize[i];
372       jp.second = end-beg;
373     if( ((end-beg) % 2) )
374       {
375       of->put( '\0' );
376       jp.second += 1;
377       }
378     assert( !(jp.second % 2) );
379     //std::cerr << "DIFF: " << i <<" -> " << jp.second << std::endl;
380     //++i;
381
382   //JpegPair &jp = v[0];
383   //jp.second = 15328;
384
385
386      //userData, UserDataSize);
387      //     CreateOneFrame(of, pImageData, fragment_size, xsize, ysize, zsize, 
388      //       samplesPerPixel, quality, JpegFragmentSize);
389      //assert( !(fragment_size % 2) );
390      pImageData += fragment_size;
391      }
392    CloseJpeg(of, JpegFragmentSize);
393 #if WITHOFFSETTABLE
394    UpdateBasicOffsetTable(of, JpegFragmentSize, bots);
395 #endif
396
397
398    size_t of_size = of->str().size();
399    UserData = new uint8_t[of_size];
400    memcpy(UserData, of->str().c_str(), of_size);
401    UserDataSize = of_size;
402
403  std::cerr << "Sortie ds PixelWriteConvert::SetCompressJPEGUserData" << std::endl; 
404 }
405
406
407 //-----------------------------------------------------------------------------
408 // Protected
409 //bool PixelWriteConvert::CompressJPEG2000(uint8_t *data, size_t size)
410 //{
411 //}
412
413 //-----------------------------------------------------------------------------
414 // Private
415
416 //-----------------------------------------------------------------------------
417 // Print
418
419 //-----------------------------------------------------------------------------
420 } // end namespace gdcm