comp.lang.ada
 help / color / mirror / Atom feed
* Color components and fixed point numbers
@ 2004-03-01 11:49 Pat
  2004-03-01 16:24 ` Robert I. Eachus
  0 siblings, 1 reply; 6+ messages in thread
From: Pat @ 2004-03-01 11:49 UTC (permalink / raw)


Hi,

I would like to declare two records representing a RGB Color with two
different percisions. The Small one with color components from 0..255
and the Wide one with components from 0..65535. Could I use fixed
point numbers to hide the different precision: e.g.

type Small_Component is delta 1/255 range 0.0 .. 1.0
type Wide_Component is delta 1/65535 range 0.0 .. 1.0

type Small_RGB is record
  r,g,b:Small_Component
end record

type Wide_RGB is record
  r,g,b:Wide_Component
end record

Then later I could use something like this to convert between the
different precisions:

w : Wide_RGB
s : Small_RGB


w.r = Wide_Component(s.r);

I tried to implement this but suprisingly Wide_Component(
Small_Component(1.0)) < 1.0 ? Does somebody know a workaround?

Thanks, Pat



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Color components and fixed point numbers
  2004-03-01 11:49 Color components and fixed point numbers Pat
@ 2004-03-01 16:24 ` Robert I. Eachus
  2004-03-02 10:58   ` Pat
  0 siblings, 1 reply; 6+ messages in thread
From: Robert I. Eachus @ 2004-03-01 16:24 UTC (permalink / raw)


Pat wrote:

> Hi,
> 
> I would like to declare two records representing a RGB Color with two
> different percisions. The Small one with color components from 0..255
> and the Wide one with components from 0..65535. Could I use fixed
> point numbers to hide the different precision: e.g.
> 
> type Small_Component is delta 1/255 range 0.0 .. 1.0
> type Wide_Component is delta 1/65535 range 0.0 .. 1.0
> 
> type Small_RGB is record
>   r,g,b:Small_Component
> end record
> 
> type Wide_RGB is record
>   r,g,b:Wide_Component
> end record
> 
> Then later I could use something like this to convert between the
> different precisions:
> 
> w : Wide_RGB
> s : Small_RGB
> 
> 
> w.r = Wide_Component(s.r);
> 
> I tried to implement this but suprisingly Wide_Component(
> Small_Component(1.0)) < 1.0 ? Does somebody know a workaround?

No workaround is required!  But I will get to that. First fix your type 
declarations:

  type Small_Component is delta 1.0/255 range 0.0 .. 1.0;
  type Wide_Component is delta 1.0/65535 range 0.0 .. 1.0;

This may just be a problem of transcription, because I would expect a 
compiler to at the least give a warning for such a declaration. Besides, 
you also omitted the semicolons.

Second, you got the numbers wrong, or you want something that many 
compilers would not support as a value for 'Small, even with a rep 
clause.  You should use:

  type Small_Component is delta 1.0/256 range 0.0 .. 1.0;
  type Wide_Component is delta 1.0/65536 range 0.0 .. 1.0;

Notice that for these types, a compiler is not required to represent 
255.0/256 and 256.0/256 differently.  In other words, a compiler is 
allowed to choose a representation with only 256 values, not 257.  You 
can control this, but usually it is what you want.  In fact, I would 
expect that you will force this representation:

for Small_Component'Size use 8;
for Wide_Component'Size use 16;

Having done all that, you will notice that the brightest colors you can 
specify are different.  For example, the brightest whites are: 
16#FFFFFF# for Small_RGB, and 16#FFFFFFFFFFFF# for Wide_RGB.  Since that 
is how the hardware works, that should be what you expect.  So 
Small_RGB'(1.0,1.0,1.0) and Wide_RGB'(1.0,1.0,1.0) are different colors. 
  Or better stated: Small_RGB(255.0/256, 255.0/256. 255.0/256) is not 
equal to Wide_RGB(65535.0/65536, 65535.0/65536, 65535.0/65536), and you 
should not expect them to be equal.

Can you force an implementation to make the two brightest whites equal? 
  It is not too difficult.  Most compilers will give the expected result 
for:

   type Small_Component is delta 1.0/256 range 1.0/256 .. 1.0;
   type Wide_Component is delta 1.0/65536 range 1.0/65536 .. 1.0;

Without any rep clauses, if that is really what you want.  I could have 
told you this straight off.  But you really need to do the thinking 
above to be sure you are doing the right thing, for whatever the right 
value of right is for you.

--
                                           Robert I. Eachus

"The only thing necessary for the triumph of evil is for good men to do 
nothing." --Edmund Burke




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Color components and fixed point numbers
  2004-03-01 16:24 ` Robert I. Eachus
