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 (srcFunc) 725 source = srcFunc((const uint8 **)&srcBits, srcOffsetX++); 726 else { 727 source = *srcBits; 728 srcBits++; 729 } 730 731 // This is valid, as only 16 bit modes will need to swap 732 if (srcSwap) 733 source = (source << 8) | (source >> 8); 734 735 if (redShift > 0) 736 result = ((source >> redShift) & redMask); 737 else if (redShift < 0) 738 result = ((source << -redShift) & redMask); 739 else 740 result = source & redMask; 741 742 if (greenShift > 0) 743 result |= ((source >> greenShift) & greenMask); 744 else if (greenShift < 0) 745 result |= ((source << -greenShift) & greenMask); 746 else 747 result |= source & greenMask; 748 749 if (blueShift > 0) 750 result |= ((source >> blueShift) & blueMask); 751 else if (blueShift < 0) 752 result |= ((source << -blueShift) & blueMask); 753 else 754 result |= source & blueMask; 755 756 if (alphaBits > 0) { 757 if (alphaShift > 0) 758 result |= ((source >> alphaShift) & alphaMask); 759 else if (alphaShift < 0) 760 result |= ((source << -alphaShift) & alphaMask); 761 else 762 result |= source & alphaMask; 763 764 // if we only had one alpha bit we want it to be 0/255 765 if (alphaBits == 1 && result & alphaMask) 766 result |= alphaMask; 767 } else 768 result |= alphaMask; 769 770 // This is valid, as only 16 bit modes will need to swap 771 if (dstSwap) 772 result = (result << 8) | (result >> 8); 773 774 if (dstFunc) 775 dstFunc((uint8 **)&dstBits, (uint8 *)&result, dstOffsetX++); 776 else { 777 *dstBits = result; 778 dstBits++; 779 } 780 781 if ((uint8*)srcBits > srcBitsEnd || (uint8*)dstBits > dstBitsEnd) 782 return B_OK; 783 } 784 785 srcBits = (srcByte*)((uint8*)srcBits + srcLinePad); 786 dstBits = (dstByte*)((uint8*)dstBits + dstLinePad); 787 dstOffsetX -= width; 788 srcOffsetX -= width; 789 } 790 791 return B_OK; 792 } 793 794 795 template<typename srcByte> 796 status_t 797 ConvertBits(const srcByte *srcBits, void *dstBits, int32 srcBitsLength, 798 int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift, 799 int32 alphaShift, int32 alphaBits, int32 srcBytesPerRow, 800 int32 dstBytesPerRow, int32 srcBitsPerPixel, color_space srcColorSpace, 801 color_space dstColorSpace, BPoint srcOffset, BPoint dstOffset, int32 width, 802 int32 height, bool srcSwap, readFunc *srcFunc) 803 { 804 switch (dstColorSpace) { 805 case B_RGBA32: 806 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 807 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 808 alphaShift - 32, alphaBits, 0x00ff0000, 0x0000ff00, 0x000000ff, 809 0xff000000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 810 32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 811 height, srcSwap, false, srcFunc, NULL); 812 break; 813 814 case B_RGBA32_BIG: 815 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 816 dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32, 817 alphaShift - 8, alphaBits, 0x0000ff00, 0x00ff0000, 0xff000000, 818 0x00000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 819 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 820 height, srcSwap, false, srcFunc, NULL); 821 break; 822 823 /* Note: we set the unused alpha to 255 here. This is because BeOS 824 uses the unused alpha for B_OP_ALPHA even though it should 825 not care about it. */ 826 case B_RGB32: 827 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 828 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 829 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, 830 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 831 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 832 height, srcSwap, false, srcFunc, NULL); 833 break; 834 835 case B_RGB32_BIG: 836 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 837 dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32, 838 0, 0, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff, 839 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 840 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 841 height, srcSwap, false, srcFunc, NULL); 842 break; 843 844 case B_RGB24: 845 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 846 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 847 0, 0, 0xff0000, 0x00ff00, 0x0000ff, 0x000000, srcBytesPerRow, 848 dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace, 849 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 850 false, srcFunc, WriteRGB24); 851 break; 852 853 case B_RGB24_BIG: 854 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 855 dstBitsLength, redShift - 8, greenShift - 16, blueShift - 24, 856 0, 0, 0x0000ff, 0x00ff00, 0xff0000, 0x000000, srcBytesPerRow, 857 dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace, 858 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 859 false, srcFunc, WriteRGB24); 860 break; 861 862 case B_RGB16: 863 case B_RGB16_BIG: 864 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 865 dstBitsLength, redShift - 16, greenShift - 11, blueShift - 5, 866 0, 0, 0xf800, 0x07e0, 0x001f, 0x0000, srcBytesPerRow, 867 dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace, 868 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 869 dstColorSpace == B_RGB16_BIG, srcFunc, NULL); 870 break; 871 872 case B_RGBA15: 873 case B_RGBA15_BIG: 874 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 875 dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5, 876 alphaShift - 16, alphaBits, 0x7c00, 0x03e0, 0x001f, 0x8000, 877 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 16, 878 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 879 height, srcSwap, dstColorSpace == B_RGBA15_BIG, srcFunc, NULL); 880 break; 881 882 case B_RGB15: 883 case B_RGB15_BIG: 884 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 885 dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5, 886 0, 0, 0x7c00, 0x03e0, 0x001f, 0x0000, srcBytesPerRow, 887 dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace, 888 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 889 dstColorSpace == B_RGB15_BIG, srcFunc, NULL); 890 break; 891 892 case B_GRAY8: 893 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 894 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 895 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, 896 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 8, 897 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 898 height, srcSwap, false, srcFunc, WriteGray8); 899 break; 900 901 case B_GRAY1: 902 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 903 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 904 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, 905 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 1, 906 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 907 height, srcSwap, false, srcFunc, WriteGray1); 908 break; 909 910 case B_CMAP8: 911 BPrivate::palette_converter(); 912 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 913 dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5, 914 0, 0, 0x7c00, 0x03e0, 0x001f, 0x0000, srcBytesPerRow, 915 dstBytesPerRow, srcBitsPerPixel, 8, srcColorSpace, 916 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 917 false, srcFunc, WriteCMAP8); 918 break; 919 920 default: 921 return B_BAD_VALUE; 922 break; 923 } 924 925 return B_OK; 926 } 927 928 929 /*! \brief Converts a source buffer in one colorspace into a destination 930 buffer of another colorspace. 931 932 \param srcBits The raw source buffer. 933 \param dstBits The raw destination buffer. 934 \param srcBytesPerRow How many bytes per row the source buffer has got. 935 \param dstBytesPerRow How many bytes per row the destination buffer has got. 936 \param srcColorSpace The colorspace the source buffer is in. 937 \param dstColorSpace The colorspace the buffer shall be converted to. 938 \param width The width (in pixels) of each row. 939 \param height The height (in pixels) of the buffers. 940 \return 941 - \c B_OK: Indicates success. 942 - \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported. 943 */ 944 status_t 945 ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength, 946 int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow, 947 color_space srcColorSpace, color_space dstColorSpace, int32 width, 948 int32 height) 949 { 950 return ConvertBits(srcBits, dstBits, srcBitsLength, dstBitsLength, 951 srcBytesPerRow, dstBytesPerRow, srcColorSpace, dstColorSpace, 952 BPoint(0, 0), BPoint(0, 0), width, height); 953 } 954 955 956 /*! \brief Converts a source buffer in one colorspace into a destination 957 buffer of another colorspace. 958 959 \param srcBits The raw source buffer. 960 \param dstBits The raw destination buffer. 961 \param srcBytesPerRow How many bytes per row the source buffer has got. 962 \param dstBytesPerRow How many bytes per row the destination buffer has got. 963 \param srcColorSpace The colorspace the source buffer is in. 964 \param dstColorSpace The colorspace the buffer shall be converted to. 965 \param srcOffset The offset at which to start reading in the source. 966 \param srcOffset The offset at which to start writing in the destination. 967 \param width The width (in pixels) to convert. 968 \param height The height (in pixels) to convert. 969 \return 970 - \c B_OK: Indicates success. 971 - \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported. 972 */ 973 status_t 974 ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength, 975 int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow, 976 color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset, 977 BPoint dstOffset, int32 width, int32 height) 978 { 979 if (!srcBits || !dstBits || srcBitsLength < 0 || dstBitsLength < 0 980 || width < 0 || height < 0 || srcBytesPerRow < 0 || dstBytesPerRow < 0) 981 return B_BAD_VALUE; 982 983 switch (srcColorSpace) { 984 case B_RGBA32: 985 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 986 dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow, 987 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 988 dstOffset, width, height, false, NULL); 989 break; 990 991 case B_RGBA32_BIG: 992 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 993 dstBitsLength, 16, 24, 32, 8, 8, srcBytesPerRow, 994 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 995 dstOffset, width, height, false, NULL); 996 break; 997 998 case B_RGB32: 999 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 1000 dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 1001 32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1002 height, false, NULL); 1003 break; 1004 1005 case B_RGB32_BIG: 1006 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 1007 dstBitsLength, 16, 24, 32, 0, 0, srcBytesPerRow, 1008 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 1009 dstOffset, width, height, false, NULL); 1010 break; 1011 1012 case B_RGB24: 1013 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1014 dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 1015 24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1016 height, false, ReadRGB24); 1017 break; 1018 1019 case B_RGB24_BIG: 1020 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1021 dstBitsLength, 8, 16, 24, 0, 0, srcBytesPerRow, dstBytesPerRow, 1022 24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1023 height, false, ReadRGB24); 1024 break; 1025 1026 case B_RGB16: 1027 case B_RGB16_BIG: 1028 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 1029 dstBitsLength, 16, 11, 5, 0, 0, srcBytesPerRow, dstBytesPerRow, 1030 16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1031 height, srcColorSpace == B_RGB16_BIG, NULL); 1032 break; 1033 1034 case B_RGBA15: 1035 case B_RGBA15_BIG: 1036 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 1037 dstBitsLength, 15, 10, 5, 16, 1, srcBytesPerRow, 1038 dstBytesPerRow, 16, srcColorSpace, dstColorSpace, srcOffset, 1039 dstOffset, width, height, srcColorSpace == B_RGBA15_BIG, NULL); 1040 break; 1041 1042 case B_RGB15: 1043 case B_RGB15_BIG: 1044 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 1045 dstBitsLength, 15, 10, 5, 0, 0, srcBytesPerRow, dstBytesPerRow, 1046 16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1047 height, srcColorSpace == B_RGB15_BIG, NULL); 1048 break; 1049 1050 case B_GRAY8: 1051 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1052 dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 1053 8, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1054 height, false, ReadGray8); 1055 break; 1056 1057 case B_GRAY1: 1058 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1059 dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 1060 1, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1061 height, false, ReadGray1); 1062 break; 1063 1064 case B_CMAP8: 1065 palette_converter(); 1066 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1067 dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow, 1068 dstBytesPerRow, 8, srcColorSpace, dstColorSpace, srcOffset, 1069 dstOffset, width, height, false, ReadCMAP8); 1070 break; 1071 1072 default: 1073 return B_BAD_VALUE; 1074 break; 1075 } 1076 } 1077 1078 } // namespace BPrivate 1079