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((void*)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 uint64 (read64Func)(const uint16 **source, int32 index); 495 typedef void (writeFunc)(uint8 **dest, uint8 *data, int32 index); 496 497 498 uint64 499 ReadRGB48(const uint16 **source, int32 index) 500 { 501 uint64 result = (*source)[0] | ((uint64)((*source)[1]) << 16) 502 | ((uint64)((*source)[2]) << 32); 503 *source += 3; 504 return result; 505 } 506 507 508 void 509 WriteRGB24(uint8 **dest, uint8 *data, int32 index) 510 { 511 (*dest)[0] = data[0]; 512 (*dest)[1] = data[1]; 513 (*dest)[2] = data[2]; 514 *dest += 3; 515 } 516 517 518 uint32 519 ReadRGB24(const uint8 **source, int32 index) 520 { 521 uint32 result = (*source)[0] | ((*source)[1] << 8) | ((*source)[2] << 16); 522 *source += 3; 523 return result; 524 } 525 526 527 void 528 WriteGray8(uint8 **dest, uint8 *data, int32 index) 529 { 530 **dest = (data[2] * 308 + data[1] * 600 + data[0] * 116) >> 10; 531 // this would boost the speed but is less accurate: 532 //*dest = (data[2] << 8) + (data[1] << 9) + (data[0] << 8) >> 10; 533 (*dest)++; 534 } 535 536 537 uint32 538 ReadGray8(const uint8 **source, int32 index) 539 { 540 uint32 result = **source; 541 (*source)++; 542 return result; 543 } 544 545 546 void 547 WriteGray1(uint8 **dest, uint8 *data, int32 index) 548 { 549 int32 shift = 7 - (index % 8); 550 **dest &= ~(0x01 << shift); 551 **dest |= (data[2] * 308 + data[1] * 600 + data[0] * 116) >> (17 - shift); 552 if (shift == 0) 553 (*dest)++; 554 } 555 556 557 uint32 558 ReadGray1(const uint8 **source, int32 index) 559 { 560 int32 shift = 7 - (index % 8); 561 // In B_GRAY1, a set bit means black (highcolor), a clear bit means white 562 // (low/view color). So we map them to 00 and 0xFF, respectively. 563 uint32 result = ((**source >> shift) & 0x01) ? 0x00 : 0xFF; 564 if (shift == 0) 565 (*source)++; 566 return result; 567 } 568 569 570 void 571 WriteCMAP8(uint8 **dest, uint8 *data, int32 index) 572 { 573 **dest = sPaletteConverter.IndexForRGBA32(*(uint32 *)data); 574 (*dest)++; 575 } 576 577 578 uint32 579 ReadCMAP8(const uint8 **source, int32 index) 580 { 581 uint32 result = sPaletteConverter.RGBA32ColorForIndex(**source); 582 (*source)++; 583 return result; 584 } 585 586 587 template<typename srcByte, typename dstByte> 588 status_t 589 ConvertBits64To32(const srcByte *srcBits, dstByte *dstBits, int32 srcBitsLength, 590 int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift, 591 int32 alphaShift, int32 alphaBits, uint32 redMask, uint32 greenMask, 592 uint32 blueMask, uint32 alphaMask, int32 srcBytesPerRow, 593 int32 dstBytesPerRow, int32 srcBitsPerPixel, int32 dstBitsPerPixel, 594 color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset, 595 BPoint dstOffset, int32 width, int32 height, bool srcSwap, bool dstSwap, 596 read64Func *srcFunc, writeFunc *dstFunc) 597 { 598 uint8* srcBitsEnd = (uint8*)srcBits + srcBitsLength; 599 uint8* dstBitsEnd = (uint8*)dstBits + dstBitsLength; 600 601 int32 srcBitsPerRow = srcBytesPerRow << 3; 602 int32 dstBitsPerRow = dstBytesPerRow << 3; 603 604 // Advance the buffers to reach their offsets 605 int32 srcOffsetX = (int32)srcOffset.x; 606 int32 dstOffsetX = (int32)dstOffset.x; 607 int32 srcOffsetY = (int32)srcOffset.y; 608 int32 dstOffsetY = (int32)dstOffset.y; 609 if (srcOffsetX < 0) { 610 dstOffsetX -= srcOffsetX; 611 srcOffsetX = 0; 612 } 613 if (srcOffsetY < 0) { 614 dstOffsetY -= srcOffsetY; 615 height += srcOffsetY; 616 srcOffsetY = 0; 617 } 618 if (dstOffsetX < 0) { 619 srcOffsetX -= dstOffsetX; 620 dstOffsetX = 0; 621 } 622 if (dstOffsetY < 0) { 623 srcOffsetY -= dstOffsetY; 624 height += dstOffsetY; 625 dstOffsetY = 0; 626 } 627 628 srcBits = (srcByte*)((uint8*)srcBits + ((srcOffsetY * srcBitsPerRow 629 + srcOffsetX * srcBitsPerPixel) >> 3)); 630 dstBits = (dstByte*)((uint8*)dstBits + ((dstOffsetY * dstBitsPerRow 631 + dstOffsetX * dstBitsPerPixel) >> 3)); 632 633 // Ensure that the width fits 634 int32 srcWidth = (srcBitsPerRow - srcOffsetX * srcBitsPerPixel) 635 / srcBitsPerPixel; 636 if (srcWidth < width) 637 width = srcWidth; 638 639 int32 dstWidth = (dstBitsPerRow - dstOffsetX * dstBitsPerPixel) 640 / dstBitsPerPixel; 641 if (dstWidth < width) 642 width = dstWidth; 643 644 if (width < 0) 645 return B_OK; 646 647 int32 srcLinePad = (srcBitsPerRow - width * srcBitsPerPixel + 7) >> 3; 648 int32 dstLinePad = (dstBitsPerRow - width * dstBitsPerPixel + 7) >> 3; 649 uint64 result; 650 uint64 source; 651 652 // srcSwap, means the lower bits come first 653 if (srcSwap) { 654 redShift -= 8; 655 greenShift -= 8; 656 blueShift -= 8; 657 alphaShift -= 8; 658 } 659 660 for (int32 i = 0; i < height; i++) { 661 for (int32 j = 0; j < width; j++) { 662 if ((uint8 *)srcBits + sizeof(srcByte) > srcBitsEnd 663 || (uint8 *)dstBits + sizeof(dstByte) > dstBitsEnd) 664 return B_OK; 665 666 if (srcFunc) 667 source = srcFunc((const uint16 **)&srcBits, srcOffsetX++); 668 else { 669 source = *srcBits; 670 srcBits++; 671 } 672 673 if (redShift > 0) 674 result = ((source >> redShift) & redMask); 675 else if (redShift < 0) 676 result = ((source << -redShift) & redMask); 677 else 678 result = source & redMask; 679 680 if (greenShift > 0) 681 result |= ((source >> greenShift) & greenMask); 682 else if (greenShift < 0) 683 result |= ((source << -greenShift) & greenMask); 684 else 685 result |= source & greenMask; 686 687 if (blueShift > 0) 688 result |= ((source >> blueShift) & blueMask); 689 else if (blueShift < 0) 690 result |= ((source << -blueShift) & blueMask); 691 else 692 result |= source & blueMask; 693 694 if (alphaBits > 0) { 695 if (alphaShift > 0) 696 result |= ((source >> alphaShift) & alphaMask); 697 else if (alphaShift < 0) 698 result |= ((source << -alphaShift) & alphaMask); 699 else 700 result |= source & alphaMask; 701 702 // if we only had one alpha bit we want it to be 0/255 703 if (alphaBits == 1 && result & alphaMask) 704 result |= alphaMask; 705 } else 706 result |= alphaMask; 707 708 if (dstFunc) 709 dstFunc((uint8 **)&dstBits, (uint8 *)&result, dstOffsetX++); 710 else { 711 *dstBits = result; 712 dstBits++; 713 } 714 } 715 716 srcBits = (srcByte*)((uint8*)srcBits + srcLinePad); 717 dstBits = (dstByte*)((uint8*)dstBits + dstLinePad); 718 dstOffsetX -= width; 719 srcOffsetX -= width; 720 } 721 722 return B_OK; 723 } 724 725 726 template<typename srcByte, typename dstByte> 727 status_t 728 ConvertBits(const srcByte *srcBits, dstByte *dstBits, int32 srcBitsLength, 729 int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift, 730 int32 alphaShift, int32 alphaBits, uint32 redMask, uint32 greenMask, 731 uint32 blueMask, uint32 alphaMask, int32 srcBytesPerRow, 732 int32 dstBytesPerRow, int32 srcBitsPerPixel, int32 dstBitsPerPixel, 733 color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset, 734 BPoint dstOffset, int32 width, int32 height, bool srcSwap, bool dstSwap, 735 readFunc *srcFunc, writeFunc *dstFunc) 736 { 737 uint8* srcBitsEnd = (uint8*)srcBits + srcBitsLength; 738 uint8* dstBitsEnd = (uint8*)dstBits + dstBitsLength; 739 740 int32 srcBitsPerRow = srcBytesPerRow << 3; 741 int32 dstBitsPerRow = dstBytesPerRow << 3; 742 743 // Advance the buffers to reach their offsets 744 int32 srcOffsetX = (int32)srcOffset.x; 745 int32 dstOffsetX = (int32)dstOffset.x; 746 int32 srcOffsetY = (int32)srcOffset.y; 747 int32 dstOffsetY = (int32)dstOffset.y; 748 if (srcOffsetX < 0) { 749 dstOffsetX -= srcOffsetX; 750 srcOffsetX = 0; 751 } 752 if (srcOffsetY < 0) { 753 dstOffsetY -= srcOffsetY; 754 height += srcOffsetY; 755 srcOffsetY = 0; 756 } 757 if (dstOffsetX < 0) { 758 srcOffsetX -= dstOffsetX; 759 dstOffsetX = 0; 760 } 761 if (dstOffsetY < 0) { 762 srcOffsetY -= dstOffsetY; 763 height += dstOffsetY; 764 dstOffsetY = 0; 765 } 766 767 srcBits = (srcByte*)((uint8*)srcBits + ((srcOffsetY * srcBitsPerRow 768 + srcOffsetX * srcBitsPerPixel) >> 3)); 769 dstBits = (dstByte*)((uint8*)dstBits + ((dstOffsetY * dstBitsPerRow 770 + dstOffsetX * dstBitsPerPixel) >> 3)); 771 772 // Ensure that the width fits 773 int32 srcWidth = (srcBitsPerRow - srcOffsetX * srcBitsPerPixel) 774 / srcBitsPerPixel; 775 if (srcWidth < width) 776 width = srcWidth; 777 778 int32 dstWidth = (dstBitsPerRow - dstOffsetX * dstBitsPerPixel) 779 / dstBitsPerPixel; 780 if (dstWidth < width) 781 width = dstWidth; 782 783 if (width < 0) 784 return B_OK; 785 786 // Catch the copy case 787 if (srcColorSpace == dstColorSpace && srcBitsPerPixel % 8 == 0) { 788 int32 copyCount = (width * srcBitsPerPixel) >> 3; 789 for (int32 i = 0; i < height; i++) { 790 // make sure we don't write beyond the bits size 791 if (copyCount > srcBitsLength) 792 copyCount = srcBitsLength; 793 if (copyCount > dstBitsLength) 794 copyCount = dstBitsLength; 795 if (copyCount == 0) 796 break; 797 798 memcpy(dstBits, srcBits, copyCount); 799 800 srcBitsLength -= copyCount; 801 dstBitsLength -= copyCount; 802 srcBits = (srcByte*)((uint8*)srcBits + srcBytesPerRow); 803 dstBits = (dstByte*)((uint8*)dstBits + dstBytesPerRow); 804 805 if ((uint8 *)srcBits > srcBitsEnd || (uint8 *)dstBits > dstBitsEnd) 806 return B_OK; 807 } 808 809 return B_OK; 810 } 811 812 int32 srcLinePad = (srcBitsPerRow - width * srcBitsPerPixel + 7) >> 3; 813 int32 dstLinePad = (dstBitsPerRow - width * dstBitsPerPixel + 7) >> 3; 814 uint32 result; 815 uint32 source; 816 817 for (int32 i = 0; i < height; i++) { 818 for (int32 j = 0; j < width; j++) { 819 if ((uint8 *)srcBits + sizeof(srcByte) > srcBitsEnd 820 || (uint8 *)dstBits + sizeof(dstByte) > dstBitsEnd) 821 return B_OK; 822 823 if (srcFunc) 824 source = srcFunc((const uint8 **)&srcBits, srcOffsetX++); 825 else { 826 source = *srcBits; 827 srcBits++; 828 } 829 830 // This is valid, as only 16 bit modes will need to swap 831 if (srcSwap) 832 source = (source << 8) | (source >> 8); 833 834 if (redShift > 0) 835 result = ((source >> redShift) & redMask); 836 else if (redShift < 0) 837 result = ((source << -redShift) & redMask); 838 else 839 result = source & redMask; 840 841 if (greenShift > 0) 842 result |= ((source >> greenShift) & greenMask); 843 else if (greenShift < 0) 844 result |= ((source << -greenShift) & greenMask); 845 else 846 result |= source & greenMask; 847 848 if (blueShift > 0) 849 result |= ((source >> blueShift) & blueMask); 850 else if (blueShift < 0) 851 result |= ((source << -blueShift) & blueMask); 852 else 853 result |= source & blueMask; 854 855 if (alphaBits > 0) { 856 if (alphaShift > 0) 857 result |= ((source >> alphaShift) & alphaMask); 858 else if (alphaShift < 0) 859 result |= ((source << -alphaShift) & alphaMask); 860 else 861 result |= source & alphaMask; 862 863 // if we only had one alpha bit we want it to be 0/255 864 if (alphaBits == 1 && result & alphaMask) 865 result |= alphaMask; 866 } else 867 result |= alphaMask; 868 869 // This is valid, as only 16 bit modes will need to swap 870 if (dstSwap) 871 result = (result << 8) | (result >> 8); 872 873 if (dstFunc) 874 dstFunc((uint8 **)&dstBits, (uint8 *)&result, dstOffsetX++); 875 else { 876 *dstBits = result; 877 dstBits++; 878 } 879 } 880 881 srcBits = (srcByte*)((uint8*)srcBits + srcLinePad); 882 dstBits = (dstByte*)((uint8*)dstBits + dstLinePad); 883 dstOffsetX -= width; 884 srcOffsetX -= width; 885 } 886 887 return B_OK; 888 } 889 890 891 template<typename srcByte> 892 status_t 893 ConvertBits64(const srcByte *srcBits, void *dstBits, int32 srcBitsLength, 894 int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift, 895 int32 alphaShift, int32 alphaBits, int32 srcBytesPerRow, 896 int32 dstBytesPerRow, int32 srcBitsPerPixel, color_space srcColorSpace, 897 color_space dstColorSpace, BPoint srcOffset, BPoint dstOffset, int32 width, 898 int32 height, bool srcSwap, read64Func *srcFunc) 899 { 900 switch (dstColorSpace) { 901 case B_RGBA32: 902 ConvertBits64To32(srcBits, (uint32 *)dstBits, srcBitsLength, 903 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 904 alphaShift - 32, alphaBits, 0x00ff0000, 0x0000ff00, 0x000000ff, 905 0xff000000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 906 32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 907 height, srcSwap, false, srcFunc, NULL); 908 break; 909 910 case B_RGBA32_BIG: 911 ConvertBits64To32(srcBits, (uint32 *)dstBits, srcBitsLength, 912 dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32, 913 alphaShift - 8, alphaBits, 0x0000ff00, 0x00ff0000, 0xff000000, 914 0x00000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 915 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 916 height, srcSwap, false, srcFunc, NULL); 917 break; 918 919 /* Note: we set the unused alpha to 255 here. This is because BeOS 920 uses the unused alpha for B_OP_ALPHA even though it should 921 not care about it. */ 922 case B_RGB32: 923 ConvertBits64To32(srcBits, (uint32 *)dstBits, srcBitsLength, 924 dstBitsLength, redShift - 24, greenShift - 32, blueShift - 16, 925 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, 926 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 927 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 928 height, srcSwap, false, srcFunc, NULL); 929 break; 930 931 case B_RGB32_BIG: 932 ConvertBits64To32(srcBits, (uint32 *)dstBits, srcBitsLength, 933 dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32, 934 0, 0, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff, 935 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 936 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 937 height, srcSwap, false, srcFunc, NULL); 938 break; 939 940 default: 941 return B_BAD_VALUE; 942 break; 943 } 944 945 return B_OK; 946 } 947 948 949 template<typename srcByte> 950 status_t 951 ConvertBits(const srcByte *srcBits, void *dstBits, int32 srcBitsLength, 952 int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift, 953 int32 alphaShift, int32 alphaBits, int32 srcBytesPerRow, 954 int32 dstBytesPerRow, int32 srcBitsPerPixel, color_space srcColorSpace, 955 color_space dstColorSpace, BPoint srcOffset, BPoint dstOffset, int32 width, 956 int32 height, bool srcSwap, readFunc *srcFunc) 957 { 958 switch (dstColorSpace) { 959 case B_RGBA32: 960 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 961 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 962 alphaShift - 32, alphaBits, 0x00ff0000, 0x0000ff00, 0x000000ff, 963 0xff000000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 964 32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 965 height, srcSwap, false, srcFunc, NULL); 966 break; 967 968 case B_RGBA32_BIG: 969 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 970 dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32, 971 alphaShift - 8, alphaBits, 0x0000ff00, 0x00ff0000, 0xff000000, 972 0x00000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 973 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 974 height, srcSwap, false, srcFunc, NULL); 975 break; 976 977 /* Note: we set the unused alpha to 255 here. This is because BeOS 978 uses the unused alpha for B_OP_ALPHA even though it should 979 not care about it. */ 980 case B_RGB32: 981 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 982 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 983 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, 984 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 985 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 986 height, srcSwap, false, srcFunc, NULL); 987 break; 988 989 case B_RGB32_BIG: 990 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 991 dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32, 992 0, 0, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff, 993 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 994 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 995 height, srcSwap, false, srcFunc, NULL); 996 break; 997 998 case B_RGB24: 999 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 1000 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 1001 0, 0, 0xff0000, 0x00ff00, 0x0000ff, 0x000000, srcBytesPerRow, 1002 dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace, 1003 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 1004 false, srcFunc, WriteRGB24); 1005 break; 1006 1007 case B_RGB24_BIG: 1008 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 1009 dstBitsLength, redShift - 8, greenShift - 16, blueShift - 24, 1010 0, 0, 0x0000ff, 0x00ff00, 0xff0000, 0x000000, srcBytesPerRow, 1011 dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace, 1012 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 1013 false, srcFunc, WriteRGB24); 1014 break; 1015 1016 case B_RGB16: 1017 case B_RGB16_BIG: 1018 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 1019 dstBitsLength, redShift - 16, greenShift - 11, blueShift - 5, 1020 0, 0, 0xf800, 0x07e0, 0x001f, 0x0000, srcBytesPerRow, 1021 dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace, 1022 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 1023 dstColorSpace == B_RGB16_BIG, srcFunc, NULL); 1024 break; 1025 1026 case B_RGBA15: 1027 case B_RGBA15_BIG: 1028 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 1029 dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5, 1030 alphaShift - 16, alphaBits, 0x7c00, 0x03e0, 0x001f, 0x8000, 1031 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 16, 1032 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1033 height, srcSwap, dstColorSpace == B_RGBA15_BIG, srcFunc, NULL); 1034 break; 1035 1036 case B_RGB15: 1037 case B_RGB15_BIG: 1038 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 1039 dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5, 1040 0, 0, 0x7c00, 0x03e0, 0x001f, 0x0000, srcBytesPerRow, 1041 dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace, 1042 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 1043 dstColorSpace == B_RGB15_BIG, srcFunc, NULL); 1044 break; 1045 1046 case B_GRAY8: 1047 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 1048 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 1049 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, 1050 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 8, 1051 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1052 height, srcSwap, false, srcFunc, WriteGray8); 1053 break; 1054 1055 case B_GRAY1: 1056 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 1057 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 1058 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, 1059 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 1, 1060 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1061 height, srcSwap, false, srcFunc, WriteGray1); 1062 break; 1063 1064 case B_CMAP8: 1065 PaletteConverter::InitializeDefault(); 1066 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 1067 dstBitsLength, redShift - 32, greenShift - 24, blueShift - 16, 1068 alphaShift - 8, alphaBits, 0xff000000, 0x00ff0000, 0x0000ff00, 1069 0x000000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 8, 1070 srcColorSpace, dstColorSpace, srcOffset, dstOffset, 1071 width, height, srcSwap, false, srcFunc, WriteCMAP8); 1072 break; 1073 1074 default: 1075 return B_BAD_VALUE; 1076 break; 1077 } 1078 1079 return B_OK; 1080 } 1081 1082 1083 /*! \brief Converts a source buffer in one colorspace into a destination 1084 buffer of another colorspace. 1085 1086 \param srcBits The raw source buffer. 1087 \param dstBits The raw destination buffer. 1088 \param srcBytesPerRow How many bytes per row the source buffer has got. 1089 \param dstBytesPerRow How many bytes per row the destination buffer has got. 1090 \param srcColorSpace The colorspace the source buffer is in. 1091 \param dstColorSpace The colorspace the buffer shall be converted to. 1092 \param width The width (in pixels) of each row. 1093 \param height The height (in pixels) of the buffers. 1094 \return 1095 - \c B_OK: Indicates success. 1096 - \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported. 1097 */ 1098 status_t 1099 ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength, 1100 int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow, 1101 color_space srcColorSpace, color_space dstColorSpace, int32 width, 1102 int32 height) 1103 { 1104 return ConvertBits(srcBits, dstBits, srcBitsLength, dstBitsLength, 1105 srcBytesPerRow, dstBytesPerRow, srcColorSpace, dstColorSpace, 1106 BPoint(0, 0), BPoint(0, 0), width, height); 1107 } 1108 1109 1110 /*! \brief Converts a source buffer in one colorspace into a destination 1111 buffer of another colorspace. 1112 1113 \param srcBits The raw source buffer. 1114 \param dstBits The raw destination buffer. 1115 \param srcBytesPerRow How many bytes per row the source buffer has got. 1116 \param dstBytesPerRow How many bytes per row the destination buffer has got. 1117 \param srcColorSpace The colorspace the source buffer is in. 1118 \param dstColorSpace The colorspace the buffer shall be converted to. 1119 \param srcOffset The offset at which to start reading in the source. 1120 \param srcOffset The offset at which to start writing in the destination. 1121 \param width The width (in pixels) to convert. 1122 \param height The height (in pixels) to convert. 1123 \return 1124 - \c B_OK: Indicates success. 1125 - \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported. 1126 */ 1127 status_t 1128 ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength, 1129 int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow, 1130 color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset, 1131 BPoint dstOffset, int32 width, int32 height) 1132 { 1133 if (!srcBits || !dstBits || srcBitsLength < 0 || dstBitsLength < 0 1134 || width < 0 || height < 0 || srcBytesPerRow < 0 || dstBytesPerRow < 0) 1135 return B_BAD_VALUE; 1136 1137 switch (srcColorSpace) { 1138 case B_RGBA64: 1139 case B_RGBA64_BIG: 1140 return ConvertBits64((const uint64 *)srcBits, dstBits, 1141 srcBitsLength, dstBitsLength, 16, 32, 48, 64, 16, 1142 srcBytesPerRow, dstBytesPerRow, 64, srcColorSpace, 1143 dstColorSpace, srcOffset, dstOffset, width, height, 1144 srcColorSpace == B_RGBA64_BIG, NULL); 1145 1146 case B_RGB48: 1147 case B_RGB48_BIG: 1148 return ConvertBits64((const uint16 *)srcBits, dstBits, 1149 srcBitsLength, dstBitsLength, 16, 32, 48, 0, 0, srcBytesPerRow, 1150 dstBytesPerRow, 48, srcColorSpace, dstColorSpace, srcOffset, 1151 dstOffset, width, height, srcColorSpace == B_RGB48_BIG, 1152 ReadRGB48); 1153 1154 case B_RGBA32: 1155 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 1156 dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow, 1157 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 1158 dstOffset, width, height, false, NULL); 1159 1160 case B_RGBA32_BIG: 1161 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 1162 dstBitsLength, 16, 24, 32, 8, 8, srcBytesPerRow, 1163 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 1164 dstOffset, width, height, false, NULL); 1165 1166 case B_RGB32: 1167 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 1168 dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 1169 32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1170 height, false, NULL); 1171 1172 case B_RGB32_BIG: 1173 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 1174 dstBitsLength, 16, 24, 32, 0, 0, srcBytesPerRow, 1175 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 1176 dstOffset, width, height, false, NULL); 1177 1178 case B_RGB24: 1179 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1180 dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 1181 24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1182 height, false, ReadRGB24); 1183 1184 case B_RGB24_BIG: 1185 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1186 dstBitsLength, 8, 16, 24, 0, 0, srcBytesPerRow, dstBytesPerRow, 1187 24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1188 height, false, ReadRGB24); 1189 1190 case B_RGB16: 1191 case B_RGB16_BIG: 1192 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 1193 dstBitsLength, 16, 11, 5, 0, 0, srcBytesPerRow, dstBytesPerRow, 1194 16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1195 height, srcColorSpace == B_RGB16_BIG, NULL); 1196 1197 case B_RGBA15: 1198 case B_RGBA15_BIG: 1199 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 1200 dstBitsLength, 15, 10, 5, 16, 1, srcBytesPerRow, 1201 dstBytesPerRow, 16, srcColorSpace, dstColorSpace, srcOffset, 1202 dstOffset, width, height, srcColorSpace == B_RGBA15_BIG, NULL); 1203 1204 case B_RGB15: 1205 case B_RGB15_BIG: 1206 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 1207 dstBitsLength, 15, 10, 5, 0, 0, srcBytesPerRow, dstBytesPerRow, 1208 16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1209 height, srcColorSpace == B_RGB15_BIG, NULL); 1210 1211 case B_GRAY8: 1212 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1213 dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 1214 8, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1215 height, false, ReadGray8); 1216 1217 case B_GRAY1: 1218 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1219 dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 1220 1, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1221 height, false, ReadGray1); 1222 1223 case B_CMAP8: 1224 PaletteConverter::InitializeDefault(); 1225 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1226 dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow, 1227 dstBytesPerRow, 8, srcColorSpace, dstColorSpace, srcOffset, 1228 dstOffset, width, height, false, ReadCMAP8); 1229 1230 default: 1231 return B_BAD_VALUE; 1232 } 1233 1234 return B_OK; 1235 } 1236 1237 } // namespace BPrivate 1238