| Home | Libraries | People | FAQ | More

## Using IO

### General Overview

The tutorial pointed out some use cases for reading and writing images in various image formats. This section will provide a more thorough overview.

The next sections will introduce the Read and Write interface. But it might be worth poiting out that by using some advanced metaprogramming techniques the interface is rather small and hopefully easy to understand.

Besides the general interface the user also has the ability to interface directly with the underlying image format. For that each reader or writer provides access to the so-called backend. For instance:

    typedef get_reader_backend< const std::string
                              , tag_t
                              >::type backend_t;

    backend_t backend = read_image_info( bmp_filename
                                       , tag_t()
                                       );

    BOOST_CHECK_EQUAL( backend._info._width , 127 );
    BOOST_CHECK_EQUAL( backend._info._height, 64 );

Of course, the typedef can be removed when using c++11's auto feature.

### Read Interface

As the Tutorial demonstrated there are a few ways to read images. Here is an enumeration of all read functions with a short description:

    * read_image - read into a gil image with no conversion. Memory is allocated.
    * read_view  - read into a gil view with no conversion.
    * read_and_convert_image - read and convert into a gil image. Memory is allocated.
    * read_and_convert_view  - read and convert into a gil view.
    * read_image_info - read the image header.

Conversion in this context is necessary if the source ( file ) has an incompatible color space with the destination ( gil image type ). If that's the case the user has to use the xxx_and_convert_xxx variants.

All functions take the filename or a device as the first parameter. The filename can be anything from a c string, std::string, std::wstring, and a boost::filesystem path. When using the path object the user needs to define the ADD_FS_PATH_SUPPORT compiler symbol to include the boost::filesystem dependency. Devices could be a FILE*, std::ifstream, and a TIFF* for TIFF images.

The second parameter is either an image or view type depending on the read_xxx function. The third and last parameter is either an instance of the image_read_settings<FormatTag> or just the FormatTag. The settings can be various depending on the format which is being read. But the all share settings for reading a partial image area. The first point describes the top left image coordinate whereas the second are the dimensions in x and y directions. Here an example of setting up partial read.

    read_image( filename
              , img
              , image_read_settings< tiff_tag >( point_t( 0, 0 ), point_t( 50, 50 ) )
              );

Each format supports reading just the header information, using read_image_info(). Please refer to the format specific sections under 3.3. A basic example follows:

    image_read_info< tiff_t > info = read_image_info( filename
                                                    , tiff_t()
                                                    );

GIL also comes with a dynamic image extension. In the context of GIL.IO a user can define an any_image type based on several image types. The IO extension would then pick the matching image type to the current image file. The following example shows this feature:

    typedef mpl::vector< gray8_image_t
                       , gray16_image_t
                       , rgb8_image_t
                       , rgba_image_t
                       > my_img_types;

    any_image< my_img_types > runtime_image;

    read_image( filename
              , runtime_image
              , tiff_tag()
              );

During the review it became clear that there is a need to read big images scanline by scanline. To support such use case a scanline_reader is implemented for all supported image formats. The scanline_read_iterators will then allow to traverse through the image. The following code sample shows the usage:

    typedef tiff_tag tag_t;

    typedef scanline_reader< typename get_read_device< const char*
                                                     , tag_t
                                                     >::type
                            , tag_t
                            > reader_t;

    reader_t reader = make_scanline_reader( "C:/boost/libs/gil/io/test_images/tiff/test.tif", tag_t() );

    typedef rgba8_image_t image_t;

    image_t dst( reader._info._width, reader._info._height );
    fill_pixels( view(dst), image_t::value_type() );

    typedef reader_t::iterator_t iterator_t;

    iterator_t it  = reader.begin();
    iterator_t end = reader.end();

    for( int row = 0; it != end; ++it, ++row )
    {
        copy_pixels( interleaved_view( reader._info._width
                                        , 1
                                        , ( image_t::view_t::x_iterator ) *it
                                        , reader._scanline_length
                                        )
                    , subimage_view( view( dst )
                                    , 0
                                    , row
                                    , reader._info._width
                                    , 1
                                    )
                    );
    }

There are many ways to travese an image but for as of now only by scanline is supported.

### Write Interface

There is only one function for writing out images, write_view. Similar to reading the first parameter is either a filename or a device. The filename can be anything from a c string, std::string, std::wstring, and a boost::filesystem path. When using the path object the user needs to define the ADD_FS_PATH_SUPPORT compiler symbol to include the boost::filesystem dependency. Devices could be a FILE*, std::ifstream, and a TIFF* for TIFF images.

The second parameter is an view object to image being written. The third and last parameter is either a tag or an image_write_info< FormatTag > object containing more settings. One example for instance is the jpeg quality. Refer to the format specific sections under 3.3. to have a list of all the possible settings.

