Palettes are just what they say they are. They define which colours you can safely use in an image without infringing on its colour depth. For instance, a 256-colour palette for a 256-colour image would be appropriate, or a greyscale palette for a greyscale image. Nothing, as far as I'm concerned, indicates a truly excellent image editor program better than the capability to read palette files. And what better to use for clarity and robustness than a user control?
First, how do palette files work? Well, first of all, there are so many variants of this image format that the .pal extension has become a generic extension meaning that any file that is intended as use as a palette file will probably have this extension. For this article, we'll be focusing on the “JASC-PAL” format, originally used by Jasc Software in Paint Shop Pro.
Here is a typical JASC-PAL palette file:
255 0 0
0 255 0
0 0 255
255 255 0
0 255 255
255 0 255
100 0 0
0 100 0
0 0 100
100 100 0
0 100 100
100 0 100
200 200 0
0 200 200
200 0 200
255 255 255
Let’s break it down to see what it does.
Line 1 - File Format Header
This is the part of the file that identifies the file as a Paint Shop Pro palette file.
Line 2 - File Format Version
The version of the file format used in this palette file.
Line 3 - Number Of Colours In The Palette
Old rules state that a JASC-PAL palette file can only contain either 256 or 16 colours. We don't play by those rules.
Line 4 and Onwards - Palette Data
Each line defines a standard RGB value for a single palette swatch.
Using the Code
That was simple! So with that out of our way, let’s get on with the actual control. We will be creating a control capable of reading a palette file. Populating itself with the swatches therein, and offering selection of each of these colours, it will be an extremely robust control, and in the interest of that, we will be using a
FlowLayoutPanel and adding a panel for every swatch that we read in from the palette file in question. But first, we need to define some global variables:
Private FileType As String
Holds the file type - Defined in the header
Private FileVersion As String
Holds the Image version
Private Colours As Integer
Holds the number of colours in the palette
Private GlobalDataArray As New ArrayList
Holds the actual palette data
Private SelectedPanel As Panel
Holds the currently selected swatch panel
Private ShowSelection As Boolean
Show the white selection square?
The global names in themselves are fairly self-explanatory, and the source code in the sample download is fully commented. But let's go through the general purpose behind the functions in the
AddColourSwatch - Adds a swatch of the specified colour to the control
OpenPaletteFile - Opens a palette file, parses the header and stores the palette data
SavePaletteFile - Saves the palette currently displayed to a file
RemoveSwatch - Removes the swatch at the specified index number
AddPaletteSwatches - Adds the swatches contained in the data passed by
OpenPaletteFile control to the control
PurgeGlobalData - Resets all global variables
HighlightSender - Highlights the swatch that raises this event
RemoveHighlightSender - Removes the highlight from the swatch that raises this event
SelectSender - Selects the swatch that raises this event.
All these functions are very simple, apart from perhaps the
OpenPalettefile is the most complex:
Public Function OpenPaletteFile(ByVal FilePath As String) As Boolean
Dim DataArray As Array
Dim OpenFile As New System.IO.StreamReader(FilePath)
Dim StringHolder As String = ""
Dim PeekHeaderLine As String = ""
PeekHeaderLine = OpenFile.ReadLine()
If PeekHeaderLine.StartsWith("JASC-PAL") Then
FileType = "JASC-PAL"
FileVersion = OpenFile.ReadLine
Colours = Val(OpenFile.ReadLine)
OpenFile = New System.IO.StreamReader(FilePath)
StringHolder = OpenFile.ReadToEnd
StringHolder = StringHolder.Replace(vbNewLine, " ")
DataArray = StringHolder.Split(" ")
For Each StringData As String In DataArray
If Not StringData.Length = 0 Then
Catch MyException As Exception
The basic process of this function is as follows:
- Clear the global data, ready to open a new file.
- Check for a header and read in header information.
- Split the rest of the file into separate values.
- Remove the empty values.
- Start to add the swatches.
Easy as pie! So where do we go from there. Well, many image editor applications can not only read and display palettes, they can also create and save custom palettes, This is where our
SavePaletteFile functions come in. Let's take a look at
Public Function AddColorSwatch(ByVal PanelColour As Color) As Boolean
Dim NewPanel As New Panel
NewPanel.BackColor = PanelColour
NewPanel.BackgroundImage = My.Resources.Palette_Seperator
NewPanel.Margin = New Padding(0)
NewPanel.Size = New Size(12, 12)
AddHandler NewPanel.MouseEnter, AddressOf HighlightSender
AddHandler NewPanel.MouseLeave, AddressOf RemoveHighlightSender
AddHandler NewPanel.Click, AddressOf SelectSender
Catch MyException As Exception
This function is
public, allowing it to be accessed from the control's parent form, perfect for adding swatches. But how does this work? Let's have a look:
- Create a new
panel, assign to it a background image and make it the appropriate size (12x12)
- Add event handlers to it, allowing it to be highlighted when the mouse hovers over it and when it's clicked.
- Add it to the
So how about saving? The capability to save customised palettes and swatches is common to many image editing applications, including Photoshop CS3 and CS4 and Paint Shop Pro.
Public Function SavePaletteFile(ByVal SaveAsJASCPAL As Boolean, _
ByVal FilePath As String) As Boolean
Dim MyStreamWriter As New System.IO.StreamWriter(FilePath)
If SaveAsJASCPAL Then
For Each CurrentPanel As Panel In SwatchLayoutPanel.Controls
MyStreamWriter.Write(CurrentPanel.BackColor.R & " ")
MyStreamWriter.Write(CurrentPanel.BackColor.G & " ")
MyStreamWriter.Write(CurrentPanel.BackColor.B & vbNewLine)
Catch MyException As Exception
It really is as simple as that. Loop through every panel in the
SwatchLayoutPanel and write its RGB value to the destination file.
So there you have it! A highly extensible palette viewer and picker to use in your applications! I sincerely hope that you have as much fun using it and modifying it as I have had creating it!
- A huge thank you to Mark James for his Silk Icon Pack (used in the demo app). Visit his site here.
- 22/12/08 - Article uploaded at 19:00