June 24, 2015
On 24 June 2015 at 03:11, Adam D. Ruppe via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Tuesday, 23 June 2015 at 16:14:59 UTC, Marc Schütz wrote:
>>
>> But that's more an argument against putting anything _except_ the basic definitions into package.d, no? Then you can always exclude the more specific stuff whenever you need it, and those modules themselves can publicly import package.d.
>
>
> What if you want the basic definitions alone to build something off of?
>
> If I want to write an image library that can share pixels with your image library, I might import std.color just to get the pixel format. I don't need the list of colors nor any algorithms, I just want to share the basic type so our two libraries can pass data back and forth.
>
> So I write like
>
> RGBA8[] readImage() {}
>
> With the std.color functions, some other library can now take that pixel array and convert it or whatever they need to do. Great, you can use my thing pretty easily.

Right, and this was what I had in mind.
I think the average user would want to: import std.color, and that's
it. They will probably want RGB8 or RGBA8.
Most users will never touch anything else in the API, so using
package.d as an "import absolutely everything" doesn't seem useful at
all to me.
Also, a use cases involving the Lab colour space almost certianly has
absolutely nothing to do with an application involving Y'UV.
I think those advanced colour space users will happily import the
package they care about.

> But I don't need any conversions myself. I don't do transformations. I don't use named colors, blending functions, or anything else. (Maybe my image format is extremely simple.)
>
>
> So pulling the rest of the library would waste compile time and binary space. Especially if a user wanted my extremely simple image format exactly because they were short on time and space.
>
>
>
> So ideally, my module would ONLY import std.color.basic_types or something like that.... but alas, RGBA8 is defined in package.d, so if I want it, whether I like it or not, I just pulled half the std.color library....

Well, 'half' is a bit of an exaggeration. There will be a lot more
that's not visible now, and I don't expect package.d will ever do
anything more than it does now.
I'm in favour of trimming package.d though. What do you suggest?

Will those aliases for common colour types cause a significant compiler performance hit if they are unreferenced? Surely the compiler won't eagerly resolve those aliases and instantiate all those colour types in the event they are never referenced?

RGB is the common case, and it could be that that's the only one
that's present in package.d... but RGB is tricky though; it's the one
that people will almost certainly want 95% of the time, but it's also
the most complicated by far, and has the most associated detail.
I don't know how to effectively trim that for the common use case, but
I was banking on the compiler not eagerly resolving all the conversion
stuff in the event the case operator is never actually invoked?
Am I wrong about the compiler? Is it more eager than I expect?


> which just pulled std.traits and std.typecons, which, thankfully, didn't import anything else, but that's not the case for so many Phobos modules.

I was very careful to limit run-away phobos dependencies.
I really care about this, and I've tried to limit import scope in all locations.


> This layout isn't bad today, the std.color in the PR is pretty small and pretty lazy thanks to the templates and local imports in them, but I still want to set a precedent in Phobos of untangling the web of dependencies by moving as much independent code as reasonably possible to independent modules.

I think I've (deliberately) done this to the best extent I am able. If you can suggest improvements, I'm all ears.

June 24, 2015
On Wednesday, 24 June 2015 at 04:47:35 UTC, Manu wrote:
> They work fine. Just cast between color structs with different component orders:
>
> BGR8 a = Color.white;
> RGB8 b = a; // <- did swizzle
>
> Is there a specific api you miss?
>
>
> On 24 June 2015 at 05:34, Tofu Ninja via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>> On Tuesday, 23 June 2015 at 14:58:35 UTC, Manu wrote:
>>>
>>> https://github.com/D-Programming-Language/phobos/pull/2845
>>>
>>> I'm getting quite happy with it.
>>> I think it's a good and fairly minimal but useful starting point.
>>>
>>> It'd be great to get some reviews from here.
>>
>>
>> Swizzels would be a nice addition.

Ahh, I was thinking more about swizzling the color channels themselves, not just conversion to different color layouts.
RGB8 a = RGB8(0,1,2);
RGB8 b = a.rbg;
assert(b == RGB8(0,2,1));
June 24, 2015
On Tuesday, 23 June 2015 at 14:58:35 UTC, Manu wrote:
> https://github.com/D-Programming-Language/phobos/pull/2845
>
> I'm getting quite happy with it.
> I think it's a good and fairly minimal but useful starting point.
>
> It'd be great to get some reviews from here.

