vil_mit.cxx
Go to the documentation of this file.
1 // This is core/vil/file_formats/vil_mit.cxx
2 //
3 // Author: Joris Schouteden
4 // Created: 18 Feb 2000
5 // Converted from vil1 by Peter Vanroose on 17 June 2003.
6 //
7 //-----------------------------------------------------------------------------
8 
9 #include <iostream>
10 #include <cstring>
11 #include "vil_mit.h"
12 
13 static char const* vil_mit_format_tag = "mit";
14 
15 #ifdef _MSC_VER
16 # include <vcl_msvc_warnings.h>
17 #endif
18 #include <cassert>
19 
20 #include <vil/vil_stream.h>
21 #include <vil/vil_image_resource.h>
22 #include <vil/vil_image_view.h>
23 #include <vil/vil_stream_read.h>
24 #include <vil/vil_stream_write.h>
25 #include <vil/vil_exception.h>
26 
27 #define MIT_UNSIGNED 0x0001
28 #define MIT_RGB 0x0002
29 #define MIT_HSB 0x0003
30 #define MIT_CAP 0x0004
31 #define MIT_SIGNED 0x0005
32 #define MIT_FLOAT 0x0006
33 #define MIT_EDGE 0x0007
34 
35 #define MIT_UCOMPLEX 0x0101
36 #define MIT_SCOMPLEX 0x0105
37 #define MIT_FCOMPLEX 0x0106
38 
39 #define MIT_UNSIGNED_E 0x0201
40 #define MIT_SIGNED_E 0x0205
41 #define MIT_FLOAT_E 0x0206
42 
43 #define MIT_UCOMPLEX_E 0x0301
44 #define MIT_SCOMPLEX_E 0x0305
45 #define MIT_FCOMPLEX_E 0x0306
46 
47 #define EDGE_HOR 0200 /* Edge direction codes */
48 #define EDGE_VER 0100
49 
50 // The mit image format is encoded (in little-endian format) as follows :
51 // 2 bytes : magic number
52 // 2 bytes : number of bits per pixel
53 // 2 bytes : width
54 // 2 bytes : height
55 // raw image data follows.
56 //
57 // E.g. :
58 // 00000000: 01 00 08 00 67 01 5A 01 6D 6D 6D 6D 6D 6D 6D 6D ....g.Z.mmmmmmmm
59 // 00000010: 6D 6D 6D 6D 6D 6D 6D 6D 6D 6D 6D 6D 6D 6D 6D 6D mmmmmmmmmmmmmmmm
60 
61 //----------------------------------------------------------------------
62 
64 {
65  is->seek(0L);
66  if (is->file_size() < 8L) return nullptr;
67  unsigned int type = vil_stream_read_little_endian_uint_16(is);
68 
69  if (!(type == MIT_UNSIGNED ||
70  type == MIT_RGB ||
71  type == MIT_SIGNED ||
72  type == MIT_FLOAT ))
73  return nullptr;
74 
75  unsigned int bpp = vil_stream_read_little_endian_uint_16(is);
76  if (bpp != 1 && bpp != 8 && bpp != 16 && bpp != 32 && bpp != 64)
77  return nullptr;
78 
79 #ifdef DEBUG
80  unsigned int width = vil_stream_read_little_endian_uint_16(is);
81  unsigned int height= vil_stream_read_little_endian_uint_16(is);
82  std::cerr << __FILE__ " : here we go:\n"
83  << __FILE__ " : type_ = " << type << std::endl
84  << __FILE__ " : bits_per_pixel_ = " << bpp << std::endl
85  << __FILE__ " : width_ = " << width << std::endl
86  << __FILE__ " : height_ = " << height << std::endl;
87 #endif
88  return new vil_mit_image(is);
89 }
90 
92  unsigned int ni, unsigned int nj, unsigned int nplanes,
93  vil_pixel_format format)
94 {
95  return new vil_mit_image(is, ni, nj, nplanes, format);
96 }
97 
98 char const* vil_mit_file_format::tag() const
99 {
100  return vil_mit_format_tag;
101 }
102 
103 /////////////////////////////////////////////////////////////////////////////
104 
106  : is_(is)
107 {
108  is_->ref();
109  if (!read_header())
110  {
111  std::cerr << "vil_mit: cannot read file header; creating dummy 0x0 image\n";
112  ni_ = nj_ = 0; components_ = 1; type_ = 1;
114  }
115 }
116 
117 char const* vil_mit_image::file_format() const
118 {
119  return vil_mit_format_tag;
120 }
121 
123  unsigned int ni, unsigned int nj, unsigned int nplanes,
124  vil_pixel_format format)
125  : is_(is), ni_(ni), nj_(nj), components_(nplanes), format_(format)
126 {
127  is_->ref();
128  write_header();
129 }
130 
132 {
133  is_->unref();
134 }
135 
136 bool vil_mit_image::get_property(char const * /*tag*/, void * /*prop*/) const
137 {
138  // This is not an in-memory image type, nor is it read-only:
139  return false;
140 }
141 
143 {
144  is_->seek(0L);
145 
147  unsigned int bpp = vil_stream_read_little_endian_uint_16(is_);
150 
151  if (type_ == MIT_UNSIGNED) { // gray
152  components_ = 1;
153  format_ = bpp==8 ? VIL_PIXEL_FORMAT_BYTE :
154  bpp==16 ? VIL_PIXEL_FORMAT_UINT_16 :
155  bpp==32 ? VIL_PIXEL_FORMAT_UINT_32 :
156  bpp==1 ? VIL_PIXEL_FORMAT_BOOL :
158  }
159  else if (type_ == MIT_SIGNED) {
160  components_ = 1;
161  format_ = bpp==8 ? VIL_PIXEL_FORMAT_SBYTE :
162  bpp==16 ? VIL_PIXEL_FORMAT_INT_16 :
163  bpp==32 ? VIL_PIXEL_FORMAT_INT_32 :
165  }
166  else if (type_ == MIT_RGB) {
167  components_ = 3;
168  format_ = bpp==8 ? VIL_PIXEL_FORMAT_BYTE :
169  bpp==16 ? VIL_PIXEL_FORMAT_UINT_16 :
170  bpp==32 ? VIL_PIXEL_FORMAT_UINT_32 :
172  }
173  else if (type_ == MIT_FLOAT) {
174  components_ = 1;
175  format_ = bpp==32 ? VIL_PIXEL_FORMAT_FLOAT :
176  bpp==64 ? VIL_PIXEL_FORMAT_DOUBLE :
178  }
179  else
180  return false;
181 
183 }
184 
186 {
187  is_->seek(0L);
188 
193  {
194  if (components_ == 3) type_ = MIT_RGB;
195  else if (components_ == 1) type_ = MIT_UNSIGNED;
196  else std::cerr << __FILE__ " : Can only write RGB or grayscale MIT images\n"
197  << " (format="<<format_<<", #components="<<components_<<")\n";
198  }
199  else if (format_ == VIL_PIXEL_FORMAT_INT_32 ||
202  {
203  if (components_ == 1) type_ = MIT_SIGNED;
204  else std::cerr << __FILE__ " : Can only write RGB or grayscale MIT images\n"
205  << " (format="<<format_<<", #components="<<components_<<")\n";
206  }
213  {
214  if (components_ == 1) type_ = MIT_RGB;
215  else std::cerr << __FILE__ " : Can only write RGB or grayscale MIT images\n"
216  << " (format="<<format_<<", #components="<<components_<<")\n";
217  }
218  else if (format_ == VIL_PIXEL_FORMAT_RGB_FLOAT ||
220  {
221  if (components_ == 1) type_ = MIT_FLOAT;
222  else std::cerr << __FILE__ " : Can only write grayscale float-pixel MIT images\n"
223  << " (format="<<format_<<", #components="<<components_<<")\n";
224  }
225  else
226  std::cerr << __FILE__ " : Can only write RGB or grayscale MIT images\n"
227  << " (format="<<format_<<", #components="<<components_<<")\n";
228 
230  unsigned int bpp = 8 * bytes_per_pixel();
231  if (format_ == VIL_PIXEL_FORMAT_BOOL) bpp = 1;
235  return true;
236 }
237 
238 static inline void swap(void* p,int length)
239 {
240  char* t = (char*)p;
241 #ifdef DEBUG
242  if (length == sizeof(vxl_uint_32) && *(vxl_uint_32*)p != 0) {
243  std::cerr << "Swapping " << *(vxl_uint_32*)p;
244  if (length == sizeof(float)) std::cerr << " (or " << *(float*)p << ')';
245  }
246 #endif
247  for (int j=0;2*j<length;++j) { char c = t[j]; t[j] = t[length-j-1]; t[length-j-1] = c; }
248 #ifdef DEBUG
249  if (length == sizeof(vxl_uint_32) && *(vxl_uint_32*)p != 0) {
250  std::cerr << " to " << *(vxl_uint_32*)p;
251  if (length == sizeof(float)) std::cerr << " (or " << *(float*)p << ')';
252  std::cerr << '\n';
253  }
254 #endif
255 }
256 
258  unsigned int y0, unsigned int ys) const
259 {
260  assert(x0+xs<=ni_);
261  assert(y0+ys<=nj_);
262  unsigned int pix_size = 8*bytes_per_pixel();
263  if (format_==VIL_PIXEL_FORMAT_BOOL) pix_size = 1;
264  if (format_==VIL_PIXEL_FORMAT_BOOL && x0%8 != 0)
265  std::cerr << "vil_mit_image::get_copy_view(): Warning: x0 should be a multiple of 8 for this type of image\n";
266  pix_size *= components_;
267 
268  vxl_uint_32 rowsize = (pix_size*xs+7)/8;
269  vil_memory_chunk_sptr buf = new vil_memory_chunk(rowsize*ys,format_);
270  auto* ib = reinterpret_cast<vxl_byte*>(buf->data());
271  for (unsigned int y = y0; y < y0+ys; ++y)
272  {
273  is_->seek(8L + y*((ni_*pix_size+7)/8) + x0*pix_size/8);
274  is_->read(ib, rowsize);
275  ib += rowsize;
276  }
277  if (VXL_BIG_ENDIAN && bytes_per_pixel() > 1) { // MIT image data is little-endian
278  ib = reinterpret_cast<vxl_byte*>(buf->data());
279  for (unsigned int i=0;i<xs*ys*components_;++i)
281  }
282 
283 #define ARGS(T) buf, reinterpret_cast<T*>(buf->data()), xs,ys,components_, components_,xs*components_,1
284  if (format_ == VIL_PIXEL_FORMAT_BOOL) return new vil_image_view<bool> (ARGS(bool));
285  else if (format_ == VIL_PIXEL_FORMAT_BYTE) return new vil_image_view<vxl_byte> (ARGS(vxl_byte));
286  else if (format_ == VIL_PIXEL_FORMAT_SBYTE) return new vil_image_view<vxl_sbyte> (ARGS(vxl_sbyte));
287  else if (format_ == VIL_PIXEL_FORMAT_UINT_16) return new vil_image_view<vxl_uint_16>(ARGS(vxl_uint_16));
288  else if (format_ == VIL_PIXEL_FORMAT_INT_16) return new vil_image_view<vxl_int_16> (ARGS(vxl_int_16));
289  else if (format_ == VIL_PIXEL_FORMAT_UINT_32) return new vil_image_view<vxl_uint_32>(ARGS(vxl_uint_32));
290  else if (format_ == VIL_PIXEL_FORMAT_INT_32) return new vil_image_view<vxl_int_32> (ARGS(vxl_int_32));
291  else if (format_ == VIL_PIXEL_FORMAT_FLOAT) return new vil_image_view<float> (ARGS(float));
292  else if (format_ == VIL_PIXEL_FORMAT_DOUBLE) return new vil_image_view<double> (ARGS(double));
293  else return nullptr;
294 #undef ARGS
295 }
296 
297 bool vil_mit_image::put_view(vil_image_view_base const& buf, unsigned int x0, unsigned int y0)
298 {
299  assert(buf.pixel_format() == format_); // pixel formats of image and buffer must match
300  if (!view_fits(buf, x0, y0) || buf.nplanes() != components_)
301  {
302  vil_exception_warning(vil_exception_out_of_bounds("vil_mit_image::put_view"));
303  return false;
304  }
305  unsigned int ni = buf.ni();
306  unsigned int nj = buf.nj();
307 #ifdef DEBUG
308  std::cerr<<"vil_mit_image::put_view() : buf="
309  <<ni<<'x'<<nj<<'x'<< buf.nplanes()<<'p'
310  <<" at ("<<x0<<','<<y0<<")\n";
311 #endif
312  auto const& ibuf = reinterpret_cast<vil_image_view<vxl_byte> const&>(buf);
313  bool buf_is_planar = false;
314  if (ibuf.istep() == int(components_) && ibuf.jstep() == int(components_*ni) &&
315  (ibuf.planestep() == 1 || components_ == 1))
316  buf_is_planar = false;
317  else if (ibuf.istep() == 1 && ibuf.jstep() == int(ni) &&
318  (ibuf.planestep() == int(ni*nj) || components_ == 1))
319  buf_is_planar = true;
320  else
321  {
322  std::cerr << "ERROR: " << __FILE__ << ":\n"
323  << " view does not fit: istep="<<ibuf.istep()
324  << ", jstep="<<ibuf.jstep()
325  << ", planestep="<<ibuf.planestep()
326  << " instead of "<<components_<<','<<components_*ni<<','<<1
327  << " or 1,"<<ni<<','<<ni*nj<<'\n';
328  return buf_is_planar; // == false
329  }
330  const vxl_byte* ob = ibuf.top_left_ptr();
331  unsigned int pix_size = 8*bytes_per_pixel();
332  if (format_==VIL_PIXEL_FORMAT_BOOL) pix_size = 1;
333  if (format_==VIL_PIXEL_FORMAT_BOOL && x0%8 != 0)
334  std::cerr << "vil_mit_image::put_view(): Warning: x0 should be a multiple of 8 for this type of image\n";
335  pix_size *= components_;
336 
337  vxl_uint_32 rowsize = (pix_size*ni+7)/8;
338 
339  if (VXL_LITTLE_ENDIAN || bytes_per_pixel() == 1) // MIT image data is little-endian
340  {
341  if (buf_is_planar && components_ > 1) // have to interleave pixels
342  {
343  vil_streampos sz = (pix_size/components_+7)/8;
344  for (unsigned int y = y0; y < y0+nj; ++y)
345  for (unsigned int x = x0; x < x0+ni; ++x)
346  {
347  is_->seek(8L + y*((ni_*pix_size+7)/8) + x*pix_size/8);
348  for (unsigned int p=0; p<components_; ++p)
349  if (sz != is_->write(ob+p*ni*nj*sz, sz))
350  std::cerr << "WARNING: " << __FILE__ << ":\n"
351  << " could not write "<<sz<<" bytes to stream; y,x="<<y<<','<<x<<'\n';
352 #ifdef DEBUG
353  else
354  std::cerr << "written "<<sz<<" bytes to stream; y,x="<<y<<','<<x<<'\n';
355 #endif
356  ob += sz;
357  }
358  }
359  else
360  for (unsigned int y = y0; y < y0+nj; ++y)
361  {
362  is_->seek(8L + y*((ni_*pix_size+7)/8) + x0*pix_size/8);
363  if ((vil_streampos)rowsize != is_->write(ob, rowsize))
364  std::cerr << "WARNING: " << __FILE__ << ":\n"
365  << " could not write "<<rowsize<<" bytes to stream; y="<<y<<'\n';
366 #ifdef DEBUG
367  else
368  std::cerr << "written "<<rowsize<<" bytes to stream; y="<<y<<'\n';
369 #endif
370  ob += rowsize;
371  }
372  }
373  else // VXL_BIG_ENDIAN ==> must swap bytes
374  {
375  if (buf_is_planar && components_ > 1) // have to interleave pixels
376  {
377  unsigned int sz = bytes_per_pixel();
378  auto* tempbuf = new vxl_byte[components_*sz];
379  for (unsigned int y = y0; y < y0+nj; ++y)
380  for (unsigned int x = x0; x < x0+ni; ++x)
381  {
382  for (unsigned int p=0; p<components_; ++p) {
383  std::memcpy(tempbuf+p*sz, ob+p*ni*nj, sz);
384  swap(tempbuf+p*sz,sz);
385  }
386  is_->seek(8L + pix_size*(y*ni_+x)/8);
387  if (vil_streampos(components_*sz) != is_->write(tempbuf, components_*sz))
388  std::cerr << "WARNING: " << __FILE__ << ":\n"
389  << " could not write "<<components_*sz<<" bytes to stream; y,x="<<y<<','<<x<<'\n';
390 #ifdef DEBUG
391  else
392  std::cerr << "written "<<components_*sz<<" bytes to stream; y,x="<<y<<','<<x<<'\n';
393 #endif
394  ob += sz;
395  }
396  delete[] tempbuf;
397  }
398  else
399  {
400  auto* tempbuf = new vxl_byte[rowsize];
401  for (unsigned int y = y0; y < y0+nj; ++y)
402  {
403  std::memcpy(tempbuf, ob, rowsize);
404  for (vxl_uint_32 i=0; i<rowsize; i+=bytes_per_pixel())
405  swap(tempbuf+i,bytes_per_pixel());
406  is_->seek(8L + bytes_per_pixel()*(y*ni_+x0));
407  if ((vil_streampos)rowsize != is_->write(tempbuf, rowsize))
408  std::cerr << "WARNING: " << __FILE__ << ":\n"
409  << " could not write "<<rowsize<<" bytes to stream; y="<<y<<'\n';
410 #ifdef DEBUG
411  else
412  std::cerr << "written "<<rowsize<<" bytes to stream; y="<<y<<'\n';
413 #endif
414  ob += rowsize;
415  }
416  delete[] tempbuf;
417  }
418  }
419  return true;
420 }
bool read_header()
Definition: vil_mit.cxx:142
~vil_mit_image() override
Definition: vil_mit.cxx:131
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.
unsigned int ni() const override
Dimensions. W x H x Components.
Definition: vil_mit.h:70
void swap(double &a, double &b)
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_mit.cxx:297
char const * tag() const override
Return a character string which uniquely identifies this format.
Definition: vil_mit.cxx:98
#define MIT_RGB
Definition: vil_mit.cxx:28
virtual vil_streampos write(void const *buf, vil_streampos n)=0
Write n bytes from buf. Returns number of bytes written.
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_mit.cxx:63
read numbers from vil_stream
unsigned int nj_
Definition: vil_mit.h:52
unsigned int type_
Definition: vil_mit.h:54
virtual void seek(vil_streampos position)=0
Goto file pointer.
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.
Image in MIT format.
#define MIT_FLOAT
Definition: vil_mit.cxx:32
unsigned ni() const
Width.
Stream interface for VIL image loaders.
Definition: vil_stream.h:21
unsigned nj() const
Height.
unsigned int components_
Definition: vil_mit.h:53
virtual enum vil_pixel_format pixel_format() const =0
Return a description of the concrete data pixel type.
Indicates that some reference was made to pixels beyond the bounds of an image.
Definition: vil_exception.h:81
vil_mit_image(vil_stream *is)
Definition: vil_mit.cxx:105
#define MIT_SIGNED
Definition: vil_mit.cxx:31
write integers to vil_stream
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_mit.cxx:91
void vil_stream_write_little_endian_uint_16(vil_stream *s, vxl_uint_16 w)
unsigned int bytes_per_pixel() const
Definition: vil_mit.h:74
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.
unsigned int ni_
Definition: vil_mit.h:51
Ref. counted block of data on the heap.
void unref()
Definition: vil_stream.cxx:31
T * top_left_ptr()
Pointer to the first (top left in plane 0) pixel.
bool write_header()
Definition: vil_mit.cxx:185
enum vil_pixel_format format_
Definition: vil_mit.h:55
#define ARGS(T)
vil_stream * is_
Definition: vil_mit.h:50
unsigned nplanes() const
Number of planes.
Generic image implementation for MIT files.
Definition: vil_mit.h:48
vxl_uint_16 vil_stream_read_little_endian_uint_16(vil_stream *s)
vxl_int_32 vil_streampos
Definition: vil_stream.h:16
unsigned int nj() const override
Dimensions: Planes x ni x nj.
Definition: vil_mit.h:71
virtual vil_streampos file_size() const =0
Amount of data in the stream.
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.
#define MIT_UNSIGNED
Definition: vil_mit.cxx:27
std::ptrdiff_t istep() const
Add this to your pixel pointer to get next i pixel.
bool get_property(char const *tag, void *prop=nullptr) const override
Extra property information.
Definition: vil_mit.cxx:136
char const * file_format() const override
Return a string describing the file format.
Definition: vil_mit.cxx:117