diff --git a/bob/io/image/__init__.py b/bob/io/image/__init__.py index 438481d4e2255a470ba73636ec1330247e2609e0..ef1b771b19a00ef2938cab8eac125fb0f949220e 100644 --- a/bob/io/image/__init__.py +++ b/bob/io/image/__init__.py @@ -1,15 +1,87 @@ # import Libraries of other lib packages import bob.io.base +# import our own Library +import bob.extension +bob.extension.load_bob_library('bob.io.image', __file__) + from . import _library from . import version from .version import module as __version__ +import os + def get_config(): """Returns a string containing the configuration information. """ import bob.extension return bob.extension.get_config(__name__, version.externals) + +def get_include_directories(): + """get_include_directories() -> includes + + Returns a list of include directories for dependent libraries, such as libjpeg, libtiff, ... + This function is automatically used by :py:func:`bob.extension.get_bob_libraries` to retrieve the non-standard include directories that are required to use the C bindings of this library in dependent classes. + You shouldn't normally need to call this function by hand. + + **Returns:** + + ``includes`` : [str] + The list of non-standard include directories required to use the C bindings of this class. + For now, only the directory for the HDF5 headers are returned. + """ + # try to use pkg_config first + from bob.extension.utils import find_header, uniq_paths + from bob.extension import pkgconfig + import logging + logger = logging.getLogger("bob.io.image") + directories = [] + for name, header in (('libjpeg', 'jpeglib.h'), ('libtiff', 'tiff.h'), ('giflib', 'gif_lib.h')): + # locate pkg-config on our own + candidates = find_header(header) + if not candidates: + logger.warn("could not find %s's `%s' - have you installed %s on this machine?" % (name, header, name)) + + directories.append(os.path.dirname(candidates[0])) + for name in ("libpng",): + try: + pkg = pkgconfig(name) + directories.extend(pkg.include_directories()) + except: + pass + return uniq_paths(directories) + + +def get_macros(): + """get_macros() -> macros + + Returns a list of preprocessor macros, such as ``(HAVE_LIBJPEG, 1)``. + This function is automatically used by :py:func:`bob.extension.get_bob_libraries` to retrieve the prerpocessor definitions that are required to use the C bindings of this library in dependent classes. + You shouldn't normally need to call this function by hand. + + **Returns:** + + ``macros`` : [str] + The list of preprocessor macros required to use the C bindings of this class. + """ + # try to use pkg_config first + from bob.extension.utils import find_header, uniq_paths + from bob.extension import pkgconfig + macros = [] + for define, header in (('HAVE_LIBJPEG', 'jpeglib.h'), ('HAVE_LIBTIFF', 'tiff.h'), ('HAVE_GIFLIB', 'gif_lib.h')): + # locate pkg-config on our own + candidates = find_header(header) + if candidates: + macros.append((define, '1')) + for define, name in (("HAVE_LIBPNG", "libpng"),): + try: + pkg = pkgconfig(name) + macros.append((define, '1')) + except: + pass + return macros + + # gets sphinx autodoc done right - don't remove it __all__ = [_ for _ in dir() if not _.startswith('_')] diff --git a/bob/io/image/bmp.cpp b/bob/io/image/cpp/bmp.cpp similarity index 92% rename from bob/io/image/bmp.cpp rename to bob/io/image/cpp/bmp.cpp index a8cd502288249ad35a63c29cb597b7aae133cb16..f74f5e80874a7ef819504230aa65a88322972874 100644 --- a/bob/io/image/bmp.cpp +++ b/bob/io/image/cpp/bmp.cpp @@ -2,10 +2,12 @@ * @file io/cxx/ImageBmpFile.cc * @date Wed Nov 28 15:36:00 2012 +0200 * @author Laurent El Shafey <laurent.el-shafey@idiap.ch> + * @author Manuel Gunther <siebenkopf@googlemail.com> * * @brief Implements an image format reader/writer for BMP files. * * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland + * Copyright (c) 2016, Regents of the University of Colorado on behalf of the University of Colorado Colorado Springs. */ #include <boost/filesystem.hpp> @@ -17,7 +19,7 @@ #include <boost/algorithm/string.hpp> #include <string> -#include <bob.io.base/File.h> +#include <bob.io.image/bmp.h> // The following documentation is mostly coming from wikipedia: // http://en.wikipedia.org/wiki/BMP_file_format @@ -918,120 +920,81 @@ static void im_save(const std::string& filename, const bob::io::base::array::int im_save_color(array, out_file.get()); } else { - boost::format m("the image in file `%s' has a number of dimensions for which this bmp codec has no support for: %s"); + boost::format m("the image in file `%s' has a number of dimensions for which this bmp codec has no support for"); m % info.str(); throw std::runtime_error(m.str()); } } else { - boost::format m("the image in file `%s' has a data type this bmp codec has no support for: %s"); + boost::format m("the image in file `%s' has a data type this bmp codec has no support for"); m % info.str(); throw std::runtime_error(m.str()); } } -class ImageBmpFile: public bob::io::base::File { - - public: //api - - ImageBmpFile(const char* path, char mode): - m_filename(path), - m_newfile(true) { - - //checks if file exists - if (mode == 'r' && !boost::filesystem::exists(path)) { - boost::format m("file '%s' is not readable"); - m % path; - throw std::runtime_error(m.str()); - } - - if (mode == 'r' || (mode == 'a' && boost::filesystem::exists(path))) { - { - im_peek(path, m_type); - m_length = 1; - m_newfile = false; - } - } - else { - m_length = 0; - m_newfile = true; - } - - } - - virtual ~ImageBmpFile() { } - - virtual const char* filename() const { - return m_filename.c_str(); - } - - virtual const bob::io::base::array::typeinfo& type_all() const { - return m_type; - } - - virtual const bob::io::base::array::typeinfo& type() const { - return m_type; - } - - virtual size_t size() const { - return m_length; - } - - virtual const char* name() const { - return s_codecname.c_str(); - } - - virtual void read_all(bob::io::base::array::interface& buffer) { - read(buffer, 0); ///we only have 1 image in an image file anyways - } +/** + * BMP class +*/ +bob::io::image::BMPFile::BMPFile(const char* path, char mode) +: m_filename(path), + m_newfile(true) +{ + //checks if file exists + if (mode == 'r' && !boost::filesystem::exists(path)) { + boost::format m("file '%s' is not readable"); + m % path; + throw std::runtime_error(m.str()); + } - virtual void read(bob::io::base::array::interface& buffer, size_t index) { - if (m_newfile) - throw std::runtime_error("uninitialized image file cannot be read"); + if (mode == 'r' || (mode == 'a' && boost::filesystem::exists(path))) { + im_peek(path, m_type); + m_length = 1; + m_newfile = false; + } else { + m_length = 0; + m_newfile = true; + } +} - if (!buffer.type().is_compatible(m_type)) buffer.set(m_type); +void bob::io::image::BMPFile::read(bob::io::base::array::interface& buffer, size_t index) { + if (m_newfile) + throw std::runtime_error("uninitialized image file cannot be read"); - if (index != 0) - throw std::runtime_error("cannot read image with index > 0 -- there is only one image in an image file"); + if (!buffer.type().is_compatible(m_type)) buffer.set(m_type); - if(!buffer.type().is_compatible(m_type)) buffer.set(m_type); - im_load(m_filename, buffer); - } + if (index != 0) + throw std::runtime_error("cannot read image with index > 0 -- there is only one image in an image file"); - virtual size_t append (const bob::io::base::array::interface& buffer) { - if (m_newfile) { - im_save(m_filename, buffer); - m_type = buffer.type(); - m_newfile = false; - m_length = 1; - return 0; - } + if(!buffer.type().is_compatible(m_type)) buffer.set(m_type); + im_load(m_filename, buffer); +} - throw std::runtime_error("image files only accept a single array"); - } +size_t bob::io::image::BMPFile::append(const bob::io::base::array::interface& buffer) { + if (m_newfile) { + im_save(m_filename, buffer); + m_type = buffer.type(); + m_newfile = false; + m_length = 1; + return 0; + } - virtual void write (const bob::io::base::array::interface& buffer) { - //overwriting position 0 should always work - if (m_newfile) { - append(buffer); - return; - } + throw std::runtime_error("image files only accept a single array"); +} - throw std::runtime_error("image files only accept a single array"); - } +void bob::io::image::BMPFile::write(const bob::io::base::array::interface& buffer) { + //overwriting position 0 should always work + if (m_newfile) { + append(buffer); + return; + } - private: //representation - std::string m_filename; - bool m_newfile; - bob::io::base::array::typeinfo m_type; - size_t m_length; + throw std::runtime_error("image files only accept a single array"); +} - static std::string s_codecname; -}; -std::string ImageBmpFile::s_codecname = "bob.image_bmp"; +std::string bob::io::image::BMPFile::s_codecname = "bob.image_bmp"; boost::shared_ptr<bob::io::base::File> make_bmp_file (const char* path, char mode) { - return boost::make_shared<ImageBmpFile>(path, mode); + return boost::make_shared<bob::io::image::BMPFile>(path, mode); } diff --git a/bob/io/image/gif.cpp b/bob/io/image/cpp/gif.cpp similarity index 88% rename from bob/io/image/gif.cpp rename to bob/io/image/cpp/gif.cpp index 092005c243ac742cbefdf9a0f6644b3b964775a4..382abf72f91247d3376896be63d5422b21d0923a 100644 --- a/bob/io/image/gif.cpp +++ b/bob/io/image/cpp/gif.cpp @@ -2,12 +2,16 @@ * @file io/cxx/ImageGifFile.cc * @date Fri Nov 23 16:53:00 2012 +0200 * @author Laurent El Shafey <laurent.el-shafey@idiap.ch> + * @author Manuel Gunther <siebenkopf@googlemail.com> * * @brief Implements an image format reader/writer using giflib. * * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland + * Copyright (c) 2016, Regents of the University of Colorado on behalf of the University of Colorado Colorado Springs. */ +#ifdef HAVE_GIFLIB + #include <boost/filesystem.hpp> #include <boost/shared_array.hpp> #include <boost/shared_ptr.hpp> @@ -17,7 +21,7 @@ #include <boost/algorithm/string.hpp> #include <string> -#include <bob.io.base/File.h> +#include <bob.io.image/gif.h> extern "C" { #include <gif_lib.h> @@ -564,109 +568,70 @@ static void im_save(const std::string& filename, const bob::io::base::array::int } -class ImageGifFile: public bob::io::base::File { - - public: //api - - ImageGifFile(const char* path, char mode): - m_filename(path), - m_newfile(true) { - - //checks if file exists - if (mode == 'r' && !boost::filesystem::exists(path)) { - boost::format m("file '%s' is not readable"); - m % path; - throw std::runtime_error(m.str()); - } - - if (mode == 'r' || (mode == 'a' && boost::filesystem::exists(path))) { - { - im_peek(path, m_type); - m_length = 1; - m_newfile = false; - } - } - else { - m_length = 0; - m_newfile = true; - } - - } - - virtual ~ImageGifFile() { } - - virtual const char* filename() const { - return m_filename.c_str(); - } - - virtual const bob::io::base::array::typeinfo& type_all() const { - return m_type; - } - - virtual const bob::io::base::array::typeinfo& type() const { - return m_type; - } - - virtual size_t size() const { - return m_length; - } - - virtual const char* name() const { - return s_codecname.c_str(); - } - - virtual void read_all(bob::io::base::array::interface& buffer) { - read(buffer, 0); ///we only have 1 image in an image file anyways - } - - virtual void read(bob::io::base::array::interface& buffer, size_t index) { - if (m_newfile) - throw std::runtime_error("uninitialized image file cannot be read"); - - if (!buffer.type().is_compatible(m_type)) buffer.set(m_type); - - if (index != 0) - throw std::runtime_error("cannot read image with index > 0 -- there is only one image in an image file"); +/** + * GIF class +*/ +bob::io::image::GIFFile::GIFFile(const char* path, char mode) +: m_filename(path), + m_newfile(true) { + + //checks if file exists + if (mode == 'r' && !boost::filesystem::exists(path)) { + boost::format m("file '%s' is not readable"); + m % path; + throw std::runtime_error(m.str()); + } - if(!buffer.type().is_compatible(m_type)) buffer.set(m_type); - im_load(m_filename, buffer); - } + if (mode == 'r' || (mode == 'a' && boost::filesystem::exists(path))) { + im_peek(path, m_type); + m_length = 1; + m_newfile = false; + } + else { + m_length = 0; + m_newfile = true; + } +} - virtual size_t append (const bob::io::base::array::interface& buffer) { - if (m_newfile) { - im_save(m_filename, buffer); - m_type = buffer.type(); - m_newfile = false; - m_length = 1; - return 0; - } +void bob::io::image::GIFFile::read(bob::io::base::array::interface& buffer, size_t index) { + if (m_newfile) + throw std::runtime_error("uninitialized image file cannot be read"); - throw std::runtime_error("image files only accept a single array"); - } + if (!buffer.type().is_compatible(m_type)) buffer.set(m_type); - virtual void write (const bob::io::base::array::interface& buffer) { - //overwriting position 0 should always work - if (m_newfile) { - append(buffer); - return; - } + if (index != 0) + throw std::runtime_error("cannot read image with index > 0 -- there is only one image in an image file"); - throw std::runtime_error("image files only accept a single array"); - } + if(!buffer.type().is_compatible(m_type)) buffer.set(m_type); + im_load(m_filename, buffer); +} - private: //representation - std::string m_filename; - bool m_newfile; - bob::io::base::array::typeinfo m_type; - size_t m_length; +size_t bob::io::image::GIFFile::append(const bob::io::base::array::interface& buffer) { + if (m_newfile) { + im_save(m_filename, buffer); + m_type = buffer.type(); + m_newfile = false; + m_length = 1; + return 0; + } - static std::string s_codecname; + throw std::runtime_error("image files only accept a single array"); +} -}; +void bob::io::image::GIFFile::write (const bob::io::base::array::interface& buffer) { + //overwriting position 0 should always work + if (m_newfile) { + append(buffer); + return; + } + throw std::runtime_error("image files only accept a single array"); +} -std::string ImageGifFile::s_codecname = "bob.image_gif"; +std::string bob::io::image::GIFFile::s_codecname = "bob.image_gif"; boost::shared_ptr<bob::io::base::File> make_gif_file (const char* path, char mode) { - return boost::make_shared<ImageGifFile>(path, mode); + return boost::make_shared<bob::io::image::GIFFile>(path, mode); } + +#endif // HAVE_GIFLIB diff --git a/bob/io/image/jpeg.cpp b/bob/io/image/cpp/jpeg.cpp similarity index 78% rename from bob/io/image/jpeg.cpp rename to bob/io/image/cpp/jpeg.cpp index 0c358b89d1dfe41b84cf2d74e2ccc1d1a5551fcb..820ef98c5c04c243543ea447977344c508fe63fd 100644 --- a/bob/io/image/jpeg.cpp +++ b/bob/io/image/cpp/jpeg.cpp @@ -2,13 +2,17 @@ * @file io/cxx/ImageJpegFile.cc * @date Wed Oct 10 16:38:00 2012 +0200 * @author Laurent El Shafey <laurent.el-shafey@idiap.ch> + * @author Manuel Gunther <siebenkopf@googlemail.com> * * @brief Implements an image format reader/writer using libjpeg. * This codec is only able to work with 3D input/output. * * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland + * Copyright (c) 2016, Regents of the University of Colorado on behalf of the University of Colorado Colorado Springs. */ +#ifdef HAVE_LIBJPEG + #include <boost/filesystem.hpp> #include <boost/shared_array.hpp> #include <boost/shared_ptr.hpp> @@ -18,7 +22,7 @@ #include <boost/algorithm/string.hpp> #include <string> -#include <bob.io.base/File.h> +#include <bob.io.image/jpeg.h> #include <jpeglib.h> @@ -301,108 +305,75 @@ static void im_save (const std::string& filename, const bob::io::base::array::in } -class ImageJpegFile: public bob::io::base::File { - - public: //api - - ImageJpegFile(const char* path, char mode): - m_filename(path), - m_newfile(true) { - - //checks if file exists - if (mode == 'r' && !boost::filesystem::exists(path)) { - boost::format m("file '%s' is not readable"); - m % path; - throw std::runtime_error(m.str()); - } - - if (mode == 'r' || (mode == 'a' && boost::filesystem::exists(path))) { - { - im_peek(path, m_type); - m_length = 1; - m_newfile = false; - } - } - else { - m_length = 0; - m_newfile = true; - } - - } - - virtual ~ImageJpegFile() { } - - virtual const char* filename() const { - return m_filename.c_str(); - } - - virtual const bob::io::base::array::typeinfo& type_all() const { - return m_type; - } - - virtual const bob::io::base::array::typeinfo& type() const { - return m_type; - } +/** + * JPEG class +*/ - virtual size_t size() const { - return m_length; - } +bob::io::image::JPEGFile::JPEGFile(const char* path, char mode) +: m_filename(path), + m_newfile(true) +{ + //checks if file exists + if (mode == 'r' && !boost::filesystem::exists(path)) { + boost::format m("file '%s' is not readable"); + m % path; + throw std::runtime_error(m.str()); + } - virtual const char* name() const { - return s_codecname.c_str(); - } + if (mode == 'r' || (mode == 'a' && boost::filesystem::exists(path))) { + im_peek(path, m_type); + m_length = 1; + m_newfile = false; + } else { + m_length = 0; + m_newfile = true; + } +} - virtual void read_all(bob::io::base::array::interface& buffer) { - read(buffer, 0); ///we only have 1 image in an image file anyways - } - virtual void read(bob::io::base::array::interface& buffer, size_t index) { - if (m_newfile) - throw std::runtime_error("uninitialized image file cannot be read"); +void bob::io::image::JPEGFile::read(bob::io::base::array::interface& buffer, size_t index) { + if (m_newfile) + throw std::runtime_error("uninitialized image file cannot be read"); - if (!buffer.type().is_compatible(m_type)) buffer.set(m_type); + if (!buffer.type().is_compatible(m_type)) buffer.set(m_type); - if (index != 0) - throw std::runtime_error("cannot read image with index > 0 -- there is only one image in an image file"); + if (index != 0) + throw std::runtime_error("cannot read image with index > 0 -- there is only one image in an image file"); - if(!buffer.type().is_compatible(m_type)) buffer.set(m_type); - im_load(m_filename, buffer); - } + if(!buffer.type().is_compatible(m_type)) buffer.set(m_type); - virtual size_t append (const bob::io::base::array::interface& buffer) { - if (m_newfile) { - im_save(m_filename, buffer); - m_type = buffer.type(); - m_newfile = false; - m_length = 1; - return 0; - } + // load jpeg + im_load(m_filename, buffer); +} - throw std::runtime_error("image files only accept a single array"); - } +size_t bob::io::image::JPEGFile::append(const bob::io::base::array::interface& buffer) { + if (m_newfile) { + im_save(m_filename, buffer); + m_type = buffer.type(); + m_newfile = false; + m_length = 1; + return 0; + } - virtual void write (const bob::io::base::array::interface& buffer) { - //overwriting position 0 should always work - if (m_newfile) { - append(buffer); - return; - } + throw std::runtime_error("image files only accept a single array"); +} - throw std::runtime_error("image files only accept a single array"); - } +void bob::io::image::JPEGFile::write(const bob::io::base::array::interface& buffer) { + //overwriting position 0 should always work + if (m_newfile) { + append(buffer); + return; + } - private: //representation - std::string m_filename; - bool m_newfile; - bob::io::base::array::typeinfo m_type; - size_t m_length; + throw std::runtime_error("image files only accept a single array"); +} - static std::string s_codecname; -}; -std::string ImageJpegFile::s_codecname = "bob.image_jpeg"; +std::string bob::io::image::JPEGFile::s_codecname = "bob.image_jpeg"; boost::shared_ptr<bob::io::base::File> make_jpeg_file (const char* path, char mode) { - return boost::make_shared<ImageJpegFile>(path, mode); + return boost::make_shared<bob::io::image::JPEGFile>(path, mode); } + +#endif // HAVE_LIBJPEG diff --git a/bob/io/image/netpbm.cpp b/bob/io/image/cpp/netpbm.cpp similarity index 84% rename from bob/io/image/netpbm.cpp rename to bob/io/image/cpp/netpbm.cpp index a99cf9775e0b1b3ea1c7060e0b5262949c72d612..d74c400393b82d4af7a96a450e5dad2b041c16ca 100644 --- a/bob/io/image/netpbm.cpp +++ b/bob/io/image/cpp/netpbm.cpp @@ -2,11 +2,13 @@ * @file io/cxx/ImageNetpbmFile.cc * @date Tue Oct 9 18:13:00 2012 +0200 * @author Laurent El Shafey <laurent.el-shafey@idiap.ch> + * @author Manuel Gunther <siebenkopf@googlemail.com> * * @brief Implements an image format reader/writer using libnetpbm. * This codec is only able to work with 2D and 3D input. * * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland + * Copyright (c) 2016, Regents of the University of Colorado on behalf of the University of Colorado Colorado Springs. */ #include <boost/filesystem.hpp> @@ -17,11 +19,9 @@ #include <boost/algorithm/string.hpp> #include <string> -#include <bob.io.base/File.h> +#include <bob.io.image/netpbm.h> -extern "C" { #include "pnmio.h" -} typedef unsigned long sample; @@ -408,7 +408,7 @@ static void im_save_color(const bob::io::base::array::interface& b, struct pam * img_data[c+0] = element_r[y*info.shape[2] + x]; img_data[c+1] = element_g[y*info.shape[2] + x]; img_data[c+2] = element_b[y*info.shape[2] + x]; - c = c + 3; + c += 3; } } pnm_writepam(out_pam, img_data); @@ -492,110 +492,69 @@ static void im_save (const std::string& filename, const bob::io::base::array::in } +/** + * NetPBM class +*/ -class ImageNetpbmFile: public bob::io::base::File { - - public: //api - - ImageNetpbmFile(const char* path, char mode): - m_filename(path), - m_newfile(true) { - - //checks if file exists - if (mode == 'r' && !boost::filesystem::exists(path)) { - boost::format m("file '%s' is not readable"); - m % path; - throw std::runtime_error(m.str()); - } - - if (mode == 'r' || (mode == 'a' && boost::filesystem::exists(path))) { - { - im_peek(path, m_type); - m_length = 1; - m_newfile = false; - } - } - else { - m_length = 0; - m_newfile = true; - } - } - - virtual ~ImageNetpbmFile() { } - - virtual const char* filename() const { - return m_filename.c_str(); - } - - virtual const bob::io::base::array::typeinfo& type_all() const { - return m_type; - } - - virtual const bob::io::base::array::typeinfo& type() const { - return m_type; - } - - virtual size_t size() const { - return m_length; - } - - virtual const char* name() const { - return s_codecname.c_str(); - } - - virtual void read_all(bob::io::base::array::interface& buffer) { - read(buffer, 0); ///we only have 1 image in an image file anyways - } - - virtual void read(bob::io::base::array::interface& buffer, size_t index) { - - if (m_newfile) - throw std::runtime_error("uninitialized image file cannot be read"); +bob::io::image::NetPBMFile::NetPBMFile(const char* path, char mode) +: m_filename(path), + m_newfile(true) +{ + //checks if file exists + if (mode == 'r' && !boost::filesystem::exists(path)) { + boost::format m("file '%s' is not readable"); + m % path; + throw std::runtime_error(m.str()); + } - if (!buffer.type().is_compatible(m_type)) buffer.set(m_type); + if (mode == 'r' || (mode == 'a' && boost::filesystem::exists(path))) { + im_peek(path, m_type); + m_length = 1; + m_newfile = false; + } else { + m_length = 0; + m_newfile = true; + } +} - if (index != 0) - throw std::runtime_error("cannot read image with index > 0 -- there is only one image in an image file"); +void bob::io::image::NetPBMFile::read(bob::io::base::array::interface& buffer, size_t index) { + if (m_newfile) + throw std::runtime_error("uninitialized image file cannot be read"); - if(!buffer.type().is_compatible(m_type)) buffer.set(m_type); - im_load(m_filename, buffer); - } + if (!buffer.type().is_compatible(m_type)) buffer.set(m_type); - virtual size_t append (const bob::io::base::array::interface& buffer) { - if (m_newfile) { - im_save(m_filename, buffer); - m_type = buffer.type(); - m_newfile = false; - m_length = 1; - return 0; - } + if (index != 0) + throw std::runtime_error("cannot read image with index > 0 -- there is only one image in an image file"); - throw std::runtime_error("image files only accept a single array"); - } - - virtual void write (const bob::io::base::array::interface& buffer) { - //overwriting position 0 should always work - if (m_newfile) { - append(buffer); - return; - } + if(!buffer.type().is_compatible(m_type)) buffer.set(m_type); + im_load(m_filename, buffer); +} - throw std::runtime_error("image files only accept a single array"); - } +size_t bob::io::image::NetPBMFile::append(const bob::io::base::array::interface& buffer) { + if (m_newfile) { + im_save(m_filename, buffer); + m_type = buffer.type(); + m_newfile = false; + m_length = 1; + return 0; + } - private: //representation - std::string m_filename; - bool m_newfile; - bob::io::base::array::typeinfo m_type; - size_t m_length; + throw std::runtime_error("image files only accept a single array"); +} - static std::string s_codecname; +void bob::io::image::NetPBMFile::write(const bob::io::base::array::interface& buffer) { + //overwriting position 0 should always work + if (m_newfile) { + append(buffer); + return; + } -}; + throw std::runtime_error("image files only accept a single array"); +} -std::string ImageNetpbmFile::s_codecname = "bob.image_netpbm"; +std::string bob::io::image::NetPBMFile::s_codecname = "bob.image_netpbm"; boost::shared_ptr<bob::io::base::File> make_netpbm_file (const char* path, char mode) { - return boost::make_shared<ImageNetpbmFile>(path, mode); + return boost::make_shared<bob::io::image::NetPBMFile>(path, mode); } diff --git a/bob/io/image/png.cpp b/bob/io/image/cpp/png.cpp similarity index 86% rename from bob/io/image/png.cpp rename to bob/io/image/cpp/png.cpp index 0feb6e63ca960f6f1720249e9bae99d9018be02e..e2ad1a75b8f1c9dbd642c7c7ce19bc979bd9137c 100644 --- a/bob/io/image/png.cpp +++ b/bob/io/image/cpp/png.cpp @@ -2,12 +2,16 @@ * @file io/cxx/ImagePngFile.cc * @date Fri Oct 12 12:08:00 2012 +0200 * @author Laurent El Shafey <laurent.el-shafey@idiap.ch> + * @author Manuel Gunther <siebenkopf@googlemail.com> * * @brief Implements an image format reader/writer using libpng. * * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland + * Copyright (c) 2016, Regents of the University of Colorado on behalf of the University of Colorado Colorado Springs. */ +#ifdef HAVE_LIBPNG + #include <boost/filesystem.hpp> #include <boost/shared_array.hpp> #include <boost/shared_ptr.hpp> @@ -17,7 +21,7 @@ #include <boost/algorithm/string.hpp> #include <string> -#include <bob.io.base/File.h> +#include <bob.io.image/png.h> extern "C" { #include <png.h> @@ -462,108 +466,72 @@ static void im_save(const std::string& filename, const bob::io::base::array::int png_destroy_write_struct(&png_ptr, &info_ptr); } -class ImagePngFile: public bob::io::base::File { - - public: //api - - ImagePngFile(const char* path, char mode): - m_filename(path), - m_newfile(true) { - - //checks if file exists - if (mode == 'r' && !boost::filesystem::exists(path)) { - boost::format m("file `%s' is not readable"); - m % path; - throw std::runtime_error(m.str()); - } - - if (mode == 'r' || (mode == 'a' && boost::filesystem::exists(path))) { - { - im_peek(path, m_type); - m_length = 1; - m_newfile = false; - } - } - else { - m_length = 0; - m_newfile = true; - } - - } - - virtual ~ImagePngFile() { } - - virtual const char* filename() const { - return m_filename.c_str(); - } - - virtual const bob::io::base::array::typeinfo& type_all() const { - return m_type; - } - - virtual const bob::io::base::array::typeinfo& type() const { - return m_type; - } - - virtual size_t size() const { - return m_length; - } - - virtual const char* name() const { - return s_codecname.c_str(); - } - virtual void read_all(bob::io::base::array::interface& buffer) { - read(buffer, 0); ///we only have 1 image in an image file anyways - } +/** + * PNG class +*/ +bob::io::image::PNGFile::PNGFile(const char* path, char mode) +: m_filename(path), + m_newfile(true) +{ + //checks if file exists + if (mode == 'r' && !boost::filesystem::exists(path)) { + boost::format m("file `%s' is not readable"); + m % path; + throw std::runtime_error(m.str()); + } - virtual void read(bob::io::base::array::interface& buffer, size_t index) { - if (m_newfile) - throw std::runtime_error("uninitialized image file cannot be read"); + if (mode == 'r' || (mode == 'a' && boost::filesystem::exists(path))) { + im_peek(path, m_type); + m_length = 1; + m_newfile = false; + } else { + m_length = 0; + m_newfile = true; + } - if (!buffer.type().is_compatible(m_type)) buffer.set(m_type); +} - if (index != 0) - throw std::runtime_error("cannot read image with index > 0 -- there is only one image in an image file"); +void bob::io::image::PNGFile::read(bob::io::base::array::interface& buffer, size_t index) { + if (m_newfile) + throw std::runtime_error("uninitialized image file cannot be read"); - if(!buffer.type().is_compatible(m_type)) buffer.set(m_type); - im_load(m_filename, buffer); - } + if (!buffer.type().is_compatible(m_type)) buffer.set(m_type); - virtual size_t append (const bob::io::base::array::interface& buffer) { - if (m_newfile) { - im_save(m_filename, buffer); - m_type = buffer.type(); - m_newfile = false; - m_length = 1; - return 0; - } + if (index != 0) + throw std::runtime_error("cannot read image with index > 0 -- there is only one image in an image file"); - throw std::runtime_error("image files only accept a single array"); - } + if(!buffer.type().is_compatible(m_type)) buffer.set(m_type); + im_load(m_filename, buffer); +} - virtual void write (const bob::io::base::array::interface& buffer) { - //overwriting position 0 should always work - if (m_newfile) { - append(buffer); - return; - } +size_t bob::io::image::PNGFile::append(const bob::io::base::array::interface& buffer) { + if (m_newfile) { + im_save(m_filename, buffer); + m_type = buffer.type(); + m_newfile = false; + m_length = 1; + return 0; + } - throw std::runtime_error("image files only accept a single array"); - } + throw std::runtime_error("image files only accept a single array"); +} - private: //representation - std::string m_filename; - bool m_newfile; - bob::io::base::array::typeinfo m_type; - size_t m_length; +void bob::io::image::PNGFile::write(const bob::io::base::array::interface& buffer) { + //overwriting position 0 should always work + if (m_newfile) { + append(buffer); + return; + } - static std::string s_codecname; + throw std::runtime_error("image files only accept a single array"); +} -}; -std::string ImagePngFile::s_codecname = "bob.image_png"; +std::string bob::io::image::PNGFile::s_codecname = "bob.image_png"; boost::shared_ptr<bob::io::base::File> make_png_file (const char* path, char mode) { - return boost::make_shared<ImagePngFile>(path, mode); + return boost::make_shared<bob::io::image::PNGFile>(path, mode); } + +#endif // HAVE_LIBPNG diff --git a/bob/io/image/pnmio.cpp b/bob/io/image/cpp/pnmio.cpp similarity index 99% rename from bob/io/image/pnmio.cpp rename to bob/io/image/cpp/pnmio.cpp index 1d44fc89e531e4625dab5c7bcd923c90a925148f..b8555cba342b556d572d80ff2971beed893ef5df 100755 --- a/bob/io/image/pnmio.cpp +++ b/bob/io/image/cpp/pnmio.cpp @@ -316,7 +316,7 @@ int read_pbm_data(FILE *f, int *img_in, int img_size, int is_ascii, int img_widt /* Decode the image contents byte-by-byte. */ for (k = 0; k < 8; k++) { if (i >= img_size) return -1; - img_in[i++] = (lum_val >> (7-k)) & 0x1; + img_in[i++] = (lum_val >> (7-k)) & 0x1; // fprintf(stderr, "i: %d, %d\n", i, img_in[i]); row_position++; if (row_position >= img_width) { diff --git a/bob/io/image/pnmio.h b/bob/io/image/cpp/pnmio.h similarity index 98% rename from bob/io/image/pnmio.h rename to bob/io/image/cpp/pnmio.h index 8b9cb168f24d105c670160023ef4443f596d2da3..0be97448b187913c2b8e010e25d39f6a92575407 100755 --- a/bob/io/image/pnmio.h +++ b/bob/io/image/cpp/pnmio.h @@ -1,6 +1,6 @@ /* * File : pnmio.h - * Description: Header file for pnmio.c. + * Description: Header file for pnmio.cpp. * Author : Nikolaos Kavvadias <nikolaos.kavvadias@gmail.com> * Copyright : (C) Nikolaos Kavvadias 2012, 2013, 2014, 2015, 2016 * Website : http://www.nkavvadias.com diff --git a/bob/io/image/tiff.cpp b/bob/io/image/cpp/tiff.cpp similarity index 82% rename from bob/io/image/tiff.cpp rename to bob/io/image/cpp/tiff.cpp index c79804db3b540a603167d923794d4174aab540fe..e3461048685a28fd38069f5257ea92c32d5d5ee9 100644 --- a/bob/io/image/tiff.cpp +++ b/bob/io/image/cpp/tiff.cpp @@ -2,12 +2,16 @@ * @file io/cxx/ImageTiffFile.cc * @date Fri Oct 12 12:08:00 2012 +0200 * @author Laurent El Shafey <laurent.el-shafey@idiap.ch> + * @author Manuel Gunther <siebenkopf@googlemail.com> * * @brief Implements an image format reader/writer using libtiff. * * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland + * Copyright (c) 2016, Regents of the University of Colorado on behalf of the University of Colorado Colorado Springs. */ +#ifdef HAVE_LIBTIFF + #include <boost/filesystem.hpp> #include <boost/shared_array.hpp> #include <boost/shared_ptr.hpp> @@ -17,7 +21,7 @@ #include <boost/algorithm/string.hpp> #include <string> -#include <bob.io.base/File.h> +#include <bob.io.image/tiff.h> extern "C" { #include <tiffio.h> @@ -105,7 +109,7 @@ void im_load_gray(boost::shared_ptr<TIFF> in_file, bob::io::base::array::interfa //Comment just to document //PHOTOMETRIC_PALETTE: In this model, a color is described with a single component. The value of the component is used as an index into the red, green and blue curves in the ColorMap field to retrieve an RGB triplet that defines the color. When PhotometricInterpretation=3 - + // Deal with photometric interpretations uint16 photo = PHOTOMETRIC_MINISBLACK; if(TIFFGetField(in_file.get(), TIFFTAG_PHOTOMETRIC, &photo) == 0 || (photo != PHOTOMETRIC_MINISBLACK && photo != PHOTOMETRIC_MINISWHITE && photo != PHOTOMETRIC_PALETTE)){ @@ -367,108 +371,71 @@ static void im_save(const std::string& filename, const bob::io::base::array::int } } -class ImageTiffFile: public bob::io::base::File { - - public: //api - - ImageTiffFile(const char* path, char mode): - m_filename(path), - m_newfile(true) { - - //checks if file exists - if (mode == 'r' && !boost::filesystem::exists(path)) { - boost::format m("file '%s' is not readable"); - m % path; - throw std::runtime_error(m.str()); - } - - if (mode == 'r' || (mode == 'a' && boost::filesystem::exists(path))) { - { - im_peek(path, m_type); - m_length = 1; - m_newfile = false; - } - } - else { - m_length = 0; - m_newfile = true; - } - - } - - virtual ~ImageTiffFile() { } - - virtual const char* filename() const { - return m_filename.c_str(); - } - - virtual const bob::io::base::array::typeinfo& type_all() const { - return m_type; - } - - virtual const bob::io::base::array::typeinfo& type() const { - return m_type; - } - - virtual size_t size() const { - return m_length; - } - - virtual const char* name() const { - return s_codecname.c_str(); - } - virtual void read_all(bob::io::base::array::interface& buffer) { - read(buffer, 0); ///we only have 1 image in an image file anyways - } +/** + * TIFF class +*/ - virtual void read(bob::io::base::array::interface& buffer, size_t index) { - if (m_newfile) - throw std::runtime_error("uninitialized image file cannot be read"); +bob::io::image::TIFFFile::TIFFFile(const char* path, char mode) +: m_filename(path), + m_newfile(true) +{ + //checks if file exists + if (mode == 'r' && !boost::filesystem::exists(path)) { + boost::format m("file '%s' is not readable"); + m % path; + throw std::runtime_error(m.str()); + } - if (!buffer.type().is_compatible(m_type)) buffer.set(m_type); + if (mode == 'r' || (mode == 'a' && boost::filesystem::exists(path))) { + im_peek(path, m_type); + m_length = 1; + m_newfile = false; + } else { + m_length = 0; + m_newfile = true; + } +} - if (index != 0) - throw std::runtime_error("cannot read image with index > 0 -- there is only one image in an image file"); +void bob::io::image::TIFFFile::read(bob::io::base::array::interface& buffer, size_t index) { + if (m_newfile) + throw std::runtime_error("uninitialized image file cannot be read"); - if(!buffer.type().is_compatible(m_type)) buffer.set(m_type); - im_load(m_filename, buffer); - } + if (!buffer.type().is_compatible(m_type)) buffer.set(m_type); - virtual size_t append (const bob::io::base::array::interface& buffer) { - if (m_newfile) { - im_save(m_filename, buffer); - m_type = buffer.type(); - m_newfile = false; - m_length = 1; - return 0; - } + if (index != 0) + throw std::runtime_error("cannot read image with index > 0 -- there is only one image in an image file"); - throw std::runtime_error("image files only accept a single array"); - } - - virtual void write (const bob::io::base::array::interface& buffer) { - //overwriting position 0 should always work - if (m_newfile) { - append(buffer); - return; - } + if(!buffer.type().is_compatible(m_type)) buffer.set(m_type); + im_load(m_filename, buffer); +} - throw std::runtime_error("image files only accept a single array"); - } +size_t bob::io::image::TIFFFile::append(const bob::io::base::array::interface& buffer) { + if (m_newfile) { + im_save(m_filename, buffer); + m_type = buffer.type(); + m_newfile = false; + m_length = 1; + return 0; + } - private: //representation - std::string m_filename; - bool m_newfile; - bob::io::base::array::typeinfo m_type; - size_t m_length; + throw std::runtime_error("image files only accept a single array"); +} - static std::string s_codecname; +void bob::io::image::TIFFFile::write(const bob::io::base::array::interface& buffer) { + //overwriting position 0 should always work + if (m_newfile) { + append(buffer); + return; + } -}; + throw std::runtime_error("image files only accept a single array"); +} -std::string ImageTiffFile::s_codecname = "bob.image_tiff"; +std::string bob::io::image::TIFFFile::s_codecname = "bob.image_tiff"; boost::shared_ptr<bob::io::base::File> make_tiff_file (const char* path, char mode) { - return boost::make_shared<ImageTiffFile>(path, mode); + return boost::make_shared<bob::io::image::TIFFFile>(path, mode); } + +#endif // HAVE_LIBTIFF diff --git a/bob/io/image/file.h b/bob/io/image/file.h index 7ac66e67128598e61c844f95c0064ce84e58d09e..a6685da88df0dc21e610fe2b5e35cebda7bb02f7 100644 --- a/bob/io/image/file.h +++ b/bob/io/image/file.h @@ -32,7 +32,9 @@ * file using a specific backend. */ boost::shared_ptr<bob::io::base::File> make_tiff_file (const char* path, char mode); +#ifdef HAVE_LIBJPEG boost::shared_ptr<bob::io::base::File> make_jpeg_file (const char* path, char mode); +#endif boost::shared_ptr<bob::io::base::File> make_gif_file (const char* path, char mode); boost::shared_ptr<bob::io::base::File> make_netpbm_file (const char* path, char mode); boost::shared_ptr<bob::io::base::File> make_png_file (const char* path, char mode); diff --git a/bob/io/image/include/bob.io.image/bmp.h b/bob/io/image/include/bob.io.image/bmp.h new file mode 100644 index 0000000000000000000000000000000000000000..803ca2f67e84d0e262e4c9b99374e2745bf7a306 --- /dev/null +++ b/bob/io/image/include/bob.io.image/bmp.h @@ -0,0 +1,101 @@ +/** + * @date Wed May 11 12:39:37 MDT 2016 + * @author Manuel Gunther <siebenkopf@googlemail.com> + * + * @brief The file provides an easy C++ interface to read and write BMP images using our own codec + * + * Copyright (c) 2016, Regents of the University of Colorado on behalf of the University of Colorado Colorado Springs. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef BOB_IO_IMAGE_BMP_H +#define BOB_IO_IMAGE_BMP_H + +#include <stdexcept> +#include <string> + +#include <boost/shared_ptr.hpp> +#include <blitz/array.h> + +#include <bob.io.base/File.h> + + +/** + * @brief Array submodule API of the I/O module + */ +namespace bob { namespace io { namespace image { + + class BMPFile: public bob::io::base::File { + + public: //api + + BMPFile(const char* path, char mode); + + virtual ~BMPFile() { } + + virtual const char* filename() const { + return m_filename.c_str(); + } + + virtual const bob::io::base::array::typeinfo& type_all() const { + return m_type; + } + + virtual const bob::io::base::array::typeinfo& type() const { + return m_type; + } + + virtual size_t size() const { + return m_length; + } + + virtual const char* name() const { + return s_codecname.c_str(); + } + + virtual void read_all(bob::io::base::array::interface& buffer) { + read(buffer, 0); ///we only have 1 image in an image file anyways + } + + virtual void read(bob::io::base::array::interface& buffer, size_t index); + + virtual size_t append (const bob::io::base::array::interface& buffer); + + virtual void write (const bob::io::base::array::interface& buffer); + + using bob::io::base::File::write; + using bob::io::base::File::read; + + private: //representation + std::string m_filename; + bool m_newfile; + bob::io::base::array::typeinfo m_type; + size_t m_length; + + static std::string s_codecname; + + }; + + inline blitz::Array<uint8_t,3> read_bmp(const std::string& filename){ + BMPFile bmp(filename.c_str(), 'r'); + return bmp.read<uint8_t,3>(0); + } + + inline void write_bmp(const blitz::Array<uint8_t,3>& image, const std::string& filename){ + BMPFile bmp(filename.c_str(), 'w'); + bmp.write(image); + } + +}}} + +#endif /* BOB_IO_IMAGE_BMP_H */ diff --git a/bob/io/image/include/bob.io.image/config.h b/bob/io/image/include/bob.io.image/config.h new file mode 100644 index 0000000000000000000000000000000000000000..9ba23c4712bd599e749eb10ee3a0ee9d6ecd3162 --- /dev/null +++ b/bob/io/image/include/bob.io.image/config.h @@ -0,0 +1,112 @@ +/** + * @author Manuel Gunther <siebenkopf@googlemail.com> + * @date Mon May 23 09:58:35 MDT 2016 + * + * @brief General directives for all modules in bob.io.image + */ + +#ifndef BOB_IO_IMAGE_CONFIG_H +#define BOB_IO_IMAGE_CONFIG_H + +/* Macros that define versions and important names */ +#define BOB_IO_IMAGE_API_VERSION 0x0200 + + +#ifdef BOB_IMPORT_VERSION + + /*************************************** + * Here we define some functions that should be used to build version dictionaries in the version.cpp file + * There will be a compiler warning, when these functions are not used, so use them! + ***************************************/ + + #include <Python.h> + #include <boost/preprocessor/stringize.hpp> + +#ifdef HAVE_LIBJPEG + #include <jpeglib.h> +#endif + +#ifdef HAVE_LIBPNG + #define PNG_SKIP_SETJMP_CHECK + // #define requires because of the problematic pngconf.h. + // Look at the thread here: + // https://bugs.launchpad.net/ubuntu/+source/libpng/+bug/218409 + #include <png.h> +#endif + +#ifdef HAVE_GIFLIB + #include <gif_lib.h> +#endif + +#ifdef HAVE_LIBTIFF + #include <tiffio.h> +#endif + + /** + * LibJPEG version + */ +#ifdef HAVE_LIBJPEG + static PyObject* libjpeg_version() { + boost::format f("%d (compiled with %d bits depth)"); + f % LIBJPEG_VERSION % BITS_IN_JSAMPLE; + return Py_BuildValue("s", f.str().c_str()); + } +#endif + + /** + * Libpng version + */ +#ifdef HAVE_LIBPNG + static PyObject* libpng_version() { + return Py_BuildValue("s", PNG_LIBPNG_VER_STRING); + } +#endif + + /** + * Libtiff version + */ +#ifdef HAVE_LIBTIFF + static PyObject* libtiff_version() { + static const std::string beg_str("LIBTIFF, Version "); + static const size_t beg_len = beg_str.size(); + std::string vtiff(TIFFGetVersion()); + + // Remove first part if it starts with "LIBTIFF, Version " + if(vtiff.compare(0, beg_len, beg_str) == 0) + vtiff = vtiff.substr(beg_len); + + // Remove multiple (copyright) lines if any + size_t end_line = vtiff.find("\n"); + if(end_line != std::string::npos) + vtiff = vtiff.substr(0,end_line); + + return Py_BuildValue("s", vtiff.c_str()); + } +#endif + + /** + * Version of giflib support + */ +#ifdef HAVE_GIFLIB + static PyObject* giflib_version() { + #ifdef GIFLIB_VERSION + return Py_BuildValue("s", GIF_LIB_VERSION); + #else + boost::format f("%s.%s.%s"); + f % BOOST_PP_STRINGIZE(GIFLIB_MAJOR) % BOOST_PP_STRINGIZE(GIFLIB_MINOR) % BOOST_PP_STRINGIZE(GIFLIB_RELEASE); + return Py_BuildValue("s", f.str().c_str()); + #endif + } +#endif + + /** + * bob.io.image c/c++ api version + */ + static PyObject* bob_io_image_version() { + return Py_BuildValue("{ss}", "api", BOOST_PP_STRINGIZE(BOB_IO_IMAGE_API_VERSION)); + } + +#endif // BOB_IMPORT_VERSION + + +#endif /* BOB_IO_IMAGE_CONFIG_H */ diff --git a/bob/io/image/include/bob.io.image/gif.h b/bob/io/image/include/bob.io.image/gif.h new file mode 100644 index 0000000000000000000000000000000000000000..f49a0253265b4858c873a7a47856bc4e6b0068c6 --- /dev/null +++ b/bob/io/image/include/bob.io.image/gif.h @@ -0,0 +1,105 @@ +/** + * @date Wed May 11 12:39:37 MDT 2016 + * @author Manuel Gunther <siebenkopf@googlemail.com> + * + * @brief The file provides an easy C++ interface to read and write GIF images using GIFLIB + * + * Copyright (c) 2016, Regents of the University of Colorado on behalf of the University of Colorado Colorado Springs. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef BOB_IO_IMAGE_GIF_H +#define BOB_IO_IMAGE_GIF_H + +#ifdef HAVE_GIFLIB + +#include <stdexcept> +#include <string> + +#include <boost/shared_ptr.hpp> +#include <blitz/array.h> + +#include <bob.io.base/File.h> + + +/** + * @brief Array submodule API of the I/O module + */ +namespace bob { namespace io { namespace image { + + class GIFFile: public bob::io::base::File { + + public: //api + + GIFFile(const char* path, char mode); + + virtual ~GIFFile() { } + + virtual const char* filename() const { + return m_filename.c_str(); + } + + virtual const bob::io::base::array::typeinfo& type_all() const { + return m_type; + } + + virtual const bob::io::base::array::typeinfo& type() const { + return m_type; + } + + virtual size_t size() const { + return m_length; + } + + virtual const char* name() const { + return s_codecname.c_str(); + } + + virtual void read_all(bob::io::base::array::interface& buffer) { + read(buffer, 0); ///we only have 1 image in an image file anyways + } + + virtual void read(bob::io::base::array::interface& buffer, size_t index); + + virtual size_t append (const bob::io::base::array::interface& buffer); + + virtual void write (const bob::io::base::array::interface& buffer); + + using bob::io::base::File::write; + using bob::io::base::File::read; + + private: //representation + std::string m_filename; + bool m_newfile; + bob::io::base::array::typeinfo m_type; + size_t m_length; + + static std::string s_codecname; + + }; + + inline blitz::Array<uint8_t,3> read_gif(const std::string& filename){ + GIFFile gif(filename.c_str(), 'r'); + return gif.read<uint8_t,3>(0); + } + + inline void write_gif(const blitz::Array<uint8_t,3>& image, const std::string& filename){ + GIFFile gif(filename.c_str(), 'w'); + gif.write(image); + } + +}}} + +#endif // HAVE_GIFLIB + +#endif /* BOB_IO_IMAGE_GIF_H */ diff --git a/bob/io/image/include/bob.io.image/jpeg.h b/bob/io/image/include/bob.io.image/jpeg.h new file mode 100644 index 0000000000000000000000000000000000000000..576ffa548e75ec77253a03abc093857043b5d102 --- /dev/null +++ b/bob/io/image/include/bob.io.image/jpeg.h @@ -0,0 +1,112 @@ +/** + * @date Wed May 11 12:39:37 MDT 2016 + * @author Manuel Gunther <siebenkopf@googlemail.com> + * + * @brief The file provides an easy C++ interface to read and write JPEG images using LIBJPEG + * + * Copyright (c) 2016, Regents of the University of Colorado on behalf of the University of Colorado Colorado Springs. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef BOB_IO_IMAGE_JPEG_H +#define BOB_IO_IMAGE_JPEG_H + +#ifdef HAVE_LIBJPEG + +#include <stdexcept> +#include <string> + +#include <boost/shared_ptr.hpp> +#include <blitz/array.h> + +#include <bob.io.base/File.h> + + +/** + * @brief Array submodule API of the I/O module + */ +namespace bob { namespace io { namespace image { + + class JPEGFile: public bob::io::base::File { + + public: //api + + + JPEGFile(const char* path, char mode); + + virtual ~JPEGFile() { } + + virtual const char* filename() const { + return m_filename.c_str(); + } + + virtual const bob::io::base::array::typeinfo& type_all() const { + return m_type; + } + + virtual const bob::io::base::array::typeinfo& type() const { + return m_type; + } + + virtual size_t size() const { + return m_length; + } + + virtual const char* name() const { + return s_codecname.c_str(); + } + + virtual void read_all(bob::io::base::array::interface& buffer) { + read(buffer, 0); ///we only have 1 image in an image file anyways + } + + virtual void read(bob::io::base::array::interface& buffer, size_t index); + + virtual size_t append (const bob::io::base::array::interface& buffer); + + virtual void write (const bob::io::base::array::interface& buffer); + + using bob::io::base::File::write; + using bob::io::base::File::read; + + private: //representation + std::string m_filename; + bool m_newfile; + bob::io::base::array::typeinfo m_type; + size_t m_length; + + static std::string s_codecname; + }; + + bool is_color_jpeg(const std::string& filename){ + JPEGFile jpeg(filename.c_str(), 'r'); + return jpeg.type().nd == 3; + } + + template <int N> + blitz::Array<uint8_t,N> read_jpeg(const std::string& filename){ + JPEGFile jpeg(filename.c_str(), 'r'); + return jpeg.read<uint8_t,N>(0); + } + + template <int N> + void write_jpeg(const blitz::Array<uint8_t,N>& image, const std::string& filename){ + JPEGFile jpeg(filename.c_str(), 'w'); + jpeg.write(image); + } + +}}} + +#endif // HAVE_LIBJPEG + +#endif /* BOB_IO_IMAGE_JPEG_H */ diff --git a/bob/io/image/include/bob.io.image/netpbm.h b/bob/io/image/include/bob.io.image/netpbm.h new file mode 100644 index 0000000000000000000000000000000000000000..6d18ed2fbde51dd8ff2eb6fa6e0a1d6f6c5e7218 --- /dev/null +++ b/bob/io/image/include/bob.io.image/netpbm.h @@ -0,0 +1,146 @@ +/** + * @date Wed May 11 12:39:37 MDT 2016 + * @author Manuel Gunther <siebenkopf@googlemail.com> + * + * @brief The file provides an easy C++ interface to read and write images using the NetPBM interface + * + * Copyright (c) 2016, Regents of the University of Colorado on behalf of the University of Colorado Colorado Springs. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef BOB_IO_IMAGE_NETPBM_H +#define BOB_IO_IMAGE_NETPBM_H + +#include <stdexcept> +#include <string> + +#include <boost/shared_ptr.hpp> +#include <blitz/array.h> + +#include <bob.io.base/File.h> + + +/** + * @brief Array submodule API of the I/O module + */ +namespace bob { namespace io { namespace image { + + class NetPBMFile: public bob::io::base::File { + + public: //api + + NetPBMFile(const char* path, char mode); + + virtual ~NetPBMFile() { } + + virtual const char* filename() const { + return m_filename.c_str(); + } + + virtual const bob::io::base::array::typeinfo& type_all() const { + return m_type; + } + + virtual const bob::io::base::array::typeinfo& type() const { + return m_type; + } + + virtual size_t size() const { + return m_length; + } + + virtual const char* name() const { + return s_codecname.c_str(); + } + + virtual void read_all(bob::io::base::array::interface& buffer) { + read(buffer, 0); ///we only have 1 image in an image file anyways + } + + virtual void read(bob::io::base::array::interface& buffer, size_t index); + + virtual size_t append (const bob::io::base::array::interface& buffer); + + virtual void write (const bob::io::base::array::interface& buffer); + + using bob::io::base::File::write; + using bob::io::base::File::read; + + private: //representation + std::string m_filename; + bool m_newfile; + bob::io::base::array::typeinfo m_type; + size_t m_length; + + static std::string s_codecname; + + }; + + template <class T> + blitz::Array<T,2> read_pbm(const std::string& filename){ + NetPBMFile pbm(filename.c_str(), 'r'); + return pbm.read<T,2>(0); + } + + template <class T> + void write_pbm(const blitz::Array<T,2>& image, const std::string& filename){ + NetPBMFile pbm(filename.c_str(), 'w'); + pbm.write(image); + } + + template <class T> + blitz::Array<T,2> read_pgm(const std::string& filename){ + NetPBMFile pgm(filename.c_str(), 'r'); + return pgm.read<T,2>(0); + } + + template <class T> + void write_pgm(const blitz::Array<T,2>& image, const std::string& filename){ + NetPBMFile pgm(filename.c_str(), 'w'); + pgm.write(image); + } + + template <class T> + blitz::Array<T,3> read_ppm(const std::string& filename){ + NetPBMFile ppm(filename.c_str(), 'r'); + return ppm.read<T,3>(0); + } + + template <class T> + inline void write_ppm(const blitz::Array<T,3>& image, const std::string& filename){ + NetPBMFile ppm(filename.c_str(), 'w'); + ppm.write(image); + } + + + bool is_color_p_m(const std::string& filename){ + NetPBMFile p_m(filename.c_str(), 'r'); + return p_m.type().nd == 3; + } + + template <class T, int N> + blitz::Array<T,N> read_p_m(const std::string& filename){ + NetPBMFile p_m(filename.c_str(), 'r'); + return p_m.read<T,N>(0); + } + + template <class T, int N> + void write_p_m(const blitz::Array<T,N>& image, const std::string& filename){ + NetPBMFile p_m(filename.c_str(), 'w'); + p_m.write(image); + } + + +}}} + +#endif /* BOB_IO_IMAGE_NETPBM_H */ diff --git a/bob/io/image/include/bob.io.image/png.h b/bob/io/image/include/bob.io.image/png.h new file mode 100644 index 0000000000000000000000000000000000000000..0bc0909ec77191d9fcf23ebb0150a9721f89accd --- /dev/null +++ b/bob/io/image/include/bob.io.image/png.h @@ -0,0 +1,112 @@ +/** + * @date Wed May 11 12:39:37 MDT 2016 + * @author Manuel Gunther <siebenkopf@googlemail.com> + * + * @brief The file provides an easy C++ interface to read and write PNG images using LIBPNG + * + * Copyright (c) 2016, Regents of the University of Colorado on behalf of the University of Colorado Colorado Springs. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef BOB_IO_IMAGE_PNG_H +#define BOB_IO_IMAGE_PNG_H + +#ifdef HAVE_LIBPNG + +#include <stdexcept> +#include <string> + +#include <boost/shared_ptr.hpp> +#include <blitz/array.h> + +#include <bob.io.base/File.h> + + +/** + * @brief Array submodule API of the I/O module + */ +namespace bob { namespace io { namespace image { + + class PNGFile: public bob::io::base::File { + + public: //api + + + PNGFile(const char* path, char mode); + + virtual ~PNGFile() { } + + virtual const char* filename() const { + return m_filename.c_str(); + } + + virtual const bob::io::base::array::typeinfo& type_all() const { + return m_type; + } + + virtual const bob::io::base::array::typeinfo& type() const { + return m_type; + } + + virtual size_t size() const { + return m_length; + } + + virtual const char* name() const { + return s_codecname.c_str(); + } + + virtual void read_all(bob::io::base::array::interface& buffer) { + read(buffer, 0); ///we only have 1 image in an image file anyways + } + + virtual void read(bob::io::base::array::interface& buffer, size_t index); + + virtual size_t append (const bob::io::base::array::interface& buffer); + + virtual void write (const bob::io::base::array::interface& buffer); + + using bob::io::base::File::write; + using bob::io::base::File::read; + + private: //representation + std::string m_filename; + bool m_newfile; + bob::io::base::array::typeinfo m_type; + size_t m_length; + + static std::string s_codecname; + }; + + bool is_color_png(const std::string& filename){ + PNGFile png(filename.c_str(), 'r'); + return png.type().nd == 3; + } + + template <class T, int N> + blitz::Array<T,N> read_png(const std::string& filename){ + PNGFile png(filename.c_str(), 'r'); + return png.read<T,N>(0); + } + + template <class T, int N> + void write_png(const blitz::Array<T,N>& image, const std::string& filename){ + PNGFile png(filename.c_str(), 'w'); + png.write(image); + } + +}}} + +#endif // HAVE_LIBPNG + +#endif /* BOB_IO_IMAGE_PNG_H */ diff --git a/bob/io/image/include/bob.io.image/tiff.h b/bob/io/image/include/bob.io.image/tiff.h new file mode 100644 index 0000000000000000000000000000000000000000..04254035c4a387f347249098f91f4ed772a8f8d6 --- /dev/null +++ b/bob/io/image/include/bob.io.image/tiff.h @@ -0,0 +1,112 @@ +/** + * @date Wed May 11 12:39:37 MDT 2016 + * @author Manuel Gunther <siebenkopf@googlemail.com> + * + * @brief The file provides an easy C++ interface to read and write TIFF images using LIBTIFF + * + * Copyright (c) 2016, Regents of the University of Colorado on behalf of the University of Colorado Colorado Springs. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef BOB_IO_IMAGE_TIFF_H +#define BOB_IO_IMAGE_TIFF_H + +#ifdef HAVE_LIBTIFF + +#include <stdexcept> +#include <string> + +#include <boost/shared_ptr.hpp> +#include <blitz/array.h> + +#include <bob.io.base/File.h> + + +/** + * @brief Array submodule API of the I/O module + */ +namespace bob { namespace io { namespace image { + + class TIFFFile: public bob::io::base::File { + + public: //api + + + TIFFFile(const char* path, char mode); + + virtual ~TIFFFile() { } + + virtual const char* filename() const { + return m_filename.c_str(); + } + + virtual const bob::io::base::array::typeinfo& type_all() const { + return m_type; + } + + virtual const bob::io::base::array::typeinfo& type() const { + return m_type; + } + + virtual size_t size() const { + return m_length; + } + + virtual const char* name() const { + return s_codecname.c_str(); + } + + virtual void read_all(bob::io::base::array::interface& buffer) { + read(buffer, 0); ///we only have 1 image in an image file anyways + } + + virtual void read(bob::io::base::array::interface& buffer, size_t index); + + virtual size_t append (const bob::io::base::array::interface& buffer); + + virtual void write (const bob::io::base::array::interface& buffer); + + using bob::io::base::File::write; + using bob::io::base::File::read; + + private: //representation + std::string m_filename; + bool m_newfile; + bob::io::base::array::typeinfo m_type; + size_t m_length; + + static std::string s_codecname; + }; + + bool is_color_tiff(const std::string& filename){ + TIFFFile tiff(filename.c_str(), 'r'); + return tiff.type().nd == 3; + } + + template <class T, int N> + blitz::Array<T,N> read_tiff(const std::string& filename){ + TIFFFile tiff(filename.c_str(), 'r'); + return tiff.read<T,N>(0); + } + + template <class T, int N> + void write_tiff(const blitz::Array<T,N>& image, const std::string& filename){ + TIFFFile tiff(filename.c_str(), 'w'); + tiff.write(image); + } + +}}} + +#endif // HAVE_LIBTIFF + +#endif /* BOB_IO_IMAGE_TIFF_H */ diff --git a/bob/io/image/main.cpp b/bob/io/image/main.cpp index f913ec96925db9ab9bdd753f5a1b02080b0697f2..d7224ec8ff63c19747b4d8cbfe9d17429c7e5efc 100644 --- a/bob/io/image/main.cpp +++ b/bob/io/image/main.cpp @@ -1,8 +1,12 @@ /** * @author Andre Anjos <andre.anjos@idiap.ch> + * @author Manuel Gunther <siebenkopf@googlemail.com> * @date Fri 16 May 12:33:38 2014 CEST * * @brief Pythonic bindings + * + * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland + * Copyright (c) 2016, Regents of the University of Colorado on behalf of the University of Colorado Colorado Springs. */ #ifdef NO_IMPORT_ARRAY @@ -15,9 +19,163 @@ #include <bob.io.base/api.h> #include "file.h" + +#include <bob.extension/documentation.h> +#include <boost/format.hpp> +#include <boost/filesystem.hpp> + +#include <bob.io.image/bmp.h> +#include <bob.io.image/jpeg.h> +#include <bob.io.image/gif.h> +#include <bob.io.image/netpbm.h> +#include <bob.io.image/png.h> +#include <bob.io.image/tiff.h> + + +#ifdef HAVE_LIBJPEG #include <jpeglib.h> +#endif + +static auto s_test_io = bob::extension::FunctionDoc( + "_test_io", + "Tests the C++ API of reading and writing images" +) +.add_prototype("tempdir") +.add_parameter("tempdir", "str", "A temporary directory to write data to") +; +static PyObject* _test_io(PyObject*, PyObject *args, PyObject* kwds) { +BOB_TRY + static char** kwlist = s_test_io.kwlist(); + + const char* tempdir; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &tempdir)) return 0; + + blitz::Array<uint8_t, 2> gray_image(100, 100); + gray_image = 0; + for (int i = 0; i < 100; ++i){ + gray_image(i, 100-i) = 127; + gray_image(i,i) = 255; + } + + blitz::Array<uint8_t, 3> color_image(3, 100, 100); + for (int i = 0; i < 3; ++i) + color_image(i, blitz::Range::all(), blitz::Range::all()) = gray_image(blitz::Range::all(), blitz::Range::all()); + + // BMP; only color images are supported + boost::filesystem::path bmp(tempdir); bmp /= std::string("color.bmp"); + bob::io::image::write_bmp(color_image, bmp.string()); + + blitz::Array<uint8_t, 3> color_bmp = bob::io::image::read_bmp(bmp.string()); + if (blitz::any(blitz::abs(color_image - color_bmp) > 0)) + throw std::runtime_error("BMP image IO did not succeed, check " + bmp.string()); + + +#ifdef HAVE_GIFLIB + // GIF; only color images are supported + boost::filesystem::path gif(tempdir); gif /= std::string("color.gif"); + bob::io::image::write_gif(color_image, gif.string()); + + blitz::Array<uint8_t, 3> color_gif = bob::io::image::read_gif(gif.string()); + if (blitz::any(blitz::abs(color_image - color_gif) > 8)) // TODO: why is GIF not lossless? + throw std::runtime_error("GIF image IO did not succeed, check " + gif.string()); +#endif + + // NetPBM + boost::filesystem::path pgm(tempdir); pgm /= std::string("gray.pgm"); + bob::io::image::write_pgm(gray_image, pgm.string()); + if (bob::io::image::is_color_p_m(pgm.string())) + throw std::runtime_error("PGM image " + pgm.string() + " is not gray as expected"); + + blitz::Array<uint8_t, 2> gray_pgm = bob::io::image::read_pgm<uint8_t>(pgm.string()); + if (blitz::any(blitz::abs(gray_image - gray_pgm) > 0)) + throw std::runtime_error("PGM image IO did not succeed, check " + pgm.string()); + + boost::filesystem::path ppm(tempdir); ppm /= std::string("color.ppm"); + bob::io::image::write_ppm(color_image, ppm.string()); + if (!bob::io::image::is_color_p_m(ppm.string())) + throw std::runtime_error("PPM image " + ppm.string() + " is not color as expected"); + + blitz::Array<uint8_t, 3> color_ppm = bob::io::image::read_ppm<uint8_t>(ppm.string()); + if (blitz::any(blitz::abs(color_image - color_ppm) > 0)) + throw std::runtime_error("PPM image IO did not succeed, check " + ppm.string()); + + +#ifdef HAVE_LIBJPEG + // JPEG + boost::filesystem::path jpeg_gray(tempdir); jpeg_gray /= std::string("gray.jpg"); + bob::io::image::write_jpeg(gray_image, jpeg_gray.string()); + if (bob::io::image::is_color_jpeg(jpeg_gray.string())) + throw std::runtime_error("JPEG image " + jpeg_gray.string() + " is not gray as expected"); + + blitz::Array<uint8_t, 2> gray_jpeg = bob::io::image::read_jpeg<2>(jpeg_gray.string()); + if (blitz::any(blitz::abs(gray_image - gray_jpeg) > 10)) + throw std::runtime_error("JPEG gray image IO did not succeed, check " + jpeg_gray.string()); + + boost::filesystem::path jpeg_color(tempdir); jpeg_color /= std::string("color.jpg"); + bob::io::image::write_jpeg(color_image, jpeg_color.string()); + if (!bob::io::image::is_color_jpeg(jpeg_color.string())) + throw std::runtime_error("JPEG image " + jpeg_color.string() + " is not color as expected"); + + blitz::Array<uint8_t, 3> color_jpeg = bob::io::image::read_jpeg<3>(jpeg_color.string()); + if (blitz::any(blitz::abs(color_image - color_jpeg) > 10)) + throw std::runtime_error("JPEG color image IO did not succeed, check " + jpeg_color.string()); +#endif + +#ifdef HAVE_LIBPNG + // PNG + boost::filesystem::path png_gray(tempdir); png_gray /= std::string("gray.png"); + bob::io::image::write_png(gray_image, png_gray.string()); + if (bob::io::image::is_color_png(png_gray.string())) + throw std::runtime_error("PNG image " + png_gray.string() + " is not gray as expected"); + + blitz::Array<uint8_t, 2> gray_png = bob::io::image::read_png<uint8_t, 2>(png_gray.string()); + if (blitz::any(blitz::abs(gray_image - gray_png) > 1)) + throw std::runtime_error("PNG gray image IO did not succeed, check " + png_gray.string()); + + boost::filesystem::path png_color(tempdir); png_color /= std::string("color.png"); + bob::io::image::write_png(color_image, png_color.string()); + if (!bob::io::image::is_color_png(png_color.string())) + throw std::runtime_error("PNG image " + png_color.string() + " is not color as expected"); + + blitz::Array<uint8_t, 3> color_png = bob::io::image::read_png<uint8_t, 3>(png_color.string()); + if (blitz::any(blitz::abs(color_image - color_png) > 1)) + throw std::runtime_error("PNG color image IO did not succeed, check " + png_color.string()); +#endif + +#ifdef HAVE_LIBTIFF + // TIFF + boost::filesystem::path tiff_gray(tempdir); tiff_gray /= std::string("gray.tiff"); + bob::io::image::write_tiff(gray_image, tiff_gray.string()); + if (bob::io::image::is_color_tiff(tiff_gray.string())) + throw std::runtime_error("TIFF image " + tiff_gray.string() + " is not gray as expected"); + + blitz::Array<uint8_t, 2> gray_tiff = bob::io::image::read_tiff<uint8_t, 2>(tiff_gray.string()); + if (blitz::any(blitz::abs(gray_image - gray_tiff) > 1)) + throw std::runtime_error("TIFF gray image IO did not succeed, check " + tiff_gray.string()); + + boost::filesystem::path tiff_color(tempdir); tiff_color /= std::string("color.tiff"); + bob::io::image::write_tiff(color_image, tiff_color.string()); + if (!bob::io::image::is_color_tiff(tiff_color.string())) + throw std::runtime_error("TIFF image " + tiff_color.string() + " is not color as expected"); + + blitz::Array<uint8_t, 3> color_tiff = bob::io::image::read_tiff<uint8_t, 3>(tiff_color.string()); + if (blitz::any(blitz::abs(color_image - color_tiff) > 1)) + throw std::runtime_error("TIFF color image IO did not succeed, check " + tiff_color.string()); +#endif + + + Py_RETURN_NONE; +BOB_CATCH_FUNCTION("_test_io", 0) +} + static PyMethodDef module_methods[] = { + { + s_test_io.name(), + (PyCFunction)_test_io, + METH_VARARGS|METH_KEYWORDS, + s_test_io.doc(), + }, {0} /* Sentinel */ }; @@ -62,6 +220,7 @@ static PyObject* create_module (void) { PyErr_Print(); } +#ifdef HAVE_LIBJPEG if (BITS_IN_JSAMPLE == 8) { if (!PyBobIoCodec_Register(".jpg", "JPEG, compresssed (libjpeg)", &make_jpeg_file)) { @@ -76,10 +235,13 @@ static PyObject* create_module (void) { PyErr_Format(PyExc_RuntimeError, "libjpeg compiled with `%d' bits depth (instead of 8). JPEG images are hence not supported.", BITS_IN_JSAMPLE); PyErr_Print(); } +#endif +#ifdef HAVE_GIFLIB if (!PyBobIoCodec_Register(".gif", "GIF (giflib)", &make_gif_file)) { PyErr_Print(); } +#endif // HAVE_GIFLIB if (!PyBobIoCodec_Register(".pbm", "PBM, indexed (libnetpbm)", &make_netpbm_file)) { diff --git a/bob/io/image/test.py b/bob/io/image/test.py index 6a8f52faef5fe432ab2b809bd55758fdc509a054..48fa152238deb082bd3c1a1373f4233736952a83 100644 --- a/bob/io/image/test.py +++ b/bob/io/image/test.py @@ -65,3 +65,15 @@ def test_netpbm(): transcode(test_utils.datafile('test_2.ppm', __name__)) # indexed, works fine # transcode(test_utils.datafile('test.jpg', __name__)) #does not work # because of re-compression + + +def test_cpp_interface(): + from ._library import _test_io + import tempfile + import shutil + + tmpdir = tempfile.mkdtemp(prefix="bob_io_image") + try: + _test_io(tmpdir) + finally: + shutil.rmtree(tmpdir) diff --git a/bob/io/image/version.cpp b/bob/io/image/version.cpp index d7c9cd6820a5fed6d4f0061d6b8b63122d18d3f3..f32ad706c5a4058252e9b74698f2c0cf3fd16420 100644 --- a/bob/io/image/version.cpp +++ b/bob/io/image/version.cpp @@ -1,5 +1,6 @@ /** * @author Andre Anjos <andre.anjos@idiap.ch> + * @author Manuel Gunther <siebenkopf@googlemail.com> * @date Wed 14 May 14:00:33 2014 CEST * * @brief Binds configuration information available from bob @@ -10,81 +11,28 @@ #include <bob.blitz/cleanup.h> #include <bob.core/config.h> #include <bob.io.base/config.h> +#include <bob.io.image/config.h> #include <boost/preprocessor/stringize.hpp> -extern "C" { - #include <jpeglib.h> - - #define PNG_SKIP_SETJMP_CHECK - // #define requires because of the problematic pngconf.h. - // Look at the thread here: - // https://bugs.launchpad.net/ubuntu/+source/libpng/+bug/218409 - #include <png.h> - #include <gif_lib.h> - #include <tiffio.h> -} - -/** - * LibJPEG version - */ -static PyObject* libjpeg_version() { - boost::format f("%d (compiled with %d bits depth)"); - f % LIBJPEG_VERSION % BITS_IN_JSAMPLE; - return Py_BuildValue("s", f.str().c_str()); -} - -/** - * Libpng version - */ -static PyObject* libpng_version() { - return Py_BuildValue("s", PNG_LIBPNG_VER_STRING); -} - -/** - * Libtiff version - */ -static PyObject* libtiff_version() { - static const std::string beg_str("LIBTIFF, Version "); - static const size_t beg_len = beg_str.size(); - std::string vtiff(TIFFGetVersion()); - - // Remove first part if it starts with "LIBTIFF, Version " - if(vtiff.compare(0, beg_len, beg_str) == 0) - vtiff = vtiff.substr(beg_len); - - // Remove multiple (copyright) lines if any - size_t end_line = vtiff.find("\n"); - if(end_line != std::string::npos) - vtiff = vtiff.substr(0,end_line); - - return Py_BuildValue("s", vtiff.c_str()); -} - -/** - * Version of giflib support - */ -static PyObject* giflib_version() { -#ifdef GIF_LIB_VERSION - return Py_BuildValue("s", GIF_LIB_VERSION); -#else - boost::format f("%s.%s.%s"); - f % BOOST_PP_STRINGIZE(GIFLIB_MAJOR) % BOOST_PP_STRINGIZE(GIFLIB_MINOR) % BOOST_PP_STRINGIZE(GIFLIB_RELEASE); - return Py_BuildValue("s", f.str().c_str()); -#endif -} - - static PyObject* build_version_dictionary() { PyObject* retval = PyDict_New(); if (!retval) return 0; auto retval_ = make_safe(retval); +#ifdef HAVE_LIBJPEG if (!dict_steal(retval, "libjpeg", libjpeg_version())) return 0; +#endif +#ifdef HAVE_LIBPNG if (!dict_steal(retval, "libpng", libpng_version())) return 0; +#endif +#ifdef HAVE_LIBTIFF if (!dict_steal(retval, "libtiff", libtiff_version())) return 0; +#endif +#ifdef HAVE_GIFLIB if (!dict_steal(retval, "giflib", giflib_version())) return 0; +#endif if (!dict_steal(retval, "HDF5", hdf5_version())) return 0; if (!dict_steal(retval, "Boost", boost_version())) return 0; if (!dict_steal(retval, "Compiler", compiler_version())) return 0; @@ -130,9 +78,13 @@ static PyObject* create_module (void) { if (!m) return 0; /* register version numbers and constants */ + if (PyModule_AddIntConstant(m, "api", BOB_IO_IMAGE_API_VERSION) < 0) return 0; if (PyModule_AddStringConstant(m, "module", BOB_EXT_MODULE_VERSION) < 0) return 0; if (PyModule_AddObject(m, "externals", build_version_dictionary()) < 0) return 0; + // call bob_io_image_version once to avoid compiler warning + auto _ = make_safe(bob_io_image_version()); + return Py_BuildValue(ret, m); } diff --git a/doc/cpp_api.rst b/doc/cpp_api.rst new file mode 100644 index 0000000000000000000000000000000000000000..070e87b9c2454fb3fd488179ea01f8c657de0588 --- /dev/null +++ b/doc/cpp_api.rst @@ -0,0 +1,188 @@ +.. vim: set fileencoding=utf-8 : +.. Manuel Gunther <siebenkopf@googlemail.com> +.. Mon May 23 15:25:41 MDT 2016 + +========= + C++ API +========= + +The C++ API of ``bob.io.image`` allows users to read and write images in different file formats. +For all image tyres, there exist two functions for reading and writing image, a function to peek the color information (if applicable) and a C++ class that can be used for more detailed information about the image. + +BMP +--- + +.. code-block: cpp + + #include <bob.io.image/bmp.h> + +.. cpp:function:: blitz::Array<uint8_t,3> bob::io::image::read_bmp(const std::string& filename) + + Reads a color BMP image of data type ``uint8_t``. + +.. cpp:function:: void bob::io::image::write_bmp(const blitz::Array<uint8_t,3>& image, const std::string& filename) + + Writes the BMP color ``image`` . + If the file exists, it will be overwritten. + Only ``uint8_t`` data type is supported. + + +GIF +--- + +.. code-block: cpp + + #include <bob.io.image/gif.h> + +.. cpp:function:: blitz::Array<uint8_t,3> bob::io::image::read_gif(const std::string& filename) + + Reads a color GIF image of data type ``uint8_t``. + +.. cpp:function:: void bob::io::image::write_gif(const blitz::Array<uint8_t,3>& image, const std::string& filename) + + Writes the GIF color ``image`` . + If the file exists, it will be overwritten. + Only ``uint8_t`` data type is supported. + + +JPEG +---- + +.. code-block: cpp + + #include <bob.io.image/jpeg.h> + +.. cpp:function:: bool bob::io::image::is_color_jpeg(const std::string& filename) + + Returns ``true`` if the JPEG image with the given name is a color image, else ``false``. + +.. cpp:function:: template <int N> blitz::Array<uint8_t,N> bob::io::image::read_jpeg(const std::string& filename) + + Reads a JPEG image of the given type (grayscale: ``N=2`` or color: ``N=3``). + Only ``uint8_t`` data type is supported. + Please assure that you read images of the correct color type, see :cpp:func:`bob::io::image::is_color_jpeg`. + +.. cpp:function:: template <int N> void bob::io::image::write_jpeg(const blitz::Array<uint8_t,N>& image, const std::string& filename) + + Writes the JPEG ``image`` of the given type (grayscale: ``N=2`` or color: ``N=3``) to a file with the given ``filename``. + If the file exists, it will be overwritten. + Only ``uint8_t`` data type is supported. + + +TIFF +---- + +.. code-block: cpp + + #include <bob.io.image/tiff.h> + +.. cpp:function:: bool bob::io::image::is_color_tiff(const std::string& filename) + + Returns ``true`` if the TIFF image with the given name is a color image, else ``false``. + +.. cpp:function:: template <class T, int N> blitz::Array<T,N> bob::io::image::read_tiff(const std::string& filename) + + Reads a TIFF image of the given type (grayscale: ``N=2`` or color: ``N=3``). + Only ``uint8_t`` and ``uint16_t`` data types are supported. + Please assure that you read images of the correct color type, see :cpp:func:`bob::io::image::is_color_tiff`. + +.. cpp:function:: template <class T, int N> void bob::io::image::write_tiff(const blitz::Array<T,N>& image, const std::string& filename) + + Writes the TIFF ``image`` of the given type (grayscale: ``N=2`` or color: ``N=3``) to a file with the given ``filename``. + If the file exists, it will be overwritten. + Only ``uint8_t`` and ``uint16_t`` data types are supported. + + +PNG +--- + +.. code-block: cpp + + #include <bob.io.image/png.h> + +.. cpp:function:: bool bob::io::image::is_color_png(const std::string& filename) + + Returns ``true`` if the PNG image with the given name is a color image, else ``false``. + +.. cpp:function:: template <class T, int N> blitz::Array<T,N> bob::io::image::read_png(const std::string& filename) + + Reads a PNG image of the given type (grayscale: ``N=2`` or color: ``N=3``). + Only ``uint8_t`` and ``uint16_t`` data types are supported. + Please assure that you read images of the correct color type, see :cpp:func:`bob::io::image::is_color_png`. + +.. cpp:function:: template <class T, int N> void bob::io::image::write_png(const blitz::Array<T,N>& image, const std::string& filename) + + Writes the PNG ``image`` of the given type (grayscale: ``N=2`` or color: ``N=3``) to a file with the given ``filename``. + If the file exists, it will be overwritten. + Only ``uint8_t`` and ``uint16_t`` data types are supported. + + +NetPBM +------ + +.. note:: + Internally, the image IO is based on the filename extension to decide, which codec to use. + Hence, the filename extension needs to match the function and data type that you use. + Use ``.pbm`` for binary, ``.pgm`` for gray level images, and any other extension (typically ``.ppm``) for color images. + +.. code-block: cpp + + #include <bob.io.image/netpbm.h> + +.. cpp:function:: bool bob::io::image::is_color_p_m(const std::string& filename) + + Returns ``true`` if the image with the given name is a color image, else ``false``. + +.. cpp:function:: template <class T, int N> blitz::Array<T,N> bob::io::image::read_p_m(const std::string& filename) + + Reads an image of the given type (grayscale: ``N=2`` or color: ``N=3``). + Only ``uint8_t`` and ``uint16_t`` data types are supported. + Please assure that you read images of the correct color type, see :cpp:func:`bob::io::image::is_color_p_m`. + +.. cpp:function:: template <class T, int N> void bob::io::image::write_p_m(const blitz::Array<T,N>& image, const std::string& filename) + + Writes the ``image`` of the given type (grayscale: ``N=2`` or color: ``N=3``) to a file with the given ``filename``. + If the file exists, it will be overwritten. + Only ``uint8_t`` and ``uint16_t`` data types are supported. + + +.. cpp:function:: template <class T> blitz::Array<T,2> bob::io::image::read_pbm(const std::string& filename) + + Reads an binary image. + Only ``uint8_t`` and ``uint16_t`` data types are supported. + Filename extension ``.pbm`` is required. + +.. cpp:function:: template <class T> void bob::io::image::write_pbm(const blitz::Array<T,2>& image, const std::string& filename) + + Writes the binary ``image`` to a file with the given ``filename``. + If the file exists, it will be overwritten. + Only ``uint8_t`` and ``uint16_t`` data types are supported. + Filename extension ``.pbm`` is required. + + +.. cpp:function:: template <class T> blitz::Array<T,2> bob::io::image::read_pgm(const std::string& filename) + + Reads an grayscale image. Only ``uint8_`` and ``uint16_`` data types are supported. + Filename extension ``.pgm`` is required. + +.. cpp:function:: template <class T> void bob::io::image::write_pgm(const blitz::Array<T,2>& image, const std::string& filename) + + Writes the grayscale ``image`` to a file with the given ``filename``. + If the file exists, it will be overwritten. + Only ``uint8_t`` and ``uint16_t`` data types are supported. + Filename extension ``.pgm`` is required. + + +.. cpp:function:: template <class T> blitz::Array<T,3> bob::io::image::read_ppm(const std::string& filename) + + Reads an binary color image. Only ``uint8_`` and ``uint16_`` data types are supported. + Filename extension cannot be ``.pbm`` or ``.pgm``. + +.. cpp:function:: template <class T> void bob::io::image::write_ppm(const blitz::Array<T,3>& image, const std::string& filename) + + Writes the color ``image`` to a file with the given ``filename``. + If the file exists, it will be overwritten. + Only ``uint8_t`` and ``uint16_t`` data types are supported. + Filename extension cannot be ``.pbm`` or ``.pgm``. + +.. include:: links.rst diff --git a/doc/index.rst b/doc/index.rst index 7fee9c07562e2d408e30515aaca48486c7b5af02..2d4e218d533f4a325c2c90fab931a783f801cdeb 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -18,12 +18,14 @@ to read and write images using its native API (:py:func:`bob.io.base.load` and At present, this plugin provides support for the following types of images: -* TIFF -* JPEG -* GIF -* PNG -* BMP -* Netpbm images (PGM, PPM, PBM) +* TIFF (gray and color) +* JPEG (gray and color) +* GIF (color only) +* PNG (gray and color) +* BMP (color only) +* Netpbm images (binary - PBM, gray - PGM, color - PPM) + +Additionally, we provide the pure C++ interface to read and write these kind of images, see :doc:`cpp_api`. Documentation ------------- @@ -33,6 +35,7 @@ Documentation guide py_api + cpp_api Indices and tables ------------------ diff --git a/setup.py b/setup.py index be00305a48efa70c2038e1025df41954a0b5de07..d614f0c6160d45f57325ae2d98bdef4737011253 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ import os from setuptools import setup, find_packages, dist dist.Distribution(dict(setup_requires=['bob.extension', 'bob.blitz'] + bob_packages)) from bob.extension.utils import egrep, find_header, find_library -from bob.blitz.extension import Extension, build_ext +from bob.blitz.extension import Extension, Library, build_ext from bob.extension.utils import load_requirements build_requires = load_requirements() @@ -35,7 +35,7 @@ def libjpeg_turbo_version(header): vv = egrep(header, r"#\s*define\s+LIBJPEG_TURBO_VERSION\s+([\d\.]+)") if not len(vv): return None - return vv[0].group(1) + ' (turbo)' + return vv[0].group(1) + '-turbo' class jpeg: @@ -111,7 +111,7 @@ class jpeg: candidates = find_library(module, version=self.version, prefixes=[prefix], only_static=only_static) if not candidates: - raise RuntimeError("cannot find required %s binary module `%s' - make sure libsvm is installed on `%s'" % (self.name, module, prefix)) + raise RuntimeError("cannot find required %s binary module `%s' - make sure `%s' is installed on `%s'" % (self.name, module, self.name, prefix)) # libraries self.libraries = [] @@ -207,7 +207,7 @@ class tiff: candidates = find_library(module, version=self.version, prefixes=[prefix], only_static=only_static) if not candidates: - raise RuntimeError("cannot find required %s binary module `%s' - make sure libsvm is installed on `%s'" % (self.name, module, prefix)) + raise RuntimeError("cannot find required %s binary module `%s' - make sure `%s' is installed on `%s'" % (self.name, module, self.name, prefix)) # libraries self.libraries = [] @@ -309,7 +309,7 @@ class gif: candidates = find_library(module, version=self.version, prefixes=[prefix], only_static=only_static) if not candidates: - raise RuntimeError("cannot find required %s binary module `%s' - make sure libsvm is installed on `%s'" % (self.name, module, prefix)) + raise RuntimeError("cannot find required %s binary module `%s' - make sure `%s' is installed on `%s'" % (self.name, module, self.name, prefix)) # libraries self.libraries = [] @@ -373,8 +373,6 @@ setup( setup_requires = build_requires, install_requires = build_requires, - - ext_modules = [ Extension("bob.io.image.version", [ @@ -390,15 +388,28 @@ setup( define_macros = define_macros, ), + Library("bob.io.image.bob_io_image", + [ + "bob/io/image/cpp/tiff.cpp", + "bob/io/image/cpp/gif.cpp", + "bob/io/image/cpp/png.cpp", + "bob/io/image/cpp/jpeg.cpp", + "bob/io/image/cpp/bmp.cpp", + "bob/io/image/cpp/pnmio.cpp", + "bob/io/image/cpp/netpbm.cpp", + ], + packages = packages, + boost_modules = boost_modules, + bob_packages = bob_packages, + version = version, + system_include_dirs = system_include_dirs, + library_dirs = library_dirs, + libraries = libraries, + define_macros = define_macros, + ), + Extension("bob.io.image._library", [ - "bob/io/image/tiff.cpp", - "bob/io/image/gif.cpp", - "bob/io/image/png.cpp", - "bob/io/image/jpeg.cpp", - "bob/io/image/bmp.cpp", - "bob/io/image/pnmio.cpp", - "bob/io/image/netpbm.cpp", "bob/io/image/main.cpp", ], packages = packages, diff --git a/version.txt b/version.txt index 2a770f88580d8c2c48b42056f4c15714558b3a27..1a78b34537ab70360822a5d0733a88ab70b02247 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.0.7b0 \ No newline at end of file +2.1.0b0