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 BLocker sPaletteConverterLock("PalConvLock"); 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 */ 448 status_t 449 PaletteConverter::InitializeDefault(bool useServer) 450 { 451 if (sPaletteConverterLock.Lock()) { 452 if (sPaletteConverter.InitCheck() != B_OK) { 453 if (useServer) 454 sPaletteConverter.SetTo(system_colors()); 455 else 456 sPaletteConverter.SetTo(kSystemPalette); 457 } 458 sPaletteConverterLock.Unlock(); 459 } 460 return B_OK; 461 } 462 463 464 typedef uint32 (readFunc)(const uint8 **source, int32 index); 465 typedef void (writeFunc)(uint8 **dest, uint8 *data, int32 index); 466 467 468 void 469 WriteRGB24(uint8 **dest, uint8 *data, int32 index) 470 { 471 (*dest)[0] = data[0]; 472 (*dest)[1] = data[1]; 473 (*dest)[2] = data[2]; 474 *dest += 3; 475 } 476 477 478 uint32 479 ReadRGB24(const uint8 **source, int32 index) 480 { 481 uint32 result = (*source)[0] | ((*source)[1] << 8) | ((*source)[2] << 16); 482 *source += 3; 483 return result; 484 } 485 486 487 void 488 WriteGray8(uint8 **dest, uint8 *data, int32 index) 489 { 490 **dest = (data[2] * 308 + data[1] * 600 + data[0] * 116) >> 10; 491 // this would boost the speed but is less accurate: 492 //*dest = (data[2] << 8) + (data[1] << 9) + (data[0] << 8) >> 10; 493 (*dest)++; 494 } 495 496 497 uint32 498 ReadGray8(const uint8 **source, int32 index) 499 { 500 uint32 result = **source; 501 (*source)++; 502 return result; 503 } 504 505 506 void 507 WriteGray1(uint8 **dest, uint8 *data, int32 index) 508 { 509 int32 shift = 7 - (index % 8); 510 **dest &= ~(0x01 << shift); 511 **dest |= (data[2] * 308 + data[1] * 600 + data[0] * 116) >> (17 - shift); 512 if (shift == 0) 513 (*dest)++; 514 } 515 516 517 uint32 518 ReadGray1(const uint8 **source, int32 index) 519 { 520 int32 shift = 7 - (index % 8); 521 uint32 result = ((**source >> shift) & 0x01) ? 0xff : 0x00; 522 if (shift == 0) 523 (*source)++; 524 return result; 525 } 526 527 528 void 529 WriteCMAP8(uint8 **dest, uint8 *data, int32 index) 530 { 531 **dest = sPaletteConverter.IndexForRGB15(*(uint16 *)data); 532 (*dest)++; 533 } 534 535 536 uint32 537 ReadCMAP8(const uint8 **source, int32 index) 538 { 539 uint32 result = sPaletteConverter.RGBA32ColorForIndex(**source); 540 (*source)++; 541 return result; 542 } 543 544 545 template<typename srcByte, typename dstByte> 546 status_t 547 ConvertBits(const srcByte *srcBits, dstByte *dstBits, int32 srcBitsLength, 548 int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift, 549 int32 alphaShift, int32 alphaBits, uint32 redMask, uint32 greenMask, 550 uint32 blueMask, uint32 alphaMask, int32 srcBytesPerRow, 551 int32 dstBytesPerRow, int32 srcBitsPerPixel, int32 dstBitsPerPixel, 552 color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset, 553 BPoint dstOffset, int32 width, int32 height, bool srcSwap, bool dstSwap, 554 readFunc *srcFunc, writeFunc *dstFunc) 555 { 556 uint8* srcBitsEnd = (uint8*)srcBits + srcBitsLength; 557 uint8* dstBitsEnd = (uint8*)dstBits + dstBitsLength; 558 559 int32 srcBitsPerRow = srcBytesPerRow << 3; 560 int32 dstBitsPerRow = dstBytesPerRow << 3; 561 562 // Advance the buffers to reach their offsets 563 int32 srcOffsetX = (int32)srcOffset.x; 564 int32 dstOffsetX = (int32)dstOffset.x; 565 int32 srcOffsetY = (int32)srcOffset.y; 566 int32 dstOffsetY = (int32)dstOffset.y; 567 if (srcOffsetX < 0) { 568 dstOffsetX -= srcOffsetX; 569 srcOffsetX = 0; 570 } 571 if (srcOffsetY < 0) { 572 dstOffsetY -= srcOffsetY; 573 height += srcOffsetY; 574 srcOffsetY = 0; 575 } 576 if (dstOffsetX < 0) { 577 srcOffsetX -= dstOffsetX; 578 dstOffsetX = 0; 579 } 580 if (dstOffsetY < 0) { 581 srcOffsetY -= dstOffsetY; 582 height += dstOffsetY; 583 dstOffsetY = 0; 584 } 585 586 srcBits = (srcByte*)((uint8*)srcBits + ((srcOffsetY * srcBitsPerRow + srcOffsetX 587 * srcBitsPerPixel) >> 3)); 588 dstBits = (dstByte*)((uint8*)dstBits + ((dstOffsetY * dstBitsPerRow + dstOffsetX 589 * dstBitsPerPixel) >> 3)); 590 591 // Ensure that the width fits 592 int32 srcWidth = (srcBitsPerRow - srcOffsetX * srcBitsPerPixel) 593 / srcBitsPerPixel; 594 if (srcWidth < width) 595 width = srcWidth; 596 597 int32 dstWidth = (dstBitsPerRow - dstOffsetX * dstBitsPerPixel) 598 / dstBitsPerPixel; 599 if (dstWidth < width) 600 width = dstWidth; 601 602 if (width < 0) 603 return B_OK; 604 605 // Catch the copy case 606 if (srcColorSpace == dstColorSpace && srcBitsPerPixel % 8 == 0) { 607 int32 copyCount = (width * srcBitsPerPixel) >> 3; 608 for (int32 i = 0; i < height; i++) { 609 // make sure we don't write beyond the bits size 610 if (copyCount > srcBitsLength) 611 copyCount = srcBitsLength; 612 if (copyCount > dstBitsLength) 613 copyCount = dstBitsLength; 614 if (copyCount == 0) 615 break; 616 617 memcpy(dstBits, srcBits, copyCount); 618 619 srcBitsLength -= copyCount; 620 dstBitsLength -= copyCount; 621 srcBits = (srcByte*)((uint8*)srcBits + srcBytesPerRow); 622 dstBits = (dstByte*)((uint8*)dstBits + dstBytesPerRow); 623 624 if ((uint8 *)srcBits > srcBitsEnd || (uint8 *)dstBits > dstBitsEnd) 625 return B_OK; 626 } 627 628 return B_OK; 629 } 630 631 int32 srcLinePad = (srcBitsPerRow - width * srcBitsPerPixel) >> 3; 632 int32 dstLinePad = (dstBitsPerRow - width * dstBitsPerPixel) >> 3; 633 uint32 result; 634 uint32 source; 635 636 for (int32 i = 0; i < height; i++) { 637 for (int32 j = 0; j < width; j++) { 638 if ((uint8 *)srcBits + sizeof(srcByte) > srcBitsEnd 639 || (uint8 *)dstBits + sizeof(dstByte) > dstBitsEnd) 640 return B_OK; 641 642 if (srcFunc) 643 source = srcFunc((const uint8 **)&srcBits, srcOffsetX++); 644 else { 645 source = *srcBits; 646 srcBits++; 647 } 648 649 // This is valid, as only 16 bit modes will need to swap 650 if (srcSwap) 651 source = (source << 8) | (source >> 8); 652 653 if (redShift > 0) 654 result = ((source >> redShift) & redMask); 655 else if (redShift < 0) 656 result = ((source << -redShift) & redMask); 657 else 658 result = source & redMask; 659 660 if (greenShift > 0) 661 result |= ((source >> greenShift) & greenMask); 662 else if (greenShift < 0) 663 result |= ((source << -greenShift) & greenMask); 664 else 665 result |= source & greenMask; 666 667 if (blueShift > 0) 668 result |= ((source >> blueShift) & blueMask); 669 else if (blueShift < 0) 670 result |= ((source << -blueShift) & blueMask); 671 else 672 result |= source & blueMask; 673 674 if (alphaBits > 0) { 675 if (alphaShift > 0) 676 result |= ((source >> alphaShift) & alphaMask); 677 else if (alphaShift < 0) 678 result |= ((source << -alphaShift) & alphaMask); 679 else 680 result |= source & alphaMask; 681 682 // if we only had one alpha bit we want it to be 0/255 683 if (alphaBits == 1 && result & alphaMask) 684 result |= alphaMask; 685 } else 686 result |= alphaMask; 687 688 // This is valid, as only 16 bit modes will need to swap 689 if (dstSwap) 690 result = (result << 8) | (result >> 8); 691 692 if (dstFunc) 693 dstFunc((uint8 **)&dstBits, (uint8 *)&result, dstOffsetX++); 694 else { 695 *dstBits = result; 696 dstBits++; 697 } 698 } 699 700 srcBits = (srcByte*)((uint8*)srcBits + srcLinePad); 701 dstBits = (dstByte*)((uint8*)dstBits + dstLinePad); 702 dstOffsetX -= width; 703 srcOffsetX -= width; 704 } 705 706 return B_OK; 707 } 708 709 710 template<typename srcByte> 711 status_t 712 ConvertBits(const srcByte *srcBits, void *dstBits, int32 srcBitsLength, 713 int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift, 714 int32 alphaShift, int32 alphaBits, int32 srcBytesPerRow, 715 int32 dstBytesPerRow, int32 srcBitsPerPixel, color_space srcColorSpace, 716 color_space dstColorSpace, BPoint srcOffset, BPoint dstOffset, int32 width, 717 int32 height, bool srcSwap, readFunc *srcFunc) 718 { 719 switch (dstColorSpace) { 720 case B_RGBA32: 721 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 722 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 723 alphaShift - 32, alphaBits, 0x00ff0000, 0x0000ff00, 0x000000ff, 724 0xff000000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 725 32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 726 height, srcSwap, false, srcFunc, NULL); 727 break; 728 729 case B_RGBA32_BIG: 730 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 731 dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32, 732 alphaShift - 8, alphaBits, 0x0000ff00, 0x00ff0000, 0xff000000, 733 0x00000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 734 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 735 height, srcSwap, false, srcFunc, NULL); 736 break; 737 738 /* Note: we set the unused alpha to 255 here. This is because BeOS 739 uses the unused alpha for B_OP_ALPHA even though it should 740 not care about it. */ 741 case B_RGB32: 742 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 743 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 744 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, 745 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 746 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 747 height, srcSwap, false, srcFunc, NULL); 748 break; 749 750 case B_RGB32_BIG: 751 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 752 dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32, 753 0, 0, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff, 754 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 755 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 756 height, srcSwap, false, srcFunc, NULL); 757 break; 758 759 case B_RGB24: 760 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 761 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 762 0, 0, 0xff0000, 0x00ff00, 0x0000ff, 0x000000, srcBytesPerRow, 763 dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace, 764 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 765 false, srcFunc, WriteRGB24); 766 break; 767 768 case B_RGB24_BIG: 769 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 770 dstBitsLength, redShift - 8, greenShift - 16, blueShift - 24, 771 0, 0, 0x0000ff, 0x00ff00, 0xff0000, 0x000000, srcBytesPerRow, 772 dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace, 773 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 774 false, srcFunc, WriteRGB24); 775 break; 776 777 case B_RGB16: 778 case B_RGB16_BIG: 779 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 780 dstBitsLength, redShift - 16, greenShift - 11, blueShift - 5, 781 0, 0, 0xf800, 0x07e0, 0x001f, 0x0000, srcBytesPerRow, 782 dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace, 783 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 784 dstColorSpace == B_RGB16_BIG, srcFunc, NULL); 785 break; 786 787 case B_RGBA15: 788 case B_RGBA15_BIG: 789 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 790 dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5, 791 alphaShift - 16, alphaBits, 0x7c00, 0x03e0, 0x001f, 0x8000, 792 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 16, 793 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 794 height, srcSwap, dstColorSpace == B_RGBA15_BIG, srcFunc, NULL); 795 break; 796 797 case B_RGB15: 798 case B_RGB15_BIG: 799 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 800 dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5, 801 0, 0, 0x7c00, 0x03e0, 0x001f, 0x0000, srcBytesPerRow, 802 dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace, 803 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 804 dstColorSpace == B_RGB15_BIG, srcFunc, NULL); 805 break; 806 807 case B_GRAY8: 808 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 809 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 810 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, 811 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 8, 812 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 813 height, srcSwap, false, srcFunc, WriteGray8); 814 break; 815 816 case B_GRAY1: 817 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 818 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 819 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, 820 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 1, 821 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 822 height, srcSwap, false, srcFunc, WriteGray1); 823 break; 824 825 case B_CMAP8: 826 PaletteConverter::InitializeDefault(); 827 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 828 dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5, 829 0, 0, 0x7c00, 0x03e0, 0x001f, 0x0000, srcBytesPerRow, 830 dstBytesPerRow, srcBitsPerPixel, 8, srcColorSpace, 831 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 832 false, srcFunc, WriteCMAP8); 833 break; 834 835 default: 836 return B_BAD_VALUE; 837 break; 838 } 839 840 return B_OK; 841 } 842 843 844 /*! \brief Converts a source buffer in one colorspace into a destination 845 buffer of another colorspace. 846 847 \param srcBits The raw source buffer. 848 \param dstBits The raw destination buffer. 849 \param srcBytesPerRow How many bytes per row the source buffer has got. 850 \param dstBytesPerRow How many bytes per row the destination buffer has got. 851 \param srcColorSpace The colorspace the source buffer is in. 852 \param dstColorSpace The colorspace the buffer shall be converted to. 853 \param width The width (in pixels) of each row. 854 \param height The height (in pixels) of the buffers. 855 \return 856 - \c B_OK: Indicates success. 857 - \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported. 858 */ 859 status_t 860 ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength, 861 int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow, 862 color_space srcColorSpace, color_space dstColorSpace, int32 width, 863 int32 height) 864 { 865 return ConvertBits(srcBits, dstBits, srcBitsLength, dstBitsLength, 866 srcBytesPerRow, dstBytesPerRow, srcColorSpace, dstColorSpace, 867 BPoint(0, 0), BPoint(0, 0), width, height); 868 } 869 870 871 /*! \brief Converts a source buffer in one colorspace into a destination 872 buffer of another colorspace. 873 874 \param srcBits The raw source buffer. 875 \param dstBits The raw destination buffer. 876 \param srcBytesPerRow How many bytes per row the source buffer has got. 877 \param dstBytesPerRow How many bytes per row the destination buffer has got. 878 \param srcColorSpace The colorspace the source buffer is in. 879 \param dstColorSpace The colorspace the buffer shall be converted to. 880 \param srcOffset The offset at which to start reading in the source. 881 \param srcOffset The offset at which to start writing in the destination. 882 \param width The width (in pixels) to convert. 883 \param height The height (in pixels) to convert. 884 \return 885 - \c B_OK: Indicates success. 886 - \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported. 887 */ 888 status_t 889 ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength, 890 int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow, 891 color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset, 892 BPoint dstOffset, int32 width, int32 height) 893 { 894 if (!srcBits || !dstBits || srcBitsLength < 0 || dstBitsLength < 0 895 || width < 0 || height < 0 || srcBytesPerRow < 0 || dstBytesPerRow < 0) 896 return B_BAD_VALUE; 897 898 switch (srcColorSpace) { 899 case B_RGBA32: 900 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 901 dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow, 902 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 903 dstOffset, width, height, false, NULL); 904 break; 905 906 case B_RGBA32_BIG: 907 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 908 dstBitsLength, 16, 24, 32, 8, 8, srcBytesPerRow, 909 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 910 dstOffset, width, height, false, NULL); 911 break; 912 913 case B_RGB32: 914 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 915 dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 916 32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 917 height, false, NULL); 918 break; 919 920 case B_RGB32_BIG: 921 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 922 dstBitsLength, 16, 24, 32, 0, 0, srcBytesPerRow, 923 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 924 dstOffset, width, height, false, NULL); 925 break; 926 927 case B_RGB24: 928 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 929 dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 930 24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 931 height, false, ReadRGB24); 932 break; 933 934 case B_RGB24_BIG: 935 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 936 dstBitsLength, 8, 16, 24, 0, 0, srcBytesPerRow, dstBytesPerRow, 937 24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 938 height, false, ReadRGB24); 939 break; 940 941 case B_RGB16: 942 case B_RGB16_BIG: 943 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 944 dstBitsLength, 16, 11, 5, 0, 0, srcBytesPerRow, dstBytesPerRow, 945 16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 946 height, srcColorSpace == B_RGB16_BIG, NULL); 947 break; 948 949 case B_RGBA15: 950 case B_RGBA15_BIG: 951 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 952 dstBitsLength, 15, 10, 5, 16, 1, srcBytesPerRow, 953 dstBytesPerRow, 16, srcColorSpace, dstColorSpace, srcOffset, 954 dstOffset, width, height, srcColorSpace == B_RGBA15_BIG, NULL); 955 break; 956 957 case B_RGB15: 958 case B_RGB15_BIG: 959 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 960 dstBitsLength, 15, 10, 5, 0, 0, srcBytesPerRow, dstBytesPerRow, 961 16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 962 height, srcColorSpace == B_RGB15_BIG, NULL); 963 break; 964 965 case B_GRAY8: 966 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 967 dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 968 8, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 969 height, false, ReadGray8); 970 break; 971 972 case B_GRAY1: 973 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 974 dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 975 1, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 976 height, false, ReadGray1); 977 break; 978 979 case B_CMAP8: 980 PaletteConverter::InitializeDefault(); 981 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 982 dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow, 983 dstBytesPerRow, 8, srcColorSpace, dstColorSpace, srcOffset, 984 dstOffset, width, height, false, ReadCMAP8); 985 break; 986 987 default: 988 return B_BAD_VALUE; 989 break; 990 } 991 992 return B_OK; 993 } 994 995 } // namespace BPrivate 996