From: Peter Duniho on
Jay Dee wrote:
> 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
From: Jeff Johnson on
"Peter Duniho" <no.peted.spam(a)no.nwlink.spam.com> wrote in message
news:esEyyY2dKHA.4880(a)TK2MSFTNGP05.phx.gbl...

> 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.


From: Tim Roberts on
"Jeff Johnson" <i.get(a)enough.spam> wrote:
>
>"Peter Duniho" <no.peted.spam(a)no.nwlink.spam.com> wrote:
>
>> 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.

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.
--
Tim Roberts, timr(a)probo.com
Providenza & Boekelheide, Inc.
From: Jay Dee on
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