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