Some points about blend/lerp:

- Using operation on rgb components usually doesn't give the expected result. It should be done, for example, blending hue saturation and brightness, rather than Red, Blue, Green (or at least using toLinear?)

- What happens if srcFactor + destFactor != 1? Maybe we should normalize srcFactor and destFactor on 0..1 using something like:
normSrcFactor = srcFactor/(srcFactor+DestFactor);
normDestFactor = destFactor/(srcFactor+DestFactor);

- Does it work with RGB only?
June 24, 2015
On 24 June 2015 at 17:18, Tofu Ninja via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Wednesday, 24 June 2015 at 04:47:35 UTC, Manu wrote:
>>
>> They work fine. Just cast between color structs with different component orders:
>>
>> BGR8 a = Color.white;
>> RGB8 b = a; // <- did swizzle
>>
>> Is there a specific api you miss?
>>
>>
>> On 24 June 2015 at 05:34, Tofu Ninja via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>>
>>> On Tuesday, 23 June 2015 at 14:58:35 UTC, Manu wrote:
>>>>
>>>>
>>>> https://github.com/D-Programming-Language/phobos/pull/2845
>>>>
>>>> I'm getting quite happy with it.
>>>> I think it's a good and fairly minimal but useful starting point.
>>>>
>>>> It'd be great to get some reviews from here.
>>>
>>>
>>>
>>> Swizzels would be a nice addition.
>
>
> Ahh, I was thinking more about swizzling the color channels themselves, not
> just conversion to different color layouts.
> RGB8 a = RGB8(0,1,2);
> RGB8 b = a.rbg;
> assert(b == RGB8(0,2,1));

Ah okay.
Yeah, it's an interesting idea. It's only applicable to RGB colours.
What's a bit awkward, is it's not entirely clear where the result of
the swizzle is assigned? Is the result of the swizzle assigned to the
colours present in the order of appearance in the current layout?
BGR8 a = Color.white;
BGR8 b = a.rbg;

is that: b=r, g=b, r=g, or is it r=r, g=b, b=g? Surely it's the former, but that means you need to be conscious of the colour layout whenever you perform a swizzle; ie, it will do different things for different layouts...
June 24, 2015
On 24 June 2015 at 17:58, Andrea Fontana via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Tuesday, 23 June 2015 at 14:58:35 UTC, Manu wrote:
>>
>> https://github.com/D-Programming-Language/phobos/pull/2845
>>
>> I'm getting quite happy with it.
>> I think it's a good and fairly minimal but useful starting point.
>>
>> It'd be great to get some reviews from here.
>
>
> Some points about blend/lerp:
>
> - Using operation on rgb components usually doesn't give the expected result. It should be done, for example, blending hue saturation and brightness, rather than Red, Blue, Green (or at least using toLinear?)

Cast your input to a linear type (or whatever colourspace you prefer)
before lerping. User needs to make the trade-off between efficiency
(approximation) and precision (in linear space).


> - What happens if srcFactor + destFactor != 1? Maybe we should normalize
> srcFactor and destFactor on 0..1 using something like:
> normSrcFactor = srcFactor/(srcFactor+DestFactor);
> normDestFactor = destFactor/(srcFactor+DestFactor);

I don't see any reason they should require to add to one. HDR is a thing. Lerp is a mathematical function, and while t=[0..1] is conventional, it's not enforced, or even necessary. I think user should make a decision to require normalisation.


> - Does it work with RGB only?

No, but like, kinda. Lab interpolates very well (by design). Technically, all spaces lerp, just that results should be expected with respect to the colour space you are working in.


I was thinking of removing those functions because they're a bit hard
to define concretely, for some of the reasons you say, and others.
I left them there to gather opinions and comments. Also to identify
missing functions if people find them to add value.
June 24, 2015
On Tuesday, 23 June 2015 at 14:58:35 UTC, Manu wrote:
> https://github.com/D-Programming-Language/phobos/pull/2845
>
> I'm getting quite happy with it.
> I think it's a good and fairly minimal but useful starting point.
>
> It'd be great to get some reviews from here.

