Storing a color value as a single byte

J

Jay Dee

I have an application that stores colour text to file currently as 4
bytes for each character (Char, Red, Green, Blue). As you can imagine,
this creates rather large files and is not ideal.

The required selection of colours is minimal and the base 16 colours
available as standard in something like MS Paint would be sufficient.

Is there a simple way to store a colour as 1 byte rather than 3?

I understand that a rounding factor would have to be applied so the
colour out may not be exactly the same as the colour in and would end
up the nearest match and don’t see this as a problem.

Finally I then intend to store a number of consecutive matching bytes,
e.g. if all text is black for the first 100 characters store the
colour black once along with the number 100 as integer or something.
I don’t se this being a problem eather.

What I am asking is for some help with the rounding formula required
for storing a colour as a single byte if possible.

public byte ColorToByte(Color color)
{
// TODO
// alpha value douse not need to be considered
}

public Color ByteToColor (byte byteIn)
{
// TODO
// alpha value douse not need to be considered
}

Many thanks to anyone with some input.

Jay Dee
 
J

Jeff Gaines

I have an application that stores colour text to file currently as 4
bytes for each character (Char, Red, Green, Blue). As you can imagine,
this creates rather large files and is not ideal.

The required selection of colours is minimal and the base 16 colours
available as standard in something like MS Paint would be sufficient.

Is there a simple way to store a colour as 1 byte rather than 3?

I understand that a rounding factor would have to be applied so the
colour out may not be exactly the same as the colour in and would end
up the nearest match and don’t see this as a problem.

Finally I then intend to store a number of consecutive matching bytes,
e.g. if all text is black for the first 100 characters store the
colour black once along with the number 100 as integer or something.
I don’t se this being a problem eather.

What I am asking is for some help with the rounding formula required
for storing a colour as a single byte if possible.

public byte ColorToByte(Color color)
{
// TODO
// alpha value douse not need to be considered
}

public Color ByteToColor (byte byteIn)
{
// TODO
// alpha value douse not need to be considered
}

Many thanks to anyone with some input.

Jay Dee

That sounds like fun :)

A single byte would give a value from 0 to 255. Could you use a lookup
table then use the lower 4 bits (0 to 15) as a colour code?
 
A

Alberto Poblacion

Jay Dee said:
Is there a simple way to store a colour as 1 byte rather than 3?

Normally this is done by means of a color table. A small table is stored
in the file that contains the 3 bytes for the few colors that the file
needs. Then, every time that a color is needed, you just store a single byte
which is the offset into the color table where the actual color is stored.
GIF files use this method.
 
U

Uwe Hercksen

Jay said:
What I am asking is for some help with the rounding formula required
for storing a colour as a single byte if possible.

public byte ColorToByte(Color color)
{
// TODO
// alpha value douse not need to be considered
}

public Color ByteToColor (byte byteIn)
{
// TODO
// alpha value douse not need to be considered
}
Hello,

the RGB color uses 3 bytes to store the color, 24 bits alltogether.
You may take the 2 most significant bits from the red, green and blue
value and pack those 6 bits into one byte for 64 different colors.

Are you familiar with bit masking and shifting using C#?
The operators >> for right shift, << for left shift, & for bitwise and,
| for bitwise or.

color.R gives you the value of the red component, color.G the green and
color.B the blue. With color.FromArgb(int r, int g, int b) you get the
color from the values for red, green and blue.

Hope that helps.

Bye
 
U

Uwe Hercksen

Uwe said:
You may take the 2 most significant bits from the red, green and blue
value and pack those 6 bits into one byte for 64 different colors.

Hello again,

for 256 different colors, you may take the most significant 3 bits from
the red and green value and only 2 bits for blue, that are 8 bits
altogether. The resolution for green and red is better than for blue.

Bye
 
P

Peter Duniho

Jay said:
I have an application that stores colour text to file currently as 4
bytes for each character (Char, Red, Green, Blue). As you can imagine,
this creates rather large files and is not ideal.

The required selection of colours is minimal and the base 16 colours
available as standard in something like MS Paint would be sufficient.

Is there a simple way to store a colour as 1 byte rather than 3? [...]

As others have pointed out, you can create a color table, assuming you
have no more than 256 different colors used in the text.

The "rounding" approach you describe could work as well, but as you note
will lose precision of the colors. Uwe's reply describes a way to do that.

All that said, depending on the nature of the text, I think there are
probably better ways than storing a color value with each character.

When dealing with colored text, it's common for there to be groups of
sequential characters all the same color. This is usually handled by
indicating in the file the "current" formatting (e.g. color), and then
assuming all characters following that format specification have the
same format. Then, you only insert a format record in the file when the
color changes.

In fact, this is how the RTF file format works. Of course, it supports
a very broad range of formatting options, and has its own overhead. But
if your files are really so large as to cause a problem, it's possible
that using RTF would be a good solution. It's portable, and there are
already implementations available (for example, you could use the
RichTextBox control to format text and then get the resulting RTF text).

