1 //////////////////////////////////////////////////////////////////////////////// 2 // 3 // File: SavePalette.cpp 4 // 5 // Date: December 1999 6 // 7 // Author: Daniel Switkin 8 // 9 // Copyright 2003 (c) by Daniel Switkin. This file is made publically available 10 // under the BSD license, with the stipulations that this complete header must 11 // remain at the top of the file indefinitely, and credit must be given to the 12 // original author in any about box using this software. 13 // 14 //////////////////////////////////////////////////////////////////////////////// 15 16 // Additional authors: Stephan Aßmus, <superstippi@gmx.de> 17 // John Scipione, <jscipione@gmail.com> 18 19 20 #include "SavePalette.h" 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 26 #include <new> 27 28 #include <Bitmap.h> 29 30 31 using std::nothrow; 32 33 extern bool debug; 34 35 36 // "web safe palette" 37 const rgb_color wsp[256] = { 38 {0xff, 0xff, 0xff, 0xff}, {0xff, 0xff, 0xcc, 0xff}, 39 {0xff, 0xff, 0x99, 0xff}, {0xff, 0xff, 0x66, 0xff}, 40 {0xff, 0xff, 0x33, 0xff}, {0xff, 0xff, 0x00, 0xff}, 41 {0xff, 0xcc, 0xff, 0xff}, {0xff, 0xcc, 0xcc, 0xff}, 42 {0xff, 0xcc, 0x99, 0xff}, {0xff, 0xcc, 0x66, 0xff}, 43 {0xff, 0xcc, 0x33, 0xff}, {0xff, 0xcc, 0x00, 0xff}, 44 {0xff, 0x99, 0xff, 0xff}, {0xff, 0x99, 0xcc, 0xff}, 45 {0xff, 0x99, 0x99, 0xff}, {0xff, 0x99, 0x66, 0xff}, 46 {0xff, 0x99, 0x33, 0xff}, {0xff, 0x99, 0x00, 0xff}, 47 {0xff, 0x66, 0xff, 0xff}, {0xff, 0x66, 0xcc, 0xff}, 48 {0xff, 0x66, 0x99, 0xff}, {0xff, 0x66, 0x66, 0xff}, 49 {0xff, 0x66, 0x33, 0xff}, {0xff, 0x66, 0x00, 0xff}, 50 {0xff, 0x33, 0xff, 0xff}, {0xff, 0x33, 0xcc, 0xff}, 51 {0xff, 0x33, 0x99, 0xff}, {0xff, 0x33, 0x66, 0xff}, 52 {0xff, 0x33, 0x33, 0xff}, {0xff, 0x33, 0x00, 0xff}, 53 {0xff, 0x00, 0xff, 0xff}, {0xff, 0x00, 0xcc, 0xff}, 54 {0xff, 0x00, 0x99, 0xff}, {0xff, 0x00, 0x66, 0xff}, 55 {0xff, 0x00, 0x33, 0xff}, {0xff, 0x00, 0x00, 0xff}, 56 {0xcc, 0xff, 0xff, 0xff}, {0xcc, 0xff, 0xcc, 0xff}, 57 {0xcc, 0xff, 0x99, 0xff}, {0xcc, 0xff, 0x66, 0xff}, 58 {0xcc, 0xff, 0x33, 0xff}, {0xcc, 0xff, 0x00, 0xff}, 59 {0xcc, 0xcc, 0xff, 0xff}, {0xcc, 0xcc, 0xcc, 0xff}, 60 {0xcc, 0xcc, 0x99, 0xff}, {0xcc, 0xcc, 0x66, 0xff}, 61 {0xcc, 0xcc, 0x33, 0xff}, {0xcc, 0xcc, 0x00, 0xff}, 62 {0xcc, 0x99, 0xff, 0xff}, {0xcc, 0x99, 0xcc, 0xff}, 63 {0xcc, 0x99, 0x99, 0xff}, {0xcc, 0x99, 0x66, 0xff}, 64 {0xcc, 0x99, 0x33, 0xff}, {0xcc, 0x99, 0x00, 0xff}, 65 {0xcc, 0x66, 0xff, 0xff}, {0xcc, 0x66, 0xcc, 0xff}, 66 {0xcc, 0x66, 0x99, 0xff}, {0xcc, 0x66, 0x66, 0xff}, 67 {0xcc, 0x66, 0x33, 0xff}, {0xcc, 0x66, 0x00, 0xff}, 68 {0xcc, 0x33, 0xff, 0xff}, {0xcc, 0x33, 0xcc, 0xff}, 69 {0xcc, 0x33, 0x99, 0xff}, {0xcc, 0x33, 0x66, 0xff}, 70 {0xcc, 0x33, 0x33, 0xff}, {0xcc, 0x33, 0x00, 0xff}, 71 {0xcc, 0x00, 0xff, 0xff}, {0xcc, 0x00, 0xcc, 0xff}, 72 {0xcc, 0x00, 0x99, 0xff}, {0xcc, 0x00, 0x66, 0xff}, 73 {0xcc, 0x00, 0x33, 0xff}, {0xcc, 0x00, 0x00, 0xff}, 74 {0x99, 0xff, 0xff, 0xff}, {0x99, 0xff, 0xcc, 0xff}, 75 {0x99, 0xff, 0x99, 0xff}, {0x99, 0xff, 0x66, 0xff}, 76 {0x99, 0xff, 0x33, 0xff}, {0x99, 0xff, 0x00, 0xff}, 77 {0x99, 0xcc, 0xff, 0xff}, {0x99, 0xcc, 0xcc, 0xff}, 78 {0x99, 0xcc, 0x99, 0xff}, {0x99, 0xcc, 0x66, 0xff}, 79 {0x99, 0xcc, 0x33, 0xff}, {0x99, 0xcc, 0x00, 0xff}, 80 {0x99, 0x99, 0xff, 0xff}, {0x99, 0x99, 0xcc, 0xff}, 81 {0x99, 0x99, 0x99, 0xff}, {0x99, 0x99, 0x66, 0xff}, 82 {0x99, 0x99, 0x33, 0xff}, {0x99, 0x99, 0x00, 0xff}, 83 {0x99, 0x66, 0xff, 0xff}, {0x99, 0x66, 0xcc, 0xff}, 84 {0x99, 0x66, 0x99, 0xff}, {0x99, 0x66, 0x66, 0xff}, 85 {0x99, 0x66, 0x33, 0xff}, {0x99, 0x66, 0x00, 0xff}, 86 {0x99, 0x33, 0xff, 0xff}, {0x99, 0x33, 0xcc, 0xff}, 87 {0x99, 0x33, 0x99, 0xff}, {0x99, 0x33, 0x66, 0xff}, 88 {0x99, 0x33, 0x33, 0xff}, {0x99, 0x33, 0x00, 0xff}, 89 {0x99, 0x00, 0xff, 0xff}, {0x99, 0x00, 0xcc, 0xff}, 90 {0x99, 0x00, 0x99, 0xff}, {0x99, 0x00, 0x66, 0xff}, 91 {0x99, 0x00, 0x33, 0xff}, {0x99, 0x00, 0x00, 0xff}, 92 {0x66, 0xff, 0xff, 0xff}, {0x66, 0xff, 0xcc, 0xff}, 93 {0x66, 0xff, 0x99, 0xff}, {0x66, 0xff, 0x66, 0xff}, 94 {0x66, 0xff, 0x33, 0xff}, {0x66, 0xff, 0x00, 0xff}, 95 {0x66, 0xcc, 0xff, 0xff}, {0x66, 0xcc, 0xcc, 0xff}, 96 {0x66, 0xcc, 0x99, 0xff}, {0x66, 0xcc, 0x66, 0xff}, 97 {0x66, 0xcc, 0x33, 0xff}, {0x66, 0xcc, 0x00, 0xff}, 98 {0x66, 0x99, 0xff, 0xff}, {0x66, 0x99, 0xcc, 0xff}, 99 {0x66, 0x99, 0x99, 0xff}, {0x66, 0x99, 0x66, 0xff}, 100 {0x66, 0x99, 0x33, 0xff}, {0x66, 0x99, 0x00, 0xff}, 101 {0x66, 0x66, 0xff, 0xff}, {0x66, 0x66, 0xcc, 0xff}, 102 {0x66, 0x66, 0x99, 0xff}, {0x66, 0x66, 0x66, 0xff}, 103 {0x66, 0x66, 0x33, 0xff}, {0x66, 0x66, 0x00, 0xff}, 104 {0x66, 0x33, 0xff, 0xff}, {0x66, 0x33, 0xcc, 0xff}, 105 {0x66, 0x33, 0x99, 0xff}, {0x66, 0x33, 0x66, 0xff}, 106 {0x66, 0x33, 0x33, 0xff}, {0x66, 0x33, 0x00, 0xff}, 107 {0x66, 0x00, 0xff, 0xff}, {0x66, 0x00, 0xcc, 0xff}, 108 {0x66, 0x00, 0x99, 0xff}, {0x66, 0x00, 0x66, 0xff}, 109 {0x66, 0x00, 0x33, 0xff}, {0x66, 0x00, 0x00, 0xff}, 110 {0x33, 0xff, 0xff, 0xff}, {0x33, 0xff, 0xcc, 0xff}, 111 {0x33, 0xff, 0x99, 0xff}, {0x33, 0xff, 0x66, 0xff}, 112 {0x33, 0xff, 0x33, 0xff}, {0x33, 0xff, 0x00, 0xff}, 113 {0x33, 0xcc, 0xff, 0xff}, {0x33, 0xcc, 0xcc, 0xff}, 114 {0x33, 0xcc, 0x99, 0xff}, {0x33, 0xcc, 0x66, 0xff}, 115 {0x33, 0xcc, 0x33, 0xff}, {0x33, 0xcc, 0x00, 0xff}, 116 {0x33, 0x99, 0xff, 0xff}, {0x33, 0x99, 0xcc, 0xff}, 117 {0x33, 0x99, 0x99, 0xff}, {0x33, 0x99, 0x66, 0xff}, 118 {0x33, 0x99, 0x33, 0xff}, {0x33, 0x99, 0x00, 0xff}, 119 {0x33, 0x66, 0xff, 0xff}, {0x33, 0x66, 0xcc, 0xff}, 120 {0x33, 0x66, 0x99, 0xff}, {0x33, 0x66, 0x66, 0xff}, 121 {0x33, 0x66, 0x33, 0xff}, {0x33, 0x66, 0x00, 0xff}, 122 {0x33, 0x33, 0xff, 0xff}, {0x33, 0x33, 0xcc, 0xff}, 123 {0x33, 0x33, 0x99, 0xff}, {0x33, 0x33, 0x66, 0xff}, 124 {0x33, 0x33, 0x33, 0xff}, {0x33, 0x33, 0x00, 0xff}, 125 {0x33, 0x00, 0xff, 0xff}, {0x33, 0x00, 0xcc, 0xff}, 126 {0x33, 0x00, 0x99, 0xff}, {0x33, 0x00, 0x66, 0xff}, 127 {0x33, 0x00, 0x33, 0xff}, {0x33, 0x00, 0x00, 0xff}, 128 {0x00, 0xff, 0xff, 0xff}, {0x00, 0xff, 0xcc, 0xff}, 129 {0x00, 0xff, 0x99, 0xff}, {0x00, 0xff, 0x66, 0xff}, 130 {0x00, 0xff, 0x33, 0xff}, {0x00, 0xff, 0x00, 0xff}, 131 {0x00, 0xcc, 0xff, 0xff}, {0x00, 0xcc, 0xcc, 0xff}, 132 {0x00, 0xcc, 0x99, 0xff}, {0x00, 0xcc, 0x66, 0xff}, 133 {0x00, 0xcc, 0x33, 0xff}, {0x00, 0xcc, 0x00, 0xff}, 134 {0x00, 0x99, 0xff, 0xff}, {0x00, 0x99, 0xcc, 0xff}, 135 {0x00, 0x99, 0x99, 0xff}, {0x00, 0x99, 0x66, 0xff}, 136 {0x00, 0x99, 0x33, 0xff}, {0x00, 0x99, 0x00, 0xff}, 137 {0x00, 0x66, 0xff, 0xff}, {0x00, 0x66, 0xcc, 0xff}, 138 {0x00, 0x66, 0x99, 0xff}, {0x00, 0x66, 0x66, 0xff}, 139 {0x00, 0x66, 0x33, 0xff}, {0x00, 0x66, 0x00, 0xff}, 140 {0x00, 0x33, 0xff, 0xff}, {0x00, 0x33, 0xcc, 0xff}, 141 {0x00, 0x33, 0x99, 0xff}, {0x00, 0x33, 0x66, 0xff}, 142 {0x00, 0x33, 0x33, 0xff}, {0x00, 0x33, 0x00, 0xff}, 143 {0x00, 0x00, 0xff, 0xff}, {0x00, 0x00, 0xcc, 0xff}, 144 {0x00, 0x00, 0x99, 0xff}, {0x00, 0x00, 0x66, 0xff}, 145 {0x00, 0x00, 0x33, 0xff}, {0x00, 0x00, 0x00, 0xff}, 146 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 147 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 148 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 149 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 150 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 151 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 152 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 153 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 154 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 155 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 156 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 157 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 158 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 159 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 160 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 161 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 162 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 163 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 164 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff}, 165 {0x00, 0x00, 0x00, 0xff}, {0x00, 0x00, 0x00, 0xff} 166 }; 167 168 169 struct ColorItem : public HashItem { 170 ColorItem(unsigned int k, unsigned int c, 171 uint8 r, uint8 g, uint8 b) 172 : 173 count(c), 174 red(r), 175 green(g), 176 blue(b) 177 { 178 key = k; 179 } 180 181 unsigned int count; 182 uint8 red; 183 uint8 green; 184 uint8 blue; 185 }; 186 187 188 SavePalette::SavePalette(int mode) 189 : 190 pal(new(nothrow) rgb_color[256]), 191 fSize(0), 192 fSizeInBits(8), 193 fMode(mode), 194 fTransparentMode(NO_TRANSPARENCY), 195 fTransparentIndex(-1), 196 fBackgroundIndex(0), 197 fFatalError(pal == NULL) 198 { 199 if (IsValid()) { 200 if (fMode == WEB_SAFE_PALETTE) { 201 memcpy(pal, wsp, sizeof(rgb_color) * 256); 202 fSize = 216; 203 } else if (fMode == BEOS_SYSTEM_PALETTE) { 204 color_map* map = (color_map*)system_colors(); 205 memcpy(pal, map->color_list, sizeof(rgb_color) * 256); 206 fSize = 256; 207 } else if (fMode == GREYSCALE_PALETTE) { 208 for (int i = 0; i < 256; i++) { 209 pal[i].red = pal[i].green = pal[i].blue = i; 210 pal[i].alpha = 0xff; 211 } 212 fSize = 256; 213 } 214 } 215 } 216 217 218 static int 219 make_key(uint8 r, uint8 g, uint8 b, uint8 bits) 220 { 221 r = r >> (8 - bits); 222 g = g >> (8 - bits); 223 b = b >> (8 - bits); 224 225 return (r << (bits * 2)) | (g << bits) | b; 226 } 227 228 229 static bool 230 touch_color_item(SFHash& hash, unsigned int key, uint8 r, uint8 g, uint8 b) 231 { 232 ColorItem* ci = (ColorItem*)hash.GetItem(key); 233 if (ci == NULL) { 234 ci = new(nothrow) ColorItem(key, 1, r, g, b); 235 if (ci == NULL) { 236 if (debug) 237 printf("Out of memory in touch_color_item()\n"); 238 return false; 239 } 240 hash.AddItem((HashItem*)ci); 241 } else { 242 ci->count++; 243 #if 0 244 // use brightest color 245 ci->red = max_c(ci->red, r); 246 ci->green = max_c(ci->green, g); 247 ci->blue = max_c(ci->blue, b); 248 #endif 249 } 250 return true; 251 } 252 253 254 SavePalette::SavePalette(BBitmap* bitmap, int32 maxSizeInBits) 255 : 256 pal(new(nothrow) rgb_color[256]), 257 fSize(0), 258 fSizeInBits(0), 259 fMode(OPTIMAL_PALETTE), 260 fTransparentMode(NO_TRANSPARENCY), 261 fTransparentIndex(-1), 262 fBackgroundIndex(0), 263 fFatalError(pal == NULL) 264 { 265 if (!IsValid()) 266 return; 267 268 SFHash hash(1 << 16); 269 if (hash.fatalerror) { 270 if (debug) 271 printf("Out of memory in SavePalette(BBitmap*)\n"); 272 fFatalError = true; 273 return; 274 } 275 276 // reject unsupported color spaces 277 // TODO: B_CMAP8 and B_GRAY8 should be really easy to support as well!! 278 color_space cs = bitmap->ColorSpace(); 279 if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG 280 && cs != B_RGBA32_BIG) { 281 if (debug) { 282 printf("Wrong color space given in SavePalette(BBitmap):\n"); 283 printf("%d %d %d %d or 0x%x\n", 284 (cs & 0xff000000) >> 24, (cs & 0xff0000) >> 16, 285 (cs & 0xff00) >> 8, cs & 0xff, cs); 286 } 287 fFatalError = true; 288 return; 289 } 290 291 BRect rect = bitmap->Bounds(); 292 uint32 height = rect.IntegerHeight() + 1; 293 uint32 width = rect.IntegerWidth() + 1; 294 uint8* bits = (uint8*)bitmap->Bits(); 295 uint32 bpr = bitmap->BytesPerRow(); 296 297 uint8 r; 298 uint8 g; 299 uint8 b; 300 uint8 useBits = 3 + maxSizeInBits / 2; 301 if (cs == B_RGB32 || cs == B_RGBA32) { 302 for (uint32 y = 0; y < height; y++) { 303 uint8* handle = bits; 304 for (uint32 x = 0; x < width; x++) { 305 b = handle[0]; 306 g = handle[1]; 307 r = handle[2]; 308 handle += 4; 309 310 uint32 key = make_key(r, g, b, useBits); 311 if (!touch_color_item(hash, key, r, g, b)) { 312 if (debug) 313 printf("Out of memory in SavePalette(BBitmap*)\n"); 314 315 fFatalError = true; 316 return; 317 } 318 } 319 bits += bpr; 320 } 321 } else if ((cs == B_RGB32_BIG || cs == B_RGBA32_BIG)) { 322 for (uint32 y = 0; y < height; y++) { 323 uint8* handle = bits; 324 for (uint32 x = 0; x < width; x++) { 325 b = handle[2]; 326 g = handle[1]; 327 r = handle[0]; 328 handle += 4; 329 330 uint32 key = make_key(r, g, b, useBits); 331 if (!touch_color_item(hash, key, r, g, b)) { 332 if (debug) 333 printf("Out of memory in SavePalette(BBitmap*)\n"); 334 fFatalError = true; 335 return; 336 } 337 } 338 bits += bpr; 339 } 340 } 341 342 int unique_colors = hash.CountItems(); 343 while (((1 << fSizeInBits) < unique_colors) 344 && (fSizeInBits < maxSizeInBits)) { 345 fSizeInBits++; 346 } 347 fSize = 1 << fSizeInBits; 348 349 ColorItem** topcolors = (ColorItem**)malloc(fSize * sizeof(ColorItem*)); 350 if (topcolors == NULL) { 351 if (debug) printf("Out of memory in SavePalette(BBitmap*)\n"); 352 fFatalError = true; 353 return; 354 } 355 ColorItem* dummy = new ColorItem(0, 0, 0, 0, 0); 356 for (int i = 0; i < fSize; i++) 357 topcolors[i] = dummy; 358 359 for (int i = 0; i < unique_colors; i++) { 360 ColorItem* ci = (ColorItem*)hash.NextItem(); 361 for (int j = 0; j < fSize; j++) { 362 if (ci->count > topcolors[j]->count) { 363 for (int k = fSize - 1; k > j; k--) { 364 topcolors[k] = topcolors[k - 1]; 365 } 366 topcolors[j] = ci; 367 break; 368 } 369 } 370 } 371 372 for (int i = 0; i < fSize; i++) { 373 pal[i].red = topcolors[i]->red; 374 pal[i].green = topcolors[i]->green; 375 pal[i].blue = topcolors[i]->blue; 376 pal[i].alpha = 0xff; 377 } 378 379 delete dummy; 380 free(topcolors); 381 } 382 383 384 SavePalette::~SavePalette() 385 { 386 delete[] pal; 387 } 388 389 390 uint8 391 SavePalette::IndexForColor(uint8 red, uint8 green, uint8 blue, uint8 alpha) 392 { 393 // standard mapping services once a palette is loaded 394 if (fTransparentMode > NO_TRANSPARENCY && alpha < 128) 395 return fTransparentIndex; 396 397 uint8 index = 0; 398 399 if (fMode == GREYSCALE_PALETTE) { 400 index = (308 * red + 600 * green + 116 * blue) / 1024; 401 // avoid transparent index 402 if (fTransparentMode == AUTO_TRANSPARENCY && index == 1 403 && fTransparentIndex == 1) { 404 index = 0; 405 } 406 } else { 407 int closestDistance = 255 * 255 * 3; 408 409 if (fTransparentMode == AUTO_TRANSPARENCY) { 410 for (int i = 0; i < fTransparentIndex && closestDistance != 0; 411 i++) { 412 int rd = (int)red - (int)pal[i].red; 413 int gd = (int)green - (int)pal[i].green; 414 int bd = (int)blue - (int)pal[i].blue; 415 int distanceAtIndex = rd * rd + gd * gd + bd * bd; 416 if (distanceAtIndex < closestDistance) { 417 closestDistance = distanceAtIndex; 418 index = i; 419 } 420 } 421 for (int i = fTransparentIndex + 1; 422 i < fSize && closestDistance != 0; i++) { 423 int rd = (int)red - (int)pal[i].red; 424 int gd = (int)green - (int)pal[i].green; 425 int bd = (int)blue - (int)pal[i].blue; 426 int distanceAtIndex = rd * rd + gd * gd + bd * bd; 427 if (distanceAtIndex < closestDistance) { 428 closestDistance = distanceAtIndex; 429 index = i; 430 } 431 } 432 } else { 433 for (int i = 0; i < fSize && closestDistance != 0; i++) { 434 int rd = (int)red - (int)pal[i].red; 435 int gd = (int)green - (int)pal[i].green; 436 int bd = (int)blue - (int)pal[i].blue; 437 int distanceAtIndex = rd * rd + gd * gd + bd * bd; 438 if (distanceAtIndex < closestDistance) { 439 closestDistance = distanceAtIndex; 440 index = i; 441 } 442 } 443 } 444 } 445 446 return index; 447 } 448 449 450 void 451 SavePalette::PrepareForAutoTransparency() 452 { 453 fTransparentMode = AUTO_TRANSPARENCY; 454 // TODO: in the SavePalette::SavePalette(BBitmap*), 455 // we don't use more colors than necessary, however, 456 // here we take a slot away for transparency, even if 457 // we might still have used less colors than the user 458 // wanted as a maximum 459 // NOTE: the last index 460 switch (fMode) { 461 case WEB_SAFE_PALETTE: 462 fTransparentIndex = 216; 463 fSize = 217; 464 break; 465 case BEOS_SYSTEM_PALETTE: 466 fTransparentIndex = 0; 467 break; 468 case GREYSCALE_PALETTE: 469 fTransparentIndex = 1; 470 break; 471 case OPTIMAL_PALETTE: 472 fTransparentIndex = fSize - 1; 473 break; 474 } 475 } 476 477 478 void 479 SavePalette::SetTransparentColor(uint8 red, uint8 green, uint8 blue) 480 { 481 fTransparentMode = COLOR_KEY_TRANSPARENCY; 482 483 bool found = false; 484 // try direct hit first 485 for (int i = 0; i < fSize; i++) { 486 if (pal[i].red == red && 487 pal[i].green == green && 488 pal[i].blue == blue) { 489 490 fTransparentIndex = i; 491 found = true; 492 493 break; 494 } 495 } 496 if (!found) { 497 // find closest match 498 fTransparentIndex = IndexForColor(red, green, blue); 499 // NOTE: This is a tough decision: 500 // -> the exact color might be contained within the image 501 // but have slipped through the net and is now not in the 502 // palette, the user still wants those pixels to be 503 // transparent of course, so it is best to match up a 504 // color from the palette 505 // -> on the other hand, the setting might still be there 506 // from some previous image and the color might not 507 // even appear in the current image at all... but I guess 508 // handling it like below is the lesser evil. 509 // match up color at index to provided transparent color, 510 // to make sure it actually works 511 pal[fTransparentIndex].red = red; 512 pal[fTransparentIndex].green = green; 513 pal[fTransparentIndex].blue = blue; 514 found = true; 515 } 516 } 517 518 519 void 520 SavePalette::GetColors(uint8* buffer, int size) const 521 { 522 int maxIndex = max_c(size / 3, fSize) - 1; 523 for (int i = 0; i <= maxIndex; i++) { 524 *buffer++ = pal[i].red; 525 *buffer++ = pal[i].green; 526 *buffer++ = pal[i].blue; 527 } 528 int rest = (maxIndex + 1) * 3; 529 if (rest < size) 530 memset(buffer, 0, size - rest); 531 } 532