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