If you simply reduce your color value from 3 bytes to 1, at best your
file sizes will reduce by half (assuming each character takes only 1
byte...if you're storing a multi-byte encoding, then obviously your size
reduction is even less). If you want a more significant reduction, you
may find it useful to store the color information as a bitmap, and then
save the bitmap separately from the text (i.e. two parts in the same
file, or two different files).

If the color information is completely random, this probably won't help
much, if at all. But assuming your color formatting for the text has
some regularity to it, image compression algorithms should have some
useful effect on the bitmap data, and could very well produce file size
savings of _much_ better than 50%. Of course, if you use JPEG, you also
have control over how much color information you lose, while PNG would
be able to represent each color exactly but won't compress as much.

Assuming you only need color information for each character (as opposed
to other formatting information), and the text is suited to recording
the color in the file only for when the character color changes (i.e.
you have significant numbers of sequential characters all the same
color), I think a custom character-run approach would probably be the
best. It's simple, and should produce a dramatic reduction in file
size. It also leaves the character data itself intact (i.e. without
extra bytes between each character) so if you want to run the result
through a simple compressor like GzipStream afterwards, you probably can
get the file size down even much more.

But I offer the other suggestions above for you to explore if you think
they might work better in your scenario.

Pete
 
J

Jeff Johnson

As others have pointed out, you can create a color table

Since this has been mentioned twice, I'll just add that images which use a
color table are referred to as "indexed" images, and this table is called a
"palette". You'll run across these terms when using graphics applications
like PhotoShop or the GIMP.
 
T

Tim Roberts

Jeff Johnson said:
Since this has been mentioned twice, I'll just add that images which use a
color table are referred to as "indexed" images, and this table is called a
"palette". You'll run across these terms when using graphics applications
like PhotoShop or the GIMP.

It's fascinating to me that the Windows community has already forgotten
about the concept of a palette. At the time Windows 95 was released,
virtually every computer in the world had a graphics card with 8 bits per
pixel, and every application programmer wasted half his time worrying about
palette realization.
 
J

Jay Dee

Thank you for your input and sorry it took so long to respond.

I looked in to all the methods mentions above and decided not to round
the colours like I first suggested. Bellow is the code I settled on
after trying all the methods mentioned above.

Many thanks for your help.

Jay Dee


#region

List<byte> list = new List<byte>();

// 2 bytes, Int16, number of lines
list.AddRange(BitConverter.GetBytes((Int16)this.chars.Count));

// each line
for (int lineIndex = 0; lineIndex < this.chars.Count; lineIndex++)
{
// int16, length of the line
list.AddRange(BitConverter.GetBytes((Int16)this.chars
[lineIndex].Count));

// each char
for (int charIndex = 0; charIndex < this.chars[lineIndex].Count;
charIndex++)
{
// 1 byte as 'char'
list.Add((byte)this.chars[lineIndex][charIndex]);
}
}

// 1 byte, EnableBackColor
list.Add(Convert.ToByte(this.EnableBackColor));

if (this.EnableBackColor)
{
if(this.chars.Count > 0 && this.chars[0].Count > 0)
{
Color color = this.charBackColors[0][0];
int count = 0;

for (int lineIndex = 0; lineIndex < this.chars.Count; lineIndex
++)
{
for (int charIndex = 0; charIndex < this.chars
[lineIndex].Count; charIndex++)
{
if (this.chars[lineIndex][charIndex] != '\0')
{
if (this.charBackColors[lineIndex][charIndex] !=
color)
{
// 4 bytes as integer, count
list.AddRange(BitConverter.GetBytes(count));

// 3 bytes to store the color RGB
list.Add(color.R);
list.Add(color.G);
list.Add(color.B);

//
count = 0;
color = this.charBackColors[lineIndex]
[charIndex];
}
}
count++;
}
}

// 4 bytes as integer, count
list.AddRange(BitConverter.GetBytes(count));

// 3 bytes to store the color RGB
list.Add(color.R);
list.Add(color.G);
list.Add(color.B);
}
}

// 1 byte, EnableForeColor
list.Add(Convert.ToByte(this.EnableForeColor));

if (this.EnableForeColor)
{
if (this.chars.Count > 0 && this.chars[0].Count > 0)
{
Color color = this.charForeColors[0][0];
int count = 0;

for (int lineIndex = 0; lineIndex < this.chars.Count; lineIndex
++)
{
for (int charIndex = 0; charIndex < this.chars
[lineIndex].Count; charIndex++)
{
if (this.chars[lineIndex][charIndex] != '\0')
{
if (this.charForeColors[lineIndex][charIndex] !=
color)
{
// 4 bytes as integer, count
list.AddRange(BitConverter.GetBytes(count));

// 3 bytes to store the color RGB
list.Add(color.R);
list.Add(color.G);
list.Add(color.B);

//
count = 0;
color = this.charForeColors[lineIndex]
[charIndex];
}
}
count++;
}
}

// 4 bytes as integer, count
list.AddRange(BitConverter.GetBytes(count));

// 3 bytes to store the color RGB
list.Add(color.R);
list.Add(color.G);
list.Add(color.B);
}
}

//
return list.ToArray();

#endregion
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top