libcvd
image_io.h
1 #ifndef CVD_IMAGE_IO_H
2 #define CVD_IMAGE_IO_H
3 
4 #include <cctype>
5 #include <cvd/convert_image.h>
6 #include <cvd/exceptions.h>
7 #include <cvd/internal/load_and_save.h>
8 #include <cvd/internal/name_CVD_rgb_types.h>
9 #include <cvd/internal/name_builtin_types.h>
10 #include <errno.h>
11 #include <fstream>
12 #include <memory>
13 #include <string>
14 #include <type_traits>
15 
16 #include <cvd/internal/io/bmp.h>
17 #include <cvd/internal/io/cvdimage.h>
18 #include <cvd/internal/io/fits.h>
19 #include <cvd/internal/io/jpeg.h>
20 #include <cvd/internal/io/png.h>
21 #include <cvd/internal/io/pnm_grok.h>
22 #include <cvd/internal/io/save_postscript.h>
23 #include <cvd/internal/io/text.h>
24 #include <cvd/internal/io/tiff.h>
25 
26 namespace CVD
27 {
28 
29 // This is not the real definition, but this is what it would look like if all
30 // the macros were expanded. The real definition is above
32 namespace ImageType
33 {
35  enum ImageType
36  {
38  Automatic = -2,
40  Unknown = -1,
43  PNM = 0,
46  JPEG = 1,
48  BMP = 2,
51  PNG = 3,
55  TIFF = 4,
63  PS = 5,
65  EPS = 6,
69  TXT = 7,
70  TEXT = 7,
75  CVD = 8,
78  FITS = 9,
79  };
80 }
81 
82 #if DOXYGEN_INCLUDE_ONLY_FOR_DOCS
83 
88 template <class C>
89 Image<C> img_load(std::istream& i);
90 
117 template <class C>
118 Image<C> img_load(const std::string& i);
119 
120 #endif
121 
122 namespace Internal
123 {
124 
125  using AllImageTypes = std::tuple<PNM::Reader, JPEG::Reader, TIFF::Reader, PNG::Reader, BMP::Reader, FITS::Reader, CVDimage::Reader, TEXT::Reader>;
126 
127  // This selects the correct image reader from the list of available readers
128  // (provided as a tuple), using the first byte of the file to decide.
129  template <class I, class ImageTypeList, int N = 0>
130  void img_load_tuple(Image<I>& im, std::istream& i, [[maybe_unused]] int c)
131  {
132  if constexpr(N == std::tuple_size_v<ImageTypeList>)
133  {
135  }
136  else
137  {
138  using ImageReader = std::tuple_element_t<N, ImageTypeList>;
139 
140  if(ImageReader::first_byte_matches(c))
141  CVD::Internal::readImage<I, ImageReader>(im, i);
142  else
143  img_load_tuple<I, ImageTypeList, N + 1>(im, i, c);
144  }
145  }
146 
147  template <class... T>
148  struct as_tuple
149  {
150  using type = std::tuple<T...>;
151  };
152 
153  template <class... T>
154  struct as_tuple<std::tuple<T...>>
155  {
156  using type = std::tuple<T...>;
157  };
158 }
159 
160 //If there's only one argument it can be a tuple or a single element typelist
161 template <class I, class Head = Internal::AllImageTypes, class... ImageTypes>
162 void img_load(Image<I>& im, std::istream& i)
163 {
164  if(!i.good())
165  {
166  //Check for one of the commonest errors and put in
167  //a special case
168  std::ifstream* fs;
169  if((fs = dynamic_cast<std::ifstream*>(&i)) && !fs->is_open())
171  else
173  }
174  int c = i.peek();
175 
176  if(!i.good())
178 
179  Internal::img_load_tuple<I, typename Internal::as_tuple<Head, ImageTypes...>::type>(im, i, c);
180 }
181 
182 template <class I, class Head = Internal::AllImageTypes, class... ImageTypes>
183 void img_load(Image<I>& im, const std::string& s)
184 {
185  std::ifstream i(s.c_str(), std::ios::in | std::ios::binary);
186 
187  if(!i.good())
188  throw Exceptions::Image_IO::OpenError(s, "for reading", errno);
189  img_load<I, Head, ImageTypes...>(im, i);
190 }
191 
192 #ifndef DOXYGEN_IGNORE_INTERNAL
193 namespace Internal
194 {
195  template <class... ImageTypes>
197  {
198  };
199 
200  template <class... ImageTypes>
201  struct ImagePromise<ImageLoaderIstream<ImageTypes...>>
202  {
203  ImagePromise(std::istream& is)
204  : i(is)
205  {
206  }
207 
208  std::istream& i;
209  template <class C>
210  void execute(Image<C>& im)
211  {
212  img_load<C, ImageTypes...>(im, i);
213  }
214  };
215 
216  template <class... ImageTypes>
218  {
219  };
220 
221  template <class... ImageTypes>
222  struct ImagePromise<ImageLoaderString<ImageTypes...>>
223  {
224  ImagePromise(const std::string& ss)
225  : s(ss)
226  {
227  }
228 
229  const std::string& s;
230  template <class C>
231  void execute(Image<C>& im)
232  {
233  img_load<C, ImageTypes...>(im, s);
234  }
235  };
236 
237 };
238 
239 template <class... ImageTypes>
240 Internal::ImagePromise<Internal::ImageLoaderIstream<ImageTypes...>> img_load(std::istream& i)
241 {
242  return i;
243 }
244 
245 template <class... ImageTypes>
246 Internal::ImagePromise<Internal::ImageLoaderString<ImageTypes...>> img_load(const std::string& i)
247 {
248  return i;
249 }
250 
252 {
253  return i;
254 }
255 
257 {
258  return i;
259 }
260 
261 #endif
262 
264 //
265 // Image saving
266 //
267 
270 ImageType::ImageType string_to_image_type(const std::string& name);
271 
279 template <class PixelType>
280 void img_save(const BasicImage<PixelType>& im, std::ostream& o, ImageType::ImageType t, const std::map<std::string, Parameter<>>& p = std::map<std::string, Parameter<>>())
281 {
282  switch(t)
283  {
284  default:
285  case ImageType::PNM:
287  case ImageType::Unknown:
288  Internal::writeImage<PixelType, PNM::Writer>(im, o, p);
289  break;
290  case ImageType::JPEG:
291  Internal::writeImage<PixelType, JPEG::writer>(im, o, p);
292  break;
293  case ImageType::PNG:
294  Internal::writeImage<PixelType, PNG::png_writer>(im, o, p);
295  break;
296  case ImageType::TIFF:
297  Internal::writeImage<PixelType, TIFF::tiff_writer>(im, o, p);
298  break;
299  case ImageType::FITS:
300  Internal::writeImage<PixelType, FITS::writer>(im, o, p);
301  break;
302  case ImageType::BMP:
303  Internal::writeImage<PixelType, BMP::Writer>(im, o, p);
304  break;
305  case ImageType::TXT:
306  Internal::writeImage<PixelType, TEXT::writer>(im, o, p);
307  break;
308  case ImageType::PS:
309  Internal::writeImage<PixelType, PS::writer>(im, o, p);
310  break;
311  case ImageType::EPS:
312  Internal::writeImage<PixelType, PS::eps_writer>(im, o, p);
313  break;
314  case ImageType::CVD:
315  Internal::writeImage<PixelType, CVDimage::writer>(im, o, p);
316  break;
317  }
318 }
319 
320 template <class PixelType>
321 void img_save(const BasicImage<PixelType>& im, const std::string& name, ImageType::ImageType t, ImageType::ImageType d = ImageType::PNM, const std::map<std::string, Parameter<>>& p = std::map<std::string, Parameter<>>())
322 {
323  std::ofstream out(name.c_str(), std::ios::out | std::ios::binary);
324  if(!out.good())
325  throw Exceptions::Image_IO::OpenError(name, "for writing", errno);
326 
327  if(t == ImageType::Automatic)
328  {
329  t = string_to_image_type(name);
330  if(t == ImageType::Unknown)
331  t = d;
332  }
333 
334  img_save(im, out, t, p);
335 }
336 
337 template <class PixelType>
338 void img_save(const BasicImage<PixelType>& im, const std::string& name, const std::map<std::string, Parameter<>>& p = std::map<std::string, Parameter<>>())
339 {
341 }
342 
344 //
345 // Legacy pnm_* functions
346 //
347 
354 template <class PixelType>
355 void pnm_save(const BasicImage<PixelType>& im, std::ostream& o)
356 {
357  img_save(im, o, ImageType::PNM);
358 }
359 
376 template <class PixelType>
377 void pnm_load(Image<PixelType>& im, std::istream& i)
378 {
379  img_load(im, i);
380 }
381 
383 //
384 // Postscript helper functions
385 //
386 
390 void output_eps_footer(std::ostream& o);
391 
399 void output_eps_header(std::ostream& o, int xs, int ys);
400 
407 void output_eps_header(std::ostream& o, const ImageRef& s);
408 
415 template <class PixelType>
416 void output_eps_header(std::ostream& o, const BasicImage<PixelType>& im)
417 {
418  output_eps_header(o, im.size());
419 }
420 
421 }
422 
423 #endif
The ifstream which the file is being read from is not open.
Definition: load_and_save.h:55
TIFF image format.
Definition: image_io.h:55
void output_eps_footer(std::ostream &o)
Outputs an EPS footer to an ostream.
Postscript format.
Definition: image_io.h:63
All classes and functions are within the CVD namespace.
Definition: argb.h:6
ImageRef size() const
What is the size of this image?
Definition: image.h:557
PNM image format (PBM, PGM or PPM).
Definition: image_io.h:43
FITS images.
Definition: image_io.h:78
void pnm_load(Image< PixelType > &im, std::istream &i)
Load a PNM image from a stream.
Definition: image_io.h:377
void pnm_save(const BasicImage< PixelType > &im, std::ostream &o)
Save an image to a stream as a PNM.
Definition: image_io.h:355
void img_save(const BasicImage< PixelType > &im, std::ostream &o, ImageType::ImageType t, const std::map< std::string, Parameter<>> &p=std::map< std::string, Parameter<>>())
Save an image to a stream.
Definition: image_io.h:280
Error in opening file.
Definition: load_and_save.h:119
This image type is not supported.
Definition: load_and_save.h:41
Placeholder type telling save_image to deduce the type from the filename.
Definition: image_io.h:38
Definition: image_io.h:148
Definition: load_and_save.h:159
The file ended before the image.
Definition: load_and_save.h:48
JPEG image format.
Definition: image_io.h:46
Plain text format.
Definition: image_io.h:69
Definition: image_ref.h:29
Definition: image_io.h:217
void output_eps_header(std::ostream &o, int xs, int ys)
Outputs an EPS header to an ostream.
Windows BMP (or DIB) format. Uncompressed 8 bit grey scale and 24 bit RGB are supported.
Definition: image_io.h:48
Definition: image.h:62
ImageType::ImageType string_to_image_type(const std::string &name)
Deduce an image type from a filename suffix.
Definition: image_io.cc:89
A generic image class to manage a block of arbitrarily padded data as an image.
Definition: image.h:273
EPS format. This outputs a complete EPS (Encapsulated PostScript) figure.
Definition: image_io.h:65
Unknown image type (can be returned by string_to_image_type.
Definition: image_io.h:40
Definition: image_io.h:196
A full image which manages its own data.
Definition: image.h:623
PNG image format.
Definition: image_io.h:51
Class for holding parameters for image savers, with type erasure.
Definition: parameter.h:18
ImageType
Possible image types.
Definition: image_io.h:35
CVD image format.
Definition: image_io.h:75