My experience (my previous job involved designing a GPU based color grading machine) is that the more you study colors, the more you realize how rich this domain is.

To me there are different features corresponding to different domains :
- spectral/multispectral colors (Satellite imagery, Medical imagery, Spectrometry), also useful for monitor calibration.
- vfx industry will want
 - sRGB, Adobe RGB with non linear gradation law (piecewise linear+gamma for sRGB)
 - camera colorspaces (Alexa, PanaLog, Gamma)
 - film colorspaces (density encoded, cineon / kodak log)
 - broadcast colorspaces YUV, YCbCr, YPbPr, DCI P3
 - physical color space XYZ (CGI rendering)
- print industry will want CMYK
- game industry will want alpha support with or without premultiplication, HSL
- academic will want perceptual colorspace (Lab, L*a*b*), distance expresses how different colors are perceived.
...

So to me there are several things to consider :
- the number of channels, their semantics, the type they use (8/10/16/32/64 bits, int, unsigned, float...)
- some format packs channels, most common form of DPX is RGB10A2 bits packed in a 32 bit word (10bits red, 10bits green, 10 bits blue, 2 bits alpha) the word might be little/bigendian
- the gradation law for those channels (linear, sRGB, log, semilog, lookup table, ...)
- alpha is a special beast when composing colors
- when the signal is captured/displayed the gamut comes into play (space of colors the device can handle) the color value can be correlated with the characteristics of the light : white balance, signal quantification, white point, black point, channel characteristics (spectrum)
- moving between colorspaces is not necessary reversible (HSL <-> RGB). It involves non trivial logic (1D LUT, 3D LUT, matrix, piecewise functions, log/pow) that also makes the transformation lossy.

Manu, I understand that you don't want this library to handle very possible cases what is your rationale for what's useful / not necessary ? I suppose most users will simply manipulate sRGB jpeg/png.
June 24, 2015
On 24 June 2015 at 20:11, Guillaume Chatelet via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Tuesday, 23 June 2015 at 14:58:35 UTC, Manu wrote:
>>
>> https://github.com/D-Programming-Language/phobos/pull/2845
>>
>> I'm getting quite happy with it.
>> I think it's a good and fairly minimal but useful starting point.
>>
>> It'd be great to get some reviews from here.
>
>
> My experience (my previous job involved designing a GPU based color grading machine) is that the more you study colors, the more you realize how rich this domain is.

Indeed, it's a very deep hole ;)
This is a library that could easily suffer literally endless feature
creep, I just want to keep it reasonable and practical to start with.

I've done CG for a decade or so, and some research related colour activity (satelite,medical,thermal imagery; my current job)


> To me there are different features corresponding to different domains :
> - spectral/multispectral colors (Satellite imagery, Medical imagery,
> Spectrometry), also useful for monitor calibration.
> - vfx industry will want
>  - sRGB, Adobe RGB with non linear gradation law (piecewise linear+gamma for
> sRGB)

Check, done.

>  - camera colorspaces (Alexa, PanaLog, Gamma)

I don't think this will come up in the near term.

>  - film colorspaces (density encoded, cineon / kodak log)

Likewise.

>  - broadcast colorspaces YUV, YCbCr, YPbPr, DCI P3

On the short-list.

>  - physical color space XYZ (CGI rendering)

Done.

> - print industry will want CMYK

This requires ICC interaction. There's OS involvement there. It's a fair way down the list.

> - game industry will want alpha support with or without premultiplication,

I don't think pre-multiplied alpha is a detail that the colour itself
really needs to know about.
I thought about this, but I think it's a niche and unnecessary
complexity. Read; over-engineering.

> HSL

Easy, on the short list.

> - academic will want perceptual colorspace (Lab, L*a*b*), distance expresses how different colors are perceived.

On the short-ish list. This requires quite a lot of care, and it takes time to get it just right.

> ...

I'm aware of all the points on your list. They aren't being overlooked.


