Bug in Form>>#asFormOfDepth:?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Bug in Form>>#asFormOfDepth:?

Christoph Thiede

Hi all,


consider the following example (print it):


"Example 1"

f := Form extent: 1 asPoint depth: 1.
f colorAt: 0 @ 0 put: Color red.
g := f asFormOfDepth: 2.
g colorAt: 0 @ 0


Expected output: Color red.

Actual output: Color black!


Other examples:


"Example 2"

f := Form extent: 1 asPoint depth: 1.
f colorAt: 0 @ 0 put: Color red.
g := f asFormOfDepth: 32.
g colorAt: 0 @ 0 "--> (Color r: 0.0 g: 0.0 b: 0.004)"


"Example 3"

f := Form extent: 1 asPoint depth: 16.
f colorAt: 0 @ 0 put: Color red.
g := f asFormOfDepth: 32.
g colorAt: 0 @ 0 "--> (Color r: 0.973 g: 0.0 b: 0.0)"

I am not familiar with color depths, but afaik Color red could be stored exactly using only 1 bit? Do I misunderstand the concept or is this really a bad output?

(I came across to this when performing #collectColors: on an 8 bit ColorForm loaded from disk, which did not work as expected.)

Best,
Christoph


Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: Bug in Form>>#asFormOfDepth:?

Tobias Pape
Hi Christoph,

> On 09.09.2019, at 13:25, Thiede, Christoph <[hidden email]> wrote:
>
> Hi all,
>
> consider the following example (print it):
>
> "Example 1"
> f := Form extent: 1 asPoint depth: 1.
> f colorAt: 0 @ 0 put: Color red.
> g := f asFormOfDepth: 2.
> g colorAt: 0 @ 0
>
> Expected output: Color red.
> Actual output: Color black!

No, Forms of depth 1 are black and white, and of depth2 are gray.

>
> Other examples:
>
> "Example 2"
> f := Form extent: 1 asPoint depth: 1.
> f colorAt: 0 @ 0 put: Color red.
> g := f asFormOfDepth: 32.
> g colorAt: 0 @ 0 "--> (Color r: 0.0 g: 0.0 b: 0.004)"

yes, because you go from black/white to 32bit. I would have expected r0g0b0, but there might some rounding go on.

>
> "Example 3"
> f := Form extent: 1 asPoint depth: 16.
> f colorAt: 0 @ 0 put: Color red.
> g := f asFormOfDepth: 32.
> g colorAt: 0 @ 0 "--> (Color r: 0.973 g: 0.0 b: 0.0)"



Something's wonky here!
If we do

        (((Form extent: 1 asPoint depth: 16)
                colorAt: 0 @ 0 put: Color red)
                asFormOfDepth: 32)
        pixelValueAt: 0@0

we get
        4294443008 (aka 0xFFF80000)  which is a 32bit value.
But the meaning is

        11111111 11111000 00000000 00000000
        ^ alpha  ^ r      ^ g      ^ b

which means that the r component is not  "upscaled" during the #asFormOfDepth: process o.O (see PS)




>
> I am not familiar with color depths, but afaik Color red could be stored exactly using only 1 bit? Do I misunderstand the concept or is this really a bad output?

No, the first bit depth to support red is 4 bit.

Have a look at Color class>>colorFromPixelValue: p depth: d

BTW: You can use a ColorForm to work with your own palette, so that you can have for example a 1-bit form with 1=yellow & 0=red…


Best regards
        -Tobias

>
> (I came across to this when performing #collectColors: on an 8 bit ColorForm loaded from disk, which did not work as expected.)
>
> Best,
> Christoph

PS: PS:
Color red is r:1.0 g:0.0 b:0.0 but stored in a different fashion:

Color comment:
"
Think of Color's instance variables as:
        r amount of red, a Float between 0.0 and 1.0.
        g amount of green, a Float between 0.0 and 1.0.
        b amount of blue, a Float between 0.0 and 1.0.
(But, in fact, the three are encoded as values from 0 to 1023 and combined in a single integer, rgb.  The user does not need to know this.)
"
that means "Color red" is stored as 0x3FF00000 or,

1111111111 0000000000 0000000000
^ red      ^ green    ^ blue

that makes 10 bit per component.

However, in the 16 bit form we have only 5 bit per component, so,

        f := Form extent: 1 asPoint depth: 16.
        f colorAt: 0 @ 0 put: Color red.
        f pixelValueAt: 0@0.

yields 0x7C00 aka

11111 00000 00000
^ r   ^ g   ^ b


Reply | Threaded
Open this post in threaded view
|

Re: Bug in Form>>#asFormOfDepth:?

Christoph Thiede

Hi Tobias,


oops, I mistook the depth with the number of bits per channel. Sorry and many thanks for your explanations!


How would one fix the upscaling issue? Form>>#colormapIfNeededFor: returns nil in example 3, the comment in Color>>#colorMapIfNeededFrom:to: states this task is delegated to BitBlt. Is this comment wrong or is the defect in the primitive called that is in BitBlt>>#copyBits?


Best,

Christoph



Von: Squeak-dev <[hidden email]> im Auftrag von Tobias Pape <[hidden email]>
Gesendet: Montag, 9. September 2019 14:56 Uhr
An: The general-purpose Squeak developers list
Betreff: Re: [squeak-dev] Bug in Form>>#asFormOfDepth:?
 
Hi Christoph,

> On 09.09.2019, at 13:25, Thiede, Christoph <[hidden email]> wrote:
>
> Hi all,
>
> consider the following example (print it):
>
> "Example 1"
> f := Form extent: 1 asPoint depth: 1.
> f colorAt: 0 @ 0 put: Color red.
> g := f asFormOfDepth: 2.
> g colorAt: 0 @ 0
>
> Expected output: Color red.
> Actual output: Color black!

No, Forms of depth 1 are black and white, and of depth2 are gray.

>
> Other examples:
>
> "Example 2"
> f := Form extent: 1 asPoint depth: 1.
> f colorAt: 0 @ 0 put: Color red.
> g := f asFormOfDepth: 32.
> g colorAt: 0 @ 0 "--> (Color r: 0.0 g: 0.0 b: 0.004)"

yes, because you go from black/white to 32bit. I would have expected r0g0b0, but there might some rounding go on.

>
> "Example 3"
> f := Form extent: 1 asPoint depth: 16.
> f colorAt: 0 @ 0 put: Color red.
> g := f asFormOfDepth: 32.
> g colorAt: 0 @ 0 "--> (Color r: 0.973 g: 0.0 b: 0.0)"



Something's wonky here!
If we do

        (((Form extent: 1 asPoint depth: 16)
                colorAt: 0 @ 0 put: Color red)
                asFormOfDepth: 32)
        pixelValueAt: 0@0

we get
        4294443008 (aka 0xFFF80000)  which is a 32bit value.
But the meaning is

        11111111 11111000 00000000 00000000
        ^ alpha  ^ r      ^ g      ^ b

which means that the r component is not  "upscaled" during the #asFormOfDepth: process o.O (see PS)




>
> I am not familiar with color depths, but afaik Color red could be stored exactly using only 1 bit? Do I misunderstand the concept or is this really a bad output?

No, the first bit depth to support red is 4 bit.

Have a look at Color class>>colorFromPixelValue: p depth: d

BTW: You can use a ColorForm to work with your own palette, so that you can have for example a 1-bit form with 1=yellow & 0=red…


Best regards
        -Tobias

>
> (I came across to this when performing #collectColors: on an 8 bit ColorForm loaded from disk, which did not work as expected.)
>
> Best,
> Christoph

PS: PS:
Color red is r:1.0 g:0.0 b:0.0 but stored in a different fashion:

Color comment:
"
Think of Color's instance variables as:
        r       amount of red, a Float between 0.0 and 1.0.
        g       amount of green, a Float between 0.0 and 1.0.
        b       amount of blue, a Float between 0.0 and 1.0.
(But, in fact, the three are encoded as values from 0 to 1023 and combined in a single integer, rgb.  The user does not need to know this.)
"
that means "Color red" is stored as 0x3FF00000 or,

1111111111 0000000000 0000000000
^ red      ^ green    ^ blue

that makes 10 bit per component.

However, in the 16 bit form we have only 5 bit per component, so,

        f := Form extent: 1 asPoint depth: 16.
        f colorAt: 0 @ 0 put: Color red.
        f pixelValueAt: 0@0.

yields 0x7C00 aka

11111 00000 00000
^ r   ^ g   ^ b




Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: Bug in Form>>#asFormOfDepth:?

Tobias Pape

> On 09.09.2019, at 15:53, Thiede, Christoph <[hidden email]> wrote:
>
> Hi Tobias,
>
> oops, I mistook the depth with the number of bits per channel. Sorry and many thanks for your explanations!
>
> How would one fix the upscaling issue? Form>>#colormapIfNeededFor: returns nil in example 3, the comment in Color>>#colorMapIfNeededFrom:to: states this task is delegated to BitBlt. Is this comment wrong or is the defect in the primitive called that is in BitBlt>>#copyBits?
>
No, that part is only for cross-conversion of Forms and ColorForms
-t

> Best,
> Christoph
>
> Von: Squeak-dev <[hidden email]> im Auftrag von Tobias Pape <[hidden email]>
> Gesendet: Montag, 9. September 2019 14:56 Uhr
> An: The general-purpose Squeak developers list
> Betreff: Re: [squeak-dev] Bug in Form>>#asFormOfDepth:?
>  
> Hi Christoph,
>
> > On 09.09.2019, at 13:25, Thiede, Christoph <[hidden email]> wrote:
> >
> > Hi all,
> >
> > consider the following example (print it):
> >
> > "Example 1"
> > f := Form extent: 1 asPoint depth: 1.
> > f colorAt: 0 @ 0 put: Color red.
> > g := f asFormOfDepth: 2.
> > g colorAt: 0 @ 0
> >
> > Expected output: Color red.
> > Actual output: Color black!
>
> No, Forms of depth 1 are black and white, and of depth2 are gray.
>
> >
> > Other examples:
> >
> > "Example 2"
> > f := Form extent: 1 asPoint depth: 1.
> > f colorAt: 0 @ 0 put: Color red.
> > g := f asFormOfDepth: 32.
> > g colorAt: 0 @ 0 "--> (Color r: 0.0 g: 0.0 b: 0.004)"
>
> yes, because you go from black/white to 32bit. I would have expected r0g0b0, but there might some rounding go on.
>
> >
> > "Example 3"
> > f := Form extent: 1 asPoint depth: 16.
> > f colorAt: 0 @ 0 put: Color red.
> > g := f asFormOfDepth: 32.
> > g colorAt: 0 @ 0 "--> (Color r: 0.973 g: 0.0 b: 0.0)"
>
>
>
> Something's wonky here!
> If we do
>
>         (((Form extent: 1 asPoint depth: 16)
>                 colorAt: 0 @ 0 put: Color red)
>                 asFormOfDepth: 32)
>         pixelValueAt: 0@0
>
> we get
>         4294443008 (aka 0xFFF80000)  which is a 32bit value.
> But the meaning is
>
>         11111111 11111000 00000000 00000000
>         ^ alpha  ^ r      ^ g      ^ b
>
> which means that the r component is not  "upscaled" during the #asFormOfDepth: process o.O (see PS)
>
>
>
>
> >
> > I am not familiar with color depths, but afaik Color red could be stored exactly using only 1 bit? Do I misunderstand the concept or is this really a bad output?
>
> No, the first bit depth to support red is 4 bit.
>
> Have a look at Color class>>colorFromPixelValue: p depth: d
>
> BTW: You can use a ColorForm to work with your own palette, so that you can have for example a 1-bit form with 1=yellow & 0=red…
>
>
> Best regards
>         -Tobias
>
> >
> > (I came across to this when performing #collectColors: on an 8 bit ColorForm loaded from disk, which did not work as expected.)
> >
> > Best,
> > Christoph
>
> PS: PS:
> Color red is r:1.0 g:0.0 b:0.0 but stored in a different fashion:
>
> Color comment:
> "
> Think of Color's instance variables as:
>         r       amount of red, a Float between 0.0 and 1.0.
>         g       amount of green, a Float between 0.0 and 1.0.
>         b       amount of blue, a Float between 0.0 and 1.0.
> (But, in fact, the three are encoded as values from 0 to 1023 and combined in a single integer, rgb.  The user does not need to know this.)
> "
> that means "Color red" is stored as 0x3FF00000 or,
>
> 1111111111 0000000000 0000000000
> ^ red      ^ green    ^ blue
>
> that makes 10 bit per component.
>
> However, in the 16 bit form we have only 5 bit per component, so,
>
>         f := Form extent: 1 asPoint depth: 16.
>         f colorAt: 0 @ 0 put: Color red.
>         f pixelValueAt: 0@0.
>
> yields 0x7C00 aka
>
> 11111 00000 00000
> ^ r   ^ g   ^ b



Reply | Threaded
Open this post in threaded view
|

Re: Bug in Form>>#asFormOfDepth:?

Bob Arning-2
In reply to this post by Tobias Pape
fwiw, Color r: 0.0 g: 0.0 b: 0.004 is squeak's way of representing black in 16 bits so 0 can mean transparent

On 9/9/19 8:56 AM, Tobias Pape wrote:
Other examples:

"Example 2"
f := Form extent: 1 asPoint depth: 1.
f colorAt: 0 @ 0 put: Color red.
g := f asFormOfDepth: 32.
g colorAt: 0 @ 0 "--> (Color r: 0.0 g: 0.0 b: 0.004)"
yes, because you go from black/white to 32bit. I would have expected r0g0b0, but there might some rounding go on.




Reply | Threaded
Open this post in threaded view
|

Re: Bug in Form>>#asFormOfDepth:?

Tobias Pape

> On 09.09.2019, at 17:03, Bob Arning <[hidden email]> wrote:
>
> fwiw, Color r: 0.0 g: 0.0 b: 0.004 is squeak's way of representing black in 16 bits so 0 can mean transparent

ah; i remember. thanks bob!

>
> On 9/9/19 8:56 AM, Tobias Pape wrote:
>>> Other examples:
>>>
>>> "Example 2"
>>> f := Form extent: 1 asPoint depth: 1.
>>> f colorAt: 0 @ 0 put: Color red.
>>> g := f asFormOfDepth: 32.
>>> g colorAt: 0 @ 0 "--> (Color r: 0.0 g: 0.0 b: 0.004)"
>>>
>> yes, because you go from black/white to 32bit. I would have expected r0g0b0, but there might some rounding go on.
>>
>>
>
>



Reply | Threaded
Open this post in threaded view
|

Re: Bug in Form>>#asFormOfDepth:?

Christoph Thiede
In reply to this post by Tobias Pape

Any chance to fix this bug for 5.3?


The following would still be a functional workaround:


(
Reminder: The bug can be reproduced using
"Example 3"
f := Form extent: 1 asPoint depth: 16.
f colorAt: 0 @ 0 put: Color red.
g := f asFormOfDepth: 32.
g colorAt: 0 @ 0
Expected: Color red
Actual: (Color r: 0.973 g: 0.0 b: 0.0)
)

Best,
Christoph

Von: Squeak-dev <[hidden email]> im Auftrag von Tobias Pape <[hidden email]>
Gesendet: Montag, 9. September 2019 16:56:03
An: The general-purpose Squeak developers list
Betreff: Re: [squeak-dev] Bug in Form>>#asFormOfDepth:?
 

> On 09.09.2019, at 15:53, Thiede, Christoph <[hidden email]> wrote:
>
> Hi Tobias,
>
> oops, I mistook the depth with the number of bits per channel. Sorry and many thanks for your explanations!
>
> How would one fix the upscaling issue? Form>>#colormapIfNeededFor: returns nil in example 3, the comment in Color>>#colorMapIfNeededFrom:to: states this task is delegated to BitBlt. Is this comment wrong or is the defect in the primitive called that is in BitBlt>>#copyBits?
>
No, that part is only for cross-conversion of Forms and ColorForms
-t

> Best,
> Christoph
>
> Von: Squeak-dev <[hidden email]> im Auftrag von Tobias Pape <[hidden email]>
> Gesendet: Montag, 9. September 2019 14:56 Uhr
> An: The general-purpose Squeak developers list
> Betreff: Re: [squeak-dev] Bug in Form>>#asFormOfDepth:?

> Hi Christoph,
>
> > On 09.09.2019, at 13:25, Thiede, Christoph <[hidden email]> wrote:
> >
> > Hi all,
> >
> > consider the following example (print it):
> >
> > "Example 1"
> > f := Form extent: 1 asPoint depth: 1.
> > f colorAt: 0 @ 0 put: Color red.
> > g := f asFormOfDepth: 2.
> > g colorAt: 0 @ 0
> >
> > Expected output: Color red.
> > Actual output: Color black!
>
> No, Forms of depth 1 are black and white, and of depth2 are gray.
>
> >
> > Other examples:
> >
> > "Example 2"
> > f := Form extent: 1 asPoint depth: 1.
> > f colorAt: 0 @ 0 put: Color red.
> > g := f asFormOfDepth: 32.
> > g colorAt: 0 @ 0 "--> (Color r: 0.0 g: 0.0 b: 0.004)"
>
> yes, because you go from black/white to 32bit. I would have expected r0g0b0, but there might some rounding go on.
>
> >
> > "Example 3"
> > f := Form extent: 1 asPoint depth: 16.
> > f colorAt: 0 @ 0 put: Color red.
> > g := f asFormOfDepth: 32.
> > g colorAt: 0 @ 0 "--> (Color r: 0.973 g: 0.0 b: 0.0)"
>
>
>
> Something's wonky here!
> If we do
>
>         (((Form extent: 1 asPoint depth: 16)
>                 colorAt: 0 @ 0 put: Color red)
>                 asFormOfDepth: 32)
>         pixelValueAt: 0@0
>
> we get
>         4294443008 (aka 0xFFF80000)  which is a 32bit value.
> But the meaning is
>
>         11111111 11111000 00000000 00000000
>         ^ alpha  ^ r      ^ g      ^ b
>
> which means that the r component is not  "upscaled" during the #asFormOfDepth: process o.O (see PS)
>
>
>
>
> >
> > I am not familiar with color depths, but afaik Color red could be stored exactly using only 1 bit? Do I misunderstand the concept or is this really a bad output?
>
> No, the first bit depth to support red is 4 bit.
>
> Have a look at Color class>>colorFromPixelValue: p depth: d
>
> BTW: You can use a ColorForm to work with your own palette, so that you can have for example a 1-bit form with 1=yellow & 0=red…
>
>
> Best regards
>         -Tobias
>
> >
> > (I came across to this when performing #collectColors: on an 8 bit ColorForm loaded from disk, which did not work as expected.)
> >
> > Best,
> > Christoph
>
> PS: PS:
> Color red is r:1.0 g:0.0 b:0.0 but stored in a different fashion:
>
> Color comment:
> "
> Think of Color's instance variables as:
>         r       amount of red, a Float between 0.0 and 1.0.
>         g       amount of green, a Float between 0.0 and 1.0.
>         b       amount of blue, a Float between 0.0 and 1.0.
> (But, in fact, the three are encoded as values from 0 to 1023 and combined in a single integer, rgb.  The user does not need to know this.)
> "
> that means "Color red" is stored as 0x3FF00000 or,
>
> 1111111111 0000000000 0000000000
> ^ red      ^ green    ^ blue
>
> that makes 10 bit per component.
>
> However, in the 16 bit form we have only 5 bit per component, so,
>
>         f := Form extent: 1 asPoint depth: 16.
>         f colorAt: 0 @ 0 put: Color red.
>         f pixelValueAt: 0@0.
>
> yields 0x7C00 aka
>
> 11111 00000 00000
> ^ r   ^ g   ^ b





Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: Bug in Form>>#asFormOfDepth:?

marcel.taeumel
Hi Christoph,

this looks performance critical. Take a look at BalloonEngine >> #bitBlt:. A color map is slower than computing the target value, according to Tim (tfel).

This issue is not that critical for the release, is it?

Btw, you can easily try out different display depth via the world menu:



Best,
Marcel

Am 15.12.2019 12:15:41 schrieb Thiede, Christoph <[hidden email]>:

Any chance to fix this bug for 5.3?


The following would still be a functional workaround:


(
Reminder: The bug can be reproduced using
"Example 3"
f := Form extent: 1 asPoint depth: 16.
f colorAt: 0 @ 0 put: Color red.
g := f asFormOfDepth: 32.
g colorAt: 0 @ 0
Expected: Color red
Actual: (Color r: 0.973 g: 0.0 b: 0.0)
)

Best,
Christoph

Von: Squeak-dev <[hidden email]> im Auftrag von Tobias Pape <[hidden email]>
Gesendet: Montag, 9. September 2019 16:56:03
An: The general-purpose Squeak developers list
Betreff: Re: [squeak-dev] Bug in Form>>#asFormOfDepth:?
 

> On 09.09.2019, at 15:53, Thiede, Christoph <[hidden email]> wrote:
>
> Hi Tobias,
>
> oops, I mistook the depth with the number of bits per channel. Sorry and many thanks for your explanations!
>
> How would one fix the upscaling issue? Form>>#colormapIfNeededFor: returns nil in example 3, the comment in Color>>#colorMapIfNeededFrom:to: states this task is delegated to BitBlt. Is this comment wrong or is the defect in the primitive called that is in BitBlt>>#copyBits?
>
No, that part is only for cross-conversion of Forms and ColorForms
-t

> Best,
> Christoph
>
> Von: Squeak-dev <[hidden email]> im Auftrag von Tobias Pape <[hidden email]>
> Gesendet: Montag, 9. September 2019 14:56 Uhr
> An: The general-purpose Squeak developers list
> Betreff: Re: [squeak-dev] Bug in Form>>#asFormOfDepth:?

> Hi Christoph,
>
> > On 09.09.2019, at 13:25, Thiede, Christoph <[hidden email]> wrote:
> >
> > Hi all,
> >
> > consider the following example (print it):
> >
> > "Example 1"
> > f := Form extent: 1 asPoint depth: 1.
> > f colorAt: 0 @ 0 put: Color red.
> > g := f asFormOfDepth: 2.
> > g colorAt: 0 @ 0
> >
> > Expected output: Color red.
> > Actual output: Color black!
>
> No, Forms of depth 1 are black and white, and of depth2 are gray.
>
> >
> > Other examples:
> >
> > "Example 2"
> > f := Form extent: 1 asPoint depth: 1.
> > f colorAt: 0 @ 0 put: Color red.
> > g := f asFormOfDepth: 32.
> > g colorAt: 0 @ 0 "--> (Color r: 0.0 g: 0.0 b: 0.004)"
>
> yes, because you go from black/white to 32bit. I would have expected r0g0b0, but there might some rounding go on.
>
> >
> > "Example 3"
> > f := Form extent: 1 asPoint depth: 16.
> > f colorAt: 0 @ 0 put: Color red.
> > g := f asFormOfDepth: 32.
> > g colorAt: 0 @ 0 "--> (Color r: 0.973 g: 0.0 b: 0.0)"
>
>
>
> Something's wonky here!
> If we do
>
>         (((Form extent: 1 asPoint depth: 16)
>                 colorAt: 0 @ 0 put: Color red)
>                 asFormOfDepth: 32)
>         pixelValueAt: 0@0
>
> we get
>         4294443008 (aka 0xFFF80000)  which is a 32bit value.
> But the meaning is
>
>         11111111 11111000 00000000 00000000
>         ^ alpha  ^ r      ^ g      ^ b
>
> which means that the r component is not  "upscaled" during the #asFormOfDepth: process o.O (see PS)
>
>
>
>
> >
> > I am not familiar with color depths, but afaik Color red could be stored exactly using only 1 bit? Do I misunderstand the concept or is this really a bad output?
>
> No, the first bit depth to support red is 4 bit.
>
> Have a look at Color class>>colorFromPixelValue: p depth: d
>
> BTW: You can use a ColorForm to work with your own palette, so that you can have for example a 1-bit form with 1=yellow & 0=red…
>
>
> Best regards
>         -Tobias
>
> >
> > (I came across to this when performing #collectColors: on an 8 bit ColorForm loaded from disk, which did not work as expected.)
> >
> > Best,
> > Christoph
>
> PS: PS:
> Color red is r:1.0 g:0.0 b:0.0 but stored in a different fashion:
>
> Color comment:
> "
> Think of Color's instance variables as:
>         r       amount of red, a Float between 0.0 and 1.0.
>         g       amount of green, a Float between 0.0 and 1.0.
>         b       amount of blue, a Float between 0.0 and 1.0.
> (But, in fact, the three are encoded as values from 0 to 1023 and combined in a single integer, rgb.  The user does not need to know this.)
> "
> that means "Color red" is stored as 0x3FF00000 or,
>
> 1111111111 0000000000 0000000000
> ^ red      ^ green    ^ blue
>
> that makes 10 bit per component.
>
> However, in the 16 bit form we have only 5 bit per component, so,
>
>         f := Form extent: 1 asPoint depth: 16.
>         f colorAt: 0 @ 0 put: Color red.
>         f pixelValueAt: 0@0.
>
> yields 0x7C00 aka
>
> 11111 00000 00000
> ^ r   ^ g   ^ b