Commit b35b7008 authored by Edwin Carlinet's avatar Edwin Carlinet
Browse files

Add support for loading/writing in streams.

	*  mln/io/freeimage_reader.hpp,
	*  mln/io/imprint.hpp,
	*  mln/io/imread.hpp,
	*  mln/io/imsave.hpp: Stream reading/writing support.
parent 91430f7c
......@@ -10,6 +10,7 @@
//# include <mln/io/typeinfo.hpp>
# include <mln/io/reader.hpp>
# include <iostream>
# include <FreeImage.h>
......@@ -23,6 +24,67 @@ namespace mln
namespace io
{
namespace internal
{
struct istream_wrapper
{
istream_wrapper(std::istream& is)
: m_original_stream(is)
{
std::istream::pos_type pos = is.tellg();
m_support_streaming = (pos != std::istream::pos_type(-1));
if (m_support_streaming) {
m_cs = &is;
m_offset = pos;
} else {
m_cs = new std::stringstream(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
is >> m_cs->rdbuf();
m_offset = 0;
}
}
~istream_wrapper()
{
if (not m_support_streaming)
delete m_cs;
}
static
unsigned read(void* buffer, unsigned size, unsigned count, fi_handle isw_)
{
istream_wrapper* isw = (istream_wrapper*) isw_;
isw->m_cs->read((char*)buffer, size * count);
return (isw->m_cs) ? count : 0;
}
static
int seek(fi_handle isw_, long offset, int origin)
{
istream_wrapper* isw = (istream_wrapper*) isw_;
if (origin == SEEK_SET) offset += isw->m_offset;
isw->m_cs->seekg(offset, (std::ios_base::seekdir) origin);
return (isw->m_cs) ? 0 : -1;
}
static
long tell(fi_handle isw_)
{
istream_wrapper* isw = (istream_wrapper*) isw_;
return isw->m_cs->tellg() - isw->m_offset;
}
private:
std::istream& m_original_stream;
std::istream* m_cs;
std::istream::off_type m_offset;
bool m_support_streaming;
};
}
class freeimage_reader : public Reader
{
public:
......@@ -30,6 +92,7 @@ namespace mln
freeimage_reader();
virtual void load(std::istream& s);
virtual void load(const char* filename);
virtual void close();
virtual void read_next_pixel(void* out);
......@@ -53,6 +116,7 @@ namespace mln
bool freeimage_reader::init_ = false;
inline
freeimage_reader::freeimage_reader()
: dib (NULL), x (0), y (0)
......@@ -64,8 +128,9 @@ namespace mln
freeimage_reader::initialize()
{
if (!init_){
init_ = true;
FreeImage_Initialise();
init_ = true;
//FreeImage_SetOutputMessage(freeimage_reader::printErr);
//FreeImage_Initialise();
}
}
......@@ -79,10 +144,10 @@ namespace mln
FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
fif = FreeImage_GetFileType(filename, 0);
if (fif == FIF_UNKNOWN)
fif = FreeImage_GetFIFFromFilename(filename);
fif = FreeImage_GetFIFFromFilename(filename);
if (fif == FIF_UNKNOWN || !FreeImage_FIFSupportsReading(fif))
throw MLNIOException("File format not supported");
throw MLNIOException("File format not supported");
dib = FreeImage_Load(fif, filename, 0);
domain.pmin[0] = 0;
......@@ -95,6 +160,43 @@ namespace mln
mln_postcondition(dib != NULL);
}
inline
void
freeimage_reader::load(std::istream& is)
{
mln_precondition(init_);
mln_precondition(dib == NULL);
internal::istream_wrapper isw(is);
fi_handle handle = (fi_handle) &isw;
FreeImageIO fio = {
internal::istream_wrapper::read,
NULL,
internal::istream_wrapper::seek,
internal::istream_wrapper::tell
};
FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
fif = FreeImage_GetFileTypeFromHandle(&fio, handle);
if (fif == FIF_UNKNOWN || !FreeImage_FIFSupportsReading(fif))
throw MLNIOException("File format not supported");
dib = FreeImage_LoadFromHandle(fif, &fio, handle, 0);
domain.pmin[0] = 0;
domain.pmin[1] = 0;
domain.pmax[0] = FreeImage_GetHeight(dib);
domain.pmax[1] = FreeImage_GetWidth(dib);
pitch = FreeImage_GetPitch(dib);
ptr = (char*)FreeImage_GetBits(dib) + pitch * (domain.pmax[0]-1);
bpp = FreeImage_GetBPP(dib) / 8;
mln_postcondition(dib != NULL);
}
inline
int freeimage_reader::get_ndim() const
......@@ -119,26 +221,30 @@ namespace mln
int bppp = FreeImage_GetBPP(dib);
int colortype = FreeImage_GetColorType(dib);
switch (type)
{
case FIT_BITMAP: break;
case FIT_UINT16: return typeid(uint16);
case FIT_INT16: return typeid(int16);
case FIT_FLOAT: return typeid(float);
default: goto error;
}
{
case FIT_BITMAP: break;
case FIT_UINT16: return typeid(uint16);
case FIT_INT16: return typeid(int16);
case FIT_UINT32: return typeid(uint32);
case FIT_INT32: return typeid(int32);
case FIT_FLOAT: return typeid(float);
case FIT_DOUBLE: return typeid(double);
default: goto error;
}
switch (bppp)
{
case 1: return typeid(bool);
case 8: return typeid(uint8);
case 16: return typeid(uint16);
case 24: switch (colortype)
{
case FIC_RGB: return typeid(rgb8);
default: goto error;
}
}
{
case 1: return typeid(bool);
case 8: return typeid(uint8);
case 16: return typeid(uint16);
case 24: switch (colortype)
{
case FIC_RGB: return typeid(rgb8);
default: goto error;
}
}
error: return typeid(void);
}
......
......@@ -70,8 +70,6 @@ namespace mln
mln_foreach(V v, ima.values())
wtext = std::max(wtext, frmter(v));
std::cout << wtext << std::endl;
//if (std::is_same<V, uint8>::value)
std::cout.width(4);
for (p[0] = domain.pmin[0]; p[0] < domain.pmax[0]; ++p[0]) {
......
......@@ -4,6 +4,7 @@
# include <string>
# include <mln/core/macros.hpp>
# include <mln/core/trace.hpp>
# include <mln/core/image_traits.hpp>
# include <mln/io/reader.hpp>
# include <mln/io/ioexception.hpp>
......@@ -11,6 +12,8 @@
# include <mln/io/freeimage_reader.hpp>
# include <mln/io/internal/demangle.hpp>
# include <iosfwd>
# include <fstream>
......@@ -28,6 +31,9 @@ namespace mln
template <typename Image, typename Reader = freeimage_reader>
void imread(const std::string& path, Image& out, Reader r = Reader());
template <typename Image, typename Reader = freeimage_reader>
void imread(std::istream& path, Image& out, Reader r = Reader());
/******************************************/
/**** Implementation ****/
......@@ -40,24 +46,24 @@ namespace mln
template <typename Image, typename Reader>
void read_raw_image(Image& ima, const typename Image::point_type& shape, Reader& r, char* buffer, int dim)
{
if (dim == Image::ndim-1)
r.read_next_line(buffer);
else {
for (int i = 0; i < shape[dim]; ++i) {
read_raw_image(ima, shape, r, buffer, dim+1);
buffer += ima.strides()[dim];
}
}
if (dim == Image::ndim-1)
r.read_next_line(buffer);
else {
for (int i = 0; i < shape[dim]; ++i) {
read_raw_image(ima, shape, r, buffer, dim+1);
buffer += ima.strides()[dim];
}
}
}
template <typename Image, typename Reader>
void imread_raw(Reader& r, Image& out)
{
mln_point(Image) p = out.domain().pmin;
mln_point(Image) shape = out.domain().shape();
mln_point(Image) p = out.domain().pmin;
mln_point(Image) shape = out.domain().shape();
char* buffer = (char*) &out(p);
read_raw_image(out, shape, r, buffer, 0);
char* buffer = (char*) &out(p);
read_raw_image(out, shape, r, buffer, 0);
}
......@@ -68,33 +74,44 @@ namespace mln
// }
template <typename Image, typename Reader>
void imread(const std::string& path, Reader r, Image& out, raw_image_tag)
void imread(std::istream& stream, Reader r, Image& out, raw_image_tag)
{
r.initialize();
r.load(path.c_str());
r.initialize();
r.load(stream);
typedef typename Image::value_type V;
typedef typename Image::value_type V;
std::type_index ridx = r.get_value_type_id();
if (Image::ndim != r.get_ndim())
throw MLNIOException("Dimensions incompatibles");
else if (ridx != typeid(V)) {
std::string ex = "Value types incompatibles: ";
(ex += "trying to load ") += demangle(ridx.name());
(ex += " in an image of ") += demangle(typeid(V).name());
throw MLNIOException(ex);
}
out.resize(r.get_domain(), out.border());
imread_raw(r, out);
r.close();
if (Image::ndim != r.get_ndim())
throw MLNIOException("Dimensions incompatibles");
else if (ridx != typeid(V)) {
std::string ex = "Value types incompatibles: ";
(ex += "trying to load ") += demangle(ridx.name());
(ex += " in an image of ") += demangle(typeid(V).name());
throw MLNIOException(ex);
}
out.resize(r.get_domain(), out.border());
imread_raw(r, out);
r.close();
}
}
template <typename Image, typename Reader>
void imread(std::istream& stream, Image& out, Reader r)
{
mln_entering("mln::io::imread");
internal::imread(stream, r, out, typename image_traits<Image>::category ());
mln_exiting();
}
template <typename Image, typename Reader>
void imread(const std::string& path, Image& out, Reader r)
{
internal::imread(path, r, out, typename image_traits<Image>::category ());
std::ifstream stream(path);
imread(stream, out, r);
//internal::imread(path, r, out, typename image_traits<Image>::category ());
}
......
#ifndef MLN_IO_IMSAVE_HPP
# define MLN_IO_IMSAVE_HPP
# include <iosfwd>
# include <fstream>
# include <FreeImage.h>
# include <mln/core/grays.hpp>
# include <mln/core/colors.hpp>
# include <mln/core/trace.hpp>
# include <mln/io/ioexception.hpp>
# include <boost/static_assert.hpp>
namespace mln
{
......@@ -16,90 +18,176 @@ namespace mln
namespace internal
{
struct ostream_wrapper
{
ostream_wrapper(std::ostream& os)
: m_original_stream(os)
{
std::ostream::pos_type pos = os.tellp();
m_support_streaming = (pos != std::ostream::pos_type(-1));
if (m_support_streaming) {
m_cs = &os;
m_offset = pos;
} else {
m_cs = new std::stringstream(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
m_offset = 0;
}
}
~ostream_wrapper()
{
if (not m_support_streaming)
{
m_cs->rdbuf()->pubseekpos(0);
m_original_stream << m_cs->rdbuf();
delete m_cs;
}
}
static
unsigned write(void* buffer, unsigned size, unsigned count, fi_handle osw_)
{
ostream_wrapper* osw = (ostream_wrapper*) osw_;
osw->m_cs->write((char*)buffer, size * count);
return (osw->m_cs) ? count : 0;
}
static
int seek(fi_handle osw_, long offset, int origin)
{
ostream_wrapper* osw = (ostream_wrapper*) osw_;
if (origin == SEEK_SET) offset += osw->m_offset;
osw->m_cs->seekp(offset, (std::ios_base::seekdir) origin);
return (osw->m_cs) ? 0 : -1;
}
static
long tell(fi_handle osw_)
{
ostream_wrapper* osw = (ostream_wrapper*) osw_;
return osw->m_cs->tellp() - osw->m_offset;
}
private:
std::ostream& m_original_stream;
std::ostream* m_cs;
std::ostream::off_type m_offset;
bool m_support_streaming;
};
template <typename Image>
void imsave(const Image& ima, const char* path, raw_image_tag)
void imsave(const Image& ima, std::ostream& os, raw_image_tag)
{
BOOST_STATIC_ASSERT((Image::ndim == 2));
static_assert(Image::ndim == 2, "This plugin does not support images with dimension > 2");
typedef mln_value(Image) V;
FreeImage_Initialise();
FREE_IMAGE_TYPE fit;
if (std::is_same<V, bool>::value or std::is_same<V, uint8>::value or std::is_same<V, rgb8>::value)
fit = FIT_BITMAP;
else if (std::is_same<V, rgb<float> >::value)
fit = FIT_RGBF;
else if (std::is_same<V, uint16>::value)
fit = FIT_UINT16;
else if (std::is_same<V, int16>::value)
fit = FIT_INT16;
else if (std::is_same<V, uint32>::value)
fit = FIT_UINT32;
else if (std::is_same<V, int32>::value)
fit = FIT_INT32;
else if (std::is_same<V, float>::value)
fit = FIT_FLOAT;
else if (std::is_same<V, double>::value)
fit = FIT_DOUBLE;
else
throw MLNIOException("Unhandled image type.");
if (std::is_same<V, bool>::value or std::is_same<V, uint8>::value or std::is_same<V, rgb8>::value)
fit = FIT_BITMAP;
else if (std::is_same<V, rgb<float> >::value)
fit = FIT_RGBF;
else if (std::is_same<V, uint16>::value)
fit = FIT_UINT16;
else if (std::is_same<V, int16>::value)
fit = FIT_INT16;
else if (std::is_same<V, uint32>::value)
fit = FIT_UINT32;
else if (std::is_same<V, int32>::value)
fit = FIT_INT32;
else if (std::is_same<V, float>::value)
fit = FIT_FLOAT;
else if (std::is_same<V, double>::value)
fit = FIT_DOUBLE;
else
throw MLNIOException("Unhandled image type.");
int h = ima.domain().shape()[0], w = ima.domain().shape()[1];
FIBITMAP* dib;
if (std::is_same<V, rgb8>::value)
dib = FreeImage_AllocateT(fit, w, h, sizeof(V) * 8, 0xFF000000, 0x00FF00, 0xFF000000);
else if (std::is_same<V, bool>::value) {
dib = FreeImage_AllocateT(fit, w, h, 1);
RGBQUAD *pal = FreeImage_GetPalette(dib);
mln_assertion(pal != NULL);
pal[1].rgbRed = 0xFF;
pal[1].rgbGreen = 0XFF;
pal[1].rgbBlue = 0xFF;
mln_assertion(FreeImage_GetColorType(dib) == FIC_MINISBLACK);
} else
dib = FreeImage_AllocateT(fit, w, h, sizeof(V) * 8);
if (std::is_same<V, rgb8>::value)
dib = FreeImage_AllocateT(fit, w, h, sizeof(V) * 8, 0xFF000000, 0x00FF00, 0xFF000000);
else if (std::is_same<V, bool>::value) {
dib = FreeImage_AllocateT(fit, w, h, 1);
RGBQUAD *pal = FreeImage_GetPalette(dib);
mln_assertion(pal != NULL);
pal[1].rgbRed = 0xFF;
pal[1].rgbGreen = 0XFF;
pal[1].rgbBlue = 0xFF;
mln_assertion(FreeImage_GetColorType(dib) == FIC_MINISBLACK);
} else
dib = FreeImage_AllocateT(fit, w, h, sizeof(V) * 8);
const size_t* strides = ima.strides();
const char* ptr = (const char*) &ima(ima.domain().pmin);
unsigned bpp = sizeof(V);
unsigned bpp = sizeof(V);
for(int y = h-1; y >= 0; --y, ptr += strides[0]) {
BYTE *bits = FreeImage_GetScanLine(dib, y);
if (std::is_same<V, rgb8>::value or std::is_same<V, rgb<float> >::value)
{
for (int j = 0; j < w; ++j) {
*(bits + j * bpp + 0) = *(ptr + j * bpp + 2);
*(bits + j * bpp + 1) = *(ptr + j * bpp + 1);
*(bits + j * bpp + 2) = *(ptr + j * bpp + 0);
}
}
else if (std::is_same<V, bool>::value)
{
for (int j = 0, z = 0; j < w; ++z)
for (int b = 7; b >= 0; --b, ++j)
bits[z] |= ptr[j] << b;
}
else
std::memcpy(bits, ptr, w * sizeof(V));
if (std::is_same<V, rgb8>::value or std::is_same<V, rgb<float> >::value)
{
for (int j = 0; j < w; ++j) {
*(bits + j * bpp + 0) = *(ptr + j * bpp + 2);
*(bits + j * bpp + 1) = *(ptr + j * bpp + 1);
*(bits + j * bpp + 2) = *(ptr + j * bpp + 0);
}
}
else if (std::is_same<V, bool>::value)
{
for (int j = 0, z = 0; j < w; ++z)
for (int b = 7; b >= 0; --b, ++j)
bits[z] |= ptr[j] << b;
}
else
std::memcpy(bits, ptr, w * sizeof(V));
}
//FreeImage_DeInitialise();
bool res = FreeImage_Save(FIF_TIFF, dib, path);
if (!res)
throw MLNIOException("Unable to save the image.");
FreeImageIO fio = {
NULL,
ostream_wrapper::write,
ostream_wrapper::seek,
ostream_wrapper::tell
};
ostream_wrapper osw(os);
fi_handle handle = (fi_handle) (&osw);
bool res = FreeImage_SaveToHandle(FIF_TIFF, dib, &fio, handle, 0);
if (!res)
throw MLNIOException("Unable to save the image.");
FreeImage_Unload(dib);
}
}
template <typename Image>
void imsave(const Image& ima, std::ostream& os)
{
mln_entering("mln::io::imsave")
template <typename Image>
void imsave(const Image& ima, const char* path)
{
internal::imsave(ima, path, typename image_traits<Image>::category ());
}
internal::imsave(ima, os, typename image_traits<Image>::category ());
os.flush();
mln_exiting();
}
template <typename Image>
void imsave(const Image& ima, const char* path)
{
if (std::strcmp(path, "-") == 0)
imsave(ima, std::cout);
else
{
std::ofstream os(path, std::ios_base::binary);
imsave(ima, os);
os.close();
}
}
} // end of namespace mln::io
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment