Medical Imaging Interaction Toolkit  2018.4.99-12ad79a3
Medical Imaging Interaction Toolkit
mitkCompressedImageContainer.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
14 #include "mitkImageReadAccessor.h"
15 
16 #include "itk_zlib.h"
17 
18 #include <cstdlib>
19 
20 mitk::CompressedImageContainer::CompressedImageContainer() : m_PixelType(nullptr), m_ImageGeometry(nullptr)
21 {
22 }
23 
25 {
26  for (auto iter = m_ByteBuffers.begin(); iter != m_ByteBuffers.end(); ++iter)
27  {
28  free(iter->first);
29  }
30 
31  delete m_PixelType;
32 }
33 
35 {
36  for (auto iter = m_ByteBuffers.begin(); iter != m_ByteBuffers.end(); ++iter)
37  {
38  free(iter->first);
39  }
40 
41  m_ByteBuffers.clear();
42 
43  // Compress diff image using zlib (will be restored on demand)
44  // determine memory size occupied by voxel data
45  m_ImageDimension = image->GetDimension();
46  m_ImageDimensions.clear();
47 
49 
50  m_OneTimeStepImageSizeInBytes = m_PixelType->GetSize(); // bits per element divided by 8
51  for (unsigned int i = 0; i < m_ImageDimension; ++i)
52  {
53  unsigned int currentImageDimension = image->GetDimension(i);
54  m_ImageDimensions.push_back(currentImageDimension);
55  if (i < 3)
56  {
57  m_OneTimeStepImageSizeInBytes *= currentImageDimension; // only the 3D memory size
58  }
59  }
60 
61  m_ImageGeometry = image->GetGeometry();
62 
64  if (m_ImageDimension > 3)
65  {
67  }
68 
69  for (unsigned int timestep = 0; timestep < m_NumberOfTimeSteps; ++timestep)
70  {
71  // allocate a buffer as specified by zlib
72  unsigned long bufferSize =
73  m_OneTimeStepImageSizeInBytes + static_cast<unsigned long>(m_OneTimeStepImageSizeInBytes * 0.2) + 12;
74  auto *byteBuffer = (unsigned char *)malloc(bufferSize);
75 
76  if (itk::Object::GetDebug())
77  {
78  // compress image here into a buffer
79  MITK_INFO << "Using ZLib version: '" << zlibVersion() << "'" << std::endl
80  << "Attempting to compress " << m_OneTimeStepImageSizeInBytes << " image bytes into a buffer of size "
81  << bufferSize << std::endl;
82  }
83 
84  ImageReadAccessor imgAcc(image, image->GetVolumeData(timestep));
85  ::Bytef *dest(byteBuffer);
86  ::uLongf destLen(bufferSize);
87  auto *source((unsigned char *)imgAcc.GetData());
88  ::uLongf sourceLen(m_OneTimeStepImageSizeInBytes);
89  int zlibRetVal = ::compress(dest, &destLen, source, sourceLen);
90  if (itk::Object::GetDebug())
91  {
92  if (zlibRetVal == Z_OK)
93  {
94  MITK_INFO << "Success, using " << destLen << " bytes of the buffer (ratio "
95  << ((double)destLen / (double)sourceLen) << ")" << std::endl;
96  }
97  else
98  {
99  switch (zlibRetVal)
100  {
101  case Z_MEM_ERROR:
102  MITK_ERROR << "not enough memory" << std::endl;
103  break;
104  case Z_BUF_ERROR:
105  MITK_ERROR << "output buffer too small" << std::endl;
106  break;
107  default:
108  MITK_ERROR << "other, unspecified error" << std::endl;
109  break;
110  }
111  }
112  }
113 
114  // only use the neccessary amount of memory, realloc the buffer!
115  byteBuffer = (unsigned char *)realloc(byteBuffer, destLen);
116  bufferSize = destLen;
117  // MITK_INFO << "Using " << bufferSize << " bytes to store compressed image (" << destLen << " needed)" <<
118  // std::endl;
119 
120  m_ByteBuffers.push_back(std::pair<unsigned char *, unsigned long>(byteBuffer, bufferSize));
121  }
122 }
123 
125 {
126  if (m_ByteBuffers.empty())
127  return nullptr;
128 
129  // uncompress image data, create an Image
131  unsigned int dims[20]; // more than 20 dimensions and bang
132  for (unsigned int dim = 0; dim < m_ImageDimension; ++dim)
133  dims[dim] = m_ImageDimensions[dim];
134 
135  image->Initialize(*m_PixelType, m_ImageDimension, dims); // this IS needed, right ?? But it does allocate memory ->
136  // does create one big lump of memory (also in windows)
137 
138  unsigned int timeStep(0);
139  for (auto iter = m_ByteBuffers.begin(); iter != m_ByteBuffers.end(); ++iter, ++timeStep)
140  {
141  ImageReadAccessor imgAcc(image, image->GetVolumeData(timeStep));
142  auto *dest((unsigned char *)imgAcc.GetData());
143  ::uLongf destLen(m_OneTimeStepImageSizeInBytes);
144  ::Bytef *source(iter->first);
145  ::uLongf sourceLen(iter->second);
146  int zlibRetVal = ::uncompress(dest, &destLen, source, sourceLen);
147  if (itk::Object::GetDebug())
148  {
149  if (zlibRetVal == Z_OK)
150  {
151  MITK_INFO << "Success, destLen now " << destLen << " bytes" << std::endl;
152  }
153  else
154  {
155  switch (zlibRetVal)
156  {
157  case Z_DATA_ERROR:
158  MITK_ERROR << "compressed data corrupted" << std::endl;
159  break;
160  case Z_MEM_ERROR:
161  MITK_ERROR << "not enough memory" << std::endl;
162  break;
163  case Z_BUF_ERROR:
164  MITK_ERROR << "output buffer too small" << std::endl;
165  break;
166  default:
167  MITK_ERROR << "other, unspecified error" << std::endl;
168  break;
169  }
170  }
171  }
172  }
173 
174  image->SetGeometry(m_ImageGeometry);
175  image->Modified();
176 
177  return image;
178 }
#define MITK_INFO
Definition: mitkLogMacros.h:18
const mitk::PixelType GetPixelType(int n=0) const
Returns the PixelType of channel n.
Definition: mitkImage.cpp:101
#define MITK_ERROR
Definition: mitkLogMacros.h:20
void SetImage(Image *)
Creates a compressed version of the image.
Image::Pointer GetImage()
Creates a full mitk::Image from its compressed version.
unsigned int GetDimension() const
Get dimension of the image.
Definition: mitkImage.cpp:106
virtual ImageDataItemPointer GetVolumeData(int t=0, int n=0, void *data=nullptr, ImportMemoryManagementType importMemoryManagement=CopyMemory) const
Definition: mitkImage.cpp:326
Image class for storing images.
Definition: mitkImage.h:72
std::vector< unsigned int > m_ImageDimensions
mitk::Image::Pointer image
static Pointer New()
vcl_size_t GetSize() const
Get size of the PixelType in bytes.
std::vector< std::pair< unsigned char *, unsigned long > > m_ByteBuffers
one for each timestep. first = pointer to compressed data; second = size of buffer in bytes ...
unsigned short PixelType
ImageReadAccessor class to get locked read access for a particular image part.
mitk::BaseGeometry * GetGeometry(int t=0) const
Return the geometry, which is a TimeGeometry, of the data as non-const pointer.
Definition: mitkBaseData.h:138