BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
TiffHandler.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Device/InputOutput/TiffHandler.cpp
6 //! @brief Implements class TiffReadStrategy.
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************** //
14 
15 #ifdef BORNAGAIN_TIFF_SUPPORT
16 
18 #include "Base/Utils/SysUtils.h"
19 #include <tiffio.hxx>
20 
21 TiffHandler::TiffHandler()
22  : m_tiff(0), m_width(0), m_height(0), m_bitsPerSample(0), m_samplesPerPixel(0),
23  m_sampleFormat(0)
24 {
25 }
26 
27 TiffHandler::~TiffHandler()
28 {
29  close();
30 }
31 
32 void TiffHandler::read(std::istream& input_stream)
33 {
34  m_tiff = TIFFStreamOpen("MemTIFF", &input_stream);
35  if (!m_tiff) {
36  throw Exceptions::FormatErrorException("TiffHandler::read() -> Can't open the file.");
37  }
38  read_header();
39  read_data();
40  close();
41 }
42 
43 const OutputData<double>* TiffHandler::getOutputData() const
44 {
45  return m_data.get();
46 }
47 
48 void TiffHandler::write(const OutputData<double>& data, std::ostream& output_stream)
49 {
50  m_data.reset(data.clone());
51  if (m_data->getRank() != 2)
52  throw Exceptions::LogicErrorException("TiffHandler::write -> Error. "
53  "Only 2-dim arrays supported");
54  m_tiff = TIFFStreamOpen("MemTIFF", &output_stream);
55  m_width = m_data->getAxis(0).size();
56  m_height = m_data->getAxis(1).size(); // this does not exist for 1d data
57  write_header();
58  write_data();
59  close();
60 }
61 
62 void TiffHandler::read_header()
63 {
64  ASSERT(m_tiff);
65  uint32 width(0);
66  uint32 height(0);
67  if (!TIFFGetField(m_tiff, TIFFTAG_IMAGEWIDTH, &width)
68  || !TIFFGetField(m_tiff, TIFFTAG_IMAGELENGTH, &height)) {
69  throw Exceptions::FormatErrorException("TiffHandler::read_header() -> Error. "
70  "Can't read width/height.");
71  }
72 
73  m_width = (size_t)width;
74  m_height = (size_t)height;
75 
76  uint16 orientationTag(0);
77  TIFFGetField(m_tiff, TIFFTAG_ORIENTATION, &orientationTag);
78 
79  bool good = true;
80 
81  // BitsPerSample defaults to 1 according to the TIFF spec.
82  if (!TIFFGetField(m_tiff, TIFFTAG_BITSPERSAMPLE, &m_bitsPerSample))
83  m_bitsPerSample = 1;
84  if (8 != m_bitsPerSample && 16 != m_bitsPerSample && 32 != m_bitsPerSample)
85  good = false;
86 
87  // they may be e.g. grayscale with 2 samples per pixel
88  if (!TIFFGetField(m_tiff, TIFFTAG_SAMPLESPERPIXEL, &m_samplesPerPixel))
89  m_samplesPerPixel = 1;
90  if (m_samplesPerPixel != 1)
91  good = false;
92 
93  if (!TIFFGetField(m_tiff, TIFFTAG_SAMPLEFORMAT, &m_sampleFormat))
94  m_sampleFormat = 1;
95 
96  switch (m_sampleFormat) {
97  case 1: // unsigned int
98  case 2: // signed int
99  break;
100  case 3: // IEEE float
101  if (32 != m_bitsPerSample)
102  good = false;
103  break;
104  default:
105  good = false;
106  }
107 
108  if (!good) {
109  std::ostringstream message;
110  message << "TiffHandler::read_header() -> Error. "
111  << "Can't read tiff image with following parameters:" << std::endl
112  << " TIFFTAG_BITSPERSAMPLE: " << m_bitsPerSample << std::endl
113  << " TIFFTAG_SAMPLESPERPIXEL: " << m_samplesPerPixel << std::endl
114  << " TIFFTAG_SAMPLEFORMAT: " << m_sampleFormat << std::endl;
115  throw Exceptions::FormatErrorException(message.str());
116  }
117 }
118 
119 void TiffHandler::read_data()
120 {
121  ASSERT(m_tiff);
122 
123  ASSERT(0 == m_bitsPerSample % 8);
124  uint16 bytesPerSample = m_bitsPerSample / 8;
125  tmsize_t buf_size = TIFFScanlineSize(m_tiff);
126  tmsize_t expected_size = bytesPerSample * m_width;
127  if (buf_size != expected_size)
129  "TiffHandler::read_data() -> Error. Wrong scanline size.");
130 
131  tdata_t buf = _TIFFmalloc(buf_size);
132  if (!buf)
134  "TiffHandler::read_data() -> Error. Can't allocate buffer.");
135 
136  create_output_data();
137 
138  std::vector<int8> line_buf;
139  line_buf.resize(buf_size, 0);
140 
141  std::vector<unsigned> axes_indices(2);
142 
143  for (uint32 row = 0; row < (uint32)m_height; row++) {
144  if (TIFFReadScanline(m_tiff, buf, row) < 0)
146  "TiffHandler::read_data() -> Error. Error in scanline.");
147 
148  memcpy(&line_buf[0], buf, buf_size);
149 
150  for (unsigned col = 0; col < m_width; ++col) {
151  axes_indices[0] = col;
152  axes_indices[1] = static_cast<unsigned>(m_height) - 1 - row;
153  size_t global_index = m_data->toGlobalIndex(axes_indices);
154 
155  void* incoming = &line_buf[col * bytesPerSample];
156  double sample = 0;
157 
158  switch (m_sampleFormat) {
159  case 1: // unsigned int
160  switch (m_bitsPerSample) {
161  case 8:
162  sample = *reinterpret_cast<uint8*>(incoming);
163  break;
164  case 16:
165  sample = *reinterpret_cast<uint16*>(incoming);
166  break;
167  case 32:
168  sample = *reinterpret_cast<uint32*>(incoming);
169  break;
170  }
171  break;
172  case 2: // signed int
173  switch (m_bitsPerSample) {
174  case 8:
175  sample = *reinterpret_cast<int8*>(incoming);
176  break;
177  case 16:
178  sample = *reinterpret_cast<int16*>(incoming);
179  break;
180  case 32:
181  sample = *reinterpret_cast<int32*>(incoming);
182  break;
183  }
184  break;
185  case 3: // IEEE float
186  sample = double(*reinterpret_cast<float*>(incoming));
187  break;
188  default:
189  throw Exceptions::FormatErrorException("TiffHandler: unexpected sample format");
190  }
191 
192  (*m_data)[global_index] = sample;
193  }
194  }
195  _TIFFfree(buf);
196 }
197 
198 void TiffHandler::write_header()
199 {
200  ASSERT(m_tiff);
201  TIFFSetField(m_tiff, TIFFTAG_ARTIST, "BornAgain.IOFactory");
202  TIFFSetField(m_tiff, TIFFTAG_DATETIME, SysUtils::getCurrentDateAndTime().c_str());
203  TIFFSetField(m_tiff, TIFFTAG_IMAGEDESCRIPTION,
204  "Image converted from BornAgain intensity file.");
205  TIFFSetField(m_tiff, TIFFTAG_SOFTWARE, "BornAgain");
206 
207  uint32 width = static_cast<uint32>(m_width);
208  uint32 height = static_cast<uint32>(m_height);
209  TIFFSetField(m_tiff, TIFFTAG_IMAGEWIDTH, width);
210  TIFFSetField(m_tiff, TIFFTAG_IMAGELENGTH, height);
211 
212  // output format, hardcoded here
213  uint16 bitPerSample = 32, samplesPerPixel = 1;
214  TIFFSetField(m_tiff, TIFFTAG_BITSPERSAMPLE, bitPerSample);
215  TIFFSetField(m_tiff, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel);
216 
217  TIFFSetField(m_tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
218 }
219 
220 void TiffHandler::write_data()
221 {
222  typedef int sample_t;
223  tmsize_t buf_size = sizeof(sample_t) * m_width;
224  tdata_t buf = _TIFFmalloc(buf_size);
225  if (!buf)
227  "TiffHandler::write_data() -> Error. Can't allocate buffer.");
228 
229  std::vector<sample_t> line_buf;
230  line_buf.resize(m_width, 0);
231  std::vector<unsigned> axes_indices(2);
232  for (unsigned row = 0; row < (uint32)m_height; row++) {
233  for (unsigned col = 0; col < line_buf.size(); ++col) {
234  axes_indices[0] = col;
235  axes_indices[1] = static_cast<unsigned>(m_height) - 1 - row;
236  size_t global_index = m_data->toGlobalIndex(axes_indices);
237  line_buf[col] = static_cast<sample_t>((*m_data)[global_index]);
238  }
239  memcpy(buf, &line_buf[0], buf_size);
240 
241  if (TIFFWriteScanline(m_tiff, buf, row) < 0)
243  "TiffHandler::write_data() -> Error. Error in TIFFWriteScanline.");
244  }
245  _TIFFfree(buf);
246  TIFFFlush(m_tiff);
247 }
248 
249 void TiffHandler::close()
250 {
251  if (m_tiff) {
252  TIFFClose(m_tiff);
253  m_tiff = 0;
254  m_width = 0;
255  m_height = 0;
256  }
257 }
258 
259 void TiffHandler::create_output_data()
260 {
261  ASSERT(m_tiff);
262  m_data.reset(new OutputData<double>);
263  m_data->addAxis("x", m_width, 0.0, double(m_width));
264  m_data->addAxis("y", m_height, 0.0, double(m_height));
265 }
266 
267 #endif // BORNAGAIN_TIFF_SUPPORT
#define ASSERT(condition)
Definition: Assert.h:26
Defines various stuff in namespace Utils.
Defines class TiffHandler.
OutputData * clone() const
Definition: OutputData.h:253
std::string getCurrentDateAndTime()
Definition: SysUtils.cpp:22