Archive Browser
Download RiffPaletteLoader.zip version 1.0.0.0, last updated 18/02/2017 (15.41 KB)
Download- md5: 3b1ed86c3076e401c7f8c1d79c610800
- sha1: b71a2ed2f72637eb844530aa845fa9642c16b74f
- sha256: 65ed960371418198622905bab618209fe66b36fb490c66c0f40a2f0548a42b3e
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
// Loading Microsoft RIFF Palette (pal) files with C#
// http://cyotek.com/blog/loading-microsoft-riff-palette-pal-files-with-csharp
namespace Cyotek.Demonstrations.RiffPaletteLoader
{
internal sealed class RiffPalette : IEnumerable<Color>
{
#region Fields
private Color[] _palette;
#endregion
#region Constructors
public RiffPalette()
{
_palette = new Color[0];
}
#endregion
#region Methods
public void Load(string fileName)
{
using (Stream stream = File.OpenRead(fileName))
{
this.Load(stream);
}
}
public void Load(Stream stream)
{
byte[] buffer;
bool eof;
buffer = new byte[1032]; // create a buffer big enough to hold a default 256 color palette
// first read and validate the form header
// this is comprised of
// * RIFF header
// * document size
// * FORM header
stream.Read(buffer, 0, 12);
if (buffer[0] != 'R' || buffer[1] != 'I' || buffer[2] != 'F' || buffer[3] != 'F')
{
throw new InvalidDataException("Source stream is not a RIFF document.");
}
// TODO: Validate the document size if required
if (buffer[8] != 'P' || buffer[9] != 'A' || buffer[10] != 'L' || buffer[11] != ' ')
{
throw new InvalidDataException("Source stream is not a palette.");
}
eof = false;
while (!eof)
{
// a RIFF document can have one or more chunks.
// for our purposes, each chunk has a 4 letter
// identifier and a size of the data part of the
// chunk. We can use these two values to either
// process the palette data, or skip data we
// don't recognise
// TODO: This procedure only supports simple, not extended, palettes
if (stream.Read(buffer, 0, 8) == 8)
{
int chunkSize;
chunkSize = buffer.ToInt(4);
// see if we have the palette data
if (buffer[0] == 'd' && buffer[1] == 'a' && buffer[2] == 't' && buffer[3] == 'a')
{
if (chunkSize > buffer.Length)
{
buffer = new byte[chunkSize];
}
if (stream.Read(buffer, 0, chunkSize) != chunkSize)
{
throw new InvalidDataException("Failed to read enough data to match chunk size.");
}
_palette = this.ReadPalette(buffer);
// only one palette in a file, so break out of the chunk scan
eof = true;
}
else
{
// not the palette data? advance the stream to the next chunk
// riff chunks are word-aligned. if the size is odd
// then a padding byte is included after the chunk
// data. This is junk data, so we just skip it
if (chunkSize % 2 != 0)
{
chunkSize++;
}
stream.Position += chunkSize;
}
}
else
{
// nothing to read, abort
eof = true;
}
}
;
}
private Color[] ReadPalette(byte[] buffer)
{
Color[] palette;
ushort count;
// The buffer should hold a LOGPALETTE structure containing
// OS version (2 bytes, always 03)
// Color count (2 bytes)
// Color data (4 bytes * color count)
count = buffer.ToInt16(2);
palette = new Color[count];
for (int i = 0; i < count; i++)
{
byte r;
byte g;
byte b;
int offset;
offset = i * 4 + 4;
r = buffer[offset];
g = buffer[offset + 1];
b = buffer[offset + 2];
// TODO: The fourth byte are flags, which we have no use for here
palette[i] = Color.FromArgb(r, g, b);
}
return palette;
}
#endregion
#region IEnumerable<Color> Interface
public IEnumerator<Color> GetEnumerator()
{
// ReSharper disable once ForCanBeConvertedToForeach
// ReSharper disable once LoopCanBeConvertedToQuery
for (int i = 0; i < _palette.Length; i++)
{
yield return _palette[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
}
Donate
This software may be used free of charge, but as with all free software there are costs involved to develop and maintain.
If this site or its services have saved you time, please consider a donation to help with running costs and timely updates.
Donate