Libhalftoner |
As it can be seen, this fragment of code has no knowledge about the class that implements the algorithm, nor where it comes from (whether it was included in the library or is a custom algorithm). It only knows that it exists and can halftone images (in this case using the error diffusion technique created by the Floyd-Steinberg pair).
Finally, class
The complete API documentation of class 1.3 - Class
Class |
Class clazz = Class.forName("some.classname"); some.classname obj = (some.classname) clazz.newInstance(); |
There is a child class of class Instanciator
for each available
algorithm. If your are not developing your own algorithm, you do not need to
concern yourself with that class. However if you do, section 2
explain how to create and registering your own Instanciator
.
The complete API documentation of class Instanciator
can be found
by following this link.
HalftonerSpec
Class HalftonerSpec
provides a type for the parameter object
pattern. Many halftoning algorithms can be customized and this interface
provides a generic solution. HalftonerSpec
s are created when needed
and passed to the halftoner when a halftoning pass is needed.
An implementation of class Halftoner
is free in its behaviour on
how to handle the HalftonerSpec
parameter. Its behaviour should be
documented however.
The complete API documentation of class HalftonerSpec
can be found
by following this link.
Image
Class Image
represents a single-channel image. Each pixels has a
maximum of 256 distinct values (a greyscale image in other words). Image objects
are immutable, their dimensions cannot be changed during their lifetime.
However, the image data itself is mutable, each individual pixel can have its
intensity changed.
Images can be created at runtime or by the operations offered by the class
ImageIO
.
The complete API documentation of class Image
can be found by
following this link.
A user that wishes to implement his own version of an algorithm can do so easily. The process requires six steps:
Halftoner
HalftonerSpec
if necessaryInstanciator
Instanciator
with class HalftonerFactory
Each step is described in detail below.
The first step is to code and test the algorithm that will be added. This step is primordial as a buggy algorithm is not that much useful.
Halftoner
Once the confidence in the algorithm is acquired, it is time to turn its code
into a class that is a child-class of the abstract class Halftoner
and overwrite the method halftone()
.
#include <Halftoner.h> class HalftonerSpec; class Image; class yourHalftoner : public Halftoner { // your method and variables public: yourHalftoner() throw(); virtual ~yourHalftoner() throw(); Image* halftone ( const Image& source, const HalftonerSpec* spec ) throw (std::invalid_argument); }; |
The code from step 1 is refactored in such a way as to implement the method
halftone()
. There are no restriction for the creation of other
methods.
HalftonerSpec
If the algorithm that is to be added can be parametrized, this step provides a
guide to the creation of a parameter object, otherwise this section can be
skipped and 0
should be passed to Halftoner::halftone()
.
Class HalftonerSpec
defines no method. It is a class that only
provides a common type. Anything can be done in child-classes and the
Halftoner
child-class just created must know how this parameter
object is laid down. Usually in yourClass::halftone()
:
halftoner::Image* yourHalftoner::halftone (const Image& source, const HalftonerSpec* spec) throw (std::invalid_argument) { const yourSpec* yspec = dynamic_cast<yourSpec*>(spec); if (0 == yspec) { std::string message("spec is not a yourSpec*"); throw std::invalid_argument(message); } // extract parameters } |
Instanciator
Class HalftonerFactory
stores Instanciator
s that
creates Halftoner
objects when requested.
Instanciator
s can be seen as pointers to constructors. To create
such an object, make a child-class of Instanciator
and implement
the function operator operator()()
. Usually, returning a new
instance is enough:
#include <Instanciator.h> class yourInstanciator : public Instanciator { public: Halftoner* operator()() const throw() { Halftoner* halftoner = new yourHalftoner(); return halftoner; } }; |
Once all the required objects (Halftoner
, HalftonerSpec
,
Instanciator
) have been defined, it is time to register the new
algorithm. The registration is simple: at the beginning of a program, a call to
HalftonerFactory::addHalftoner
is all that is required. A unique
key needs to be defined and remembered so that the newly added algorithm can be
called back.
#include <HalftonerFactory.h> void f() { const char* yourKey = "yourKey"; Instanciator* instanciator = new yourInstanciator(); HalftonerFactory::addHalftoner(yourKey, instanciator); // ... } |
Once registered, the factory takes charge of the memory of the Instanciator
s,
so it is strongly suggested that the Instanciator
be created on the
heap and never deleted manually, its memory will be deleted at the end of the
program by the factory. A similar process also happens for the key.
Using the new algorithm, once registered, is as simple as using the built-ins.
The new algorithm is requested by the method HalftonerFactory::getInstance()
with the correct key.
void f() { const char* key = "yourKey"; Halftoner* yourHalftoner = HalftonerFactory::getInstance(key); //... } |
General |
Home |
Sourceforge.net |
About |
News |
Download |
Latest Release |
Other Releases |
For Developers |
Browse CVS |
Documentation |
API |
Design |
TODO |
Known Bugs |
Help |
FAQ |
Report Bug |
Contact |