1 /* 2 * Copyright 2001-2006, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold (bonefish@users.sf.net) 7 * Michael Lotz <mmlr@mlotz.ch> 8 */ 9 10 /** This file contains colorspace conversion functions 11 * and a palette <-> true color conversion class. 12 */ 13 14 #include "ColorConversion.h" 15 16 #include <InterfaceDefs.h> 17 #include <Locker.h> 18 #include <Point.h> 19 20 #include <new> 21 #include <string.h> 22 23 24 using std::nothrow; 25 26 27 namespace BPrivate { 28 29 // TODO: system palette -- hard-coded for now, when the app server is ready 30 // we should use system_colors() or BScreen::ColorMap(). 31 // Stefano: We cannot do that, since this code is also used by client-side only BBitmaps, 32 // and also by the app_server 33 const rgb_color kSystemPalette[] = { 34 { 0, 0, 0, 255 }, { 8, 8, 8, 255 }, { 16, 16, 16, 255 }, 35 { 24, 24, 24, 255 }, { 32, 32, 32, 255 }, { 40, 40, 40, 255 }, 36 { 48, 48, 48, 255 }, { 56, 56, 56, 255 }, { 64, 64, 64, 255 }, 37 { 72, 72, 72, 255 }, { 80, 80, 80, 255 }, { 88, 88, 88, 255 }, 38 { 96, 96, 96, 255 }, { 104, 104, 104, 255 }, { 112, 112, 112, 255 }, 39 { 120, 120, 120, 255 }, { 128, 128, 128, 255 }, { 136, 136, 136, 255 }, 40 { 144, 144, 144, 255 }, { 152, 152, 152, 255 }, { 160, 160, 160, 255 }, 41 { 168, 168, 168, 255 }, { 176, 176, 176, 255 }, { 184, 184, 184, 255 }, 42 { 192, 192, 192, 255 }, { 200, 200, 200, 255 }, { 208, 208, 208, 255 }, 43 { 216, 216, 216, 255 }, { 224, 224, 224, 255 }, { 232, 232, 232, 255 }, 44 { 240, 240, 240, 255 }, { 248, 248, 248, 255 }, { 0, 0, 255, 255 }, 45 { 0, 0, 229, 255 }, { 0, 0, 204, 255 }, { 0, 0, 179, 255 }, 46 { 0, 0, 154, 255 }, { 0, 0, 129, 255 }, { 0, 0, 105, 255 }, 47 { 0, 0, 80, 255 }, { 0, 0, 55, 255 }, { 0, 0, 30, 255 }, 48 { 255, 0, 0, 255 }, { 228, 0, 0, 255 }, { 203, 0, 0, 255 }, 49 { 178, 0, 0, 255 }, { 153, 0, 0, 255 }, { 128, 0, 0, 255 }, 50 { 105, 0, 0, 255 }, { 80, 0, 0, 255 }, { 55, 0, 0, 255 }, 51 { 30, 0, 0, 255 }, { 0, 255, 0, 255 }, { 0, 228, 0, 255 }, 52 { 0, 203, 0, 255 }, { 0, 178, 0, 255 }, { 0, 153, 0, 255 }, 53 { 0, 128, 0, 255 }, { 0, 105, 0, 255 }, { 0, 80, 0, 255 }, 54 { 0, 55, 0, 255 }, { 0, 30, 0, 255 }, { 0, 152, 51, 255 }, 55 { 255, 255, 255, 255 }, { 203, 255, 255, 255 }, { 203, 255, 203, 255 }, 56 { 203, 255, 152, 255 }, { 203, 255, 102, 255 }, { 203, 255, 51, 255 }, 57 { 203, 255, 0, 255 }, { 152, 255, 255, 255 }, { 152, 255, 203, 255 }, 58 { 152, 255, 152, 255 }, { 152, 255, 102, 255 }, { 152, 255, 51, 255 }, 59 { 152, 255, 0, 255 }, { 102, 255, 255, 255 }, { 102, 255, 203, 255 }, 60 { 102, 255, 152, 255 }, { 102, 255, 102, 255 }, { 102, 255, 51, 255 }, 61 { 102, 255, 0, 255 }, { 51, 255, 255, 255 }, { 51, 255, 203, 255 }, 62 { 51, 255, 152, 255 }, { 51, 255, 102, 255 }, { 51, 255, 51, 255 }, 63 { 51, 255, 0, 255 }, { 255, 152, 255, 255 }, { 255, 152, 203, 255 }, 64 { 255, 152, 152, 255 }, { 255, 152, 102, 255 }, { 255, 152, 51, 255 }, 65 { 255, 152, 0, 255 }, { 0, 102, 255, 255 }, { 0, 102, 203, 255 }, 66 { 203, 203, 255, 255 }, { 203, 203, 203, 255 }, { 203, 203, 152, 255 }, 67 { 203, 203, 102, 255 }, { 203, 203, 51, 255 }, { 203, 203, 0, 255 }, 68 { 152, 203, 255, 255 }, { 152, 203, 203, 255 }, { 152, 203, 152, 255 }, 69 { 152, 203, 102, 255 }, { 152, 203, 51, 255 }, { 152, 203, 0, 255 }, 70 { 102, 203, 255, 255 }, { 102, 203, 203, 255 }, { 102, 203, 152, 255 }, 71 { 102, 203, 102, 255 }, { 102, 203, 51, 255 }, { 102, 203, 0, 255 }, 72 { 51, 203, 255, 255 }, { 51, 203, 203, 255 }, { 51, 203, 152, 255 }, 73 { 51, 203, 102, 255 }, { 51, 203, 51, 255 }, { 51, 203, 0, 255 }, 74 { 255, 102, 255, 255 }, { 255, 102, 203, 255 }, { 255, 102, 152, 255 }, 75 { 255, 102, 102, 255 }, { 255, 102, 51, 255 }, { 255, 102, 0, 255 }, 76 { 0, 102, 152, 255 }, { 0, 102, 102, 255 }, { 203, 152, 255, 255 }, 77 { 203, 152, 203, 255 }, { 203, 152, 152, 255 }, { 203, 152, 102, 255 }, 78 { 203, 152, 51, 255 }, { 203, 152, 0, 255 }, { 152, 152, 255, 255 }, 79 { 152, 152, 203, 255 }, { 152, 152, 152, 255 }, { 152, 152, 102, 255 }, 80 { 152, 152, 51, 255 }, { 152, 152, 0, 255 }, { 102, 152, 255, 255 }, 81 { 102, 152, 203, 255 }, { 102, 152, 152, 255 }, { 102, 152, 102, 255 }, 82 { 102, 152, 51, 255 }, { 102, 152, 0, 255 }, { 51, 152, 255, 255 }, 83 { 51, 152, 203, 255 }, { 51, 152, 152, 255 }, { 51, 152, 102, 255 }, 84 { 51, 152, 51, 255 }, { 51, 152, 0, 255 }, { 230, 134, 0, 255 }, 85 { 255, 51, 203, 255 }, { 255, 51, 152, 255 }, { 255, 51, 102, 255 }, 86 { 255, 51, 51, 255 }, { 255, 51, 0, 255 }, { 0, 102, 51, 255 }, 87 { 0, 102, 0, 255 }, { 203, 102, 255, 255 }, { 203, 102, 203, 255 }, 88 { 203, 102, 152, 255 }, { 203, 102, 102, 255 }, { 203, 102, 51, 255 }, 89 { 203, 102, 0, 255 }, { 152, 102, 255, 255 }, { 152, 102, 203, 255 }, 90 { 152, 102, 152, 255 }, { 152, 102, 102, 255 }, { 152, 102, 51, 255 }, 91 { 152, 102, 0, 255 }, { 102, 102, 255, 255 }, { 102, 102, 203, 255 }, 92 { 102, 102, 152, 255 }, { 102, 102, 102, 255 }, { 102, 102, 51, 255 }, 93 { 102, 102, 0, 255 }, { 51, 102, 255, 255 }, { 51, 102, 203, 255 }, 94 { 51, 102, 152, 255 }, { 51, 102, 102, 255 }, { 51, 102, 51, 255 }, 95 { 51, 102, 0, 255 }, { 255, 0, 255, 255 }, { 255, 0, 203, 255 }, 96 { 255, 0, 152, 255 }, { 255, 0, 102, 255 }, { 255, 0, 51, 255 }, 97 { 255, 175, 19, 255 }, { 0, 51, 255, 255 }, { 0, 51, 203, 255 }, 98 { 203, 51, 255, 255 }, { 203, 51, 203, 255 }, { 203, 51, 152, 255 }, 99 { 203, 51, 102, 255 }, { 203, 51, 51, 255 }, { 203, 51, 0, 255 }, 100 { 152, 51, 255, 255 }, { 152, 51, 203, 255 }, { 152, 51, 152, 255 }, 101 { 152, 51, 102, 255 }, { 152, 51, 51, 255 }, { 152, 51, 0, 255 }, 102 { 102, 51, 255, 255 }, { 102, 51, 203, 255 }, { 102, 51, 152, 255 }, 103 { 102, 51, 102, 255 }, { 102, 51, 51, 255 }, { 102, 51, 0, 255 }, 104 { 51, 51, 255, 255 }, { 51, 51, 203, 255 }, { 51, 51, 152, 255 }, 105 { 51, 51, 102, 255 }, { 51, 51, 51, 255 }, { 51, 51, 0, 255 }, 106 { 255, 203, 102, 255 }, { 255, 203, 152, 255 }, { 255, 203, 203, 255 }, 107 { 255, 203, 255, 255 }, { 0, 51, 152, 255 }, { 0, 51, 102, 255 }, 108 { 0, 51, 51, 255 }, { 0, 51, 0, 255 }, { 203, 0, 255, 255 }, 109 { 203, 0, 203, 255 }, { 203, 0, 152, 255 }, { 203, 0, 102, 255 }, 110 { 203, 0, 51, 255 }, { 255, 227, 70, 255 }, { 152, 0, 255, 255 }, 111 { 152, 0, 203, 255 }, { 152, 0, 152, 255 }, { 152, 0, 102, 255 }, 112 { 152, 0, 51, 255 }, { 152, 0, 0, 255 }, { 102, 0, 255, 255 }, 113 { 102, 0, 203, 255 }, { 102, 0, 152, 255 }, { 102, 0, 102, 255 }, 114 { 102, 0, 51, 255 }, { 102, 0, 0, 255 }, { 51, 0, 255, 255 }, 115 { 51, 0, 203, 255 }, { 51, 0, 152, 255 }, { 51, 0, 102, 255 }, 116 { 51, 0, 51, 255 }, { 51, 0, 0, 255 }, { 255, 203, 51, 255 }, 117 { 255, 203, 0, 255 }, { 255, 255, 0, 255 }, { 255, 255, 51, 255 }, 118 { 255, 255, 102, 255 }, { 255, 255, 152, 255 }, { 255, 255, 203, 255 }, 119 { 255, 255, 255, 0 } // B_TRANSPARENT_MAGIC_CMAP8 120 }; 121 122 123 /*! \brief Returns the brightness of an RGB 24 color. 124 \param red Value of the red component. 125 \param green Value of the green component. 126 \param blue Value of the blue component. 127 \return The brightness for the supplied RGB color as a value between 0 128 and 255. 129 */ 130 static inline 131 uint8 132 brightness_for(uint8 red, uint8 green, uint8 blue) 133 { 134 // brightness = 0.301 * red + 0.586 * green + 0.113 * blue 135 // we use for performance reasons: 136 // brightness = (308 * red + 600 * green + 116 * blue) / 1024 137 return uint8((308 * red + 600 * green + 116 * blue) / 1024); 138 } 139 140 141 /*! \brief Returns the "distance" between two RGB colors. 142 143 This functions defines an metric on the RGB color space. The distance 144 between two colors is 0, if and only if the colors are equal. 145 146 \param red1 Red component of the first color. 147 \param green1 Green component of the first color. 148 \param blue1 Blue component of the first color. 149 \param red2 Red component of the second color. 150 \param green2 Green component of the second color. 151 \param blue2 Blue component of the second color. 152 \return The distance between the given colors. 153 */ 154 static inline 155 unsigned 156 color_distance(uint8 red1, uint8 green1, uint8 blue1, 157 uint8 red2, uint8 green2, uint8 blue2) 158 { 159 // euklidian distance (its square actually) 160 int rd = (int)red1 - (int)red2; 161 int gd = (int)green1 - (int)green2; 162 int bd = (int)blue1 - (int)blue2; 163 //return rd * rd + gd * gd + bd * bd; 164 165 // distance according to psycho-visual tests 166 int rmean = ((int)red1 + (int)red2) / 2; 167 return (((512 + rmean) * rd * rd) >> 8) 168 + 4 * gd * gd 169 + (((767 - rmean) * bd * bd) >> 8); 170 } 171 172 173 /*! \brief Creates an uninitialized PaletteConverter. 174 */ 175 PaletteConverter::PaletteConverter() 176 : fColorMap(NULL), 177 fOwnColorMap(NULL), 178 fCStatus(B_NO_INIT) 179 { 180 } 181 182 183 /*! \brief Creates a PaletteConverter and initializes it to the supplied 184 palette. 185 \param palette The palette being a 256 entry rgb_color array. 186 */ 187 PaletteConverter::PaletteConverter(const rgb_color *palette) 188 : fColorMap(NULL), 189 fOwnColorMap(NULL), 190 fCStatus(B_NO_INIT) 191 { 192 SetTo(palette); 193 } 194 195 196 /*! \brief Creates a PaletteConverter and initializes it to the supplied 197 color map. 198 \param colorMap The completely initialized color map. 199 */ 200 PaletteConverter::PaletteConverter(const color_map *colorMap) 201 : fColorMap(NULL), 202 fOwnColorMap(NULL), 203 fCStatus(B_NO_INIT) 204 { 205 SetTo(colorMap); 206 } 207 208 209 /*! \brief Frees all resources associated with this object. 210 */ 211 PaletteConverter::~PaletteConverter() 212 { 213 delete fOwnColorMap; 214 } 215 216 217 /*! \brief Initializes the converter to the supplied palette. 218 \param palette The palette being a 256 entry rgb_color array. 219 \return \c B_OK, if everything went fine, an error code otherwise. 220 */ 221 status_t 222 PaletteConverter::SetTo(const rgb_color *palette) 223 { 224 // cleanup 225 SetTo((const color_map*)NULL); 226 status_t error = (palette ? B_OK : B_BAD_VALUE); 227 // alloc color map 228 if (error == B_OK) { 229 fOwnColorMap = new(nothrow) color_map; 230 if (fOwnColorMap == NULL) 231 error = B_NO_MEMORY; 232 } 233 // init color map 234 if (error == B_OK) { 235 fColorMap = fOwnColorMap; 236 // init color list 237 memcpy(fOwnColorMap->color_list, palette, sizeof(rgb_color) * 256); 238 // init index map 239 // TODO: build this list takes about 2 seconds in qemu on my system 240 // (because of color_distance()) 241 for (int32 color = 0; color < 32768; color++) { 242 // get components 243 uint8 red = (color & 0x7c00) >> 7; 244 uint8 green = (color & 0x3e0) >> 2; 245 uint8 blue = (color & 0x1f) << 3; 246 red |= red >> 5; 247 green |= green >> 5; 248 blue |= blue >> 5; 249 // find closest color 250 uint8 closestIndex = 0; 251 unsigned closestDistance = UINT_MAX; 252 for (int32 i = 0; i < 256; i++) { 253 const rgb_color &c = fOwnColorMap->color_list[i]; 254 unsigned distance = color_distance(red, green, blue, 255 c.red, c.green, c.blue); 256 if (distance < closestDistance) { 257 closestIndex = i; 258 closestDistance = distance; 259 } 260 } 261 fOwnColorMap->index_map[color] = closestIndex; 262 } 263 // no need to init inversion map 264 } 265 fCStatus = error; 266 return error; 267 } 268 269 270 /*! \brief Initializes the converter to the supplied color map. 271 \param colorMap The completely initialized color map. 272 \return \c B_OK, if everything went fine, an error code otherwise. 273 */ 274 status_t 275 PaletteConverter::SetTo(const color_map *colorMap) 276 { 277 // cleanup 278 if (fOwnColorMap) { 279 delete fOwnColorMap; 280 fOwnColorMap = NULL; 281 } 282 // set 283 fColorMap = colorMap; 284 fCStatus = (fColorMap ? B_OK : B_BAD_VALUE); 285 return fCStatus; 286 } 287 288 289 /*! \brief Returns the result of the last initialization via constructor or 290 SetTo(). 291 \return \c B_OK, if the converter is properly initialized, an error code 292 otherwise. 293 */ 294 status_t 295 PaletteConverter::InitCheck() const 296 { 297 return fCStatus; 298 } 299 300 301 /*! \brief Returns the palette color index closest to a given RGB 15 color. 302 303 The object must be properly initialized. 304 305 \param rgb The RGB 15 color value (R[14:10]G[9:5]B[4:0]). 306 \return The palette color index for the supplied color. 307 */ 308 inline 309 uint8 310 PaletteConverter::IndexForRGB15(uint16 rgb) const 311 { 312 return fColorMap->index_map[rgb]; 313 } 314 315 316 /*! \brief Returns the palette color index closest to a given RGB 15 color. 317 318 The object must be properly initialized. 319 320 \param red Red component of the color (R[4:0]). 321 \param green Green component of the color (G[4:0]). 322 \param blue Blue component of the color (B[4:0]). 323 \return The palette color index for the supplied color. 324 */ 325 inline 326 uint8 327 PaletteConverter::IndexForRGB15(uint8 red, uint8 green, uint8 blue) const 328 { 329 // the 5 least significant bits are used 330 return fColorMap->index_map[(red << 10) | (green << 5) | blue]; 331 } 332 333 334 /*! \brief Returns the palette color index closest to a given RGB 16 color. 335 336 The object must be properly initialized. 337 338 \param rgb The RGB 16 color value (R[15:11]G[10:5]B[4:0]). 339 \return The palette color index for the supplied color. 340 */ 341 inline 342 uint8 343 PaletteConverter::IndexForRGB16(uint16 rgb) const 344 { 345 return fColorMap->index_map[(rgb >> 1) & 0x7fe0 | rgb & 0x1f]; 346 } 347 348 349 /*! \brief Returns the palette color index closest to a given RGB 16 color. 350 351 The object must be properly initialized. 352 353 \param red Red component of the color (R[4:0]). 354 \param green Green component of the color (G[5:0]). 355 \param blue Blue component of the color (B[4:0]). 356 \return The palette color index for the supplied color. 357 */ 358 inline 359 uint8 360 PaletteConverter::IndexForRGB16(uint8 red, uint8 green, uint8 blue) const 361 { 362 // the 5 (for red, blue) / 6 (for green) least significant bits are used 363 return fColorMap->index_map[(red << 10) | ((green & 0x3e) << 4) | blue]; 364 } 365 366 367 /*! \brief Returns the palette color index closest to a given RGB 32 color. 368 369 The object must be properly initialized. 370 371 \param rgb The RGB 32 color value (R[31:24]G[23:16]B[15:8]). 372 \return The palette color index for the supplied color. 373 */ 374 inline 375 uint8 376 PaletteConverter::IndexForRGB24(uint32 rgb) const 377 { 378 return fColorMap->index_map[((rgb & 0xf8000000) >> 17) 379 | ((rgb & 0xf80000) >> 14) 380 | ((rgb & 0xf800) >> 11)]; 381 } 382 383 384 /*! \brief Returns the palette color index closest to a given RGB 24 color. 385 386 The object must be properly initialized. 387 388 \param red Red component of the color. 389 \param green Green component of the color. 390 \param blue Blue component of the color. 391 \return The palette color index for the supplied color. 392 */ 393 inline 394 uint8 395 PaletteConverter::IndexForRGB24(uint8 red, uint8 green, uint8 blue) const 396 { 397 return fColorMap->index_map[((red & 0xf8) << 7) 398 | ((green & 0xf8) << 2) 399 | (blue >> 3)]; 400 } 401 402 403 /*! \brief Returns the palette color index closest to a given Gray 8 color. 404 405 The object must be properly initialized. 406 407 \param gray The Gray 8 color value. 408 \return The palette color index for the supplied color. 409 */ 410 inline 411 uint8 412 PaletteConverter::IndexForGray(uint8 gray) const 413 { 414 return IndexForRGB24(gray, gray, gray); 415 } 416 417 418 /*! \brief Returns the RGB color for a given palette color index. 419 420 The object must be properly initialized. 421 422 \param index The palette color index. 423 \return The color for the supplied palette color index. 424 */ 425 inline 426 const rgb_color & 427 PaletteConverter::RGBColorForIndex(uint8 index) const 428 { 429 return fColorMap->color_list[index]; 430 } 431 432 433 /*! \brief Returns the RGB 15 color for a given palette color index. 434 435 The object must be properly initialized. 436 437 \param index The palette color index. 438 \return The color for the supplied palette color index 439 (R[14:10]G[9:5]B[4:0]). 440 */ 441 inline 442 uint16 443 PaletteConverter::RGB15ColorForIndex(uint8 index) const 444 { 445 const rgb_color &color = fColorMap->color_list[index]; 446 return ((color.red & 0xf8) << 7) 447 | ((color.green & 0xf8) << 2) 448 | (color.blue >> 3); 449 } 450 451 452 /*! \brief Returns the RGB 16 color for a given palette color index. 453 454 The object must be properly initialized. 455 456 \param index The palette color index. 457 \return The color for the supplied palette color index 458 (R[15:11]G[10:5]B[4:0]). 459 */ 460 inline 461 uint16 462 PaletteConverter::RGB16ColorForIndex(uint8 index) const 463 { 464 const rgb_color &color = fColorMap->color_list[index]; 465 return ((color.red & 0xf8) << 8) 466 | ((color.green & 0xfc) << 3) 467 | (color.blue >> 3); 468 } 469 470 471 /*! \brief Returns the RGBA 32 color for a given palette color index. 472 473 The object must be properly initialized. 474 475 \param index The palette color index. 476 \return The color for the supplied palette color index 477 (A[31:24]B[23:16]G[15:8]R[7:0]). 478 */ 479 inline 480 uint32 481 PaletteConverter::RGBA32ColorForIndex(uint8 index) const 482 { 483 const rgb_color &color = fColorMap->color_list[index]; 484 return (color.red << 16) | (color.green << 8) | color.blue 485 | (color.alpha << 24); 486 } 487 488 489 /*! \brief Returns the RGBA 32 color for a given palette color index. 490 491 The object must be properly initialized. 492 493 \param index The palette color index. 494 \param red Reference to the variable the red component shall be stored 495 into. 496 \param green Reference to the variable the green component shall be stored 497 into. 498 \param blue Reference to the variable the blue component shall be stored 499 into. 500 \param alpha Reference to the variable the alpha component shall be stored 501 into. 502 */ 503 inline 504 void 505 PaletteConverter::RGBA32ColorForIndex(uint8 index, uint8 &red, uint8 &green, 506 uint8 &blue, uint8 &alpha) const 507 { 508 const rgb_color &color = fColorMap->color_list[index]; 509 red = color.red; 510 green = color.green; 511 blue = color.blue; 512 alpha = color.alpha; 513 } 514 515 516 /*! \brief Returns the Gray 8 color for a given palette color index. 517 518 The object must be properly initialized. 519 520 \param index The palette color index. 521 \return The color for the supplied palette color index. 522 */ 523 inline 524 uint8 525 PaletteConverter::GrayColorForIndex(uint8 index) const 526 { 527 const rgb_color &color = fColorMap->color_list[index]; 528 return brightness_for(color.red, color.green, color.blue); 529 } 530 531 532 static BLocker sPaletteConverterLock("PalConvLock"); 533 static PaletteConverter sPaletteConverter; 534 535 536 /*! \brief Initialize the global instance of PaletteConverter using the system color palette. 537 \return B_OK. 538 */ 539 /* static */ 540 status_t 541 PaletteConverter::InitializeDefault(bool useServer) 542 { 543 if (sPaletteConverterLock.Lock()) { 544 if (sPaletteConverter.InitCheck() != B_OK) { 545 if (useServer) 546 sPaletteConverter.SetTo(system_colors()); 547 else 548 sPaletteConverter.SetTo(kSystemPalette); 549 } 550 sPaletteConverterLock.Unlock(); 551 } 552 return B_OK; 553 } 554 555 556 typedef uint32 (readFunc)(const uint8 **source, int32 index); 557 typedef void (writeFunc)(uint8 **dest, uint8 *data, int32 index); 558 559 560 void 561 WriteRGB24(uint8 **dest, uint8 *data, int32 index) 562 { 563 (*dest)[0] = data[0]; 564 (*dest)[1] = data[1]; 565 (*dest)[2] = data[2]; 566 *dest += 3; 567 } 568 569 570 uint32 571 ReadRGB24(const uint8 **source, int32 index) 572 { 573 uint32 result = (*source)[0] | ((*source)[1] << 8) | ((*source)[2] << 16); 574 *source += 3; 575 return result; 576 } 577 578 579 void 580 WriteGray8(uint8 **dest, uint8 *data, int32 index) 581 { 582 **dest = data[2] * 308 + data[1] * 600 + data[0] * 116 >> 10; 583 // this would boost the speed but is less accurate: 584 //*dest = (data[2] << 8) + (data[1] << 9) + (data[0] << 8) >> 10; 585 (*dest)++; 586 } 587 588 589 uint32 590 ReadGray8(const uint8 **source, int32 index) 591 { 592 uint32 result = **source; 593 (*source)++; 594 return result; 595 } 596 597 598 void 599 WriteGray1(uint8 **dest, uint8 *data, int32 index) 600 { 601 int32 shift = 7 - (index % 8); 602 **dest &= ~(0x01 << shift); 603 **dest |= (data[2] * 308 + data[1] * 600 + data[0] * 116) >> (17 - shift); 604 if (shift == 0) 605 (*dest)++; 606 } 607 608 609 uint32 610 ReadGray1(const uint8 **source, int32 index) 611 { 612 int32 shift = 7 - (index % 8); 613 uint32 result = ((**source >> shift) & 0x01) ? 0xff : 0x00; 614 if (shift == 0) 615 (*source)++; 616 return result; 617 } 618 619 620 void 621 WriteCMAP8(uint8 **dest, uint8 *data, int32 index) 622 { 623 **dest = sPaletteConverter.IndexForRGB15(*(uint16 *)data); 624 (*dest)++; 625 } 626 627 628 uint32 629 ReadCMAP8(const uint8 **source, int32 index) 630 { 631 uint32 result = sPaletteConverter.RGBA32ColorForIndex(**source); 632 (*source)++; 633 return result; 634 } 635 636 637 template<typename srcByte, typename dstByte> 638 status_t 639 ConvertBits(const srcByte *srcBits, dstByte *dstBits, int32 srcBitsLength, 640 int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift, 641 int32 alphaShift, int32 alphaBits, uint32 redMask, uint32 greenMask, 642 uint32 blueMask, uint32 alphaMask, int32 srcBytesPerRow, 643 int32 dstBytesPerRow, int32 srcBitsPerPixel, int32 dstBitsPerPixel, 644 color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset, 645 BPoint dstOffset, int32 width, int32 height, bool srcSwap, bool dstSwap, 646 readFunc *srcFunc, writeFunc *dstFunc) 647 { 648 uint8* srcBitsEnd = (uint8*)srcBits + srcBitsLength; 649 uint8* dstBitsEnd = (uint8*)dstBits + dstBitsLength; 650 651 int32 srcBitsPerRow = srcBytesPerRow << 3; 652 int32 dstBitsPerRow = dstBytesPerRow << 3; 653 654 // Advance the buffers to reach their offsets 655 int32 srcOffsetX = (int32)srcOffset.x; 656 int32 dstOffsetX = (int32)dstOffset.x; 657 int32 srcOffsetY = (int32)srcOffset.y; 658 int32 dstOffsetY = (int32)dstOffset.y; 659 if (srcOffsetX < 0) { 660 dstOffsetX -= srcOffsetX; 661 srcOffsetX = 0; 662 } 663 if (srcOffsetY < 0) { 664 dstOffsetY -= srcOffsetY; 665 height += srcOffsetY; 666 srcOffsetY = 0; 667 } 668 if (dstOffsetX < 0) { 669 srcOffsetX -= dstOffsetX; 670 dstOffsetX = 0; 671 } 672 if (dstOffsetY < 0) { 673 srcOffsetY -= dstOffsetY; 674 height += dstOffsetY; 675 dstOffsetY = 0; 676 } 677 678 srcBits = (srcByte*)((uint8*)srcBits + (srcOffsetY * srcBitsPerRow + srcOffsetX 679 * srcBitsPerPixel >> 3)); 680 dstBits = (dstByte*)((uint8*)dstBits + (dstOffsetY * dstBitsPerRow + dstOffsetX 681 * dstBitsPerPixel >> 3)); 682 683 // Ensure that the width fits 684 int32 srcWidth = (srcBitsPerRow - srcOffsetX * srcBitsPerPixel) 685 / srcBitsPerPixel; 686 if (srcWidth < width) 687 width = srcWidth; 688 689 int32 dstWidth = (dstBitsPerRow - dstOffsetX * dstBitsPerPixel) 690 / dstBitsPerPixel; 691 if (dstWidth < width) 692 width = dstWidth; 693 694 if (width < 0) 695 return B_OK; 696 697 // Catch the copy case 698 if (srcColorSpace == dstColorSpace && srcBitsPerPixel % 8 == 0) { 699 int32 copyCount = (width * srcBitsPerPixel) >> 3; 700 for (int32 i = 0; i < height; i++) { 701 // make sure we don't write beyond the bits size 702 if (copyCount > srcBitsLength) 703 copyCount = srcBitsLength; 704 if (copyCount > dstBitsLength) 705 copyCount = dstBitsLength; 706 if (copyCount == 0) 707 break; 708 709 memcpy(dstBits, srcBits, copyCount); 710 711 srcBitsLength -= copyCount; 712 dstBitsLength -= copyCount; 713 srcBits = (srcByte*)((uint8*)srcBits + srcBytesPerRow); 714 dstBits = (dstByte*)((uint8*)dstBits + dstBytesPerRow); 715 716 if ((uint8 *)srcBits > srcBitsEnd || (uint8 *)dstBits > dstBitsEnd) 717 return B_OK; 718 } 719 720 return B_OK; 721 } 722 723 int32 srcLinePad = (srcBitsPerRow - width * srcBitsPerPixel) >> 3; 724 int32 dstLinePad = (dstBitsPerRow - width * dstBitsPerPixel) >> 3; 725 uint32 result; 726 uint32 source; 727 728 for (int32 i = 0; i < height; i++) { 729 for (int32 j = 0; j < width; j++) { 730 if ((uint8 *)srcBits + sizeof(srcByte) > srcBitsEnd 731 || (uint8 *)dstBits + sizeof(dstByte) > dstBitsEnd) 732 return B_OK; 733 734 if (srcFunc) 735 source = srcFunc((const uint8 **)&srcBits, srcOffsetX++); 736 else { 737 source = *srcBits; 738 srcBits++; 739 } 740 741 // This is valid, as only 16 bit modes will need to swap 742 if (srcSwap) 743 source = (source << 8) | (source >> 8); 744 745 if (redShift > 0) 746 result = ((source >> redShift) & redMask); 747 else if (redShift < 0) 748 result = ((source << -redShift) & redMask); 749 else 750 result = source & redMask; 751 752 if (greenShift > 0) 753 result |= ((source >> greenShift) & greenMask); 754 else if (greenShift < 0) 755 result |= ((source << -greenShift) & greenMask); 756 else 757 result |= source & greenMask; 758 759 if (blueShift > 0) 760 result |= ((source >> blueShift) & blueMask); 761 else if (blueShift < 0) 762 result |= ((source << -blueShift) & blueMask); 763 else 764 result |= source & blueMask; 765 766 if (alphaBits > 0) { 767 if (alphaShift > 0) 768 result |= ((source >> alphaShift) & alphaMask); 769 else if (alphaShift < 0) 770 result |= ((source << -alphaShift) & alphaMask); 771 else 772 result |= source & alphaMask; 773 774 // if we only had one alpha bit we want it to be 0/255 775 if (alphaBits == 1 && result & alphaMask) 776 result |= alphaMask; 777 } else 778 result |= alphaMask; 779 780 // This is valid, as only 16 bit modes will need to swap 781 if (dstSwap) 782 result = (result << 8) | (result >> 8); 783 784 if (dstFunc) 785 dstFunc((uint8 **)&dstBits, (uint8 *)&result, dstOffsetX++); 786 else { 787 *dstBits = result; 788 dstBits++; 789 } 790 } 791 792 srcBits = (srcByte*)((uint8*)srcBits + srcLinePad); 793 dstBits = (dstByte*)((uint8*)dstBits + dstLinePad); 794 dstOffsetX -= width; 795 srcOffsetX -= width; 796 } 797 798 return B_OK; 799 } 800 801 802 template<typename srcByte> 803 status_t 804 ConvertBits(const srcByte *srcBits, void *dstBits, int32 srcBitsLength, 805 int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift, 806 int32 alphaShift, int32 alphaBits, int32 srcBytesPerRow, 807 int32 dstBytesPerRow, int32 srcBitsPerPixel, color_space srcColorSpace, 808 color_space dstColorSpace, BPoint srcOffset, BPoint dstOffset, int32 width, 809 int32 height, bool srcSwap, readFunc *srcFunc) 810 { 811 switch (dstColorSpace) { 812 case B_RGBA32: 813 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 814 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 815 alphaShift - 32, alphaBits, 0x00ff0000, 0x0000ff00, 0x000000ff, 816 0xff000000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 817 32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 818 height, srcSwap, false, srcFunc, NULL); 819 break; 820 821 case B_RGBA32_BIG: 822 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 823 dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32, 824 alphaShift - 8, alphaBits, 0x0000ff00, 0x00ff0000, 0xff000000, 825 0x00000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 826 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 827 height, srcSwap, false, srcFunc, NULL); 828 break; 829 830 /* Note: we set the unused alpha to 255 here. This is because BeOS 831 uses the unused alpha for B_OP_ALPHA even though it should 832 not care about it. */ 833 case B_RGB32: 834 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 835 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 836 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, 837 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 838 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 839 height, srcSwap, false, srcFunc, NULL); 840 break; 841 842 case B_RGB32_BIG: 843 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 844 dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32, 845 0, 0, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff, 846 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 847 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 848 height, srcSwap, false, srcFunc, NULL); 849 break; 850 851 case B_RGB24: 852 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 853 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 854 0, 0, 0xff0000, 0x00ff00, 0x0000ff, 0x000000, srcBytesPerRow, 855 dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace, 856 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 857 false, srcFunc, WriteRGB24); 858 break; 859 860 case B_RGB24_BIG: 861 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 862 dstBitsLength, redShift - 8, greenShift - 16, blueShift - 24, 863 0, 0, 0x0000ff, 0x00ff00, 0xff0000, 0x000000, srcBytesPerRow, 864 dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace, 865 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 866 false, srcFunc, WriteRGB24); 867 break; 868 869 case B_RGB16: 870 case B_RGB16_BIG: 871 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 872 dstBitsLength, redShift - 16, greenShift - 11, blueShift - 5, 873 0, 0, 0xf800, 0x07e0, 0x001f, 0x0000, srcBytesPerRow, 874 dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace, 875 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 876 dstColorSpace == B_RGB16_BIG, srcFunc, NULL); 877 break; 878 879 case B_RGBA15: 880 case B_RGBA15_BIG: 881 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 882 dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5, 883 alphaShift - 16, alphaBits, 0x7c00, 0x03e0, 0x001f, 0x8000, 884 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 16, 885 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 886 height, srcSwap, dstColorSpace == B_RGBA15_BIG, srcFunc, NULL); 887 break; 888 889 case B_RGB15: 890 case B_RGB15_BIG: 891 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 892 dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5, 893 0, 0, 0x7c00, 0x03e0, 0x001f, 0x0000, srcBytesPerRow, 894 dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace, 895 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 896 dstColorSpace == B_RGB15_BIG, srcFunc, NULL); 897 break; 898 899 case B_GRAY8: 900 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 901 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 902 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, 903 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 8, 904 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 905 height, srcSwap, false, srcFunc, WriteGray8); 906 break; 907 908 case B_GRAY1: 909 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 910 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 911 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, 912 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 1, 913 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 914 height, srcSwap, false, srcFunc, WriteGray1); 915 break; 916 917 case B_CMAP8: 918 PaletteConverter::InitializeDefault(); 919 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 920 dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5, 921 0, 0, 0x7c00, 0x03e0, 0x001f, 0x0000, srcBytesPerRow, 922 dstBytesPerRow, srcBitsPerPixel, 8, srcColorSpace, 923 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 924 false, srcFunc, WriteCMAP8); 925 break; 926 927 default: 928 return B_BAD_VALUE; 929 break; 930 } 931 932 return B_OK; 933 } 934 935 936 /*! \brief Converts a source buffer in one colorspace into a destination 937 buffer of another colorspace. 938 939 \param srcBits The raw source buffer. 940 \param dstBits The raw destination buffer. 941 \param srcBytesPerRow How many bytes per row the source buffer has got. 942 \param dstBytesPerRow How many bytes per row the destination buffer has got. 943 \param srcColorSpace The colorspace the source buffer is in. 944 \param dstColorSpace The colorspace the buffer shall be converted to. 945 \param width The width (in pixels) of each row. 946 \param height The height (in pixels) of the buffers. 947 \return 948 - \c B_OK: Indicates success. 949 - \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported. 950 */ 951 status_t 952 ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength, 953 int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow, 954 color_space srcColorSpace, color_space dstColorSpace, int32 width, 955 int32 height) 956 { 957 return ConvertBits(srcBits, dstBits, srcBitsLength, dstBitsLength, 958 srcBytesPerRow, dstBytesPerRow, srcColorSpace, dstColorSpace, 959 BPoint(0, 0), BPoint(0, 0), width, height); 960 } 961 962 963 /*! \brief Converts a source buffer in one colorspace into a destination 964 buffer of another colorspace. 965 966 \param srcBits The raw source buffer. 967 \param dstBits The raw destination buffer. 968 \param srcBytesPerRow How many bytes per row the source buffer has got. 969 \param dstBytesPerRow How many bytes per row the destination buffer has got. 970 \param srcColorSpace The colorspace the source buffer is in. 971 \param dstColorSpace The colorspace the buffer shall be converted to. 972 \param srcOffset The offset at which to start reading in the source. 973 \param srcOffset The offset at which to start writing in the destination. 974 \param width The width (in pixels) to convert. 975 \param height The height (in pixels) to convert. 976 \return 977 - \c B_OK: Indicates success. 978 - \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported. 979 */ 980 status_t 981 ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength, 982 int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow, 983 color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset, 984 BPoint dstOffset, int32 width, int32 height) 985 { 986 if (!srcBits || !dstBits || srcBitsLength < 0 || dstBitsLength < 0 987 || width < 0 || height < 0 || srcBytesPerRow < 0 || dstBytesPerRow < 0) 988 return B_BAD_VALUE; 989 990 switch (srcColorSpace) { 991 case B_RGBA32: 992 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 993 dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow, 994 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 995 dstOffset, width, height, false, NULL); 996 break; 997 998 case B_RGBA32_BIG: 999 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 1000 dstBitsLength, 16, 24, 32, 8, 8, srcBytesPerRow, 1001 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 1002 dstOffset, width, height, false, NULL); 1003 break; 1004 1005 case B_RGB32: 1006 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 1007 dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 1008 32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1009 height, false, NULL); 1010 break; 1011 1012 case B_RGB32_BIG: 1013 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 1014 dstBitsLength, 16, 24, 32, 0, 0, srcBytesPerRow, 1015 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 1016 dstOffset, width, height, false, NULL); 1017 break; 1018 1019 case B_RGB24: 1020 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1021 dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 1022 24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1023 height, false, ReadRGB24); 1024 break; 1025 1026 case B_RGB24_BIG: 1027 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1028 dstBitsLength, 8, 16, 24, 0, 0, srcBytesPerRow, dstBytesPerRow, 1029 24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1030 height, false, ReadRGB24); 1031 break; 1032 1033 case B_RGB16: 1034 case B_RGB16_BIG: 1035 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 1036 dstBitsLength, 16, 11, 5, 0, 0, srcBytesPerRow, dstBytesPerRow, 1037 16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1038 height, srcColorSpace == B_RGB16_BIG, NULL); 1039 break; 1040 1041 case B_RGBA15: 1042 case B_RGBA15_BIG: 1043 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 1044 dstBitsLength, 15, 10, 5, 16, 1, srcBytesPerRow, 1045 dstBytesPerRow, 16, srcColorSpace, dstColorSpace, srcOffset, 1046 dstOffset, width, height, srcColorSpace == B_RGBA15_BIG, NULL); 1047 break; 1048 1049 case B_RGB15: 1050 case B_RGB15_BIG: 1051 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 1052 dstBitsLength, 15, 10, 5, 0, 0, srcBytesPerRow, dstBytesPerRow, 1053 16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1054 height, srcColorSpace == B_RGB15_BIG, NULL); 1055 break; 1056 1057 case B_GRAY8: 1058 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1059 dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 1060 8, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1061 height, false, ReadGray8); 1062 break; 1063 1064 case B_GRAY1: 1065 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1066 dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 1067 1, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1068 height, false, ReadGray1); 1069 break; 1070 1071 case B_CMAP8: 1072 PaletteConverter::InitializeDefault(); 1073 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1074 dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow, 1075 dstBytesPerRow, 8, srcColorSpace, dstColorSpace, srcOffset, 1076 dstOffset, width, height, false, ReadCMAP8); 1077 break; 1078 1079 default: 1080 return B_BAD_VALUE; 1081 break; 1082 } 1083 1084 return B_OK; 1085 } 1086 1087 } // namespace BPrivate 1088