Writing an any_image<...> is supported. See the following example:

    typedef mpl::vector< gray8_image_t
                       , gray16_image_t
                       , rgb8_image_t
                       , rgba_image_t
                       > my_img_types;

    any_image< my_img_types > runtime_image;

    // fill any_image

    write_view( filename
              , view( runtime_image )
              , tiff_tag()
              );

### Compiler Symbols

The following table gives an overview of all supported compiler symbols that can be set by the user:

Table 1.1. Compiler Symbols

Symbol | Description
--- | ---
BOOST_GIL_IO_ENABLE_GRAY_ALPHA | Enable the color space "gray_alpha".
BOOST_GIL_IO_ADD_FS_PATH_SUPPORT | Enable boost::filesystem 3.0 library.
BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED | Use libpng in floating point mode. This symbol is incompatible with BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED.
BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED | Use libpng in integer mode. This symbol is incompatible with BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED.
BOOST_GIL_EXTENSION_IO_JPEG_C_LIB_COMPILED_AS_CPLUSPLUS | libjpeg is compiled as c++ lib.
BOOST_GIL_EXTENSION_IO_PNG_C_LIB_COMPILED_AS_CPLUSPLUS | libpng is compiled as c++ lib.
BOOST_GIL_EXTENSION_IO_RAW_C_LIB_COMPILED_AS_CPLUSPLUS | libraw is compiled as c++ lib.
BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS | libtiff is compiled as c++ lib.
BOOST_GIL_IO_TEST_ALLOW_READING_IMAGES | Allow basic test images to be read from local hard drive. The paths can be set in paths.hpp
BOOST_GIL_IO_TEST_ALLOW_WRITING_IMAGES | Allow images to be written to the local hard drive. The paths can be set in paths.hpp
BOOST_GIL_IO_USE_BMP_TEST_SUITE_IMAGES | Run tests using the bmp test images suite. See http://entropymine.com/jason/bmpsuite/
BOOST_GIL_IO_USE_PNG_TEST_SUITE_IMAGES | Run tests using the png test images suite. See http://www.schaik.com/pngsuite/pngsuite.html
BOOST_GIL_IO_USE_PNM_TEST_SUITE_IMAGES | Run tests using the pnm test images suite. Send me an email for accessing the files.
BOOST_GIL_IO_USE_TARGA_FILEFORMAT_TEST_SUITE_IMAGES | Run tests using the targa file format test images suite. See http://www.fileformat.info/format/tga/sample/index.htm
BOOST_GIL_IO_USE_TIFF_LIBTIFF_TEST_SUITE_IMAGES | Run tests using the targa file format test images suite. See http://www.remotesensing.org/libtiff/images.html
BOOST_GIL_IO_USE_TIFF_GRAPHICSMAGICK_TEST_SUITE_IMAGES | Run tests using the targa file format test images suite. See ftp://ftp.graphicsmagick.org/pub/tiff-samples/tiff-sample-images-be.tar.gz

### Supported Image Formats

#### BMP

For a general overview of the BMP image file format go to the following http://en.wikipedia.org/wiki/BMP_file_format.

Please note, the code has not been tested on X Windows System variations of the BMP format which are usually referred to XBM and XPM formats.

Here, only the MS Windows and OS/2 format is relevant.

Currently the code is able to read and write the following image types:

Read: gray1_image_t, gray4_image_t, gray8_image_t, rgb8_image_t and, rgba8_image_t Write: rgb8_image_t and, rgba8_image_t

The lack of having an indexed image type in gil restricts the current interface to only write out non-indexed images. This is subject to change soon.

#### JPEG

For a general overview of the JPEG image file format go to the following http://en.wikipedia.org/wiki/JPEG.

This jpeg extension is based on the libjpeg library which can be found here, JPEG_Lib.

The user has to make sure this library is properly installed. I strongly recommend the user to build the library yourself. It could potentially save you a lot of trouble.

Currently the code is able to read and write the following image types:

Read: gray8_image_t, rgb8_image_t, cmyk8_image_t Write: gray8_image_t, rgb8_image_t, cmyk8_image_t

Reading YCbCr or YCCK images is possible but might result in inaccuracies since both color spaces aren't available yet for gil. For now these color space are read as rgb images. This is subject to change soon.

#### PNG

For a general overview of the PNG image file format go to the following http://en.wikipedia.org/wiki/Portable_Network_Graphics.

This png extension is based on the libpng, which can be found here, _PNG_Lib.

The user has to make sure this library is properly installed. I strongly recommend the user to build the library yourself. It could potentially save you a lot of trouble.

Currently the code is able to read and write the following image types:

