138032Speter/* 2261363Sgshapiro * Copyright 2001-2006, Haiku Inc. 364565Sgshapiro * Distributed under the terms of the MIT License. 438032Speter * 538032Speter * Authors: 638032Speter * Ingo Weinhold (bonefish@users.sf.net) 738032Speter * Michael Lotz <mmlr@mlotz.ch> 838032Speter */ 938032Speter 1038032Speter/** This file contains colorspace conversion functions 1138032Speter * and a palette <-> true color conversion class. 1238032Speter */ 13266692Sgshapiro 1438032Speter#include "ColorConversion.h" 1538032Speter 1638032Speter#include <InterfaceDefs.h> 1738032Speter#include <Locker.h> 1838032Speter#include <Point.h> 1938032Speter 2038032Speter#include <Palette.h> 2138032Speter 2238032Speter#include <new> 2364565Sgshapiro#include <string.h> 2464565Sgshapiro 2564565Sgshapiro 2638032Speterusing std::nothrow; 2738032Speter 2864565Sgshapiro 2938032Speternamespace BPrivate { 3038032Speter 3138032Speter/*! \brief Returns the brightness of an RGB 24 color. 3238032Speter \param red Value of the red component. 3364565Sgshapiro \param green Value of the green component. 3438032Speter \param blue Value of the blue component. 3564565Sgshapiro \return The brightness for the supplied RGB color as a value between 0 3664565Sgshapiro and 255. 3738032Speter*/ 3838032Speterstatic inline 3938032Speteruint8 4038032Speterbrightness_for(uint8 red, uint8 green, uint8 blue) 4138032Speter{ 4238032Speter // brightness = 0.301 * red + 0.586 * green + 0.113 * blue 4364565Sgshapiro // we use for performance reasons: 4438032Speter // brightness = (308 * red + 600 * green + 116 * blue) / 1024 4564565Sgshapiro return uint8((308 * red + 600 * green + 116 * blue) / 1024); 4664565Sgshapiro} 4764565Sgshapiro 4864565Sgshapiro 4964565Sgshapiro/*! \brief Returns the "distance" between two RGB colors. 5064565Sgshapiro 5164565Sgshapiro This functions defines an metric on the RGB color space. The distance 5264565Sgshapiro between two colors is 0, if and only if the colors are equal. 5364565Sgshapiro 5464565Sgshapiro \param red1 Red component of the first color. 5564565Sgshapiro \param green1 Green component of the first color. 5638032Speter \param blue1 Blue component of the first color. 5738032Speter \param red2 Red component of the second color. 5838032Speter \param green2 Green component of the second color. 5990795Sgshapiro \param blue2 Blue component of the second color. 6038032Speter \return The distance between the given colors. 6138032Speter*/ 62157006Sgshapirostatic inline 63168520Sgshapirounsigned 64168520Sgshapirocolor_distance(uint8 red1, uint8 green1, uint8 blue1, 65168520Sgshapiro uint8 red2, uint8 green2, uint8 blue2) 66168520Sgshapiro{ 67168520Sgshapiro // euklidian distance (its square actually) 68157006Sgshapiro int rd = (int)red1 - (int)red2; 69110563Sgshapiro int gd = (int)green1 - (int)green2; 70157006Sgshapiro int bd = (int)blue1 - (int)blue2; 71110563Sgshapiro //return rd * rd + gd * gd + bd * bd; 72157006Sgshapiro 73157006Sgshapiro // distance according to psycho-visual tests 74157006Sgshapiro int rmean = ((int)red1 + (int)red2) / 2; 75157006Sgshapiro return (((512 + rmean) * rd * rd) >> 8) 76157006Sgshapiro + 4 * gd * gd 77157006Sgshapiro + (((767 - rmean) * bd * bd) >> 8); 78157006Sgshapiro} 79168520Sgshapiro 80157006Sgshapiro 81157006Sgshapiro/*! \brief Creates an uninitialized PaletteConverter. 82157006Sgshapiro*/ 8390795SgshapiroPaletteConverter::PaletteConverter() 84157006Sgshapiro : fColorMap(NULL), 85157006Sgshapiro fOwnColorMap(NULL), 8690795Sgshapiro fCStatus(B_NO_INIT) 87157006Sgshapiro{ 88157006Sgshapiro} 89157006Sgshapiro 90157006Sgshapiro 91157006Sgshapiro/*! \brief Creates a PaletteConverter and initializes it to the supplied 92157006Sgshapiro palette. 9390795Sgshapiro \param palette The palette being a 256 entry rgb_color array. 94157006Sgshapiro*/ 95157006SgshapiroPaletteConverter::PaletteConverter(const rgb_color *palette) 96157006Sgshapiro : fColorMap(NULL), 97157006Sgshapiro fOwnColorMap(NULL), 9890795Sgshapiro fCStatus(B_NO_INIT) 9990795Sgshapiro{ 10090795Sgshapiro SetTo(palette); 10190795Sgshapiro} 10290795Sgshapiro 10390795Sgshapiro 10490795Sgshapiro/*! \brief Creates a PaletteConverter and initializes it to the supplied 10590795Sgshapiro color map. 10664565Sgshapiro \param colorMap The completely initialized color map. 10764565Sgshapiro*/ 10864565SgshapiroPaletteConverter::PaletteConverter(const color_map *colorMap) 10964565Sgshapiro : fColorMap(NULL), 11064565Sgshapiro fOwnColorMap(NULL), 11171348Sgshapiro fCStatus(B_NO_INIT) 11264565Sgshapiro{ 11364565Sgshapiro SetTo(colorMap); 11464565Sgshapiro} 115261363Sgshapiro 116261363Sgshapiro 117261363Sgshapiro/*! \brief Frees all resources associated with this object. 11864565Sgshapiro*/ 11964565SgshapiroPaletteConverter::~PaletteConverter() 12064565Sgshapiro{ 12164565Sgshapiro delete fOwnColorMap; 12264565Sgshapiro} 12364565Sgshapiro 12464565Sgshapiro 12590795Sgshapiro/*! \brief Initializes the converter to the supplied palette. 12664565Sgshapiro \param palette The palette being a 256 entry rgb_color array. 12790795Sgshapiro \return \c B_OK, if everything went fine, an error code otherwise. 128203004Sgshapiro*/ 129203004Sgshapirostatus_t 13090795SgshapiroPaletteConverter::SetTo(const rgb_color *palette) 131203004Sgshapiro{ 132203004Sgshapiro // cleanup 133203004Sgshapiro SetTo((const color_map*)NULL); 134203004Sgshapiro status_t error = (palette ? B_OK : B_BAD_VALUE); 135203004Sgshapiro // alloc color map 136203004Sgshapiro if (error == B_OK) { 137203004Sgshapiro fOwnColorMap = new(nothrow) color_map; 138203004Sgshapiro if (fOwnColorMap == NULL) 139203004Sgshapiro error = B_NO_MEMORY; 14090795Sgshapiro } 14190795Sgshapiro // init color map 14290795Sgshapiro if (error == B_OK) { 14390795Sgshapiro fColorMap = fOwnColorMap; 14490795Sgshapiro // init color list 14538032Speter memcpy(fOwnColorMap->color_list, palette, sizeof(rgb_color) * 256); 14690795Sgshapiro // init index map 14790795Sgshapiro// TODO: build this list takes about 2 seconds in qemu on my system 14890795Sgshapiro// (because of color_distance()) 14990795Sgshapiro for (int32 color = 0; color < 32768; color++) { 15064565Sgshapiro // get components 15164565Sgshapiro uint8 red = (color & 0x7c00) >> 7; 15290795Sgshapiro uint8 green = (color & 0x3e0) >> 2; 15364565Sgshapiro uint8 blue = (color & 0x1f) << 3; 15490795Sgshapiro red |= red >> 5; 15564565Sgshapiro green |= green >> 5; 15690795Sgshapiro blue |= blue >> 5; 15764565Sgshapiro // find closest color 15864565Sgshapiro uint8 closestIndex = 0; 15964565Sgshapiro unsigned closestDistance = UINT_MAX; 16098125Sgshapiro for (int32 i = 0; i < 256; i++) { 16198125Sgshapiro const rgb_color &c = fOwnColorMap->color_list[i]; 16298125Sgshapiro unsigned distance = color_distance(red, green, blue, 16398125Sgshapiro c.red, c.green, c.blue); 16498125Sgshapiro if (distance < closestDistance) { 16598125Sgshapiro closestIndex = i; 16698125Sgshapiro closestDistance = distance; 16798125Sgshapiro } 16898125Sgshapiro } 169132946Sgshapiro fOwnColorMap->index_map[color] = closestIndex; 170132946Sgshapiro } 171132946Sgshapiro // no need to init inversion map 17298125Sgshapiro } 173132946Sgshapiro fCStatus = error; 174132946Sgshapiro return error; 175132946Sgshapiro} 176132946Sgshapiro 177132946Sgshapiro 178132946Sgshapiro/*! \brief Initializes the converter to the supplied color map. 179132946Sgshapiro \param colorMap The completely initialized color map. 18038032Speter \return \c B_OK, if everything went fine, an error code otherwise. 18138032Speter*/ 18238032Speterstatus_t 18338032SpeterPaletteConverter::SetTo(const color_map *colorMap) 18438032Speter{ 18538032Speter // cleanup 18638032Speter if (fOwnColorMap) { 18764565Sgshapiro delete fOwnColorMap; 18864565Sgshapiro fOwnColorMap = NULL; 18964565Sgshapiro } 19038032Speter // set 19164565Sgshapiro fColorMap = colorMap; 19264565Sgshapiro fCStatus = (fColorMap ? B_OK : B_BAD_VALUE); 19364565Sgshapiro return fCStatus; 19438032Speter} 19564565Sgshapiro 19664565Sgshapiro 19764565Sgshapiro/*! \brief Returns the result of the last initialization via constructor or 19838032Speter SetTo(). 19964565Sgshapiro \return \c B_OK, if the converter is properly initialized, an error code 20064565Sgshapiro otherwise. 20164565Sgshapiro*/ 20238032Speterstatus_t 20364565SgshapiroPaletteConverter::InitCheck() const 20464565Sgshapiro{ 20564565Sgshapiro return fCStatus; 20638032Speter} 20764565Sgshapiro 20864565Sgshapiro 20964565Sgshapiro/*! \brief Returns the palette color index closest to a given RGB 15 color. 21038032Speter 21164565Sgshapiro The object must be properly initialized. 21264565Sgshapiro 21364565Sgshapiro \param rgb The RGB 15 color value (R[14:10]G[9:5]B[4:0]). 21438032Speter \return The palette color index for the supplied color. 21564565Sgshapiro*/ 21664565Sgshapiroinline 21764565Sgshapirouint8 21838032SpeterPaletteConverter::IndexForRGB15(uint16 rgb) const 21964565Sgshapiro{ 22064565Sgshapiro return fColorMap->index_map[rgb]; 22164565Sgshapiro} 22238032Speter 22364565Sgshapiro 22464565Sgshapiro/*! \brief Returns the palette color index closest to a given RGB 15 color. 22564565Sgshapiro 22664565Sgshapiro The object must be properly initialized. 22790795Sgshapiro 22890795Sgshapiro \param red Red component of the color (R[4:0]). 22990795Sgshapiro \param green Green component of the color (G[4:0]). 23090795Sgshapiro \param blue Blue component of the color (B[4:0]). 23190795Sgshapiro \return The palette color index for the supplied color. 23238032Speter*/ 23390795Sgshapiroinline 23490795Sgshapirouint8 23590795SgshapiroPaletteConverter::IndexForRGB15(uint8 red, uint8 green, uint8 blue) const 23638032Speter{ 23738032Speter // the 5 least significant bits are used 23838032Speter return fColorMap->index_map[(red << 10) | (green << 5) | blue]; 23938032Speter} 24038032Speter 24190795Sgshapiro 24238032Speter/*! \brief Returns the palette color index closest to a given RGB 16 color. 24390795Sgshapiro 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*/ 249inline 250uint8 251PaletteConverter::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*/ 266inline 267uint8 268PaletteConverter::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*/ 282inline 283uint8 284PaletteConverter::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*/ 301inline 302uint8 303PaletteConverter::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 RGBA 32 color. 312 313 The object must be properly initialized. 314 315 \param rgb The RGB 32A color value (R[31:24]G[23:16]B[15:8]A[7:0]). 316 \return The palette color index for the supplied color. 317*/ 318inline 319uint8 320PaletteConverter::IndexForRGBA32(uint32 rgba) const 321{ 322 if ((rgba & 0x000000ff) < 128) 323 return B_TRANSPARENT_MAGIC_CMAP8; 324 return IndexForRGB24(rgba); 325} 326 327 328/*! \brief Returns the palette color index closest to a given Gray 8 color. 329 330 The object must be properly initialized. 331 332 \param gray The Gray 8 color value. 333 \return The palette color index for the supplied color. 334*/ 335inline 336uint8 337PaletteConverter::IndexForGray(uint8 gray) const 338{ 339 return IndexForRGB24(gray, gray, gray); 340} 341 342 343/*! \brief Returns the RGB color for a given palette color index. 344 345 The object must be properly initialized. 346 347 \param index The palette color index. 348 \return The color for the supplied palette color index. 349*/ 350inline 351const rgb_color & 352PaletteConverter::RGBColorForIndex(uint8 index) const 353{ 354 return fColorMap->color_list[index]; 355} 356 357 358/*! \brief Returns the RGB 15 color for a given palette color index. 359 360 The object must be properly initialized. 361 362 \param index The palette color index. 363 \return The color for the supplied palette color index 364 (R[14:10]G[9:5]B[4:0]). 365*/ 366inline 367uint16 368PaletteConverter::RGB15ColorForIndex(uint8 index) const 369{ 370 const rgb_color &color = fColorMap->color_list[index]; 371 return ((color.red & 0xf8) << 7) 372 | ((color.green & 0xf8) << 2) 373 | (color.blue >> 3); 374} 375 376 377/*! \brief Returns the RGB 16 color for a given palette color index. 378 379 The object must be properly initialized. 380 381 \param index The palette color index. 382 \return The color for the supplied palette color index 383 (R[15:11]G[10:5]B[4:0]). 384*/ 385inline 386uint16 387PaletteConverter::RGB16ColorForIndex(uint8 index) const 388{ 389 const rgb_color &color = fColorMap->color_list[index]; 390 return ((color.red & 0xf8) << 8) 391 | ((color.green & 0xfc) << 3) 392 | (color.blue >> 3); 393} 394 395 396/*! \brief Returns the RGBA 32 color for a given palette color index. 397 398 The object must be properly initialized. 399 400 \param index The palette color index. 401 \return The color for the supplied palette color index 402 (A[31:24]B[23:16]G[15:8]R[7:0]). 403*/ 404inline 405uint32 406PaletteConverter::RGBA32ColorForIndex(uint8 index) const 407{ 408 const rgb_color &color = fColorMap->color_list[index]; 409 return (color.red << 16) | (color.green << 8) | color.blue 410 | (color.alpha << 24); 411} 412 413 414/*! \brief Returns the RGBA 32 color for a given palette color index. 415 416 The object must be properly initialized. 417 418 \param index The palette color index. 419 \param red Reference to the variable the red component shall be stored 420 into. 421 \param green Reference to the variable the green component shall be stored 422 into. 423 \param blue Reference to the variable the blue component shall be stored 424 into. 425 \param alpha Reference to the variable the alpha component shall be stored 426 into. 427*/ 428inline 429void 430PaletteConverter::RGBA32ColorForIndex(uint8 index, uint8 &red, uint8 &green, 431 uint8 &blue, uint8 &alpha) const 432{ 433 const rgb_color &color = fColorMap->color_list[index]; 434 red = color.red; 435 green = color.green; 436 blue = color.blue; 437 alpha = color.alpha; 438} 439 440 441/*! \brief Returns the Gray 8 color for a given palette color index. 442 443 The object must be properly initialized. 444 445 \param index The palette color index. 446 \return The color for the supplied palette color index. 447*/ 448inline 449uint8 450PaletteConverter::GrayColorForIndex(uint8 index) const 451{ 452 const rgb_color &color = fColorMap->color_list[index]; 453 return brightness_for(color.red, color.green, color.blue); 454} 455 456 457static pthread_once_t sPaletteConverterInitOnce = PTHREAD_ONCE_INIT; 458static PaletteConverter sPaletteConverter; 459 460 461/*! \brief Initialize the global instance of PaletteConverter using the system color palette. 462 \return B_OK. 463*/ 464/*static*/ status_t 465PaletteConverter::InitializeDefault(bool useServer) 466{ 467 if (sPaletteConverter.InitCheck() != B_OK) { 468 pthread_once(&sPaletteConverterInitOnce, 469 useServer 470 ? &_InitializeDefaultAppServer 471 : &_InitializeDefaultNoAppServer); 472 } 473 474 return sPaletteConverter.InitCheck(); 475} 476 477 478/*static*/ void 479PaletteConverter::_InitializeDefaultAppServer() 480{ 481 sPaletteConverter.SetTo(system_colors()); 482} 483 484 485/*static*/ void 486PaletteConverter::_InitializeDefaultNoAppServer() 487{ 488 sPaletteConverter.SetTo(kSystemPalette); 489} 490 491 492typedef uint32 (readFunc)(const uint8 **source, int32 index); 493typedef void (writeFunc)(uint8 **dest, uint8 *data, int32 index); 494 495 496void 497WriteRGB24(uint8 **dest, uint8 *data, int32 index) 498{ 499 (*dest)[0] = data[0]; 500 (*dest)[1] = data[1]; 501 (*dest)[2] = data[2]; 502 *dest += 3; 503} 504 505 506uint32 507ReadRGB24(const uint8 **source, int32 index) 508{ 509 uint32 result = (*source)[0] | ((*source)[1] << 8) | ((*source)[2] << 16); 510 *source += 3; 511 return result; 512} 513 514 515void 516WriteGray8(uint8 **dest, uint8 *data, int32 index) 517{ 518 **dest = (data[2] * 308 + data[1] * 600 + data[0] * 116) >> 10; 519 // this would boost the speed but is less accurate: 520 //*dest = (data[2] << 8) + (data[1] << 9) + (data[0] << 8) >> 10; 521 (*dest)++; 522} 523 524 525uint32 526ReadGray8(const uint8 **source, int32 index) 527{ 528 uint32 result = **source; 529 (*source)++; 530 return result; 531} 532 533 534void 535WriteGray1(uint8 **dest, uint8 *data, int32 index) 536{ 537 int32 shift = 7 - (index % 8); 538 **dest &= ~(0x01 << shift); 539 **dest |= (data[2] * 308 + data[1] * 600 + data[0] * 116) >> (17 - shift); 540 if (shift == 0) 541 (*dest)++; 542} 543 544 545uint32 546ReadGray1(const uint8 **source, int32 index) 547{ 548 int32 shift = 7 - (index % 8); 549 uint32 result = ((**source >> shift) & 0x01) ? 0xff : 0x00; 550 if (shift == 0) 551 (*source)++; 552 return result; 553} 554 555 556void 557WriteCMAP8(uint8 **dest, uint8 *data, int32 index) 558{ 559 **dest = sPaletteConverter.IndexForRGBA32(*(uint32 *)data); 560 (*dest)++; 561} 562 563 564uint32 565ReadCMAP8(const uint8 **source, int32 index) 566{ 567 uint32 result = sPaletteConverter.RGBA32ColorForIndex(**source); 568 (*source)++; 569 return result; 570} 571 572 573template<typename srcByte, typename dstByte> 574status_t 575ConvertBits(const srcByte *srcBits, dstByte *dstBits, int32 srcBitsLength, 576 int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift, 577 int32 alphaShift, int32 alphaBits, uint32 redMask, uint32 greenMask, 578 uint32 blueMask, uint32 alphaMask, int32 srcBytesPerRow, 579 int32 dstBytesPerRow, int32 srcBitsPerPixel, int32 dstBitsPerPixel, 580 color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset, 581 BPoint dstOffset, int32 width, int32 height, bool srcSwap, bool dstSwap, 582 readFunc *srcFunc, writeFunc *dstFunc) 583{ 584 uint8* srcBitsEnd = (uint8*)srcBits + srcBitsLength; 585 uint8* dstBitsEnd = (uint8*)dstBits + dstBitsLength; 586 587 int32 srcBitsPerRow = srcBytesPerRow << 3; 588 int32 dstBitsPerRow = dstBytesPerRow << 3; 589 590 // Advance the buffers to reach their offsets 591 int32 srcOffsetX = (int32)srcOffset.x; 592 int32 dstOffsetX = (int32)dstOffset.x; 593 int32 srcOffsetY = (int32)srcOffset.y; 594 int32 dstOffsetY = (int32)dstOffset.y; 595 if (srcOffsetX < 0) { 596 dstOffsetX -= srcOffsetX; 597 srcOffsetX = 0; 598 } 599 if (srcOffsetY < 0) { 600 dstOffsetY -= srcOffsetY; 601 height += srcOffsetY; 602 srcOffsetY = 0; 603 } 604 if (dstOffsetX < 0) { 605 srcOffsetX -= dstOffsetX; 606 dstOffsetX = 0; 607 } 608 if (dstOffsetY < 0) { 609 srcOffsetY -= dstOffsetY; 610 height += dstOffsetY; 611 dstOffsetY = 0; 612 } 613 614 srcBits = (srcByte*)((uint8*)srcBits + ((srcOffsetY * srcBitsPerRow + srcOffsetX 615 * srcBitsPerPixel) >> 3)); 616 dstBits = (dstByte*)((uint8*)dstBits + ((dstOffsetY * dstBitsPerRow + dstOffsetX 617 * dstBitsPerPixel) >> 3)); 618 619 // Ensure that the width fits 620 int32 srcWidth = (srcBitsPerRow - srcOffsetX * srcBitsPerPixel) 621 / srcBitsPerPixel; 622 if (srcWidth < width) 623 width = srcWidth; 624 625 int32 dstWidth = (dstBitsPerRow - dstOffsetX * dstBitsPerPixel) 626 / dstBitsPerPixel; 627 if (dstWidth < width) 628 width = dstWidth; 629 630 if (width < 0) 631 return B_OK; 632 633 // Catch the copy case 634 if (srcColorSpace == dstColorSpace && srcBitsPerPixel % 8 == 0) { 635 int32 copyCount = (width * srcBitsPerPixel) >> 3; 636 for (int32 i = 0; i < height; i++) { 637 // make sure we don't write beyond the bits size 638 if (copyCount > srcBitsLength) 639 copyCount = srcBitsLength; 640 if (copyCount > dstBitsLength) 641 copyCount = dstBitsLength; 642 if (copyCount == 0) 643 break; 644 645 memcpy(dstBits, srcBits, copyCount); 646 647 srcBitsLength -= copyCount; 648 dstBitsLength -= copyCount; 649 srcBits = (srcByte*)((uint8*)srcBits + srcBytesPerRow); 650 dstBits = (dstByte*)((uint8*)dstBits + dstBytesPerRow); 651 652 if ((uint8 *)srcBits > srcBitsEnd || (uint8 *)dstBits > dstBitsEnd) 653 return B_OK; 654 } 655 656 return B_OK; 657 } 658 659 int32 srcLinePad = (srcBitsPerRow - width * srcBitsPerPixel) >> 3; 660 int32 dstLinePad = (dstBitsPerRow - width * dstBitsPerPixel) >> 3; 661 uint32 result; 662 uint32 source; 663 664 for (int32 i = 0; i < height; i++) { 665 for (int32 j = 0; j < width; j++) { 666 if ((uint8 *)srcBits + sizeof(srcByte) > srcBitsEnd 667 || (uint8 *)dstBits + sizeof(dstByte) > dstBitsEnd) 668 return B_OK; 669 670 if (srcFunc) 671 source = srcFunc((const uint8 **)&srcBits, srcOffsetX++); 672 else { 673 source = *srcBits; 674 srcBits++; 675 } 676 677 // This is valid, as only 16 bit modes will need to swap 678 if (srcSwap) 679 source = (source << 8) | (source >> 8); 680 681 if (redShift > 0) 682 result = ((source >> redShift) & redMask); 683 else if (redShift < 0) 684 result = ((source << -redShift) & redMask); 685 else 686 result = source & redMask; 687 688 if (greenShift > 0) 689 result |= ((source >> greenShift) & greenMask); 690 else if (greenShift < 0) 691 result |= ((source << -greenShift) & greenMask); 692 else 693 result |= source & greenMask; 694 695 if (blueShift > 0) 696 result |= ((source >> blueShift) & blueMask); 697 else if (blueShift < 0) 698 result |= ((source << -blueShift) & blueMask); 699 else 700 result |= source & blueMask; 701 702 if (alphaBits > 0) { 703 if (alphaShift > 0) 704 result |= ((source >> alphaShift) & alphaMask); 705 else if (alphaShift < 0) 706 result |= ((source << -alphaShift) & alphaMask); 707 else 708 result |= source & alphaMask; 709 710 // if we only had one alpha bit we want it to be 0/255 711 if (alphaBits == 1 && result & alphaMask) 712 result |= alphaMask; 713 } else 714 result |= alphaMask; 715 716 // This is valid, as only 16 bit modes will need to swap 717 if (dstSwap) 718 result = (result << 8) | (result >> 8); 719 720 if (dstFunc) 721 dstFunc((uint8 **)&dstBits, (uint8 *)&result, dstOffsetX++); 722 else { 723 *dstBits = result; 724 dstBits++; 725 } 726 } 727 728 srcBits = (srcByte*)((uint8*)srcBits + srcLinePad); 729 dstBits = (dstByte*)((uint8*)dstBits + dstLinePad); 730 dstOffsetX -= width; 731 srcOffsetX -= width; 732 } 733 734 return B_OK; 735} 736 737 738template<typename srcByte> 739status_t 740ConvertBits(const srcByte *srcBits, void *dstBits, int32 srcBitsLength, 741 int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift, 742 int32 alphaShift, int32 alphaBits, int32 srcBytesPerRow, 743 int32 dstBytesPerRow, int32 srcBitsPerPixel, color_space srcColorSpace, 744 color_space dstColorSpace, BPoint srcOffset, BPoint dstOffset, int32 width, 745 int32 height, bool srcSwap, readFunc *srcFunc) 746{ 747 switch (dstColorSpace) { 748 case B_RGBA32: 749 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 750 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 751 alphaShift - 32, alphaBits, 0x00ff0000, 0x0000ff00, 0x000000ff, 752 0xff000000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 753 32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 754 height, srcSwap, false, srcFunc, NULL); 755 break; 756 757 case B_RGBA32_BIG: 758 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 759 dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32, 760 alphaShift - 8, alphaBits, 0x0000ff00, 0x00ff0000, 0xff000000, 761 0x00000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 762 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 763 height, srcSwap, false, srcFunc, NULL); 764 break; 765 766 /* Note: we set the unused alpha to 255 here. This is because BeOS 767 uses the unused alpha for B_OP_ALPHA even though it should 768 not care about it. */ 769 case B_RGB32: 770 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 771 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 772 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, 773 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 774 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 775 height, srcSwap, false, srcFunc, NULL); 776 break; 777 778 case B_RGB32_BIG: 779 ConvertBits(srcBits, (uint32 *)dstBits, srcBitsLength, 780 dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32, 781 0, 0, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff, 782 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32, 783 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 784 height, srcSwap, false, srcFunc, NULL); 785 break; 786 787 case B_RGB24: 788 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 789 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 790 0, 0, 0xff0000, 0x00ff00, 0x0000ff, 0x000000, srcBytesPerRow, 791 dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace, 792 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 793 false, srcFunc, WriteRGB24); 794 break; 795 796 case B_RGB24_BIG: 797 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 798 dstBitsLength, redShift - 8, greenShift - 16, blueShift - 24, 799 0, 0, 0x0000ff, 0x00ff00, 0xff0000, 0x000000, srcBytesPerRow, 800 dstBytesPerRow, srcBitsPerPixel, 24, srcColorSpace, 801 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 802 false, srcFunc, WriteRGB24); 803 break; 804 805 case B_RGB16: 806 case B_RGB16_BIG: 807 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 808 dstBitsLength, redShift - 16, greenShift - 11, blueShift - 5, 809 0, 0, 0xf800, 0x07e0, 0x001f, 0x0000, srcBytesPerRow, 810 dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace, 811 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 812 dstColorSpace == B_RGB16_BIG, srcFunc, NULL); 813 break; 814 815 case B_RGBA15: 816 case B_RGBA15_BIG: 817 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 818 dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5, 819 alphaShift - 16, alphaBits, 0x7c00, 0x03e0, 0x001f, 0x8000, 820 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 16, 821 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 822 height, srcSwap, dstColorSpace == B_RGBA15_BIG, srcFunc, NULL); 823 break; 824 825 case B_RGB15: 826 case B_RGB15_BIG: 827 ConvertBits(srcBits, (uint16 *)dstBits, srcBitsLength, 828 dstBitsLength, redShift - 15, greenShift - 10, blueShift - 5, 829 0, 0, 0x7c00, 0x03e0, 0x001f, 0x0000, srcBytesPerRow, 830 dstBytesPerRow, srcBitsPerPixel, 16, srcColorSpace, 831 dstColorSpace, srcOffset, dstOffset, width, height, srcSwap, 832 dstColorSpace == B_RGB15_BIG, srcFunc, NULL); 833 break; 834 835 case B_GRAY8: 836 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 837 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 838 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, 839 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 8, 840 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 841 height, srcSwap, false, srcFunc, WriteGray8); 842 break; 843 844 case B_GRAY1: 845 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 846 dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8, 847 0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, 848 srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 1, 849 srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 850 height, srcSwap, false, srcFunc, WriteGray1); 851 break; 852 853 case B_CMAP8: 854 PaletteConverter::InitializeDefault(); 855 ConvertBits(srcBits, (uint8 *)dstBits, srcBitsLength, 856 dstBitsLength, redShift - 32, greenShift - 24, blueShift - 16, 857 alphaShift - 8, alphaBits, 0xff000000, 0x00ff0000, 0x0000ff00, 858 0x000000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 8, 859 srcColorSpace, dstColorSpace, srcOffset, dstOffset, 860 width, height, srcSwap, false, srcFunc, WriteCMAP8); 861 break; 862 863 default: 864 return B_BAD_VALUE; 865 break; 866 } 867 868 return B_OK; 869} 870 871 872/*! \brief Converts a source buffer in one colorspace into a destination 873 buffer of another colorspace. 874 875 \param srcBits The raw source buffer. 876 \param dstBits The raw destination buffer. 877 \param srcBytesPerRow How many bytes per row the source buffer has got. 878 \param dstBytesPerRow How many bytes per row the destination buffer has got. 879 \param srcColorSpace The colorspace the source buffer is in. 880 \param dstColorSpace The colorspace the buffer shall be converted to. 881 \param width The width (in pixels) of each row. 882 \param height The height (in pixels) of the buffers. 883 \return 884 - \c B_OK: Indicates success. 885 - \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported. 886*/ 887status_t 888ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength, 889 int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow, 890 color_space srcColorSpace, color_space dstColorSpace, int32 width, 891 int32 height) 892{ 893 return ConvertBits(srcBits, dstBits, srcBitsLength, dstBitsLength, 894 srcBytesPerRow, dstBytesPerRow, srcColorSpace, dstColorSpace, 895 BPoint(0, 0), BPoint(0, 0), width, height); 896} 897 898 899/*! \brief Converts a source buffer in one colorspace into a destination 900 buffer of another colorspace. 901 902 \param srcBits The raw source buffer. 903 \param dstBits The raw destination buffer. 904 \param srcBytesPerRow How many bytes per row the source buffer has got. 905 \param dstBytesPerRow How many bytes per row the destination buffer has got. 906 \param srcColorSpace The colorspace the source buffer is in. 907 \param dstColorSpace The colorspace the buffer shall be converted to. 908 \param srcOffset The offset at which to start reading in the source. 909 \param srcOffset The offset at which to start writing in the destination. 910 \param width The width (in pixels) to convert. 911 \param height The height (in pixels) to convert. 912 \return 913 - \c B_OK: Indicates success. 914 - \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported. 915*/ 916status_t 917ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength, 918 int32 dstBitsLength, int32 srcBytesPerRow, int32 dstBytesPerRow, 919 color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset, 920 BPoint dstOffset, int32 width, int32 height) 921{ 922 if (!srcBits || !dstBits || srcBitsLength < 0 || dstBitsLength < 0 923 || width < 0 || height < 0 || srcBytesPerRow < 0 || dstBytesPerRow < 0) 924 return B_BAD_VALUE; 925 926 switch (srcColorSpace) { 927 case B_RGBA32: 928 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 929 dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow, 930 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 931 dstOffset, width, height, false, NULL); 932 break; 933 934 case B_RGBA32_BIG: 935 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 936 dstBitsLength, 16, 24, 32, 8, 8, srcBytesPerRow, 937 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 938 dstOffset, width, height, false, NULL); 939 break; 940 941 case B_RGB32: 942 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 943 dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 944 32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 945 height, false, NULL); 946 break; 947 948 case B_RGB32_BIG: 949 return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength, 950 dstBitsLength, 16, 24, 32, 0, 0, srcBytesPerRow, 951 dstBytesPerRow, 32, srcColorSpace, dstColorSpace, srcOffset, 952 dstOffset, width, height, false, NULL); 953 break; 954 955 case B_RGB24: 956 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 957 dstBitsLength, 24, 16, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 958 24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 959 height, false, ReadRGB24); 960 break; 961 962 case B_RGB24_BIG: 963 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 964 dstBitsLength, 8, 16, 24, 0, 0, srcBytesPerRow, dstBytesPerRow, 965 24, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 966 height, false, ReadRGB24); 967 break; 968 969 case B_RGB16: 970 case B_RGB16_BIG: 971 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 972 dstBitsLength, 16, 11, 5, 0, 0, srcBytesPerRow, dstBytesPerRow, 973 16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 974 height, srcColorSpace == B_RGB16_BIG, NULL); 975 break; 976 977 case B_RGBA15: 978 case B_RGBA15_BIG: 979 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 980 dstBitsLength, 15, 10, 5, 16, 1, srcBytesPerRow, 981 dstBytesPerRow, 16, srcColorSpace, dstColorSpace, srcOffset, 982 dstOffset, width, height, srcColorSpace == B_RGBA15_BIG, NULL); 983 break; 984 985 case B_RGB15: 986 case B_RGB15_BIG: 987 return ConvertBits((const uint16 *)srcBits, dstBits, srcBitsLength, 988 dstBitsLength, 15, 10, 5, 0, 0, srcBytesPerRow, dstBytesPerRow, 989 16, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 990 height, srcColorSpace == B_RGB15_BIG, NULL); 991 break; 992 993 case B_GRAY8: 994 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 995 dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 996 8, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 997 height, false, ReadGray8); 998 break; 999 1000 case B_GRAY1: 1001 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1002 dstBitsLength, 8, 8, 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 1003 1, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width, 1004 height, false, ReadGray1); 1005 break; 1006 1007 case B_CMAP8: 1008 PaletteConverter::InitializeDefault(); 1009 return ConvertBits((const uint8 *)srcBits, dstBits, srcBitsLength, 1010 dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow, 1011 dstBytesPerRow, 8, srcColorSpace, dstColorSpace, srcOffset, 1012 dstOffset, width, height, false, ReadCMAP8); 1013 break; 1014 1015 default: 1016 return B_BAD_VALUE; 1017 break; 1018 } 1019 1020 return B_OK; 1021} 1022 1023} // namespace BPrivate 1024