Pixel operations and colorspaces
Boudewijn Rempt
boud at valdyas.org
Mon Aug 15 20:06:28 CEST 2005
I'm getting bogged down when trying to work with the colormodel classes --
they are getting too big, and I'm not succeeding in making it possible to
warn users when they try a filter or another operation that isn't natively
supported. Besides, adding a new operation is a lot of work and means adding
code all over the place.
I think the following design will help us achieve more flexibility, smaller
classes and a clearer and safer user interface.
I want to define a class KisPixelOp which is the abstraction of the idea of
messing with one or more pixels as expressed by an array of Q_UINT8's.
A given colorstrategy can provide a given pixelop natively, or return a
default implementation; a default implementation implements the same
algorithm, but may have to downscale or upscale the pixel data or convert it
to a colorspace that may have a smaller gamut.
If a filter or a plugin or even a core part of Krita needs to mess with some
pixels, it will ask the colormodel of the current paint device for an
implementation; it then needs to downcast the implementation to the needed
subclass. For instance:
// The cast is necessary because we need to be able to call the
// specialized process method which may have any amount and type of
// parameters. No need for genericity here, because we _know_ what we
// want :-).
KisApplyAdjustmentOp * adjustop =
dynamic_cast<KisApplyAdjustmentOp*>(dev->colorStrategy()->getOp("applyAdjustment");
if (!adjustop) {
KMessageBox::error(0, i18n("Brightness/contrast adjustment is not possible
with this image type.");
}
if (!adjustop->isNative()) {
KMessageBox::questionYesNo(0, i18n("Brightness/contrast adjustment may
cause information loss when used with this image type. Do you want to
continue?"));
}
KisBrightnessContrastFilterConfiguration* configBC =
(KisBrightnessContrastFilterConfiguration*) config;
KisColorAdjustment *adj =
src->colorStrategy()->createBrightnessContrastAdjustment(configBC->transfer);
KisRectIteratorPixel dstIt = dst->createRectIterator(rect.x(), rect.y(),
rect.width(), rect.height(), true );
KisRectIteratorPixel srcIt = src->createRectIterator(rect.x(), rect.y(),
rect.width(), rect.height(), false);
setProgressTotalSteps(rect.width() * rect.height());
Q_INT32 pixelsProcessed = 0;
while( ! srcIt.isDone() && !cancelRequested())
{
Q_UINT32 npix;
npix = srcIt.nConseqPixels();
// change the brightness and contrast
adjustOp->applyAdjustment(srcIt.oldRawData(), dstIt.rawData(), adj,
npix);
srcIt+=npix;
dstIt+=npix;
pixelsProcessed++;
setProgress(pixelsProcessed);
}
If a plugin wants to add a new pixelop, it can create one or more
implementations for one or more colormodels and register them with the
colormodels. You can also implement a generic op that converts pixel data
using toQColor and nativeColor, for instance, or through XYZ, applies the
operation and then converts it back.
As an API for registring pixelops I think it'd work to add something like this
to KisColorSpaceRegistry:
/**
* Add a new pixelop to the specified colorspace. If default is
* true, then this pixelop will be used whenever any colorspace doesn't
* have a specific implementation. If that is the case, the pixelop needs
* to take care of all conversions between colormodels, so it isn't any old
* pixel op that can handle the responsibilty.
*/
addPixelOp(KisID colorspace, KisPixelOp * op);
/**
* Retrieve a default pixel op. This is called by the colormodels, not by
* filters or other clients
*/
getPixelOp(KisID * id);
No doubt I'll encounter some hitches with this scheme, so if anyone can point
them out beforehand, that'd be helpful. But I think that, all things
considered, this is a pretty sound scheme.
--
Boudewijn Rempt
http://www.valdyas.org/fading/index.cgi
More information about the kimageshop
mailing list