Input Output system
There are two mechanisms for doing I/O in RAVL: via streams, and
via the Load() / Save() functions.
The standard C++ stream mechanism (See "The C++ Programming Language" by
B. Stroustrup) will read and write objects in a format unique to RAVL.
The details for this mechanism and a variation that allows the
creation of binary streams can be found in Ravl.Core.IO.Streams. On the other hand,
Load() / Save() mechanism is useful where
there is a choice of file formats, or where implicit data conversion
is needed.
There is also a mechanism for dealing with sequences of objects, a
description of which can be found in Ravl.OS.Sequence.
The Load() / Save() global functions provide a more
sophisticated I/O mechanism. They were originally developed for the ImageC template class (see Image I/O), but are now available for
other classes as well. The mechanism identifies the type of file being loaded,
and selects the appropriate code for loading it, if it exists. It will also do
certain type conversions automatically where its is deemed safe to do so. The
algorithm picks the conversion with the least conversion cost, resolving any
ambiguity by using the format with the highest priority.
For example, to read a real image from an RAVL ASCII "streams" format file
and store it in a pgm file:
ImageC<RealT> x;
Load("fred", x);
Save("jim.pgm", x);
The pixel types in the files "fred" and "jim.pgm" are unknown at compile time; the appropriate
type conversions therefore have to be selected at run time.
A more complete example of how to use this mechanism is given in exFileFormat.cc. To use this
mechanism you'll have to include the RavlIO library in
defs.mk :
USESLIBS = RavlIO ....
A list of currently supported formats can be obtained with the
conv program:
conv -lf
A list of automatic type conversions that are available can also be found:
conv -lc
N.B. If you are not using shared libraries (see "shared" command-line option in QMake), the increase
in size of your executable from this library can be large, because all of
the possible formats and conversions have to be allowed for at compile/link
time.
Writing your own stuff
Simple Class IO
Writing your own file I/O is a little more complicated. If all you want to do is
load and save your own class, write basic stream operators for your class and
then instantiate an instance of FileFormatStreamC class as a global variable.
The following example shows how a file format for loading and saving RealT
objects to ASCII streams (type "stream") was created.
#include "Ravl/DP/FileFormatStream.hh"
FileFormatStreamC <RealT> FileFormatStream_RealT;
If you wanted to write the data to a binary stream (type "abs") instead, you would use:
#include "Ravl/DP/FileFormatBinStream.hh"
FileFormatBinStreamC <RealT> FileFormatBinStream_RealT;
Writing Conversions
Writing your own data conversion classes is not much more difficult. You have
to write a simple function which does the conversion and then instantiate an
instance of the converter class DPConverterFuncC . The following example shows
the standard code for converting an IntT to a RealT . Note this conversion is
safe since no information is lost. Care must be taken when writing these
functions, especially if you lose information in the conversion, as it can lead
to unexpected results. The final parameter (= 1 in this example) indicates the
degree of loss. (1 indicates no loss; 8 used to indicate double -> unsigned
byte).
#include "Ravl/DP/Converter.hh"
RealT DPConvIntT2RealT(const IntT &val)
{ return (RealT) val; }
DP_REGISTER_CONVERTION(DPConvIntT2RealT,1);
Creating a new file format
The procedure for creating entirely new file formats is more involved. I'll
give only an outline of the procedure here:
- Create a new class each format that you wish to add one for loading and
one for saving. These shoud be derived from DPIPortBodyC<> and DPOPortBodyC<>
respectively.
- Create a new FileFormatXXXC class derived from FileFormatBodyC. In this
class overide the virtuals functions which identify the file format and create
the input and output streams.
- Create a static instance of the new file format class, to register it with
the IO mechansim.
Normal functions:
Load(const StringC &,DataT &,StringC,bool) | Load a single object. |
Save(const StringC &,const DataT &,StringC,bool) | Save a single object. |
Load(IStreamC &,DataT &,StringC,bool) | Load a single object from a stream |
Save(OStreamC &,const DataT &,StringC,bool) | Save a single object to a stream |
ListFormats(bool,const StringC &,const type_info &) | List all file formats that support the given type. |
Identify(const StringC &) | Identify a file. |
Identify(IStreamC &) | Identify a stream. |
Advanced functions:
Develop functions:
BaseLoad(const StringC &,StringC,const type_info &,bool) | Base load function. |
BaseSave(const StringC &,StringC,const type_info &,bool) | Base save function. |
BaseLoad(IStreamC &,StringC,const type_info &,bool) | Base load function for streams. |
BaseSave(OStreamC &,StringC,const type_info &,bool) | Base save function for streams |
InitCoreIO(void) | Initalise core IO. |
InitFixedIndexIO(void) | Initalise Fixed size index io methods. |
|