1// tPaletteImage.cpp 
2// 
3// A simple palettized image. Comprised of Width x Height pixel data storing indexes into a palette. The palette is 
4// simply an array of tPixels (RGB). Index resolution is determined by the pixel format (1 to 8 bits). The number of 
5// palette entries (colours) is 2 ^ the index-resolution. 
6// 
7// Copyright (c) 2022, 2024 Tristan Grimmer. 
8// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby 
9// granted, provided that the above copyright notice and this permission notice appear in all copies. 
10// 
11// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 
12// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 
13// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
14// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
15// PERFORMANCE OF THIS SOFTWARE. 
16 
17#include <Foundation/tAssert.h> 
18#include <Foundation/tStandard.h> 
19#include <Foundation/tBitArray.h> 
20#include "Image/tPaletteImage.h" 
21namespace tImage 
22
23 
24 
25bool tPaletteImage::Set(const tPaletteImage& src
26
27 if (&src == this
28 return true
29 
30 Clear(); 
31 if (!src.IsValid()) 
32 return false
33 
34 PixelFormat = src.PixelFormat
35 Width = src.Width
36 Height = src.Height
37 
38 int dataSize = src.GetDataSize(); 
39 tAssert((dataSize > 0) && src.PixelData); 
40 PixelData = new uint8[dataSize]; 
41 tStd::tMemcpy(dest: PixelData, src: src.PixelData, numBytes: dataSize); 
42 
43 int palSize = src.GetPaletteSize(); 
44 tAssert((palSize > 0) && src.Palette); 
45 Palette = new tColour3b[palSize]; 
46 tStd::tMemcpy(dest: Palette, src: src.Palette, numBytes: palSize*sizeof(tColour3b)); 
47 
48 return true
49
50 
51 
52bool tPaletteImage::Set(tPixelFormat fmt, int width, int height
53
54 Clear(); 
55 if (!tIsPaletteFormat(format: fmt) || (width <= 0) || (height <= 0)) 
56 return false
57 
58 PixelFormat = fmt
59 Width = width
60 Height = height
61 
62 int dataSize = GetDataSize(); 
63 tAssert(dataSize > 0); 
64 PixelData = new uint8[dataSize]; 
65 tStd::tMemset(dest: PixelData, val: 0, numBytes: dataSize); 
66 
67 int palSize = GetPaletteSize(); 
68 tAssert(palSize > 0); 
69 Palette = new tColour3b[palSize]; 
70 tStd::tMemset(dest: Palette, val: 0, numBytes: palSize*sizeof(tColour3b)); 
71 
72 return true
73
74 
75 
76bool tPaletteImage::Set(tPixelFormat fmt, int width, int height, const uint8* pixelData, const tColour3b* palette
77
78 Clear(); 
79 if (!tIsPaletteFormat(format: fmt) || (width <= 0) || (height <= 0) || !pixelData || !palette
80 return false
81 
82 PixelFormat = fmt
83 Width = width
84 Height = height
85 
86 int dataSize = GetDataSize(); 
87 tAssert(dataSize > 0); 
88 PixelData = new uint8[dataSize]; 
89 tStd::tMemcpy(dest: PixelData, src: pixelData, numBytes: dataSize); 
90 
91 int palSize = GetPaletteSize(); 
92 tAssert(palSize > 0); 
93 Palette = new tColour3b[palSize]; 
94 tStd::tMemcpy(dest: Palette, src: palette, numBytes: palSize*sizeof(tColour3b)); 
95 
96 return true
97
98 
99 
100bool tPaletteImage::Set(tPixelFormat fmt, int width, int height, const tPixel4b* pixels, tQuantize::Method quantMethod
101
102 Clear(); 
103 if (!tIsPaletteFormat(format: fmt) || (width <= 0) || (height <= 0) || !pixels
104 return false
105 
106 tPixel3b* rgbPixels = new tPixel3b[width*height]; 
107 for (int i = 0; i < width*height; i++) 
108
109 rgbPixels[i].R = pixels[i].R
110 rgbPixels[i].G = pixels[i].G
111 rgbPixels[i].B = pixels[i].B
112
113 bool success = Set(fmt, width, height, pixels: rgbPixels, quantMethod); 
114 
115 delete[] rgbPixels
116 return success
117
118 
119 
120bool tPaletteImage::Set(tPixelFormat fmt, int width, int height, const tPixel3b* pixels, tQuantize::Method quantMethod
121
122 Clear(); 
123 if (!tIsPaletteFormat(format: fmt) || (width <= 0) || (height <= 0) || !pixels
124 return false
125 
126 PixelFormat = fmt
127 Width = width
128 Height = height
129 int numColours = GetPaletteSize(); 
130 Palette = new tColour3b[numColours]; 
131 int dataSize = GetDataSize(); 
132 PixelData = new uint8[dataSize]; 
133 
134 uint8* indices = new uint8[width*height]; 
135 
136 // Step 1. Call quantize. Populates the palette and the indices. 
137 switch (quantMethod
138
139 case tQuantize::Method::Fixed
140 tQuantizeFixed::QuantizeImage(numColours, width, height, pixels, destPalette: Palette, destIndices: indices); 
141 break
142 
143 case tQuantize::Method::Spatial
144 tQuantizeSpatial::QuantizeImage(numColours, width, height, pixels, destPalette: Palette, destIndices: indices); 
145 break
146 
147 case tQuantize::Method::Neu
148 tQuantizeNeu::QuantizeImage(numColours, width, height, pixels, destPalette: Palette, destIndices: indices); 
149 break
150 
151 case tQuantize::Method::Wu
152 tQuantizeWu::QuantizeImage(numColours, width, height, pixels, destPalette: Palette, destIndices: indices); 
153 break
154 
155 default
156 delete[] indices
157 Clear(); 
158 return false
159
160 
161 // Step 2. Populate PixelData from indices. 
162 int bpp = tGetBitsPerPixel(fmt); 
163 int numBits = Width*Height*bpp
164 int bitIndex = 0
165 tBitArray8 bitArray(PixelData, numBits, true); 
166 for (int y = 0; y < Height; y++) 
167
168 for (int x = 0; x < Width; x++) 
169
170 bitArray.SetBits(n: bitIndex, c: bpp, v: indices[x + y*Width]); 
171 bitIndex += bpp
172
173
174  
175 delete[] indices
176 return true
177
178 
179 
180bool tPaletteImage::Get(tPixel4b* pixels
181
182 if (!IsValid() || !pixels
183 return false
184 
185 int bpp = tGetBitsPerPixel(PixelFormat); 
186 int numBits = Width*Height*bpp
187 int bitIndex = 0
188 tBitArray8 bitArray(PixelData, numBits, true); 
189 for (int y = 0; y < Height; y++) 
190
191 for (int x = 0; x < Width; x++) 
192
193 uint8 palIdx = bitArray.GetBits(n: bitIndex, c: bpp); 
194 tColour3b& colour = Palette[palIdx]; 
195 pixels[x + y*Width].Set(r: colour.R, g: colour.G, b: colour.B); 
196 bitIndex += bpp
197
198
199 
200 return true
201
202 
203 
204bool tPaletteImage::Get(tPixel3b* pixels
205
206 if (!IsValid() || !pixels
207 return false
208 
209 int bpp = tGetBitsPerPixel(PixelFormat); 
210 int numBits = Width*Height*bpp
211 int bitIndex = 0
212 tBitArray8 bitArray(PixelData, numBits, true); 
213 for (int y = 0; y < Height; y++) 
214
215 for (int x = 0; x < Width; x++) 
216
217 uint8 palIdx = bitArray.GetBits(n: bitIndex, c: bpp); 
218 tColour3b& colour = Palette[palIdx]; 
219 pixels[x + y*Width].Set(r: colour.R, g: colour.G, b: colour.B); 
220 bitIndex += bpp
221
222
223 
224 return true
225
226 
227 
228int tPaletteImage::GetDataSize() const 
229
230 int numBits = Width*Height*tGetBitsPerPixel(PixelFormat); 
231 int numBytes = (numBits + 7) / 8
232 return numBytes
233
234 
235 
236int tPaletteImage::GetPaletteSize() const 
237
238 return tMath::tPow2(n: tGetBitsPerPixel(PixelFormat)); 
239
240 
241 
242
243