vil_viff.cxx
Go to the documentation of this file.
1 // This is core/vil/file_formats/vil_viff.cxx
2 #include <complex>
3 #include <iostream>
4 #include <cstring>
5 #include "vil_viff.h"
6 #include <cassert>
7 #ifdef _MSC_VER
8 # include <vcl_msvc_warnings.h>
9 #endif
10 
11 static char const* vil_viff_format_tag = "viff";
12 
13 
14 #include <vil/vil_stream.h>
15 #include <vil/vil_image_resource.h>
16 #include <vil/vil_image_view.h>
17 #include <vil/vil_exception.h>
18 
19 static inline void swap(void* p,int length)
20 {
21  char* t = (char*)p;
22 #ifdef DEBUG
23  if (length == sizeof(vxl_uint_32) && *(vxl_uint_32*)p != 0) {
24  std::cerr << "Swapping " << *(vxl_uint_32*)p;
25  if (length == sizeof(float))
26  std::cerr << " (or " << *(float*)p << ')';
27  }
28 #endif
29  for (int j=0;2*j<length;++j)
30  {
31  char c = t[j];
32  t[j] = t[length-j-1];
33  t[length-j-1] = c;
34  }
35 #ifdef DEBUG
36  if (length == sizeof(vxl_uint_32) && *(vxl_uint_32*)p != 0) {
37  std::cerr << " to " << *(vxl_uint_32*)p;
38  if (length == sizeof(float))
39  std::cerr << " (or " << *(float*)p << ')';
40  std::cerr << '\n';
41  }
42 #endif
43 }
44 
46 {
47  // Attempt to read header
48  if (!is) return nullptr;
49  is->seek(0L);
50  vil_viff_xvimage header;
51  if (VIFF_HEADERSIZE != is->read((void*)(&header),VIFF_HEADERSIZE))
52  return nullptr;
53 
54  if (header.identifier != (char)XV_FILE_MAGIC_NUM ||
55  header.file_type != (char)XV_FILE_TYPE_XVIFF)
56  return nullptr;
57 
58  vxl_uint_32 dst = header.data_storage_type;
59  if ((dst & 0xff) == 0)
60  swap(&dst,sizeof(dst));
61  switch (dst)
62  {
63  case VFF_TYP_BIT:
64  case VFF_TYP_1_BYTE:
65  case VFF_TYP_2_BYTE:
66  case VFF_TYP_4_BYTE:
67  case VFF_TYP_FLOAT:
68  case VFF_TYP_DOUBLE:
69  case VFF_TYP_COMPLEX:
70  case VFF_TYP_DCOMPLEX:
71  return new vil_viff_image(is);
72  default:
73  std::cout << "vil_viff: non supported data type: VFF_TYP "
74  << header.data_storage_type << std::endl;
75  return nullptr;
76  }
77 }
78 
80  unsigned int ni, unsigned int nj, unsigned int nplanes,
81  vil_pixel_format format)
82 {
83  return new vil_viff_image(is, ni, nj, nplanes, format);
84 }
85 
86 char const* vil_viff_file_format::tag() const
87 {
88  return vil_viff_format_tag;
89 }
90 
91 /////////////////////////////////////////////////////////////////////////////
92 
94  : is_(is)
95 {
96  is_->ref();
97  if (!read_header())
98  {
99  std::cerr << "vil_viff: cannot read file header; creating dummy 0x0 image\n";
100  start_of_data_ = VIFF_HEADERSIZE; endian_consistent_ = true;
101  ni_ = nj_ = 0; nplanes_ = 1;
103  }
104 }
105 
106 char const* vil_viff_image::file_format() const
107 {
108  return vil_viff_format_tag;
109 }
110 
112  unsigned int ni, unsigned int nj, unsigned int nplanes,
113  vil_pixel_format format)
114  : is_(is), ni_(ni), nj_(nj),
115  nplanes_(nplanes), start_of_data_(VIFF_HEADERSIZE),
116  format_(format), endian_consistent_(true)
117 {
118  is_->ref();
119  write_header();
120 }
121 
123 {
124  is_->unref();
125 }
126 
127 bool vil_viff_image::get_property(char const * /*tag*/, void * /*prop*/) const
128 {
129  // This is not an in-memory image type, nor is it read-only:
130  return false;
131 }
132 
134 {
135  // Go to start
136  is_->seek(0L);
137  start_of_data_ = VIFF_HEADERSIZE;
138 
139  // Read header
140  if (VIFF_HEADERSIZE != is_->read((void*)(&header_),VIFF_HEADERSIZE))
141  return false;
142 
143  if (header_.identifier != (char)XV_FILE_MAGIC_NUM ||
144  header_.file_type != (char)XV_FILE_TYPE_XVIFF)
145  return false;
146 
147  check_endian();
148 
149  //Copy ni and nj from header
150  vxl_uint_32 rs = header_.row_size;
151  vxl_uint_32 cs = header_.col_size;
152  vxl_uint_32 dst = header_.data_storage_type;
153  vxl_uint_32 ndb = header_.num_data_bands;
154 
155  vxl_uint_32 ispare1 = header_.ispare1;
156  vxl_uint_32 ispare2 = header_.ispare2;
157  float fspare1 = header_.fspare1;
158  float fspare2 = header_.fspare2;
159 
160  if (!endian_consistent_)
161  {
162  swap(&rs,sizeof(rs));
163  swap(&cs,sizeof(cs));
164  swap(&dst,sizeof(dst));
165  swap(&ndb,sizeof(ndb));
166  swap(&ispare1,sizeof(ispare1));
167  swap(&ispare2,sizeof(ispare2));
168  swap(&fspare1,sizeof(fspare1));
169  swap(&fspare2,sizeof(fspare2));
170  }
171 
172  ni_ = rs;
173  nj_ = cs;
174  nplanes_ = (int)ndb; // number of colour bands
175 
176  // decide on data storage type
178  if (dst == VFF_TYP_BIT)
180  else if (dst == VFF_TYP_1_BYTE)
182  else if (dst == VFF_TYP_2_BYTE)
184  else if (dst == VFF_TYP_4_BYTE)
186  else if (dst == VFF_TYP_FLOAT)
188  else if (dst == VFF_TYP_DOUBLE)
190  else if (dst == VFF_TYP_COMPLEX)
192  else if (dst == VFF_TYP_DCOMPLEX)
194  else
195  std::cout << "vil_viff: non supported data type: VFF_TYP " << dst << '\n';
197 }
198 
200 {
201  is_->seek(0L);
203 
206  type=VFF_TYP_4_BYTE;
207  else if (format_==VIL_PIXEL_FORMAT_UINT_16 ||
209  type=VFF_TYP_2_BYTE;
210  else if (format_==VIL_PIXEL_FORMAT_BYTE ||
212  type=VFF_TYP_1_BYTE;
213  else if (format_==VIL_PIXEL_FORMAT_BOOL)
214  type=VFF_TYP_BIT;
216  type=VFF_TYP_FLOAT;
218  type=VFF_TYP_DOUBLE;
220  type=VFF_TYP_COMPLEX;
222  type=VFF_TYP_DCOMPLEX;
223  else
224  {
225  std::cout << "vil_viff: non supported data type: " << (short)format_ << '\n';
226  return false;
227  }
228 
229  //create header
230  vil_viff_xvimage image(ni_, nj_, type, nplanes_);
231 
232  //make local copy of header
233  std::memcpy(&header_, &image, sizeof(header_));
234  start_of_data_ = sizeof(header_);
235 
236 
237  is_->write((void*)(&header_), start_of_data_);
238  start_of_data_ = is_->tell();
239  return true;
240 }
241 
243  unsigned int y0, unsigned int ys) const
244 {
245  assert(x0+xs<=ni_);
246  assert(y0+ys<=nj_);
247  unsigned int pix_size = 8*vil_pixel_format_sizeof_components(format_);
248  if (format_==VIL_PIXEL_FORMAT_BOOL) pix_size = 1;
249  if (format_==VIL_PIXEL_FORMAT_BOOL && x0%8 != 0)
250  std::cerr << "vil_viff_image::get_copy_view(): Warning: x0 should be a multiple of 8 for this type of image\n";
251 
252  vxl_uint_32 rowsize = (pix_size*xs+7)/8;
253  vxl_uint_32 tbytes = rowsize*ys*nplanes_;
255  auto* ib = reinterpret_cast<vxl_byte*>(buf->data());
256  for (unsigned int p = 0; p<nplanes_; ++p) {
257  for (unsigned int y = y0; y < y0+ys; ++y) {
258  is_->seek(start_of_data_ + p*nj_*((ni_*pix_size+7)/8)
259  + y*((ni_*pix_size+7)/8)
260  + x0*pix_size/8);
261  is_->read(ib, rowsize);
262  ib += rowsize;
263  }
264  }
265  if (!endian_consistent_) {
266  ib = reinterpret_cast<vxl_byte*>(buf->data());
267  for (unsigned int i=0;i<tbytes;i+=(pix_size+7)/8)
268  swap(ib+i,(pix_size+7)/8);
269  }
270 
271 #define ARGS(T) buf, reinterpret_cast<T*>(buf->data()), xs,ys,nplanes_, 1,xs,xs*ys
272  if (format_ == VIL_PIXEL_FORMAT_BOOL) return new vil_image_view<bool> (ARGS(bool));
273  else if (format_ == VIL_PIXEL_FORMAT_BYTE) return new vil_image_view<vxl_byte> (ARGS(vxl_byte));
274  else if (format_ == VIL_PIXEL_FORMAT_UINT_16) return new vil_image_view<vxl_uint_16> (ARGS(vxl_uint_16));
275  else if (format_ == VIL_PIXEL_FORMAT_UINT_32) return new vil_image_view<vxl_uint_32> (ARGS(vxl_uint_32));
276  else if (format_ == VIL_PIXEL_FORMAT_FLOAT) return new vil_image_view<float> (ARGS(float));
277  else if (format_ == VIL_PIXEL_FORMAT_DOUBLE) return new vil_image_view<double> (ARGS(double));
278  else if (format_ == VIL_PIXEL_FORMAT_COMPLEX_FLOAT) return new vil_image_view<std::complex<float> > (ARGS(std::complex<float>));
279  else if (format_ == VIL_PIXEL_FORMAT_COMPLEX_DOUBLE) return new vil_image_view<std::complex<double> >(ARGS(std::complex<double>));
280  else return nullptr;
281 #undef ARGS
282 }
283 
284 bool vil_viff_image::put_view(vil_image_view_base const& buf, unsigned int x0, unsigned int y0)
285 {
286  assert(buf.pixel_format() == format_); // pixel formats of image and buffer must match
287  if (!view_fits(buf, x0, y0) || buf.nplanes() != nplanes())
288  {
289  vil_exception_warning(vil_exception_out_of_bounds("vil_viff_image::put_view"));
290  return false;
291  }
292  unsigned int ni = buf.ni();
293  unsigned int nj = buf.nj();
294 #ifdef DEBUG
295  std::cerr << "vil_viff_image::put_view() : buf="
296  << ni<<'x'<<nj<<'x'<< buf.nplanes()<<'p'
297  << " at ("<<x0<<','<<y0<<")\n";
298 #endif
299  //std::cout << "buf=" << buf << '\n';
300  auto const& ibuf = reinterpret_cast<vil_image_view<vxl_byte> const&>(buf);
301  //std::cout << "ibuf=" << ibuf << '\n';
302  if (ibuf.istep() != 1 || ibuf.jstep() != int(ni) ||
303  (ibuf.planestep() != int(ni*nj) && nplanes() != 1))
304  {
305  std::cerr << "ERROR: " << __FILE__ << ":\n"
306  << " view does not fit: istep="<<ibuf.istep()
307  << ", jstep="<<ibuf.jstep()
308  << ", planestep="<<ibuf.planestep()
309  << " instead of 1,"<<ni<<','<<ni*nj<<'\n';
310  return false;
311  }
312  const vxl_byte* ob = ibuf.top_left_ptr();
313  unsigned int pix_size = 8*vil_pixel_format_sizeof_components(format_);
314  if (format_==VIL_PIXEL_FORMAT_BOOL) pix_size = 1;
315  if (format_==VIL_PIXEL_FORMAT_BOOL && x0%8 != 0)
316  std::cerr << "vil_viff_image::put_view(): Warning: x0 should be a multiple of 8 for this type of image\n";
317 
318  vxl_uint_32 rowsize = (pix_size*ni+7)/8;
319  if (endian_consistent_ || pix_size <= 8)
320  for (unsigned int p = 0; p<nplanes_; ++p)
321  for (unsigned int y = y0; y < y0+nj; ++y) {
322  is_->seek(start_of_data_ + p*nj_*((ni_*pix_size+7)/8)
323  + y*((ni_*pix_size+7)/8)
324  + x0*pix_size/8);
325  if ((vil_streampos)rowsize != is_->write(ob, rowsize))
326  std::cerr << "WARNING: " << __FILE__ << ":\n"
327  << " could not write "<<rowsize<<" EC bytes to stream;\n"
328  << " p="<<p<<", y="<<y<<'\n';
329 #ifdef DEBUG
330  else
331  std::cerr << "written "<<rowsize<<" EC bytes to stream; p="<<p<<", y="<<y<<'\n';
332 #endif
333  ob += rowsize;
334  }
335  else { // !endian_consistent_ ==> must swap bytes
336  auto* tempbuf = new vxl_byte[rowsize];
337  for (unsigned int p = 0; p<nplanes_; ++p)
338  for (unsigned int y = y0; y < y0+nj; ++y) {
339  std::memcpy(tempbuf, ob, rowsize);
340  for (unsigned int i=0; i<rowsize; i+=pix_size/8)
341  swap(tempbuf+i,pix_size/8);
342  is_->seek(start_of_data_ + p*ni_*nj_*pix_size/8 + pix_size*(y*ni_+x0)/8);
343  if ((vil_streampos)rowsize != is_->write(tempbuf, rowsize))
344  std::cerr << "WARNING: " << __FILE__ << ":\n"
345  << " could not write "<<rowsize<<" NEC bytes to stream;\n"
346  << " p="<<p<<", y="<<y<<'\n';
347 #ifdef DEBUG
348  else
349  std::cerr << "written "<<rowsize<<" NEC bytes to stream; p="<<p<<", y="<<y<<'\n';
350 #endif
351  ob += rowsize;
352  }
353  delete[] tempbuf;
354  }
355  return true;
356 }
357 
359 {
360  // check if format is consistent
361  // Check the data_storage_type in the header
362  // If it is between 1 and 255, the "Endian" is consistent with the system
363  // if not, we swap and check again
364 
365  vxl_uint_32 dst = header_.data_storage_type;
366 
367  endian_consistent_ = ((dst & 0xff) != 0);
368 #ifdef DEBUG
369  if (endian_consistent_)
370  std::cerr << "Endian is Consistent\n";
371  else
372  std::cerr << "Endian is NOT Consistent\n";
373 #endif
374  return endian_consistent_;
375 }
376 
377 void vil_viff_image::set_ispare1(vxl_uint_32 ispare1)
378 {
380  int longsize = sizeof(vxl_uint_32);
381  auto* bytes = new vxl_byte[longsize];
382  std::memcpy(bytes,&ispare1,longsize);
383  if (!endian_consistent_)
384  swap(bytes,longsize);
385 
386  is_->seek((int)((vxl_byte*)&header_.ispare1 - (vxl_byte*)&header_));
387  is_->write(bytes, longsize);
388  delete[] bytes;
389 }
390 
391 void vil_viff_image::set_ispare2(vxl_uint_32 ispare2)
392 {
394  int longsize = sizeof(vxl_uint_32);
395  auto* bytes = new vxl_byte[longsize];
396  std::memcpy(bytes,&ispare2,longsize);
397  if (!endian_consistent_)
398  swap(bytes,longsize);
399 
400  is_->seek((int)((vxl_byte*)&header_.ispare2 - (vxl_byte*)&header_));
401  is_->write(bytes, longsize);
402  delete[] bytes;
403 }
404 
405 void vil_viff_image::set_fspare1(float fspare1)
406 {
408  int floatsize = sizeof(float);
409  auto* bytes = new vxl_byte[floatsize];
410  std::memcpy(bytes,&fspare1,floatsize);
411  if (!endian_consistent_)
412  swap(bytes,floatsize);
413 
414  is_->seek((int)((vxl_byte*)&header_.fspare1 - (vxl_byte*)&header_));
415  is_->write(bytes, floatsize);
416 
417  delete[] bytes;
418 }
419 
420 void vil_viff_image::set_fspare2(float fspare2)
421 {
423  int floatsize = sizeof(float);
424  auto* bytes = new vxl_byte[floatsize];
425  std::memcpy(bytes,&fspare2,floatsize);
426  if (!endian_consistent_)
427  swap(bytes,floatsize);
428 
429  is_->seek((int)((vxl_byte*)&header_.fspare2 - (vxl_byte*)&header_));
430  is_->write(bytes, floatsize);
431  delete[] bytes;
432 }
Stream interface for VIL image loaders.
An abstract base class of smart pointers to actual image data in memory.
vil_pixel_format
Describes the type of the concrete data.
virtual bool view_fits(const vil_image_view_base &im, unsigned i0, unsigned j0)
Check that a view will fit into the data at the given offset.
vxl_uint_32 ispare2() const
Definition: vil_viff.h:81
std::complex<float> is a scalar for vil's purposes.
virtual vil_streampos tell() const =0
Return file pointer.
bool write_header()
Definition: vil_viff.cxx:199
void swap(double &a, double &b)
vil_streampos start_of_data_
Definition: vil_viff.h:45
vxl_uint_32 ispare1
virtual vil_streampos write(void const *buf, vil_streampos n)=0
Write n bytes from buf. Returns number of bytes written.
bool get_property(char const *tag, void *prop=nullptr) const override
Extra property information.
Definition: vil_viff.cxx:127
char const * file_format() const override
Return a string describing the file format.
Definition: vil_viff.cxx:106
vil_viff_xvimage header_
Definition: vil_viff.h:49
float fspare1() const
Definition: vil_viff.h:82
void set_fspare1(float fspare1)
Definition: vil_viff.cxx:405
virtual void seek(vil_streampos position)=0
Goto file pointer.
unsigned int nplanes_
Definition: vil_viff.h:43
unsigned int ni_
Definition: vil_viff.h:41
virtual vil_streampos read(void *buf, vil_streampos n)=0
Read n bytes into buf. Returns number of bytes read.
Exceptions thrown by vil, and a mechanism for turning them off.
~vil_viff_image() override
Definition: vil_viff.cxx:122
vil_stream * is_
Definition: vil_viff.h:40
unsigned vil_pixel_format_sizeof_components(enum vil_pixel_format f)
Return the number of bytes used by each component of pixel format f.
bool endian_consistent_
Definition: vil_viff.h:48
enum vil_pixel_format format_
Definition: vil_viff.h:46
unsigned int nj_
Definition: vil_viff.h:42
unsigned ni() const
Width.
Stream interface for VIL image loaders.
Definition: vil_stream.h:21
vxl_uint_32 row_size
unsigned nj() const
Height.
void set_fspare2(float fspare2)
Definition: vil_viff.cxx:420
virtual enum vil_pixel_format pixel_format() const =0
Return a description of the concrete data pixel type.
unsigned int nj() const override
Dimensions: Planes x ni x nj.
Definition: vil_viff.h:66
vxl_uint_32 ispare2
Indicates that some reference was made to pixels beyond the bounds of an image.
Definition: vil_exception.h:81
void set_ispare1(vxl_uint_32 ispare1)
Definition: vil_viff.cxx:377
bool check_endian()
Definition: vil_viff.cxx:358
unsigned int nplanes() const override
Dimensions: Planes x ni x nj.
Definition: vil_viff.h:67
void ref()
up/down the reference count.
Definition: vil_stream.h:45
vil_image_view_base_sptr get_copy_view() const
Create a read/write view of a copy of all the data.
A base class reference-counting view of some image data.
vxl_uint_32 data_storage_type
Ref. counted block of data on the heap.
void unref()
Definition: vil_stream.cxx:31
unsigned int ni() const override
Dimensions. Planes x W x H.
Definition: vil_viff.h:65
vxl_uint_32 num_data_bands
#define ARGS(T)
unsigned nplanes() const
Number of planes.
void set_ispare2(vxl_uint_32 ispare2)
Definition: vil_viff.cxx:391
bool put_view(vil_image_view_base const &buf, unsigned int x0, unsigned int y0) override
Write buf into this at position (x0,y0).
Definition: vil_viff.cxx:284
vxl_int_32 vil_streampos
Definition: vil_stream.h:16
float fspare2() const
Definition: vil_viff.h:83
vxl_uint_32 col_size
void vil_exception_warning(T exception)
Throw an exception indicating a potential problem.
Definition: vil_exception.h:37
Representation of a generic image source or destination.
char const * tag() const override
Return a character string which uniquely identifies this format.
Definition: vil_viff.cxx:86
vil_image_resource_sptr make_output_image(vil_stream *vs, unsigned int ni, unsigned int nj, unsigned int nplanes, vil_pixel_format format) override
Definition: vil_viff.cxx:79
bool read_header()
Definition: vil_viff.cxx:133
Generic image implementation for VIFF (Khoros) files.
Definition: vil_viff.h:38
std::ptrdiff_t istep() const
Add this to your pixel pointer to get next i pixel.
vil_image_resource_sptr make_input_image(vil_stream *vs) override
Attempt to make a generic_image which will read from vil_stream vs.
Definition: vil_viff.cxx:45
std::complex<double> is a scalar for vil's purposes.
vil_viff_data_storage
vil_viff_image(vil_stream *is)
Definition: vil_viff.cxx:93
Loader for Khoros 1.0 images.
vxl_uint_32 ispare1() const
User defined spare values in header.
Definition: vil_viff.h:80