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