// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.IO;
namespace SixLabors.Fonts.Tables.General {
///
/// Represents the color palette table, which contains one or more palettes of colors
/// used by color fonts (e.g., COLR table).
///
///
internal class CpalTable : Table
{
///
/// The table name identifier.
///
internal const string TableName = "CPAL";
///
/// The offsets into the palette entries array for each palette.
///
private readonly ushort[] paletteOffsets;
///
/// The combined array of color records for all palettes.
///
private readonly GlyphColor[] paletteEntries;
///
/// Initializes a new instance of the class.
///
/// The index of each palette's first color record.
/// The combined color records for all palettes.
public CpalTable(ushort[] paletteOffsets, GlyphColor[] paletteEntries)
{
this.paletteEntries = paletteEntries;
this.paletteOffsets = paletteOffsets;
}
///
/// Gets the glyph color at the specified palette and entry indices.
///
/// The zero-based palette index.
/// The zero-based entry index within the palette.
/// The .
public GlyphColor GetGlyphColor(int paletteIndex, int paletteEntryIndex)
=> this.paletteEntries[this.paletteOffsets[paletteIndex] + paletteEntryIndex];
///
/// Loads the from the specified font reader.
///
/// The font reader.
/// The , or if the table is not present.
public static CpalTable? Load(FontReader fontReader)
{
if (!fontReader.TryGetReaderAtTablePosition(TableName, out BigEndianBinaryReader? binaryReader))
{
return null;
}
using (binaryReader)
{
return Load(binaryReader);
}
}
///
/// Loads the from the specified binary reader.
///
/// The big-endian binary reader.
/// The .
public static CpalTable Load(BigEndianBinaryReader reader)
{
// FORMAT 0
// Type | Name | Description
// ----------|---------------------------------|----------------------------------------------------------------------------------------------------
// uint16 | version | Table version number (=0).
// uint16 | numPaletteEntries | Number of palette entries in each palette.
// uint16 | numPalettes | Number of palettes in the table.
// uint16 | numColorRecords | Total number of color records, combined for all palettes.
// Offset32 | offsetFirstColorRecord | Offset from the beginning of CPAL table to the first ColorRecord.
// uint16 | colorRecordIndices[numPalettes] | Index of each paletteās first color record in the combined color record array.
// additional format 1 fields
// Offset32 | offsetPaletteTypeArray | Offset from the beginning of CPAL table to the Palette Type Array. Set to 0 if no array is provided.
// Offset32 | offsetPaletteLabelArray | Offset from the beginning of CPAL table to the Palette Labels Array. Set to 0 if no array is provided.
// Offset32 | offsetPaletteEntryLabelArray | Offset from the beginning of CPAL table to the Palette Entry Label Array.Set to 0 if no array is provided.
ushort version = reader.ReadUInt16();
ushort numPaletteEntries = reader.ReadUInt16();
ushort numPalettes = reader.ReadUInt16();
ushort numColorRecords = reader.ReadUInt16();
uint offsetFirstColorRecord = reader.ReadOffset32();
ushort[]? colorRecordIndices = reader.ReadUInt16Array(numPalettes);
uint offsetPaletteTypeArray = 0;
uint offsetPaletteLabelArray = 0;
uint offsetPaletteEntryLabelArray = 0;
if (version == 1)
{
offsetPaletteTypeArray = reader.ReadOffset32();
offsetPaletteLabelArray = reader.ReadOffset32();
offsetPaletteEntryLabelArray = reader.ReadOffset32();
}
reader.Seek(offsetFirstColorRecord, SeekOrigin.Begin);
GlyphColor[] palettes = new GlyphColor[numColorRecords];
for (int n = 0; n < numColorRecords; n++)
{
byte blue = reader.ReadByte();
byte green = reader.ReadByte();
byte red = reader.ReadByte();
byte alpha = reader.ReadByte();
palettes[n] = new GlyphColor(red, green, blue, alpha);
}
return new CpalTable(colorRecordIndices, palettes);
}
}
}