
Adam Badura wrote:
So, more on topic: is an actual implementation of the proposed color lib in development? ie. is there any code that I can compile and take a look at the decisions being made in context?
I have included only one example (rather simple just to check if everything compiles) because you were hurrying me so much... :)
Sorry if I have been sounding like a arrogant manager or something, I was just tring to say have the code out quickly, cause it's easier to fix design issues /before/ you write 53 classes depending in it. Or at least, I should have. Disclaimer: Below is my _personal_ opinion about the library, anyone who's looked at my previous posts will know that I'm not always the brightest something in the something!
I compiled on Microsoft Visual C++ Toolkit 2003 and Borland C++ 5.5 both compiled without errors.
You should also test with GCC, btw. But two is one more that most test with! (Heck, it's /two/ more than some test with.)
So what do the files containt? Almost everything is in color.hpp because almost everything is template or inline. Now only RGB model is implemented - I wanted to get clear idea what to do and how do it. Then write CMYK or YUV (they should be almost the same) and project conversions. Then write the rest.
I'm not sure CMYK is common as a representation in memory. HSV and YUV are more likely, though. Maybe some of the CIE formats?
Actual project looks like this:
1) We have classes for color data representations (in color.hpp components_rgb, components_32b, components_32b_inv). They are responsible for storing and serving "raw" data. This is done because for a color class (see 3) it does not matter wheather color components have all 8 or 16 bits or how are they placed in memory. Color class (see 3) must know only some details given in components_traits (see 2). Color representation class must serve 6 functions:
TYPE_OF_R r() const; // return R value void r(TYPE_OF_R value); // set R value TYPE_OF_G g() const; // return G value void g(TYPE_OF_G value); // set G value TYPE_OF_B b() const; // return B value void b(TYPE_OF_B value); // set B value
ugh... getter-setter methods. Why don't we just directly access the values? This /is/ only the representation in memory, right?
They should be as fast as only possible. No error checking - color class (see 3) will do it when needed. Also a copy constructor and copy operator should be available but this usually is no problem because default compiler generated one will do. All this is introduced to allow use of library with other libraries (DirectX, OpenGL, native WinAPI, ...) and formats of color storing.
Sensible.
I declared all this classes actually as structures to emphasise on importance of memory model. This classes have to be allocated in memory exactyl as they have data memers to allow worinkg with buffers for and from other devices and libraries.
2) We have template class components_traits which has to be specialized for every representation class (see 1). It serves basic static data of the component:
typedef TYPE_OF_R r_type; typedef TYPE_OF_G g_type; typedef TYPE_OF_B b_type; static const r_type r_min; static const r_type r_max; static const g_type g_min; static const g_type g_max; static const b_type b_min; static const b_type b_max;
OK. (Although I don't know how often min and max for each type will be used. Hue for HSV is about all I can think of, and even then, full range should be more common than [0, 360) ) Requiring a specialisation every time shouldn't be neccesary: template <class Repr> components_traits { typedef typename Repr::r_type r_type; // .. static const r_type r_min = typename template numeric_limits<r_type>::min(); // .. }; Then you just need to define r_type, etc in the representation. Keep the traits class, though. It may be usefull for edge cases and using other interfaces.
this is used be color class (see 3) in conversions correcting values and defining interface. r_type, g_type and b_type must be convertable to long double and must construct from long double. This is no problem in case of standard types. And because this types must (or at least should to be functional) behave like number so requirement is quite natural...
3) We have color class. It is parametrized by representation class (see 1) and its traits (see 2).
Sounds reasonable, however, see below
This class gives 2 way access to color data. First one is unified by type long double. Components are of type long double in range [0; 1]. Actually the can be in any representation but they color class takes care of conversion to long double. Conversion form long double to actual representation is done by the representation (by the type of component) so kind of rounding is determined there and in usual case it will be rounding to nearest representable color (or it should be like this). This is added to allow writing of generic functions taht do not care about actual representation and its limits. But it should be remembered that this is not the fastes access (aspecially in writng) because it requires conversions and mathematical operations. Second is by actual component type (all functions postfixed with _o). This is as fast as possible but not as generic... All (write) functions come in few versions. Version without postfix makes no error chcecking (to be used in releas version of program to make it faster). Version ending in _c corrects values. If value given for component is smaller the minimum for that component minimum is writen instead, if value is larger then maximum then maximum is writen instead. This is aspecially useful for generic functions because rounding in floating point operations can actually take value beyond accepted range. Version ending in _e throws an exception when component value is out of range (or when component is out of range see further remarks). This is intended to be used in debuging application and then in release to replace by non-checking calls. I writed an indexed function where index 0 gives (or sets) R, 1 is for G and 2 is for B. But they only are available in long double version because actual component tpyes me be different.
All this sounds like it could be done cleaner with generic programming. You already are exposing the types of the components: why pass everything though long double? The behaviour of the functions would be better determined by a policy template parameter, IMHO. Less names to keep track of. So: // Default traits = color_traits< rgbx_8 >, like basic_string typedef color_rgb< rgbx_8, colors::exception_policy > my_color; my_color::r_type red_value;
So I think its all by now.
What do I want to do futher? 1) add "nice features" like functions "darker", "brighter" and so on...
Just one "lightness" should do: we have to figure out what canonical colourspace to use, or whether the user can specify it, though.
2) add comparing with or without "toleration range" (colors [0.00000001, 0.0, 0.0] and [0.0, 0.0, 0.0] really do not differ that much aspecially converted to integer based representation...
This is more general a problem than color (unfortunately).
3) add and test useful representations 4) add reading and writing form a string and all web-color as predefined, but this will I do perhabs after completting everything else (actually there is an << operator defined but only to ease testing)
The library shouldn't try to handle every format ever used to store color, of course.
5) add other models and convertions betwean them
A lot of the work will be trying to define how to have a sensible interface to drasticly different color representations. Think STL: a lot of very different ways to contain things, but everything can be used with a single generalised interface. Of course, you can should still be able to access the special abilities of each type (like you can op [] for vector, splice for list, in STL).
So what you think?
It could be very usefull> Colour is one of those things that doesn't want to be tied to a number, though, so you have a bit of work infront of you. I hope (for your sake!) that you know what you've gotten yourself into.
Adam Badura
<snip binary files dumped inline> Looks like something along the line killed the files.