> So to me there are several things to consider :
> - the number of channels, their semantics, the type they use (8/10/16/32/64
> bits, int, unsigned, float...)
> - some format packs channels, most common form of DPX is RGB10A2 bits packed
> in a 32 bit word (10bits red, 10bits green, 10 bits blue, 2 bits alpha) the
> word might be little/bigendian

Check. My background is realtime rendering ;)
I know what I'm doing here.

> - the gradation law for those channels (linear, sRGB, log, semilog, lookup
> table, ...)

All present or planned.

> - alpha is a special beast when composing colors

The colour type itself can't reasonably make any useful decision for the user here, this is related to the functions that combine colours.

> - when the signal is captured/displayed the gamut comes into play (space of colors the device can handle) the color value can be correlated with the characteristics of the light : white balance, signal quantification, white point, black point, channel characteristics (spectrum)

On the mid-range-list. Chromatic adaptation is necessary for Lab at least. This is mostly ancillary functionality though, it lives beside the present offering.

> - moving between colorspaces is not necessary reversible (HSL <-> RGB). It
> involves non trivial logic (1D LUT, 3D LUT, matrix, piecewise functions,
> log/pow) that also makes the transformation lossy.

Yup. Can only do the best possible for each conversion. People making use of those colour spaces and performing such conversions understand these details.


> Manu, I understand that you don't want this library to handle very possible cases what is your rationale for what's useful / not necessary ? I suppose most users will simply manipulate sRGB jpeg/png.

Nothing is off the table. I start with RGB, since it's the 99% case.
That leads to XYZ for RGB conversions, and HSV is also very easy from
there. I had planned for that to be the initial offering.
I have made a start on Y'UV, Lab, and the compressed colour formats
typical in realtime gfx.
Advanced features are best driven by demand. There's no point
supporting scientific colour analysis if there's nobody to use it,
while a video professional sits waiting for broadcast related stuff...

I think the overwhelming use will be for loading+displaying images,
and rendering using opengl/dx/whatever.
Therefore, sRGB with all gamma conventions supported. Other RGB colour
spaces are easy from there; just definitions in a table (done, but
need tests).
PackedRGB is next (numerous requests already), then probably HSV.
After that, it's open to request. I'd like to work on some HDR related tools.

I can see a pretty clear distinction between what's *necessary* in a
standard colour library (ie, to facilitate other libraries), and
'would be nice' for niche or expert use :)
Don't worry, I'm an optics nerd!
June 24, 2015
On Wednesday, 24 June 2015 at 11:02:04 UTC, Manu wrote:
> Don't worry, I'm an optics nerd!

Well I can tell by reading the PR already ;)
I just wanted to make sure :
- nothing important was overlooked
- what was the scope ot the proposal

Now I think my main concern is about conversions getting out of control (there's already quite a few static ifs).

Also do you plan on adding SIMD specializations ?

On a related note, I designed a player a few years ago which relied on GLSL shaders for the colorspace conversions, so it might be good to compare the implementations (https://github.com/mikrosimage/duke/blob/develop/src/duke/engine/ColorSpace.cpp#L38). My secret dream is to reimplement it in D : C++ simply is too slow to develop with and it's a single person project so it's stale basically...
June 24, 2015
On a tangent, I need a name for the struct that will represent HSL/HSV/HSI/HCY.
They're all basically identical, and might as well be a parameter to a
shared type... but I can't think of a name for that type! >_<
I can't reasonably call it any of those or it would be confused,
rather, each of those would be an alias for an instantiation of each
type.
I'm thinking along the lines of PolarRGB? It's not really that though.
I can't think of any other good names.
alias HSL = PolarRGB!(Type.HSL);

Naming things is so hard!
June 24, 2015
I probably didn't express myself very clearly, with the double negation...

What I wanted to suggest is to put into package.d _only_ the very minimum that you will always need, e.g. the basic structures. Example:

std/
  color/
    package.d        # only very basic stuff
    definitions.d    # enums like red/green/teal
    transform.d      # color transformation functions,
                     # contains `public import std.color;`
    all.d            # public import ... everything ...;