Started in late 2002, OOo’s module basegfx
is now a pretty mature collection of data structures and algorithms
for graphics processing. The set of exported headers sport abstract
data types such as:
- points, vectors, boxes, ranges, bezier curves
- matrices
- polygons and collections of polygons (“poly-polygons”)
- 1D, 2D, 3D
- integer and double-precision floating point
- a poly-polygon clipper (comparable to what
gpc is doing) - a poly-polygon triangulator (convert a polygon to triangles, which
can be fed to a GPU) - a function to generate stroked paths from a given polygon
- plus a lot of basic, but very useful stuff (like svg im/export, scan
conversion, arc and circle generation, etc.)
</ul
Those are (where sensible) provided in the flavors
In addition, especially the polygon ADTs are shipped with a set of associated algorithms (provided as free functions, instead of
member functions):
What’s missing, though, is everything related to bitmaps. That’s where
basebmp
comes into play, started a few weeks ago and set to provide for pixel
processing, what basegfx provides for the symbolic graphics
primitives.
I’ve initially started this work by using AGG, but quickly found out that
adding pixel formats other than integer true color ones is pretty hard
(Because the code is largely undocumented. Because the assumption that
pixel values can be modified by shift left and right operations, and
are PODs (i.e. non-class types) is all over the place. And because
basically, a way to somehow get a hold to the famous extra level of indirection is
missing. Which, as usual, would have solved this software engineering
problem). Instead of starting from scratch, we’ve based this on vigra, a framework for generic image processing, which provides an elegant way to add ‘special processing’ before an actual pixel gets assigned a value.
In order to really get to the point here, I first need to sketch the
way generic bitmap processing works: it’s the idea of separating data
access and the actual bitmap manipulation algorithm, using C++
templates. The concept is borrowed from the STL – bitmap pixel can be
accessed by (two-dimensional) iterators, which in a very basic sense
behave like a pointer:
while( i!=end ) *i++ = rand();
If i
is a bitmap iterator, the pixel will be set to
random values with this algorithm. The type of i can be chosen freely,
and so can the actual pixel format of the bitmap. If one wants to
e.g. add palette lookup to this algorithm (or scale the random values
into the appropriate color range) without changing the algorithm’s code, either extremely ugly hacks
involving proxy objects are necessary (because operator*() is expected
to return an lvalue, which gets assigned the new value directly), or
one needs a direct way to ‘see’ both the iterator and the new value
prior to assignment:
while( i!=end ) acc.set(i++, rand());
The acc
variable is a pixel accessor in vigra lingo,
which takes the iterator and the new value, and accesses the
corresponding pixel. Now, adding palette lookup, scaling, blending,
mask operations and much more is as easy as providing a different
accessor to the algorithms is. Plus, it’s completely orthogonal to
both the iterator implementation, and the algorithm used. That means,
you define a set of iterators (for packed-pixel images, for r8g8b8
images, for r5g6r5 images), a set of accessors (for true color pixel,
for palette lookup, for blitting through a binary mask), and a set of
algorithms. And you combine all those freely, i.e. you have the
cartesian product of variations to choose from.