Boudewijn Rempt boud at
Mon Jul 26 18:01:33 CEST 2004

On Monday 26 July 2004 15:12, Casper Boemann wrote:

> 1) Display on screen (obviously), and I think the current way is right on
> the money. But we need to extend it to handle invisible channels.

And compositing layers of different types. One thing I'm working on currently 
-- stalled a bit because I'm waiting for the iterators to get finished and 
four your work on auto-extending layers is selections. Currently, I model a 
selection as a layer with a 256 bit grayscale colour model. Composite this 
with a user-settable opacity, and you have a very clear way of representing 
discontinuous selections. I hope. But for that, it's necessary to be able to 
mix colour models in one image. The groundwork has been done, but I still 
need to do a lot for that.

> 2) Infodocker (showing on screen in numbers what the value under the
> cursorpointer is). This could be accomplished by returning it as a string.
> That way any kind of channel could be shown, since it would be up to the
> colorstrategy to format the string.


> 3)Histograms. Hmm tricky in the general, since a channel could be anything
> (even bitflags perhabs, though that could outwardly be shown as seperate
> channels). On the other hand absolutely no gui should go into the
> colorstrategy, so what to do? 

Not GUI, but some information, like the names of the channels a colour model 
supports and boundary conditions does need to come from the colour strategy.

> Perhaps a function to extract a channel as a 
> double (should preserve all scalar values even longs with full precision).
> How does the histogram function the decide the number of bins. Well
> obviously we cannot have 2^32 bins anyway as that would take up 16 gigs of
> memory. For gui purposes 256 bins should suffice. Functions telling the
> theoretically range of values of the channel should also be provided then.
> That would return 0-255.0 or 0-1.0E256 or something like that. The
> colorstrategy might know that even though it's a double only values 0-1.0
> are valid, and so that is returned.

This is all not too hard to solve; for now we're limited to 8 bits anyway, and 
for the next release, we'll have to downsample a bit. Photogenics doesn't 
offer a histogram, and I wonder whether a histogram is all that necessary for 
high definition images. I intend to use the same widget for a levels dialog, 
by the way.

> 4) Filters and Scripts. I think they should be limited to the compositions
> and other general functions (eg colordistance) we might come up with. But
> perhabs this is not enough for some kinds of manipulation. I don't know
> what might be needed. Insights anyone? please be specific.

Hm. There are a lot of different possibilities to mess with pixels that we 
cannot all foresee, nor want to add to the colour strategy. For instance:

* darken/lighten pixel/channel
* composite
* copy from x,y to x',y'
* compute a value for x,y from the surrounding pixels (for instance when
  scaling or convolving)
* compute something from two different pixels
* create a whole new, exciting pixel to put in place of the current pixel

For some computations, a colour must be converted to HSV and then back, I 

You don't want to push the actual operations that a filter wants to implement 
into the colour strategy -- except for the composition, I think -- because 
that has the following disadvantages:

* Color strategies will get out of sync. Already a problem because the color 
strategies we have currently don't support the same set of composite ops.
* Creating new filters gets pretty hard because they need to add stuff to all 
the colour strategies.

Now if we could define a basic set of building blocks that makes it possible 
to build any imaginable image operation, we should put the building blocks 
into every color strategy. If that proves impossible, we need to expose the 
raw channel data to the outside world. And that'll mean that there will be, 
once we start building 16-bit channels and the like, plugins that cannot work 
with every colour strategy.

For now it's enough that those algorithms that want to mess with pixel data 
can loop over the channels, extract the relevant byte, and mess with that.

Or have a small type hierarchy for channel data -- simpler than one for every 
possible pixel, and a bit like Cyrille's KisQuantum, only more extensive. No 
doubt this can be done with templates, but I understand this a little better.

class KisChannel {

	KisChannel() {};
	virtual ~KisChannel() {};
	Q_UINT8 getDataAsByte() = 0;
	Q_UINT32 getDataAsInt() = 0;
	float getDataAsFloat() = 0;
	double getDataAsDouble() = 0;

