New special effects library

Zack Rusin zack at kde.org
Fri Dec 15 16:26:32 GMT 2006


Hey,

KImageEffects served its purpose (it's arguable whether it ever had one). We 
obviously need something to easily add special effects to our application and 
it's clear the infrastructure KImageEffects had won't work for the coming 
years.

I've sat down during my vacations last week and started working on a 
replacement. Some of my requirements for it were:

- Support for all kinds of surfaces on which filtering can be applied to. That 
includes:
   o OpenGL textures
   o QImage
   o QPixmap

- Hardware acceleration, 

- Support for filtering chains - meaning be able to simply create a chain of 
filters, e.g. Emboss->Perspective Transform->Blur. Cache that chain and 
execute on demand. 

- Dynamic nature of the whole library. Meaning additional filters can be 
added/removed without binary or even source incompatible changes.

- Support for pure-rendering filters. This is strictly connected to hardware 
acceleration. In a lot of cases you just want to say "render this with that 
effect" and don't really want to get the result in your application, you just 
want to render it. With OpenGL rendering with a filter can be a few hundred 
of times faster than rendering/fetching of the result. So ability to 
just "attach" rendering filters, without forcing any client side data 
transmission is very important for proper/efficient hardware acceleration.

- Ability to add new surfaces as both source and destination of all the 
effects. This is to be able to connect the effects to the objects which 
Phonon or Krita are rendering to with very simple hooks. 

- Intelligent filters. Meaning as a user you shouldn't have to care what's is 
happening under the hood - the framework should decide the fastest way 
possible of filtering your surfaces. For example if you have a huge QImage 
and you want it blurred, and the framework happens to have a Gaussian blur 
implemented in GLSL it will magically convert your image to an OpenGL texture 
and use OpenGL for the rest of the operation, without you ever noticing. 


Having said that. I have a basic version of a library implementing it. Here's 
very simply what is happening:
The top-level compositing object is called Layer. Layer is a wrapper around 
the rendering surface (QImage, QPixmap, OpenGL texture, etc). It knows how to 
convert between all of them. 
The most important methods from Layer are:
- bool Layer::add(Filter &); which adds a new Filter to the filter chain for 
the given layer
- various void Layer::draw() methods which loosly coorespond to all 
QPainter::draw(QImage) methods,
- Layer Layer::composition() const, which actually returns the result of the 
composition, note that if you want to just render your Layer with some 
filters added to it, you just call draw on it, and never need to call 
composition().

The filters are encapsulated by the Filter object. One creates a Filter with a 
string name of the filter. Filter names are like paths, where the first part 
is the group and the second part is algorithm name, e.g. "/blur/gaussian" is 
a full filtername. You can create Filter with just groups, e.g.:
Filter f; //creates null filter, use isNull to query it
Filter f("/blur/gaussian"); //creates a gaussian blur filter
Filter f("/blur"); //creates a blurring filter - framework will pick the best
                         //one for your as soon as you add it to a Layer

Those are the basics. So if you'd like to blur an a hello.png you'd do:
Layer layer("hello.png");
Filter f("/blur");
f.setArgument("radius", 5); //Filter has possibleArguments method
                                   //which returns all acceptable 
                                   //arguments one can pass to this Filter
layer.add(f);
.... and now...
QPainter p(...);
layer.draw(&p, 0, 0); // renders results
... or ...
Layer result = layer.composition(); //returns result
QImage img = result.toImage(); //converts to a QImage
img.save("blurred.png");  //saves result to a png

"But I just want to blur a QImage you say", fear not, for the lazy who don't 
care about all this fancy stuff and just want to filter a QImage and get a 
result there's a simpler way :
QImage img("hello.png");
if (KImageFx::applyFilter(&img, "/blur", "radius=10")) {
     //success
     img.save("blurred.png");
}

I created two simple examples. One is trivial and just uses applyFilter to 
blur an image given on the command line. The other is an application in which 
you can create filter chains and view the results in real-time. It's kinda 
like QuartCompositor in OSX which made a lot of people loose their minds, but 
cooler of course ;) A very early screenshot is here:
http://chaos.troll.no/%7Ezrusin/kimagefx.png
(yes, there's only one filter there now ;) but you can already see the basics)

Ah, and since my internet connection is very flaky at the moment and i've been 
havily hacking on it I'm using git right now, so if you want to give this a 
try. And I strongly suggest you do! Do:
git clone http://ktown.kde.org/~zrusin/dev/kimagefx.git
once that's done enter kimagefx and type qmake && make; There's examples 
directory with both examples. 

z




More information about the kde-core-devel mailing list