@ 2004-03-02 10:58   ` Pat
  2004-03-02 16:39     ` Robert I. Eachus
  2004-03-02 22:23     ` tmoran
  0 siblings, 2 replies; 6+ messages in thread
From: Pat @ 2004-03-02 10:58 UTC (permalink / raw)


Thank you very much for your answer.

> First fix your type declarations ... Besides, you also omitted the semicolons.

Sorry, was just too lazy...

> Second, you got the numbers wrong, or you want something that many 
> compilers would not support as a value for 'Small, even with a rep 
> clause.  You should use:

I'm very new to Ada, so what is rep clause?

> Since that is how the hardware works, that should be what you expect.  So 
> Small_RGB'(1.0,1.0,1.0) and Wide_RGB'(1.0,1.0,1.0) are different colors. 
>  Or better stated: Small_RGB(255.0/256, 255.0/256. 255.0/256) is not 
> equal to Wide_RGB(65535.0/65536, 65535.0/65536, 65535.0/65536), and you 
> should not expect them to be equal.

Yes, this is the reason why I used 255 and 65535 as denominator. I am
not a
expert on color conversion or representation, but I think 0.0 should
represent
the darkest and 1.0 the brigthest color independent from the
representation as
integers. So 255 and 65535 should be the same brightness.

If I would use integer arithmetic I would do it like this:

  type Small_Comp is range 0 .. 255;
  type Wide_Comp is range 0 .. 65535;

  --  Small_Comp'Last and Wide_Comp'Last should represent the same
brightest color
  --  Small_COmp'First and Wide_Comp'Last should represent the same
darkest color

  w : Wide_Comp;
  s : Small_Comp:=?;

  w := s*65535 / 255; -- equals w:=s*257
  s := w / 257;

I though the reason why 1.0/255 is not working may be that there is no
exact
floating point representation of 1.0/255 and so due to rounding 255 *
(1.0/255) < 1.0 .


> Can you force an implementation to make the two brightest whites equal? 
>   It is not too difficult.  Most compilers will give the expected result 
> for:
>
>   type Small_Component is delta 1.0/256 range 1.0/256 .. 1.0;
>   type Wide_Component is delta 1.0/65536 range 1.0/65536 .. 1.0;

I think this will only move my problem, so that now the darkest colors
are
not identical.

Thank you very much, Pat



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Color components and fixed point numbers
  2004-03-02 10:58   ` Pat
@ 2004-03-02 16:39     ` Robert I. Eachus
  2004-03-02 22:23     ` tmoran
  1 sibling, 0 replies; 6+ messages in thread
From: Robert I. Eachus @ 2004-03-02 16:39 UTC (permalink / raw)


Pat wrote:

> I'm very new to Ada, so what is rep clause?

