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