	KisChannel &operator+=(const KisChannel &) = 0;
	KisChannel &operator-=(const KisChannel &) = 0;
	KisChannel &operator*=(int) = 0;
	KisChannel &operator*=(long) = 0;
	KisChannel &operator*=(double) = 0;
	KisChannel &operator/=(int) = 0;
	KisChannel &operator/=(long) = 0;
	KisChannel &operator/=(double) = 0;

	bool operator==(const KisChannel &, const KisChannel &) = 0;
	bool operator!=(const KisChannel &, const KisChannel &) = 0;
	KisChannel operator+(const KisChannel &, const KisChannel &) = 0;
	KisChannel operator-(const KisChannel &, const KisChannel &) = 0;
	KisChannel operator*(const KisChannel &, int) = 0;
	KisChannel operator*(int, const KisChannel &) = 0;
	KisChannel operator*(const KisChannel &, long) = 0;
	KisChannel operator*(long, const KisChannel &) = 0;
	KisChannel operator*(const KisChannel &, double) = 0;
	KisChannel operator*(double, const KisChannel &) = 0;
	KisChannel operator-(const KisChannel &) = 0;
	KisChannel operator/(const KisChannel &, int) = 0;
	KisChannel operator/(const KisChannel &, long) = 0;

class KisByteChannel  {

	KisChannel(Q_UINT8 data) {m_data = data;}

	Q_UINT8 m_data;

class KisIntChannel  {

	KisChannel(Q_UINT32 data) {m_data = data;}

	Q_UINT32 m_data;

class KisFloatChannel  {

	KisChannel(float data) {m_data = data;}

	Q_UINT8 m_data;

class KisDoubleChannel  {

	KisChannel(double data) {m_data = data;}

	double m_data;

Now the filters can work on a simple KisChannel, adding, multiplying,
dividing to their heart's content.

> 5) ChannelDocker. Showing the names of channels, visibillity status and
> more. Although not exactly individual pixeldata, it should still be shown
> in an independant manner. I think ChannelInfo does that right?


> 6)Mode change (say from rgb to cmyk). Should go through a single mediator.
> Be it a Lab colorstrategy or perhabs just koColor (not sure if koColor fits
> the following requirements though). The important thing is that no lowering
> of gamut should be imposed by the mediator (only the to and from modes).
> Also it should be colorspace aware (there are unlimited number of rgb
> spaces, so handling one rgb space is not enough - thats why we need lcms)

koColor doesn't fit the bill yet -- but might be expanded, and we can make do 
with it for now. koColor supports (with some bugs):

8 bit lab,
8 bit rgb,
8 bit hsv,
8 bit cmyk

Which should suffice for our first release.

> 7)Colorpicker. Again no restriction of gamut. Should also be colorspace
> aware. The standard ko/kde/qt things may not be enough. We may need to do
> our own. 

We can nick a cmyk colour picker, or at least the guts, from Scribus.

> Also a true palette (like in the real world) would be nice, so the 
> need for our own gui is also needed for other reasons. This is a
> paint/color/imagemanipulation application after all, so things that work
> for a normal office application probably is not enough for us. The best way
> in my opinion is again to go throught a mediator like Lab or xyz

You won't be able to mix colours realistically without some sophisticated 
stuff; the papers I have read have sampled paint with a spectrometer, 
isolated about 100 frequencies and then reduced the number of frequencies 
until the mixing became too unreliable. We cannot simply use their data 
because they only published a paper about the technique. Corel Painter makes 
it look like it can mix paint realistically, but if you look at the colours 
they are simply mixing RGB. (See the link to Impasto on the Krita website: 
I'm in  the train currently, so cannot look it up.)

(By the way, it might even be nice to have, in the future, virtual iterators, 
i.e., iterators that generate a pixel value for a region of pixels, or for a 
virtual pixel that lies between two (or four) pixels.)

Boudewijn Rempt |

More information about the kimageshop mailing list