Read: gray1, gray2, gray4, gray8, gray16, gray_alpha_8, gray_alpha_16, rgb8, rgb16, rgba8, rgba16 Write: gray1, gray2, gray4, gray8, gray16, gray_alpha_8, gray_alpha_16, rgb8, rgb16, rgba8, rgba16

For reading gray_alpha images the user has to enable the ENABLE_GRAY_ALPHA compiler switch. This color space is defined in the toolbox by using gray_alpha.hpp.

#### PNM

For a general overview of the PNM image file format go to the following http://en.wikipedia.org/wiki/Portable_anymap.

No external library is needed for the pnm format. Both ascii and binary formats are supported.

Currently the code is able to read and write the following image types:

Read: gray1, gray8, rgb8 Write: gray1, gray8, rgb8

When reading a mono text image the data is read as a gray8 image.

#### RAW

For a general overview see _RAW_Wiki.

Currently the extension is only able to read rgb8 images.

#### TARGA

For a general overview of the BMP image file format go to the following TARGA_Wiki.

Currently the code is able to read and write the following image types:

Read: rgb8_image_t and rgba8_image_t Write: rgb8_image_t and rgba8_image_t

The lack of having an indexed image type in gil restricts the current interface to only write out non-indexed images. This is subject to change soon.

#### TIFF

For a general overview of the TIFF image file format go to the following http://en.wikipedia.org/wiki/Tagged_Image_File_Format.

This tiff extension is based on the libtiff, which can be found, http://www.remotesensing.org/libtiff/.

The user has to make sure this library is properly installed. I strongly recommend the user to build the library yourself. It could potentially save you a lot of trouble.

TIFF images can virtually encode all kinds of channel sizes representing various color spaces. Even planar images are possible. For instance, rbg323 or gray7. The channels also can have specific formats, like integer values or floating point values. For a complete set of options please consult the following websites:

- http://www.awaresystems.be/imaging/tiff/tifftags/baseline.html
- http://www.awaresystems.be/imaging/tiff/tifftags/extension.html

The author of this extension is not claiming all tiff formats are supported. This extension is likely to be a moving target adding new features with each new milestone. Here is an incomplete lists:

- Multi-page tiffs - read only
- Strip tiffs - read and write support
- Tiled tiffs - read and write support with user defined tiled sizes
- bit images tiffs - fully supported, like gray1_image_t ( minisblack )
- planar tiffs - fully supported
- floating point tiffs - fully supported
- palette tiffs - supported but no indexed image type is available as of now

This gil extension uses two different test image suites to test read and write capabilities. See test_image folder. It's advisable to use ImageMagick's test viewer to display images.

### Extending GIL::IO with new Formats

Extending the gil::io with new formats is meant to be simple and straightforward. Before adding I would recommend to have a look at existing implementations and then trying to follow a couple of guidelines:

- Create the following files for your new xxx format
  - xxx_read.hpp // Only includes read code
  - xxx_write.hpp // Only includes write code
  - xxx_all.hpp // includes xxx_read.hpp and xxx_write.hpp
- Add the code to the boost::gil::detail namespace
- Create a tag type for the new format. Like this:

      struct xxx_tag : format_tag {};

- Create the image_read_info for the new format. It contains all the information that are necessary to read an image. It should be filled and returned by the get_info() member of the reader class. See below.

      template<> struct image_read_info< xxx_tag > {};

- Create the image_write_info for the new format. It contains all the information that are necessary to write an image.

      template<> struct image_write_info< xxx_tag > {};

- Use the following reader skeleton as a start:

      template< typename Device
              , typename ConversionPolicy
              >
      class reader< Device
                  , xxx_tag
                  , ConversionPolicy
                  >
                  : public reader_base< xxx_tag
                                      , ConversionPolicy
                                      >
      {
      private:

          typedef typename ConversionPolicy::color_converter_type cc_t;

      public:

          reader( Device& device )
          : _io_dev( device )
          {}

          reader( Device&     device
                , const cc_t& cc
                )
          : _io_dev( device )
          , reader_base< xxx_tag
                       , ConversionPolicy
                       >( cc )
          {}

          image_read_info< xxx_tag > get_info()
          {
              // your implementation here
          }

          template< typename View >
          void apply( const View& dst_view )
          {
              // your implementation here
          }
      };

- The writer skeleton:

      template< typename Device >
      class writer< Device
                  , xxx_tag
                  >
      {
      public:

          writer( Device & file )
          : out(file)
          {}

          template<typename View>
          void apply( const View& view )
          {
              // your implementation here
          }

          template<typename View>
          void apply( const View&                        view
                    , const image_write_info< xxx_tag >& info )
          {
              // your implementation here
          }
      };