Ada shorthand for representation clause, see RM 13.1 through 13.6, and 
elsewhere throughout the reference manual.  Different rep clauses handle 
different aspects of a type's representation.  In the case of 
fixed-point types, 'Small and 'Delta can both be set by rep clauses (see 
  RM 3.5.10 http://www.adaic.org/standards/95lrm/html/RM-3-5-10.html for 
the attributes of a fixed-point type.  The key here is 'Small which can 
be set by a rep clauses. (Technically by an attribute definition clause, 
but you can see why everyone uses the shorthand.)

Why it matters is that, by default, the compiler will choose a power of 
two (or ten for decimal fixed-point types) as the 'Small of a type. 
With a rep clause you can require that the small for the type be exactly 
the delta for the type. Compilers can reject rep clauses that they don't 
support.  But for 'Small compilers have gotten pretty good over the 
years.  I have used Pi/10_000, and 1.0/1_296_000 for angle measures. 
(Tenth of a milliradian, and arc seconds respectively.)  The Ada 95 
rules made it much easier than in Ada 83 for a compiler to support such 
a rep clause.

> Yes, this is the reason why I used 255 and 65535 as denominator. I am
> not a expert on color conversion or representation, but I think 0.0
> should represent the darkest and 1.0 the brigthest color independent
> from the representation as integers. So 255 and 65535 should be the
> same brightness.

Maybe they should, and if they did, you could write the rep clauses to 
force such a representation.  But as I say, in all current computer 
hardware that I am aware of, FFFFFF is equal to FF00FF00FF00 not 
FFFFFFFFFFFF.  Don't let that worry you though, if you look at the 
'real' specifications for displays (or the NTSC or PAL broadcast rules) 
you will find that the actual representable color range for most 
monitors is much less than that.

For example, if a monitor is specified as having a 500:1 constrast 
ratio--which is pretty good--that means that the darkest black is 
1/500th of the brightest white.  That means that all 24-bit colors can 
be distinguished (at least with measuring equipment), but usually you 
will run into saturation above FF80FF80FF80, and blacks below 
008000800080 will not be distinguishable.  (Actually you have to have a 
very good eye to be able to see a brightness difference of less than 5%. 
  You might think that would make 24-bit color no different from 16-bit 
color (actually 15-bit color), but there are low-light levels where the 
differences are noticable to a trained eye.

I have an Amiga that can generate an NTSC (broadcast) display signal. 
But if you do that you have to be aware that the brightest NTSC color is 
technically C0C0C0, and blacks below around 191919 should also not be 
used.  The computer will generate those colors in NTSC mode, but 
technically it violates the broadcast standard.  (And the NTSC signal 
will violate broadcast standards.) Most NTSC monitors will start having 
some trouble with color saturations above D0 or so. Computer monitors, 
though will support all the way up to FF without blooming or tearing, 
even if they saturate well before then.  Of course they do this by 
clipping the analog signals.

-- 
                                           Robert I. Eachus

"The only thing necessary for the triumph of evil is for good men to do 
nothing." --Edmund Burke




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Color components and fixed point numbers
  2004-03-02 10:58   ` Pat
  2004-03-02 16:39     ` Robert I. Eachus
@ 2004-03-02 22:23     ` tmoran
  2004-03-04 13:31       ` Pat
  1 sibling, 1 reply; 6+ messages in thread
From: tmoran @ 2004-03-02 22:23 UTC (permalink / raw)


>Yes, this is the reason why I used 255 and 65535 as denominator. I am
>not a
>expert on color conversion or representation, but I think 0.0 should
>represent
>the darkest and 1.0 the brigthest color independent from the
>representation as
>integers. So 255 and 65535 should be the same brightness.

  You are expanding 8 bits into 16 bits so the question is what to
use to pad out the extra 8 bits.  Using 1.0/256 and 1.0/65536 pads
with zeros.
Declaring
  type Small_Comp is delta 1.0 / 255 range 0.0 .. 1.0;
  for Small_Comp'small use 1.0/255;
  for Small_Comp'Size use 8;

  type Wide_Comp is delta 1.0 / 65535 range 0.0 .. 1.0;
  for Wide_Comp'small use 1.0/65535;
  for Wide_Comp'Size use 16;

pads with greater than zero.

Note that 0.5 is then not exactly representable since 0.5*255= 127.5 I
have one compiler that truncates to 7F and another that rounds to 80.  In
the first case doubling 0.5 will give a value less than 1.0, in the second
case it's greater than 1.0 (and raises Constraint_Error), so the
finiteness of the arithmetic shows up anyway.  OTOH, with power-of-two
deltas, neither range will include 1.0 (Small_Comp'last= 0.996 and
Wide_Comp'last = 0.99609), and Small_Comp(Wide_Comp'last) will overflow.

IMO, black is black, ie 00 = 0000, but "brightest" is not really fixed.
Is the brightness of the screen using 8 bit color and Small_Comp'last the
same as, or slightly less than, the brightness using Wide_Comp'last?  And
what happens if you turn up the monitor's brightness control?  "1.0" is a
very artifical value.

As Robert Eachus pointed out, NTSC has other problems, like "blacker
than black", which you may or may not have to take account of in your
programming.

The bottom line is that you need to make sure your graphics algorithms
stay safely away from 1.0.  As Robert Eachus pointed out, NTSC has other
problems (like "blacker than black") so you better stay away from 0.0
also.  Given those facts, the difference between a power-of-two delta and
a power-of-two-minus-one is a minor point.



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Color components and fixed point numbers
  2004-03-02 22:23     ` tmoran
@ 2004-03-04 13:31       ` Pat
  0 siblings, 0 replies; 6+ messages in thread
From: Pat @ 2004-03-04 13:31 UTC (permalink / raw)


tmoran@acm.org wrote 

> Declaring
>   type Small_Comp is delta 1.0 / 255 range 0.0 .. 1.0;
>   for Small_Comp'small use 1.0/255;
>   for Small_Comp'Size use 8;
> 
>   type Wide_Comp is delta 1.0 / 65535 range 0.0 .. 1.0;
>   for Wide_Comp'small use 1.0/65535;
>   for Wide_Comp'Size use 16;
> 
> pads with greater than zero.
> 
> Note that 0.5 is then not exactly representable since 0.5*255= 127.5 I
> have one compiler that truncates to 7F and another that rounds to 80.  

Isn't it specified how the compiler has to round, if he has to convert
a
floating point constant into a fixed point value?


> IMO, black is black, ie 00 = 0000, but "brightest" is not really fixed.
> Is the brightness of the screen using 8 bit color and Small_Comp'last the
> same as, or slightly less than, the brightness using Wide_Comp'last?  And
> what happens if you turn up the monitor's brightness control?  "1.0" is a
> very artifical value.

I don't really care how at last a montior or whatever converts my
color to light. I care more about the abstract value of a brightest
color in color model I am using while doing calculation with the
color. So often I want to convert a 8-bit color component to a 16-bit
one to have more precision while doing calculations on it and
afterwards I will convert it back into a 8-bit one.

Anyway, thank you very much for your answers, best regards, Pat



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2004-03-04 13:31 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-03-01 11:49 Color components and fixed point numbers Pat
2004-03-01 16:24 ` Robert I. Eachus
2004-03-02 10:58   ` Pat
2004-03-02 16:39     ` Robert I. Eachus
2004-03-02 22:23     ` tmoran
2004-03-04 13:31       ` Pat

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox