diff --git a/headers/private/interface/ColorConversion.h b/headers/private/interface/ColorConversion.h new file mode 100644 index 0000000000..7e2160be3b --- /dev/null +++ b/headers/private/interface/ColorConversion.h @@ -0,0 +1,50 @@ +#ifndef _COLOR_CONVERSION_H_ +#define _COLOR_CONVERSION_H_ + +#include + +namespace BPrivate { + +status_t ConvertBits(const void *srcBuffer, void *dstBuffer, + uint32 srcBytesPerRow, uint32 dstBytesPerRow, color_space srcColorSpace, + color_space dstColorSpace, int32 width, int32 height); + + +/*! \brief Helper class for conversion between RGB and palette colors. +*/ +class PaletteConverter { +public: + PaletteConverter(); + PaletteConverter(const rgb_color *palette); + PaletteConverter(const color_map *colorMap); + ~PaletteConverter(); + + status_t SetTo(const rgb_color *palette); + status_t SetTo(const color_map *colorMap); + status_t InitCheck() const; + + inline uint8 IndexForRGB15(uint16 rgb) const; + inline uint8 IndexForRGB15(uint8 red, uint8 green, uint8 blue) const; + inline uint8 IndexForRGB16(uint16 rgb) const; + inline uint8 IndexForRGB16(uint8 red, uint8 green, uint8 blue) const; + inline uint8 IndexForRGB24(uint32 rgb) const; + inline uint8 IndexForRGB24(uint8 red, uint8 green, uint8 blue) const; + inline uint8 IndexForGray(uint8 gray) const; + + inline const rgb_color &RGBColorForIndex(uint8 index) const; + inline uint16 RGB15ColorForIndex(uint8 index) const; + inline uint16 RGB16ColorForIndex(uint8 index) const; + inline uint32 RGBA32ColorForIndex(uint8 index) const; + inline void RGBA32ColorForIndex(uint8 index, uint8 &red, uint8 &green, + uint8 &blue, uint8 &alpha) const; + inline uint8 GrayColorForIndex(uint8 index) const; + +private: + const color_map *fColorMap; + color_map *fOwnColorMap; + status_t fCStatus; +}; + +} // namespace BPrivate + +#endif diff --git a/src/kits/interface/Bitmap.cpp b/src/kits/interface/Bitmap.cpp index e0480065fe..da81661166 100644 --- a/src/kits/interface/Bitmap.cpp +++ b/src/kits/interface/Bitmap.cpp @@ -25,103 +25,13 @@ #include #include +#include "ColorConversion.h" + // Includes to be able to talk to the app_server #include #include -// TODO: system palette -- hard-coded for now, when the app server is ready -// we should use system_colors() or BScreen::ColorMap(). -const rgb_color kSystemPalette[] = { - { 0, 0, 0, 255 }, { 8, 8, 8, 255 }, { 16, 16, 16, 255 }, - { 24, 24, 24, 255 }, { 32, 32, 32, 255 }, { 40, 40, 40, 255 }, - { 48, 48, 48, 255 }, { 56, 56, 56, 255 }, { 64, 64, 64, 255 }, - { 72, 72, 72, 255 }, { 80, 80, 80, 255 }, { 88, 88, 88, 255 }, - { 96, 96, 96, 255 }, { 104, 104, 104, 255 }, { 112, 112, 112, 255 }, - { 120, 120, 120, 255 }, { 128, 128, 128, 255 }, { 136, 136, 136, 255 }, - { 144, 144, 144, 255 }, { 152, 152, 152, 255 }, { 160, 160, 160, 255 }, - { 168, 168, 168, 255 }, { 176, 176, 176, 255 }, { 184, 184, 184, 255 }, - { 192, 192, 192, 255 }, { 200, 200, 200, 255 }, { 208, 208, 208, 255 }, - { 216, 216, 216, 255 }, { 224, 224, 224, 255 }, { 232, 232, 232, 255 }, - { 240, 240, 240, 255 }, { 248, 248, 248, 255 }, { 0, 0, 255, 255 }, - { 0, 0, 229, 255 }, { 0, 0, 204, 255 }, { 0, 0, 179, 255 }, - { 0, 0, 154, 255 }, { 0, 0, 129, 255 }, { 0, 0, 105, 255 }, - { 0, 0, 80, 255 }, { 0, 0, 55, 255 }, { 0, 0, 30, 255 }, - { 255, 0, 0, 255 }, { 228, 0, 0, 255 }, { 203, 0, 0, 255 }, - { 178, 0, 0, 255 }, { 153, 0, 0, 255 }, { 128, 0, 0, 255 }, - { 105, 0, 0, 255 }, { 80, 0, 0, 255 }, { 55, 0, 0, 255 }, - { 30, 0, 0, 255 }, { 0, 255, 0, 255 }, { 0, 228, 0, 255 }, - { 0, 203, 0, 255 }, { 0, 178, 0, 255 }, { 0, 153, 0, 255 }, - { 0, 128, 0, 255 }, { 0, 105, 0, 255 }, { 0, 80, 0, 255 }, - { 0, 55, 0, 255 }, { 0, 30, 0, 255 }, { 0, 152, 51, 255 }, - { 255, 255, 255, 255 }, { 203, 255, 255, 255 }, { 203, 255, 203, 255 }, - { 203, 255, 152, 255 }, { 203, 255, 102, 255 }, { 203, 255, 51, 255 }, - { 203, 255, 0, 255 }, { 152, 255, 255, 255 }, { 152, 255, 203, 255 }, - { 152, 255, 152, 255 }, { 152, 255, 102, 255 }, { 152, 255, 51, 255 }, - { 152, 255, 0, 255 }, { 102, 255, 255, 255 }, { 102, 255, 203, 255 }, - { 102, 255, 152, 255 }, { 102, 255, 102, 255 }, { 102, 255, 51, 255 }, - { 102, 255, 0, 255 }, { 51, 255, 255, 255 }, { 51, 255, 203, 255 }, - { 51, 255, 152, 255 }, { 51, 255, 102, 255 }, { 51, 255, 51, 255 }, - { 51, 255, 0, 255 }, { 255, 152, 255, 255 }, { 255, 152, 203, 255 }, - { 255, 152, 152, 255 }, { 255, 152, 102, 255 }, { 255, 152, 51, 255 }, - { 255, 152, 0, 255 }, { 0, 102, 255, 255 }, { 0, 102, 203, 255 }, - { 203, 203, 255, 255 }, { 203, 203, 203, 255 }, { 203, 203, 152, 255 }, - { 203, 203, 102, 255 }, { 203, 203, 51, 255 }, { 203, 203, 0, 255 }, - { 152, 203, 255, 255 }, { 152, 203, 203, 255 }, { 152, 203, 152, 255 }, - { 152, 203, 102, 255 }, { 152, 203, 51, 255 }, { 152, 203, 0, 255 }, - { 102, 203, 255, 255 }, { 102, 203, 203, 255 }, { 102, 203, 152, 255 }, - { 102, 203, 102, 255 }, { 102, 203, 51, 255 }, { 102, 203, 0, 255 }, - { 51, 203, 255, 255 }, { 51, 203, 203, 255 }, { 51, 203, 152, 255 }, - { 51, 203, 102, 255 }, { 51, 203, 51, 255 }, { 51, 203, 0, 255 }, - { 255, 102, 255, 255 }, { 255, 102, 203, 255 }, { 255, 102, 152, 255 }, - { 255, 102, 102, 255 }, { 255, 102, 51, 255 }, { 255, 102, 0, 255 }, - { 0, 102, 152, 255 }, { 0, 102, 102, 255 }, { 203, 152, 255, 255 }, - { 203, 152, 203, 255 }, { 203, 152, 152, 255 }, { 203, 152, 102, 255 }, - { 203, 152, 51, 255 }, { 203, 152, 0, 255 }, { 152, 152, 255, 255 }, - { 152, 152, 203, 255 }, { 152, 152, 152, 255 }, { 152, 152, 102, 255 }, - { 152, 152, 51, 255 }, { 152, 152, 0, 255 }, { 102, 152, 255, 255 }, - { 102, 152, 203, 255 }, { 102, 152, 152, 255 }, { 102, 152, 102, 255 }, - { 102, 152, 51, 255 }, { 102, 152, 0, 255 }, { 51, 152, 255, 255 }, - { 51, 152, 203, 255 }, { 51, 152, 152, 255 }, { 51, 152, 102, 255 }, - { 51, 152, 51, 255 }, { 51, 152, 0, 255 }, { 230, 134, 0, 255 }, - { 255, 51, 203, 255 }, { 255, 51, 152, 255 }, { 255, 51, 102, 255 }, - { 255, 51, 51, 255 }, { 255, 51, 0, 255 }, { 0, 102, 51, 255 }, - { 0, 102, 0, 255 }, { 203, 102, 255, 255 }, { 203, 102, 203, 255 }, - { 203, 102, 152, 255 }, { 203, 102, 102, 255 }, { 203, 102, 51, 255 }, - { 203, 102, 0, 255 }, { 152, 102, 255, 255 }, { 152, 102, 203, 255 }, - { 152, 102, 152, 255 }, { 152, 102, 102, 255 }, { 152, 102, 51, 255 }, - { 152, 102, 0, 255 }, { 102, 102, 255, 255 }, { 102, 102, 203, 255 }, - { 102, 102, 152, 255 }, { 102, 102, 102, 255 }, { 102, 102, 51, 255 }, - { 102, 102, 0, 255 }, { 51, 102, 255, 255 }, { 51, 102, 203, 255 }, - { 51, 102, 152, 255 }, { 51, 102, 102, 255 }, { 51, 102, 51, 255 }, - { 51, 102, 0, 255 }, { 255, 0, 255, 255 }, { 255, 0, 203, 255 }, - { 255, 0, 152, 255 }, { 255, 0, 102, 255 }, { 255, 0, 51, 255 }, - { 255, 175, 19, 255 }, { 0, 51, 255, 255 }, { 0, 51, 203, 255 }, - { 203, 51, 255, 255 }, { 203, 51, 203, 255 }, { 203, 51, 152, 255 }, - { 203, 51, 102, 255 }, { 203, 51, 51, 255 }, { 203, 51, 0, 255 }, - { 152, 51, 255, 255 }, { 152, 51, 203, 255 }, { 152, 51, 152, 255 }, - { 152, 51, 102, 255 }, { 152, 51, 51, 255 }, { 152, 51, 0, 255 }, - { 102, 51, 255, 255 }, { 102, 51, 203, 255 }, { 102, 51, 152, 255 }, - { 102, 51, 102, 255 }, { 102, 51, 51, 255 }, { 102, 51, 0, 255 }, - { 51, 51, 255, 255 }, { 51, 51, 203, 255 }, { 51, 51, 152, 255 }, - { 51, 51, 102, 255 }, { 51, 51, 51, 255 }, { 51, 51, 0, 255 }, - { 255, 203, 102, 255 }, { 255, 203, 152, 255 }, { 255, 203, 203, 255 }, - { 255, 203, 255, 255 }, { 0, 51, 152, 255 }, { 0, 51, 102, 255 }, - { 0, 51, 51, 255 }, { 0, 51, 0, 255 }, { 203, 0, 255, 255 }, - { 203, 0, 203, 255 }, { 203, 0, 152, 255 }, { 203, 0, 102, 255 }, - { 203, 0, 51, 255 }, { 255, 227, 70, 255 }, { 152, 0, 255, 255 }, - { 152, 0, 203, 255 }, { 152, 0, 152, 255 }, { 152, 0, 102, 255 }, - { 152, 0, 51, 255 }, { 152, 0, 0, 255 }, { 102, 0, 255, 255 }, - { 102, 0, 203, 255 }, { 102, 0, 152, 255 }, { 102, 0, 102, 255 }, - { 102, 0, 51, 255 }, { 102, 0, 0, 255 }, { 51, 0, 255, 255 }, - { 51, 0, 203, 255 }, { 51, 0, 152, 255 }, { 51, 0, 102, 255 }, - { 51, 0, 51, 255 }, { 51, 0, 0, 255 }, { 255, 203, 51, 255 }, - { 255, 203, 0, 255 }, { 255, 255, 0, 255 }, { 255, 255, 51, 255 }, - { 255, 255, 102, 255 }, { 255, 255, 152, 255 }, { 255, 255, 203, 255 }, - { 255, 255, 255, 0 } // B_TRANSPARENT_MAGIC_CMAP8 -}; - - // get_raw_bytes_per_row /*! \brief Returns the number of bytes per row needed to store the actual bitmap data (not including any padding) given a color space and a @@ -201,486 +111,6 @@ get_bytes_per_row(color_space colorSpace, int32 width) return bpr; } -// brightness_for -/*! \brief Returns the brightness of an RGB 24 color. - \param red Value of the red component. - \param green Value of the green component. - \param blue Value of the blue component. - \return The brightness for the supplied RGB color as a value between 0 - and 255. -*/ -static inline -uint8 -brightness_for(uint8 red, uint8 green, uint8 blue) -{ - // brightness = 0.301 * red + 0.586 * green + 0.113 * blue - // we use for performance reasons: - // brightness = (308 * red + 600 * green + 116 * blue) / 1024 - return uint8((308 * red + 600 * green + 116 * blue) / 1024); -} - -// color_distance -/*! \brief Returns the "distance" between two RGB colors. - - This functions defines an metric on the RGB color space. The distance - between two colors is 0, if and only if the colors are equal. - - \param red1 Red component of the first color. - \param green1 Green component of the first color. - \param blue1 Blue component of the first color. - \param red2 Red component of the second color. - \param green2 Green component of the second color. - \param blue2 Blue component of the second color. - \return The distance between the given colors. -*/ -static inline -unsigned -color_distance(uint8 red1, uint8 green1, uint8 blue1, - uint8 red2, uint8 green2, uint8 blue2) -{ - // euklidian distance (its square actually) - int rd = (int)red1 - (int)red2; - int gd = (int)green1 - (int)green2; - int bd = (int)blue1 - (int)blue2; -// return rd * rd + gd * gd + bd * bd; - - // distance according to psycho-visual tests - int rmean = ((int)red1 + (int)red2) / 2; - return (((512 + rmean) * rd * rd) >> 8) - + 4 * gd * gd - + (((767 - rmean) * bd * bd) >> 8); -} - -// bit_mask, inverse_bit_mask -static inline int32 bit_mask(int32 bit) { return (1 << bit); } -static inline int32 inverse_bit_mask(int32 bit) { return ~bit_mask(bit); } - - -////////////////////// -// PaletteConverter // -////////////////////// - -namespace BPrivate { - -/*! \brief Helper class for conversion between RGB and palette colors. -*/ -class PaletteConverter { -public: - PaletteConverter(); - PaletteConverter(const rgb_color *palette); - PaletteConverter(const color_map *colorMap); - ~PaletteConverter(); - - status_t SetTo(const rgb_color *palette); - status_t SetTo(const color_map *colorMap); - status_t InitCheck() const; - - inline uint8 IndexForRGB15(uint16 rgb) const; - inline uint8 IndexForRGB15(uint8 red, uint8 green, uint8 blue) const; - inline uint8 IndexForRGB16(uint16 rgb) const; - inline uint8 IndexForRGB16(uint8 red, uint8 green, uint8 blue) const; - inline uint8 IndexForRGB24(uint32 rgb) const; - inline uint8 IndexForRGB24(uint8 red, uint8 green, uint8 blue) const; - inline uint8 IndexForGray(uint8 gray) const; - - inline const rgb_color &RGBColorForIndex(uint8 index) const; - inline uint16 RGB15ColorForIndex(uint8 index) const; - inline uint16 RGB16ColorForIndex(uint8 index) const; - inline uint32 RGB24ColorForIndex(uint8 index) const; - inline void RGB24ColorForIndex(uint8 index, uint8 &red, uint8 &green, - uint8 &blue, uint8 &alpha) const; - inline uint8 GrayColorForIndex(uint8 index) const; - -private: - const color_map *fColorMap; - color_map *fOwnColorMap; - status_t fCStatus; -}; - -} // namespace BPrivate - -using BPrivate::PaletteConverter; -using namespace std; - -// constructor -/*! \brief Creates an uninitialized PaletteConverter. -*/ -PaletteConverter::PaletteConverter() - : fColorMap(NULL), - fOwnColorMap(NULL), - fCStatus(B_NO_INIT) -{ -} - -// constructor -/*! \brief Creates a PaletteConverter and initializes it to the supplied - palette. - \param palette The palette being a 256 entry rgb_color array. -*/ -PaletteConverter::PaletteConverter(const rgb_color *palette) - : fColorMap(NULL), - fOwnColorMap(NULL), - fCStatus(B_NO_INIT) -{ - SetTo(palette); -} - -// constructor -/*! \brief Creates a PaletteConverter and initializes it to the supplied - color map. - \param colorMap The completely initialized color map. -*/ -PaletteConverter::PaletteConverter(const color_map *colorMap) - : fColorMap(NULL), - fOwnColorMap(NULL), - fCStatus(B_NO_INIT) -{ - SetTo(colorMap); -} - -// destructor -/*! \brief Frees all resources associated with this object. -*/ -PaletteConverter::~PaletteConverter() -{ - delete fOwnColorMap; -} - -// SetTo -/*! \brief Initializes the converter to the supplied palette. - \param palette The palette being a 256 entry rgb_color array. - \return \c B_OK, if everything went fine, an error code otherwise. -*/ -status_t -PaletteConverter::SetTo(const rgb_color *palette) -{ - // cleanup - SetTo((const color_map*)NULL); - status_t error = (palette ? B_OK : B_BAD_VALUE); - // alloc color map - if (error == B_OK) { - fOwnColorMap = new(nothrow) color_map; - if (fOwnColorMap == NULL) - error = B_NO_MEMORY; - } - // init color map - if (error == B_OK) { - fColorMap = fOwnColorMap; - // init color list - memcpy(fOwnColorMap->color_list, palette, sizeof(rgb_color) * 256); - // init index map -// TODO: build this list takes about 2 seconds in qemu on my system -// (because of color_distance()) - for (int32 color = 0; color < 32768; color++) { - // get components - uint8 red = (color & 0x7c00) >> 7; - uint8 green = (color & 0x3e0) >> 2; - uint8 blue = (color & 0x1f) << 3; - red |= red >> 5; - green |= green >> 5; - blue |= blue >> 5; - // find closest color - uint8 closestIndex = 0; - unsigned closestDistance = UINT_MAX; - for (int32 i = 0; i < 256; i++) { - const rgb_color &c = fOwnColorMap->color_list[i]; - unsigned distance = color_distance(red, green, blue, - c.red, c.green, c.blue); - if (distance < closestDistance) { - closestIndex = i; - closestDistance = distance; - } - } - fOwnColorMap->index_map[color] = closestIndex; - } - // no need to init inversion map - } - fCStatus = error; - return error; -} - -// SetTo -/*! \brief Initializes the converter to the supplied color map. - \param colorMap The completely initialized color map. - \return \c B_OK, if everything went fine, an error code otherwise. -*/ -status_t -PaletteConverter::SetTo(const color_map *colorMap) -{ - // cleanup - if (fOwnColorMap) { - delete fOwnColorMap; - fOwnColorMap = NULL; - } - // set - fColorMap = colorMap; - fCStatus = (fColorMap ? B_OK : B_BAD_VALUE); - return fCStatus; -} - -// InitCheck -/*! \brief Returns the result of the last initialization via constructor or - SetTo(). - \return \c B_OK, if the converter is properly initialized, an error code - otherwise. -*/ -status_t -PaletteConverter::InitCheck() const -{ - return fCStatus; -} - -// IndexForRGB15 -/*! \brief Returns the palette color index closest to a given RGB 15 color. - - The object must be properly initialized. - - \param rgb The RGB 15 color value (R[14:10]G[9:5]B[4:0]). - \return The palette color index for the supplied color. -*/ -inline -uint8 -PaletteConverter::IndexForRGB15(uint16 rgb) const -{ - return fColorMap->index_map[rgb]; -} - -// IndexForRGB15 -/*! \brief Returns the palette color index closest to a given RGB 15 color. - - The object must be properly initialized. - - \param red Red component of the color (R[4:0]). - \param green Green component of the color (G[4:0]). - \param blue Blue component of the color (B[4:0]). - \return The palette color index for the supplied color. -*/ -inline -uint8 -PaletteConverter::IndexForRGB15(uint8 red, uint8 green, uint8 blue) const -{ - // the 5 least significant bits are used - return fColorMap->index_map[(red << 10) | (green << 5) | blue]; -} - -// IndexForRGB16 -/*! \brief Returns the palette color index closest to a given RGB 16 color. - - The object must be properly initialized. - - \param rgb The RGB 16 color value (R[15:11]G[10:5]B[4:0]). - \return The palette color index for the supplied color. -*/ -inline -uint8 -PaletteConverter::IndexForRGB16(uint16 rgb) const -{ - return fColorMap->index_map[(rgb >> 1) & 0x7fe0 | rgb & 0x1f]; -} - -// IndexForRGB16 -/*! \brief Returns the palette color index closest to a given RGB 16 color. - - The object must be properly initialized. - - \param red Red component of the color (R[4:0]). - \param green Green component of the color (G[5:0]). - \param blue Blue component of the color (B[4:0]). - \return The palette color index for the supplied color. -*/ -inline -uint8 -PaletteConverter::IndexForRGB16(uint8 red, uint8 green, uint8 blue) const -{ - // the 5 (for red, blue) / 6 (for green) least significant bits are used - return fColorMap->index_map[(red << 10) | ((green & 0x3e) << 4) | blue]; -} - -// IndexForRGB24 -/*! \brief Returns the palette color index closest to a given RGB 32 color. - - The object must be properly initialized. - - \param rgb The RGB 32 color value (R[31:24]G[23:16]B[15:8]). - \return The palette color index for the supplied color. -*/ -inline -uint8 -PaletteConverter::IndexForRGB24(uint32 rgb) const -{ - return fColorMap->index_map[((rgb & 0xf8000000) >> 17) - | ((rgb & 0xf80000) >> 14) - | ((rgb & 0xf800) >> 11)]; -} - -// IndexForRGB24 -/*! \brief Returns the palette color index closest to a given RGB 24 color. - - The object must be properly initialized. - - \param red Red component of the color. - \param green Green component of the color. - \param blue Blue component of the color. - \return The palette color index for the supplied color. -*/ -inline -uint8 -PaletteConverter::IndexForRGB24(uint8 red, uint8 green, uint8 blue) const -{ - return fColorMap->index_map[((red & 0xf8) << 7) - | ((green & 0xf8) << 2) - | (blue >> 3)]; -} - -// IndexForGray -/*! \brief Returns the palette color index closest to a given Gray 8 color. - - The object must be properly initialized. - - \param gray The Gray 8 color value. - \return The palette color index for the supplied color. -*/ -inline -uint8 -PaletteConverter::IndexForGray(uint8 gray) const -{ - return IndexForRGB24(gray, gray, gray); -} - -// RGBColorForIndex -/*! \brief Returns the RGB color for a given palette color index. - - The object must be properly initialized. - - \param index The palette color index. - \return The color for the supplied palette color index. -*/ -inline -const rgb_color & -PaletteConverter::RGBColorForIndex(uint8 index) const -{ - return fColorMap->color_list[index]; -} - -// RGB15ColorForIndex -/*! \brief Returns the RGB 15 color for a given palette color index. - - The object must be properly initialized. - - \param index The palette color index. - \return The color for the supplied palette color index - (R[14:10]G[9:5]B[4:0]). -*/ -inline -uint16 -PaletteConverter::RGB15ColorForIndex(uint8 index) const -{ - const rgb_color &color = fColorMap->color_list[index]; - return ((color.red & 0xf8) << 7) - | ((color.green & 0xf8) << 2) - | (color.blue >> 3); -} - -// RGB16ColorForIndex -/*! \brief Returns the RGB 16 color for a given palette color index. - - The object must be properly initialized. - - \param index The palette color index. - \return The color for the supplied palette color index - (R[15:11]G[10:5]B[4:0]). -*/ -inline -uint16 -PaletteConverter::RGB16ColorForIndex(uint8 index) const -{ - const rgb_color &color = fColorMap->color_list[index]; - return ((color.red & 0xf8) << 8) - | ((color.green & 0xfc) << 3) - | (color.blue >> 3); -} - -// RGB24ColorForIndex -/*! \brief Returns the RGB 24 color for a given palette color index. - - The object must be properly initialized. - - \param index The palette color index. - \return The color for the supplied palette color index - (R[31:24]G[23:16]B[15:8]). -*/ -inline -uint32 -PaletteConverter::RGB24ColorForIndex(uint8 index) const -{ - const rgb_color &color = fColorMap->color_list[index]; - return (color.blue << 24) | (color.red << 8) | (color.green << 16) | color.alpha; -} - -// RGB24ColorForIndex -/*! \brief Returns the RGB 24 color for a given palette color index. - - The object must be properly initialized. - - \param index The palette color index. - \param red Reference to the variable the red component shall be stored - into. - \param green Reference to the variable the green component shall be stored - into. - \param blue Reference to the variable the blue component shall be stored - into. -*/ -inline -void -PaletteConverter::RGB24ColorForIndex(uint8 index, uint8 &red, uint8 &green, - uint8 &blue, uint8 &alpha) const -{ - const rgb_color &color = fColorMap->color_list[index]; - red = color.red; - green = color.green; - blue = color.blue; - alpha = color.alpha; -} - -// GrayColorForIndex -/*! \brief Returns the Gray 8 color for a given palette color index. - - The object must be properly initialized. - - \param index The palette color index. - \return The color for the supplied palette color index. -*/ -inline -uint8 -PaletteConverter::GrayColorForIndex(uint8 index) const -{ - const rgb_color &color = fColorMap->color_list[index]; - return brightness_for(color.red, color.green, color.blue); -} - -// TODO: Remove these and palette_converter() when BScreen is available. -static BLocker gPaletteConverterLock("BBitmap_PalConvLock"); -static PaletteConverter gPaletteConverter; - -// palette_converter -/*! \brief Returns a PaletteConverter using the system color palette. - \return A PaletteConverter. -*/ -static -const PaletteConverter* -palette_converter() -{ - if (gPaletteConverterLock.Lock()) { - if (gPaletteConverter.InitCheck() != B_OK) - gPaletteConverter.SetTo(kSystemPalette); - gPaletteConverterLock.Unlock(); - } - return &gPaletteConverter; -} - - -// #pragma mark - - // constructor /*! \brief Creates and initializes a BBitmap. @@ -988,758 +418,6 @@ BBitmap::Bounds() const return fBounds; } -//////////////////////////////////////// -// structures defining the pixel layout - -struct rgb32_pixel { - uint8 blue; - uint8 green; - uint8 red; - uint8 alpha; -}; - -struct rgb32_big_pixel { - uint8 red; - uint8 green; - uint8 blue; - uint8 alpha; -}; - -struct rgb24_pixel { - uint8 blue; - uint8 green; - uint8 red; -}; - -struct rgb24_big_pixel { - uint8 red; - uint8 green; - uint8 blue; -}; - -struct rgb16_pixel { - uint8 gb; // G[2:0],B[4:0] - uint8 rg; // 16: R[4:0],G[5:3] - // 15: -[0],R[4:0],G[4:3] -}; - -struct rgb16_big_pixel { - uint8 rg; // 16: R[4:0],G[5:3] - // 15: -[0],R[4:0],G[4:3] - uint8 gb; // G[2:0],B[4:0] -}; - -//////////////////////////////////////////////////////// -// types defining what is needed to store a color value - -struct rgb_color_value { - uint8 red; - uint8 green; - uint8 blue; - uint8 alpha; -}; - -typedef uint8 gray_color_value; - -//////////////////////////////////////////////////////////////////// -// Reader classes being able to read pixels of certain color spaces - -// BaseReader -template -struct BaseReader { - typedef _PixelType pixel_t; - - BaseReader(const void *data) : pixels((const pixel_t*)data) {} - - inline void SetTo(const void *data) { pixels = (const pixel_t*)data; } - - inline void NextRow(int32 skip) - { - pixels = (const pixel_t*)((const char*)pixels + skip); - } - - const pixel_t *pixels; -}; - -// RGB24Reader -template -struct RGB24Reader : public BaseReader<_PixelType> { - typedef rgb_color_value preferred_color_value_t; - typedef _PixelType pixel_t; - - RGB24Reader(const void *data) : BaseReader<_PixelType>(data) {} - - inline void Read(rgb_color_value &color) - { - const pixel_t &pixel = *BaseReader<_PixelType>::pixels; - color.red = pixel.red; - color.green = pixel.green; - color.blue = pixel.blue; - BaseReader<_PixelType>::pixels++; - } - - inline void Read(gray_color_value &gray) - { - rgb_color_value color; - Read(color); - gray = brightness_for(color.red, color.green, color.blue); - } -}; - -// RGB16Reader -template -struct RGB16Reader : public BaseReader<_PixelType> { - typedef rgb_color_value preferred_color_value_t; - typedef _PixelType pixel_t; - - RGB16Reader(const void *data) : BaseReader<_PixelType>(data) {} - - inline void Read(rgb_color_value &color) - { - // rg: R[4:0],G[5:3] - // gb: G[2:0],B[4:0] - const pixel_t &pixel = *BaseReader<_PixelType>::pixels; - color.red = pixel.rg & 0xf8; - color.green = ((pixel.rg & 0x07) << 5) & ((pixel.gb & 0xe0) >> 3); - color.blue = (pixel.gb & 0x1f) << 3; - color.red |= color.red >> 5; - color.green |= color.green >> 6; - color.blue |= color.blue >> 5; - BaseReader<_PixelType>::pixels++; - } - - inline void Read(gray_color_value &gray) - { - rgb_color_value color; - Read(color); - gray = brightness_for(color.red, color.green, color.blue); - } -}; - -// RGB15Reader -template -struct RGB15Reader : public BaseReader<_PixelType> { - typedef rgb_color_value preferred_color_value_t; - typedef _PixelType pixel_t; - - RGB15Reader(const void *data) : BaseReader<_PixelType>(data) {} - - inline void Read(rgb_color_value &color) - { - // rg: -[0],R[4:0],G[4:3] - // gb: G[2:0],B[4:0] - const pixel_t &pixel = *BaseReader<_PixelType>::pixels; - color.red = (pixel.rg & 0x7c) << 1; - color.green = ((pixel.rg & 0x03) << 6) & ((pixel.gb & 0xe0) >> 2); - color.blue = (pixel.gb & 0x1f) << 3; - color.red |= color.red >> 5; - color.green |= color.green >> 5; - color.blue |= color.blue >> 5; - BaseReader<_PixelType>::pixels++; - } - - inline void Read(gray_color_value &gray) - { - rgb_color_value color; - Read(color); - gray = brightness_for(color.red, color.green, color.blue); - } -}; - -// CMAP8Reader -struct CMAP8Reader : public BaseReader { - typedef rgb_color_value preferred_color_value_t; - - CMAP8Reader(const void *data, const PaletteConverter &converter) - : BaseReader(data), converter(converter) {} - - inline void Read(rgb_color_value &color) - { - converter.RGB24ColorForIndex(*BaseReader::pixels, color.red, color.green, - color.blue, color.alpha); - BaseReader::pixels++; - } - - inline void Read(gray_color_value &gray) - { - gray = converter.GrayColorForIndex(*BaseReader::pixels); - BaseReader::pixels++; - } - - const PaletteConverter &converter; -}; - -// Gray8Reader -struct Gray8Reader : public BaseReader { - typedef gray_color_value preferred_color_value_t; - - Gray8Reader(const void *data) : BaseReader(data) {} - - inline void Read(rgb_color_value &color) - { - color.red = color.green = color.blue = *BaseReader::pixels; - BaseReader::pixels++; - } - - inline void Read(gray_color_value &gray) - { - gray = *BaseReader::pixels; - BaseReader::pixels++; - } -}; - -// Gray1Reader -struct Gray1Reader : public BaseReader { - typedef gray_color_value preferred_color_value_t; - - Gray1Reader(const void *data) : BaseReader(data), bit(7) {} - - inline void SetTo(const void *data) - { - pixels = (const pixel_t*)data; - bit = 7; - } - - inline void NextRow(int32 skip) - { - if (bit == 7) - pixels = (const pixel_t*)((const char*)pixels + skip); - else { - pixels = (const pixel_t*)((const char*)pixels + skip + 1); - bit = 7; - } - } - - inline void Read(rgb_color_value &color) - { - if (*pixels & bit_mask(bit)) - color.red = color.green = color.blue = 255; - else - color.red = color.green = color.blue = 0; - bit--; - if (bit == -1) { - pixels++; - bit = 7; - } - } - - inline void Read(gray_color_value &gray) - { - if (*pixels & bit_mask(bit)) - gray = 255; - else - gray = 0; - bit--; - if (bit == -1) { - pixels++; - bit = 7; - } - } - - int32 bit; -}; - - -//////////////////////////////////////////////////////////////////// -// Writer classes being able to write pixels of certain color spaces - -// BaseWriter -template -struct BaseWriter { - typedef _PixelType pixel_t; - - BaseWriter(void *data) : pixels((pixel_t*)data) {} - - inline void SetTo(void *data) { pixels = (pixel_t*)data; } - - pixel_t *pixels; -}; - - -// RGB32Writer -template -struct RGB32Writer : public BaseWriter<_PixelType> { - typedef rgb_color_value preferred_color_value_t; - typedef _PixelType pixel_t; - - RGB32Writer(void *data) : BaseWriter<_PixelType>(data) {} - - inline void Write(const rgb_color_value &color) - { - pixel_t &pixel = *BaseWriter<_PixelType>::pixels; - pixel.red = color.red; - pixel.green = color.green; - pixel.blue = color.blue; - pixel.alpha = color.alpha; - BaseWriter<_PixelType>::pixels++; - } - - inline void Write(const gray_color_value &gray) - { - pixel_t &pixel = *BaseWriter<_PixelType>::pixels; - pixel.red = gray; - pixel.green = gray; - pixel.blue = gray; - pixel.alpha = 255; - BaseWriter<_PixelType>::pixels++; - } -}; - -// RGB24Writer -template -struct RGB24Writer : public BaseWriter<_PixelType> { - typedef rgb_color_value preferred_color_value_t; - typedef _PixelType pixel_t; - - RGB24Writer(void *data) : BaseWriter<_PixelType>(data) {} - - inline void Write(const rgb_color_value &color) - { - pixel_t &pixel = *BaseWriter<_PixelType>::pixels; - pixel.red = color.red; - pixel.green = color.green; - pixel.blue = color.blue; - BaseWriter<_PixelType>::pixels++; - } - - inline void Write(const gray_color_value &gray) - { - pixel_t &pixel = *BaseWriter<_PixelType>::pixels; - pixel.red = gray; - pixel.green = gray; - pixel.blue = gray; - BaseWriter<_PixelType>::pixels++; - } -}; - -// RGB16Writer -template -struct RGB16Writer : public BaseWriter<_PixelType> { - typedef rgb_color_value preferred_color_value_t; - typedef _PixelType pixel_t; - - RGB16Writer(void *data) : BaseWriter<_PixelType>(data) {} - - inline void Write(const rgb_color_value &color) - { - // rg: R[4:0],G[5:3] - // gb: G[2:0],B[4:0] - pixel_t &pixel = *BaseWriter<_PixelType>::pixels; - pixel.rg = (color.red & 0xf8) | (color.green >> 5); - pixel.gb = ((color.green & 0x1c) << 3) | (color.blue >> 3); - BaseWriter<_PixelType>::pixels++; - } - - inline void Write(const gray_color_value &gray) - { - pixel_t &pixel = *BaseWriter<_PixelType>::pixels; - pixel.rg = (gray & 0xf8) | (gray >> 5); - pixel.gb = ((gray & 0x1c) << 3) | (gray >> 3); - BaseWriter<_PixelType>::pixels++; - } -}; - -// RGB15Writer -template -struct RGB15Writer : public BaseWriter<_PixelType> { - typedef rgb_color_value preferred_color_value_t; - typedef _PixelType pixel_t; - - RGB15Writer(void *data) : BaseWriter<_PixelType>(data) {} - - inline void Write(const rgb_color_value &color) - { - // rg: -[0],R[4:0],G[4:3] - // gb: G[2:0],B[4:0] - pixel_t &pixel = *BaseWriter<_PixelType>::pixels; - pixel.rg = ((color.red & 0xf8) >> 1) | (color.green >> 6); - pixel.gb = ((color.green & 0x38) << 2) | (color.blue >> 3); - BaseWriter<_PixelType>::pixels++; - } - - inline void Write(const gray_color_value &gray) - { - pixel_t &pixel = *BaseWriter<_PixelType>::pixels; - pixel.rg = ((gray & 0xf8) >> 1) | (gray >> 6); - pixel.gb = ((gray & 0x38) << 2) | (gray >> 3); - BaseWriter<_PixelType>::pixels++; - } -}; - -// CMAP8Writer -struct CMAP8Writer : public BaseWriter { - typedef rgb_color_value preferred_color_value_t; - - CMAP8Writer(void *data, const PaletteConverter &converter) - : BaseWriter(data), converter(converter) {} - - inline void Write(const rgb_color_value &color) - { - *pixels = converter.IndexForRGB24(color.red, color.green, color.blue); - pixels++; - } - - inline void Write(const gray_color_value &gray) - { - *pixels = converter.IndexForGray(gray); - pixels++; - } - - const PaletteConverter &converter; -}; - -// Gray8Writer -struct Gray8Writer : public BaseWriter { - typedef gray_color_value preferred_color_value_t; - - Gray8Writer(void *data) : BaseWriter(data) {} - - inline void Write(const rgb_color_value &color) - { - *pixels = brightness_for(color.red, color.green, color.blue); - pixels++; - } - - inline void Write(const gray_color_value &gray) - { - *pixels = gray; - pixels++; - } -}; - -// Gray1Writer -struct Gray1Writer : public BaseWriter { - typedef gray_color_value preferred_color_value_t; - - Gray1Writer(void *data) : BaseWriter(data), bit(7) {} - - inline void SetTo(void *data) { pixels = (pixel_t*)data; bit = 7; } - - inline void Write(const gray_color_value &gray) - { - *pixels = (*pixels & inverse_bit_mask(bit)) - | (gray & 0x80) >> (7 - bit); - bit--; - if (bit == -1) { - pixels++; - bit = 7; - } - } - - inline void Write(const rgb_color_value &color) - { - Write(brightness_for(color.red, color.green, color.blue)); - } - - int32 bit; -}; - - -// set_bits_worker -/*! \brief Worker function that reads bitmap data from one buffer and writes - it (converted) to another one. - \param Reader The pixel reader class. - \param Writer The pixel writer class. - \param color_value_t The color value type used to transport a pixel from - the reader to the writer. - \param inData A pointer to the buffer to be read. - \param inLength The length (in bytes) of the "in" buffer. - \param inBPR The number of bytes per row in the "in" buffer. - \param inRowSkip The number of bytes per row in the "in" buffer serving as - padding. - \param outData A pointer to the buffer to be written to. - \param outLength The length (in bytes) of the "out" buffer. - \param outOffset The offset (in bytes) relative to \a outData from which - the function shall start writing. - \param outBPR The number of bytes per row in the "out" buffer. - \param rawOutBPR The number of bytes per row in the "out" buffer actually - containing bitmap data (i.e. not including the padding). - \param _reader A reader object. The pointer to the data doesn't need to - be initialized. - \param _writer A writer object. The pointer to the data doesn't need to - be initialized. - \return \c B_OK, if everything went fine, an error code otherwise. -*/ -template -static -status_t -set_bits_worker(const void *inData, int32 inLength, int32 inBPR, - int32 inRowSkip, void *outData, int32 outLength, - int32 outOffset, int32 outBPR, int32 rawOutBPR, - Reader _reader, Writer _writer) -{ - status_t error = B_OK; - Reader reader(_reader); - Writer writer(_writer); - reader.SetTo(inData); - writer.SetTo((char*)outData + outOffset); - const char *inEnd = (const char*)inData + inLength - - sizeof(typename Reader::pixel_t); - const char *inLastRow = (const char*)inData + inLength - - (inBPR - inRowSkip); - const char *outEnd = (const char*)outData + outLength - - sizeof(typename Writer::pixel_t); - char *outRow = (char*)outData + outOffset - outOffset % outBPR; - const char *outRowEnd = outRow + rawOutBPR - sizeof(typename Writer::pixel_t); - while ((const char*)reader.pixels <= inEnd - && (const char*)writer.pixels <= outEnd) { - // process one row - if ((const char*)reader.pixels <= inLastRow) { - // at least a complete row left - while ((const char*)writer.pixels <= outRowEnd) { - color_value_t color; - reader.Read(color); - writer.Write(color); - } - } else { - // no complete row left - // but maybe the complete end of the first row - while ((const char*)reader.pixels <= inEnd - && (const char*)writer.pixels <= outRowEnd) { - color_value_t color; - reader.Read(color); - writer.Write(color); - } - } - // must be here, not in the if-branch (end of first row) - outRow += outBPR; - outRowEnd += outBPR; - reader.NextRow(inRowSkip); - writer.SetTo(outRow); - } - return error; -} - -// set_bits_worker_gray1 -/*! \brief Worker function that reads bitmap data from one buffer and writes - it (converted) to another one, which uses color space \c B_GRAY1. - \param Reader The pixel reader class. - \param Writer The pixel writer class. - \param color_value_t The color value type used to transport a pixel from - the reader to the writer. - \param inData A pointer to the buffer to be read. - \param inLength The length (in bytes) of the "in" buffer. - \param inBPR The number of bytes per row in the "in" buffer. - \param inRowSkip The number of bytes per row in the "in" buffer serving as - padding. - \param outData A pointer to the buffer to be written to. - \param outLength The length (in bytes) of the "out" buffer. - \param outOffset The offset (in bytes) relative to \a outData from which - the function shall start writing. - \param outBPR The number of bytes per row in the "out" buffer. - \param width The number of pixels per row in "in" and "out" data. - \param _reader A reader object. The pointer to the data doesn't need to - be initialized. - \param _writer A writer object. The pointer to the data doesn't need to - be initialized. - \return \c B_OK, if everything went fine, an error code otherwise. -*/ -template -static -status_t -set_bits_worker_gray1(const void *inData, int32 inLength, int32 inBPR, - int32 inRowSkip, void *outData, int32 outLength, - int32 outOffset, int32 outBPR, int32 width, - Reader _reader, Writer _writer) -{ - status_t error = B_OK; - Reader reader(_reader); - Writer writer(_writer); - reader.SetTo(inData); - writer.SetTo((char*)outData + outOffset); - const char *inEnd = (const char*)inData + inLength - - sizeof(typename Reader::pixel_t); - const char *inLastRow = (const char*)inData + inLength - - (inBPR - inRowSkip); - const char *outEnd = (const char*)outData + outLength - outBPR; - char *outRow = (char*)outData + outOffset - outOffset % outBPR; - int32 x = max(0L, width - ((char*)outData + outOffset - outRow) * 8) - 1; - while ((const char*)reader.pixels <= inEnd - && (const char*)writer.pixels <= outEnd) { - // process one row - if ((const char*)reader.pixels <= inLastRow) { - // at least a complete row left - while (x >= 0) { - color_value_t color; - reader.Read(color); - writer.Write(color); - x--; - } - } else { - // no complete row left - // but maybe the complete end of the first row - while ((const char*)reader.pixels <= inEnd && x >= 0) { - color_value_t color; - reader.Read(color); - writer.Write(color); - x--; - } - } - // must be here, not in the if-branch (end of first row) - x = width - 1; - outRow += outBPR; - reader.NextRow(inRowSkip); - writer.SetTo(outRow); - } - return error; -} - -// set_bits -/*! \brief Helper function that reads bitmap data from one buffer and writes - it (converted) to another one. - \param Reader The pixel reader class. - \param inData A pointer to the buffer to be read. - \param inLength The length (in bytes) of the "in" buffer. - \param inBPR The number of bytes per row in the "in" buffer. - \param inRowSkip The number of bytes per row in the "in" buffer serving as - padding. - \param outData A pointer to the buffer to be written to. - \param outLength The length (in bytes) of the "out" buffer. - \param outOffset The offset (in bytes) relative to \a outData from which - the function shall start writing. - \param outBPR The number of bytes per row in the "out" buffer. - \param rawOutBPR The number of bytes per row in the "out" buffer actually - containing bitmap data (i.e. not including the padding). - \param outColorSpace Color space of the target buffer. - \param width The number of pixels per row in "in" and "out" data. - \param reader A reader object. The pointer to the data doesn't need to - be initialized. - \param paletteConverter Reference to a PaletteConverter to be used, if - a conversion from or to \c B_CMAP8 has to be done. - \return \c B_OK, if everything went fine, an error code otherwise. -*/ -template -static -status_t -set_bits(const void *inData, int32 inLength, int32 inBPR, int32 inRowSkip, - void *outData, int32 outLength, int32 outOffset, int32 outBPR, - int32 rawOutBPR, color_space outColorSpace, int32 width, - Reader reader, const PaletteConverter &paletteConverter) -{ - status_t error = B_OK; - switch (outColorSpace) { - // supported - case B_RGB32: case B_RGBA32: - { - typedef RGB32Writer Writer; - typedef typename Reader::preferred_color_value_t color_value_t; - error = set_bits_worker( - inData, inLength, inBPR, inRowSkip, outData, outLength, - outOffset, outBPR, rawOutBPR, reader, Writer(outData)); - break; - } - case B_RGB32_BIG: case B_RGBA32_BIG: - { - typedef RGB32Writer Writer; - typedef typename Reader::preferred_color_value_t color_value_t; - error = set_bits_worker( - inData, inLength, inBPR, inRowSkip, outData, outLength, - outOffset, outBPR, rawOutBPR, reader, Writer(outData)); - break; - } - case B_RGB24: - { - typedef RGB24Writer Writer; - typedef typename Reader::preferred_color_value_t color_value_t; - error = set_bits_worker( - inData, inLength, inBPR, inRowSkip, outData, outLength, - outOffset, outBPR, rawOutBPR, reader, Writer(outData)); - break; - } - case B_RGB24_BIG: - { - typedef RGB24Writer Writer; - typedef typename Reader::preferred_color_value_t color_value_t; - error = set_bits_worker( - inData, inLength, inBPR, inRowSkip, outData, outLength, - outOffset, outBPR, rawOutBPR, reader, Writer(outData)); - break; - } - case B_RGB16: - { - typedef RGB16Writer Writer; - typedef typename Reader::preferred_color_value_t color_value_t; - error = set_bits_worker( - inData, inLength, inBPR, inRowSkip, outData, outLength, - outOffset, outBPR, rawOutBPR, reader, Writer(outData)); - break; - } - case B_RGB16_BIG: - { - typedef RGB16Writer Writer; - typedef typename Reader::preferred_color_value_t color_value_t; - error = set_bits_worker( - inData, inLength, inBPR, inRowSkip, outData, outLength, - outOffset, outBPR, rawOutBPR, reader, Writer(outData)); - break; - } - case B_RGB15: case B_RGBA15: - { - typedef RGB15Writer Writer; - typedef typename Reader::preferred_color_value_t color_value_t; - error = set_bits_worker( - inData, inLength, inBPR, inRowSkip, outData, outLength, - outOffset, outBPR, rawOutBPR, reader, Writer(outData)); - break; - } - case B_RGB15_BIG: case B_RGBA15_BIG: - { - typedef RGB15Writer Writer; - typedef typename Reader::preferred_color_value_t color_value_t; - error = set_bits_worker( - inData, inLength, inBPR, inRowSkip, outData, outLength, - outOffset, outBPR, rawOutBPR, reader, Writer(outData)); - break; - } - case B_CMAP8: - { - typedef CMAP8Writer Writer; - typedef typename Reader::preferred_color_value_t color_value_t; - error = set_bits_worker( - inData, inLength, inBPR, inRowSkip, outData, outLength, - outOffset, outBPR, rawOutBPR, reader, - Writer(outData, paletteConverter)); - break; - } - case B_GRAY8: - { - typedef Gray8Writer Writer; - typedef gray_color_value color_value_t; - error = set_bits_worker( - inData, inLength, inBPR, inRowSkip, outData, outLength, - outOffset, outBPR, rawOutBPR, reader, Writer(outData)); - break; - } - case B_GRAY1: - { - typedef Gray1Writer Writer; - typedef gray_color_value color_value_t; - error = set_bits_worker_gray1( - inData, inLength, inBPR, inRowSkip, outData, outLength, - outOffset, outBPR, width, reader, Writer(outData)); - break; - } - // unsupported - case B_NO_COLOR_SPACE: - case B_YUV9: case B_YUV12: - case B_UVL32: case B_UVLA32: - case B_LAB32: case B_LABA32: - case B_HSI32: case B_HSIA32: - case B_HSV32: case B_HSVA32: - case B_HLS32: case B_HLSA32: - case B_CMY32: case B_CMYA32: case B_CMYK32: - case B_UVL24: case B_LAB24: case B_HSI24: - case B_HSV24: case B_HLS24: case B_CMY24: - case B_YCbCr422: case B_YUV422: - case B_YCbCr411: case B_YUV411: - case B_YCbCr444: case B_YUV444: - case B_YCbCr420: case B_YUV420: - default: - error = B_BAD_VALUE; - break; - } - return error; -} // SetBits /*! \brief Assigns data to the bitmap. @@ -1821,154 +499,35 @@ BBitmap::SetBits(const void *data, int32 length, int32 offset, */ status_t BBitmap::ImportBits(const void *data, int32 length, int32 bpr, int32 offset, - color_space colorSpace) + color_space colorSpace) { AssertPtr(); - status_t error = (InitCheck() == B_OK ? B_OK : B_NO_INIT); - // check params - if (error == B_OK && (data == NULL || offset > fSize || length < 0)) - error = B_BAD_VALUE; - // get BPR - int32 width = 0; - int32 inRowSkip = 0; - if (error == B_OK) { - width = fBounds.IntegerWidth() + 1; - if (bpr < 0) - bpr = get_bytes_per_row(colorSpace, width); - inRowSkip = bpr - get_raw_bytes_per_row(colorSpace, width); - if (inRowSkip < 0) - error = B_BAD_VALUE; - } - if (error != B_OK) { - // catch error case - } else if (colorSpace == fColorSpace && bpr == fBytesPerRow) { + if (InitCheck() != B_OK) + return B_NO_INIT; + + if (!data || offset > fSize || length < 0) + return B_BAD_VALUE; + + if (colorSpace == fColorSpace && bpr == fBytesPerRow) { length = min(length, fSize - offset); - memcpy((char*)fBasePtr + offset, data, length); - } else { - // TODO: Retrieve color map from BScreen, when available: - // PaletteConverter paletteConverter(BScreen().ColorMap()); - const PaletteConverter &paletteConverter = *palette_converter(); - int32 rawOutBPR = get_raw_bytes_per_row(fColorSpace, width); - switch (colorSpace) { - // supported - case B_RGB32: case B_RGBA32: - { - typedef RGB24Reader Reader; - error = set_bits(data, length, bpr, inRowSkip, - fBasePtr, fSize, offset, fBytesPerRow, rawOutBPR, - fColorSpace, width, Reader(data), paletteConverter); - break; - } - case B_RGB32_BIG: case B_RGBA32_BIG: - { - typedef RGB24Reader Reader; - error = set_bits(data, length, bpr, inRowSkip, - fBasePtr, fSize, offset, fBytesPerRow, rawOutBPR, - fColorSpace, width, Reader(data), paletteConverter); - break; - } - case B_RGB24: - { - typedef RGB24Reader Reader; - error = set_bits(data, length, bpr, inRowSkip, - fBasePtr, fSize, offset, fBytesPerRow, rawOutBPR, - fColorSpace, width, Reader(data), paletteConverter); - break; - } - case B_RGB24_BIG: - { - typedef RGB24Reader Reader; - error = set_bits(data, length, bpr, inRowSkip, - fBasePtr, fSize, offset, fBytesPerRow, rawOutBPR, - fColorSpace, width, Reader(data), paletteConverter); - break; - } - case B_RGB16: - { - typedef RGB16Reader Reader; - error = set_bits(data, length, bpr, inRowSkip, - fBasePtr, fSize, offset, fBytesPerRow, rawOutBPR, - fColorSpace, width, Reader(data), paletteConverter); - break; - } - case B_RGB16_BIG: - { - typedef RGB16Reader Reader; - error = set_bits(data, length, bpr, inRowSkip, - fBasePtr, fSize, offset, fBytesPerRow, rawOutBPR, - fColorSpace, width, Reader(data), paletteConverter); - break; - } - case B_RGB15: case B_RGBA15: - { - typedef RGB15Reader Reader; - error = set_bits(data, length, bpr, inRowSkip, - fBasePtr, fSize, offset, fBytesPerRow, rawOutBPR, - fColorSpace, width, Reader(data), paletteConverter); - break; - } - case B_RGB15_BIG: case B_RGBA15_BIG: - { - typedef RGB15Reader Reader; - error = set_bits(data, length, bpr, inRowSkip, - fBasePtr, fSize, offset, fBytesPerRow, rawOutBPR, - fColorSpace, width, Reader(data), paletteConverter); - break; - } - case B_CMAP8: - { - typedef CMAP8Reader Reader; - error = set_bits(data, length, bpr, inRowSkip, - fBasePtr, fSize, offset, fBytesPerRow, rawOutBPR, - fColorSpace, width, Reader(data, paletteConverter), - paletteConverter); - break; - } - case B_GRAY8: - { - typedef Gray8Reader Reader; - error = set_bits(data, length, bpr, inRowSkip, - fBasePtr, fSize, offset, fBytesPerRow, rawOutBPR, - fColorSpace, width, Reader(data), paletteConverter); - break; - } - case B_GRAY1: - { - typedef Gray1Reader Reader; - error = set_bits(data, length, bpr, inRowSkip, - fBasePtr, fSize, offset, fBytesPerRow, rawOutBPR, - fColorSpace, width, Reader(data), paletteConverter); - break; - } - // unsupported - case B_NO_COLOR_SPACE: - case B_YUV9: case B_YUV12: - case B_UVL32: case B_UVLA32: - case B_LAB32: case B_LABA32: - case B_HSI32: case B_HSIA32: - case B_HSV32: case B_HSVA32: - case B_HLS32: case B_HLSA32: - case B_CMY32: case B_CMYA32: case B_CMYK32: - case B_UVL24: case B_LAB24: case B_HSI24: - case B_HSV24: case B_HLS24: case B_CMY24: - case B_YCbCr422: case B_YUV422: - case B_YCbCr411: case B_YUV411: - case B_YCbCr444: case B_YUV444: - case B_YCbCr420: case B_YUV420: - default: - error = B_BAD_VALUE; - break; - } + memcpy((char *)fBasePtr + offset, data, length); + return B_OK; } - return error; + + int32 width = fBounds.IntegerWidth() + 1; + if (bpr < 0) + bpr = get_bytes_per_row(colorSpace, width); + + return BPrivate::ConvertBits(data, fBasePtr, bpr, fBytesPerRow, + colorSpace, fColorSpace, width, fBounds.IntegerHeight() + 1); } // ImportBits /*! \briefly Assigns another bitmap's data to this bitmap. The supplied bitmap must have the exactly same dimensions as this bitmap. - Its data are converted to the color space of this bitmap. + Its data is converted to the color space of this bitmap. The currently supported source/target color spaces are \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. @@ -1982,20 +541,14 @@ BBitmap::ImportBits(const void *data, int32 length, int32 bpr, int32 offset, status_t BBitmap::ImportBits(const BBitmap *bitmap) { - status_t error = (InitCheck() == B_OK ? B_OK : B_NO_INIT); - // check param - if (error == B_OK && bitmap == NULL) - error = B_BAD_VALUE; - if (error == B_OK && bitmap->InitCheck() != B_OK) - error = B_BAD_VALUE; - if (error == B_OK && bitmap->Bounds() != fBounds) - error = B_BAD_VALUE; - // set bits - if (error == B_OK) { - error = ImportBits(bitmap->Bits(), bitmap->BitsLength(), - bitmap->BytesPerRow(), 0, bitmap->ColorSpace()); - } - return error; + if (InitCheck() != B_OK) + return B_NO_INIT; + + if (!bitmap || bitmap->InitCheck() != B_OK || bitmap->Bounds() != fBounds) + return B_BAD_VALUE; + + return ImportBits(bitmap->Bits(), bitmap->BitsLength(), + bitmap->BytesPerRow(), 0, bitmap->ColorSpace()); } diff --git a/src/kits/interface/ColorConversion.cpp b/src/kits/interface/ColorConversion.cpp new file mode 100644 index 0000000000..a8e276743b --- /dev/null +++ b/src/kits/interface/ColorConversion.cpp @@ -0,0 +1,924 @@ +/* + * Copyright 2001-2006, Haiku Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold (bonefish@users.sf.net) + * Michael Lotz + */ + +/** This file contains colorspace conversion functions + * and a palette <-> true color conversion class. + */ + +#include "ColorConversion.h" +#include +#include + +namespace BPrivate { + +// TODO: system palette -- hard-coded for now, when the app server is ready +// we should use system_colors() or BScreen::ColorMap(). +const rgb_color kSystemPalette[] = { + { 0, 0, 0, 255 }, { 8, 8, 8, 255 }, { 16, 16, 16, 255 }, + { 24, 24, 24, 255 }, { 32, 32, 32, 255 }, { 40, 40, 40, 255 }, + { 48, 48, 48, 255 }, { 56, 56, 56, 255 }, { 64, 64, 64, 255 }, + { 72, 72, 72, 255 }, { 80, 80, 80, 255 }, { 88, 88, 88, 255 }, + { 96, 96, 96, 255 }, { 104, 104, 104, 255 }, { 112, 112, 112, 255 }, + { 120, 120, 120, 255 }, { 128, 128, 128, 255 }, { 136, 136, 136, 255 }, + { 144, 144, 144, 255 }, { 152, 152, 152, 255 }, { 160, 160, 160, 255 }, + { 168, 168, 168, 255 }, { 176, 176, 176, 255 }, { 184, 184, 184, 255 }, + { 192, 192, 192, 255 }, { 200, 200, 200, 255 }, { 208, 208, 208, 255 }, + { 216, 216, 216, 255 }, { 224, 224, 224, 255 }, { 232, 232, 232, 255 }, + { 240, 240, 240, 255 }, { 248, 248, 248, 255 }, { 0, 0, 255, 255 }, + { 0, 0, 229, 255 }, { 0, 0, 204, 255 }, { 0, 0, 179, 255 }, + { 0, 0, 154, 255 }, { 0, 0, 129, 255 }, { 0, 0, 105, 255 }, + { 0, 0, 80, 255 }, { 0, 0, 55, 255 }, { 0, 0, 30, 255 }, + { 255, 0, 0, 255 }, { 228, 0, 0, 255 }, { 203, 0, 0, 255 }, + { 178, 0, 0, 255 }, { 153, 0, 0, 255 }, { 128, 0, 0, 255 }, + { 105, 0, 0, 255 }, { 80, 0, 0, 255 }, { 55, 0, 0, 255 }, + { 30, 0, 0, 255 }, { 0, 255, 0, 255 }, { 0, 228, 0, 255 }, + { 0, 203, 0, 255 }, { 0, 178, 0, 255 }, { 0, 153, 0, 255 }, + { 0, 128, 0, 255 }, { 0, 105, 0, 255 }, { 0, 80, 0, 255 }, + { 0, 55, 0, 255 }, { 0, 30, 0, 255 }, { 0, 152, 51, 255 }, + { 255, 255, 255, 255 }, { 203, 255, 255, 255 }, { 203, 255, 203, 255 }, + { 203, 255, 152, 255 }, { 203, 255, 102, 255 }, { 203, 255, 51, 255 }, + { 203, 255, 0, 255 }, { 152, 255, 255, 255 }, { 152, 255, 203, 255 }, + { 152, 255, 152, 255 }, { 152, 255, 102, 255 }, { 152, 255, 51, 255 }, + { 152, 255, 0, 255 }, { 102, 255, 255, 255 }, { 102, 255, 203, 255 }, + { 102, 255, 152, 255 }, { 102, 255, 102, 255 }, { 102, 255, 51, 255 }, + { 102, 255, 0, 255 }, { 51, 255, 255, 255 }, { 51, 255, 203, 255 }, + { 51, 255, 152, 255 }, { 51, 255, 102, 255 }, { 51, 255, 51, 255 }, + { 51, 255, 0, 255 }, { 255, 152, 255, 255 }, { 255, 152, 203, 255 }, + { 255, 152, 152, 255 }, { 255, 152, 102, 255 }, { 255, 152, 51, 255 }, + { 255, 152, 0, 255 }, { 0, 102, 255, 255 }, { 0, 102, 203, 255 }, + { 203, 203, 255, 255 }, { 203, 203, 203, 255 }, { 203, 203, 152, 255 }, + { 203, 203, 102, 255 }, { 203, 203, 51, 255 }, { 203, 203, 0, 255 }, + { 152, 203, 255, 255 }, { 152, 203, 203, 255 }, { 152, 203, 152, 255 }, + { 152, 203, 102, 255 }, { 152, 203, 51, 255 }, { 152, 203, 0, 255 }, + { 102, 203, 255, 255 }, { 102, 203, 203, 255 }, { 102, 203, 152, 255 }, + { 102, 203, 102, 255 }, { 102, 203, 51, 255 }, { 102, 203, 0, 255 }, + { 51, 203, 255, 255 }, { 51, 203, 203, 255 }, { 51, 203, 152, 255 }, + { 51, 203, 102, 255 }, { 51, 203, 51, 255 }, { 51, 203, 0, 255 }, + { 255, 102, 255, 255 }, { 255, 102, 203, 255 }, { 255, 102, 152, 255 }, + { 255, 102, 102, 255 }, { 255, 102, 51, 255 }, { 255, 102, 0, 255 }, + { 0, 102, 152, 255 }, { 0, 102, 102, 255 }, { 203, 152, 255, 255 }, + { 203, 152, 203, 255 }, { 203, 152, 152, 255 }, { 203, 152, 102, 255 }, + { 203, 152, 51, 255 }, { 203, 152, 0, 255 }, { 152, 152, 255, 255 }, + { 152, 152, 203, 255 }, { 152, 152, 152, 255 }, { 152, 152, 102, 255 }, + { 152, 152, 51, 255 }, { 152, 152, 0, 255 }, { 102, 152, 255, 255 }, + { 102, 152, 203, 255 }, { 102, 152, 152, 255 }, { 102, 152, 102, 255 }, + { 102, 152, 51, 255 }, { 102, 152, 0, 255 }, { 51, 152, 255, 255 }, + { 51, 152, 203, 255 }, { 51, 152, 152, 255 }, { 51, 152, 102, 255 }, + { 51, 152, 51, 255 }, { 51, 152, 0, 255 }, { 230, 134, 0, 255 }, + { 255, 51, 203, 255 }, { 255, 51, 152, 255 }, { 255, 51, 102, 255 }, + { 255, 51, 51, 255 }, { 255, 51, 0, 255 }, { 0, 102, 51, 255 }, + { 0, 102, 0, 255 }, { 203, 102, 255, 255 }, { 203, 102, 203, 255 }, + { 203, 102, 152, 255 }, { 203, 102, 102, 255 }, { 203, 102, 51, 255 }, + { 203, 102, 0, 255 }, { 152, 102, 255, 255 }, { 152, 102, 203, 255 }, + { 152, 102, 152, 255 }, { 152, 102, 102, 255 }, { 152, 102, 51, 255 }, + { 152, 102, 0, 255 }, { 102, 102, 255, 255 }, { 102, 102, 203, 255 }, + { 102, 102, 152, 255 }, { 102, 102, 102, 255 }, { 102, 102, 51, 255 }, + { 102, 102, 0, 255 }, { 51, 102, 255, 255 }, { 51, 102, 203, 255 }, + { 51, 102, 152, 255 }, { 51, 102, 102, 255 }, { 51, 102, 51, 255 }, + { 51, 102, 0, 255 }, { 255, 0, 255, 255 }, { 255, 0, 203, 255 }, + { 255, 0, 152, 255 }, { 255, 0, 102, 255 }, { 255, 0, 51, 255 }, + { 255, 175, 19, 255 }, { 0, 51, 255, 255 }, { 0, 51, 203, 255 }, + { 203, 51, 255, 255 }, { 203, 51, 203, 255 }, { 203, 51, 152, 255 }, + { 203, 51, 102, 255 }, { 203, 51, 51, 255 }, { 203, 51, 0, 255 }, + { 152, 51, 255, 255 }, { 152, 51, 203, 255 }, { 152, 51, 152, 255 }, + { 152, 51, 102, 255 }, { 152, 51, 51, 255 }, { 152, 51, 0, 255 }, + { 102, 51, 255, 255 }, { 102, 51, 203, 255 }, { 102, 51, 152, 255 }, + { 102, 51, 102, 255 }, { 102, 51, 51, 255 }, { 102, 51, 0, 255 }, + { 51, 51, 255, 255 }, { 51, 51, 203, 255 }, { 51, 51, 152, 255 }, + { 51, 51, 102, 255 }, { 51, 51, 51, 255 }, { 51, 51, 0, 255 }, + { 255, 203, 102, 255 }, { 255, 203, 152, 255 }, { 255, 203, 203, 255 }, + { 255, 203, 255, 255 }, { 0, 51, 152, 255 }, { 0, 51, 102, 255 }, + { 0, 51, 51, 255 }, { 0, 51, 0, 255 }, { 203, 0, 255, 255 }, + { 203, 0, 203, 255 }, { 203, 0, 152, 255 }, { 203, 0, 102, 255 }, + { 203, 0, 51, 255 }, { 255, 227, 70, 255 }, { 152, 0, 255, 255 }, + { 152, 0, 203, 255 }, { 152, 0, 152, 255 }, { 152, 0, 102, 255 }, + { 152, 0, 51, 255 }, { 152, 0, 0, 255 }, { 102, 0, 255, 255 }, + { 102, 0, 203, 255 }, { 102, 0, 152, 255 }, { 102, 0, 102, 255 }, + { 102, 0, 51, 255 }, { 102, 0, 0, 255 }, { 51, 0, 255, 255 }, + { 51, 0, 203, 255 }, { 51, 0, 152, 255 }, { 51, 0, 102, 255 }, + { 51, 0, 51, 255 }, { 51, 0, 0, 255 }, { 255, 203, 51, 255 }, + { 255, 203, 0, 255 }, { 255, 255, 0, 255 }, { 255, 255, 51, 255 }, + { 255, 255, 102, 255 }, { 255, 255, 152, 255 }, { 255, 255, 203, 255 }, + { 255, 255, 255, 0 } // B_TRANSPARENT_MAGIC_CMAP8 +}; + + +/*! \brief Returns the brightness of an RGB 24 color. + \param red Value of the red component. + \param green Value of the green component. + \param blue Value of the blue component. + \return The brightness for the supplied RGB color as a value between 0 + and 255. +*/ +static inline +uint8 +brightness_for(uint8 red, uint8 green, uint8 blue) +{ + // brightness = 0.301 * red + 0.586 * green + 0.113 * blue + // we use for performance reasons: + // brightness = (308 * red + 600 * green + 116 * blue) / 1024 + return uint8((308 * red + 600 * green + 116 * blue) / 1024); +} + + +/*! \brief Returns the "distance" between two RGB colors. + + This functions defines an metric on the RGB color space. The distance + between two colors is 0, if and only if the colors are equal. + + \param red1 Red component of the first color. + \param green1 Green component of the first color. + \param blue1 Blue component of the first color. + \param red2 Red component of the second color. + \param green2 Green component of the second color. + \param blue2 Blue component of the second color. + \return The distance between the given colors. +*/ +static inline +unsigned +color_distance(uint8 red1, uint8 green1, uint8 blue1, + uint8 red2, uint8 green2, uint8 blue2) +{ + // euklidian distance (its square actually) + int rd = (int)red1 - (int)red2; + int gd = (int)green1 - (int)green2; + int bd = (int)blue1 - (int)blue2; + //return rd * rd + gd * gd + bd * bd; + + // distance according to psycho-visual tests + int rmean = ((int)red1 + (int)red2) / 2; + return (((512 + rmean) * rd * rd) >> 8) + + 4 * gd * gd + + (((767 - rmean) * bd * bd) >> 8); +} + + +/*! \brief Creates an uninitialized PaletteConverter. +*/ +PaletteConverter::PaletteConverter() + : fColorMap(NULL), + fOwnColorMap(NULL), + fCStatus(B_NO_INIT) +{ +} + + +/*! \brief Creates a PaletteConverter and initializes it to the supplied + palette. + \param palette The palette being a 256 entry rgb_color array. +*/ +PaletteConverter::PaletteConverter(const rgb_color *palette) + : fColorMap(NULL), + fOwnColorMap(NULL), + fCStatus(B_NO_INIT) +{ + SetTo(palette); +} + + +/*! \brief Creates a PaletteConverter and initializes it to the supplied + color map. + \param colorMap The completely initialized color map. +*/ +PaletteConverter::PaletteConverter(const color_map *colorMap) + : fColorMap(NULL), + fOwnColorMap(NULL), + fCStatus(B_NO_INIT) +{ + SetTo(colorMap); +} + + +/*! \brief Frees all resources associated with this object. +*/ +PaletteConverter::~PaletteConverter() +{ + delete fOwnColorMap; +} + + +/*! \brief Initializes the converter to the supplied palette. + \param palette The palette being a 256 entry rgb_color array. + \return \c B_OK, if everything went fine, an error code otherwise. +*/ +status_t +PaletteConverter::SetTo(const rgb_color *palette) +{ + // cleanup + SetTo((const color_map*)NULL); + status_t error = (palette ? B_OK : B_BAD_VALUE); + // alloc color map + if (error == B_OK) { + fOwnColorMap = new(nothrow) color_map; + if (fOwnColorMap == NULL) + error = B_NO_MEMORY; + } + // init color map + if (error == B_OK) { + fColorMap = fOwnColorMap; + // init color list + memcpy(fOwnColorMap->color_list, palette, sizeof(rgb_color) * 256); + // init index map +// TODO: build this list takes about 2 seconds in qemu on my system +// (because of color_distance()) + for (int32 color = 0; color < 32768; color++) { + // get components + uint8 red = (color & 0x7c00) >> 7; + uint8 green = (color & 0x3e0) >> 2; + uint8 blue = (color & 0x1f) << 3; + red |= red >> 5; + green |= green >> 5; + blue |= blue >> 5; + // find closest color + uint8 closestIndex = 0; + unsigned closestDistance = UINT_MAX; + for (int32 i = 0; i < 256; i++) { + const rgb_color &c = fOwnColorMap->color_list[i]; + unsigned distance = color_distance(red, green, blue, + c.red, c.green, c.blue); + if (distance < closestDistance) { + closestIndex = i; + closestDistance = distance; + } + } + fOwnColorMap->index_map[color] = closestIndex; + } + // no need to init inversion map + } + fCStatus = error; + return error; +} + + +/*! \brief Initializes the converter to the supplied color map. + \param colorMap The completely initialized color map. + \return \c B_OK, if everything went fine, an error code otherwise. +*/ +status_t +PaletteConverter::SetTo(const color_map *colorMap) +{ + // cleanup + if (fOwnColorMap) { + delete fOwnColorMap; + fOwnColorMap = NULL; + } + // set + fColorMap = colorMap; + fCStatus = (fColorMap ? B_OK : B_BAD_VALUE); + return fCStatus; +} + + +/*! \brief Returns the result of the last initialization via constructor or + SetTo(). + \return \c B_OK, if the converter is properly initialized, an error code + otherwise. +*/ +status_t +PaletteConverter::InitCheck() const +{ + return fCStatus; +} + + +/*! \brief Returns the palette color index closest to a given RGB 15 color. + + The object must be properly initialized. + + \param rgb The RGB 15 color value (R[14:10]G[9:5]B[4:0]). + \return The palette color index for the supplied color. +*/ +inline +uint8 +PaletteConverter::IndexForRGB15(uint16 rgb) const +{ + return fColorMap->index_map[rgb]; +} + + +/*! \brief Returns the palette color index closest to a given RGB 15 color. + + The object must be properly initialized. + + \param red Red component of the color (R[4:0]). + \param green Green component of the color (G[4:0]). + \param blue Blue component of the color (B[4:0]). + \return The palette color index for the supplied color. +*/ +inline +uint8 +PaletteConverter::IndexForRGB15(uint8 red, uint8 green, uint8 blue) const +{ + // the 5 least significant bits are used + return fColorMap->index_map[(red << 10) | (green << 5) | blue]; +} + + +/*! \brief Returns the palette color index closest to a given RGB 16 color. + + The object must be properly initialized. + + \param rgb The RGB 16 color value (R[15:11]G[10:5]B[4:0]). + \return The palette color index for the supplied color. +*/ +inline +uint8 +PaletteConverter::IndexForRGB16(uint16 rgb) const +{ + return fColorMap->index_map[(rgb >> 1) & 0x7fe0 | rgb & 0x1f]; +} + + +/*! \brief Returns the palette color index closest to a given RGB 16 color. + + The object must be properly initialized. + + \param red Red component of the color (R[4:0]). + \param green Green component of the color (G[5:0]). + \param blue Blue component of the color (B[4:0]). + \return The palette color index for the supplied color. +*/ +inline +uint8 +PaletteConverter::IndexForRGB16(uint8 red, uint8 green, uint8 blue) const +{ + // the 5 (for red, blue) / 6 (for green) least significant bits are used + return fColorMap->index_map[(red << 10) | ((green & 0x3e) << 4) | blue]; +} + + +/*! \brief Returns the palette color index closest to a given RGB 32 color. + + The object must be properly initialized. + + \param rgb The RGB 32 color value (R[31:24]G[23:16]B[15:8]). + \return The palette color index for the supplied color. +*/ +inline +uint8 +PaletteConverter::IndexForRGB24(uint32 rgb) const +{ + return fColorMap->index_map[((rgb & 0xf8000000) >> 17) + | ((rgb & 0xf80000) >> 14) + | ((rgb & 0xf800) >> 11)]; +} + + +/*! \brief Returns the palette color index closest to a given RGB 24 color. + + The object must be properly initialized. + + \param red Red component of the color. + \param green Green component of the color. + \param blue Blue component of the color. + \return The palette color index for the supplied color. +*/ +inline +uint8 +PaletteConverter::IndexForRGB24(uint8 red, uint8 green, uint8 blue) const +{ + return fColorMap->index_map[((red & 0xf8) << 7) + | ((green & 0xf8) << 2) + | (blue >> 3)]; +} + + +/*! \brief Returns the palette color index closest to a given Gray 8 color. + + The object must be properly initialized. + + \param gray The Gray 8 color value. + \return The palette color index for the supplied color. +*/ +inline +uint8 +PaletteConverter::IndexForGray(uint8 gray) const +{ + return IndexForRGB24(gray, gray, gray); +} + + +/*! \brief Returns the RGB color for a given palette color index. + + The object must be properly initialized. + + \param index The palette color index. + \return The color for the supplied palette color index. +*/ +inline +const rgb_color & +PaletteConverter::RGBColorForIndex(uint8 index) const +{ + return fColorMap->color_list[index]; +} + + +/*! \brief Returns the RGB 15 color for a given palette color index. + + The object must be properly initialized. + + \param index The palette color index. + \return The color for the supplied palette color index + (R[14:10]G[9:5]B[4:0]). +*/ +inline +uint16 +PaletteConverter::RGB15ColorForIndex(uint8 index) const +{ + const rgb_color &color = fColorMap->color_list[index]; + return ((color.red & 0xf8) << 7) + | ((color.green & 0xf8) << 2) + | (color.blue >> 3); +} + + +/*! \brief Returns the RGB 16 color for a given palette color index. + + The object must be properly initialized. + + \param index The palette color index. + \return The color for the supplied palette color index + (R[15:11]G[10:5]B[4:0]). +*/ +inline +uint16 +PaletteConverter::RGB16ColorForIndex(uint8 index) const +{ + const rgb_color &color = fColorMap->color_list[index]; + return ((color.red & 0xf8) << 8) + | ((color.green & 0xfc) << 3) + | (color.blue >> 3); +} + + +/*! \brief Returns the RGBA 32 color for a given palette color index. + + The object must be properly initialized. + + \param index The palette color index. + \return The color for the supplied palette color index + (A[31:24]B[23:16]G[15:8]R[7:0]). +*/ +inline +uint32 +PaletteConverter::RGBA32ColorForIndex(uint8 index) const +{ + const rgb_color &color = fColorMap->color_list[index]; + return (color.red << 16) | (color.green << 8) | color.blue + | (color.alpha << 24); +} + + +/*! \brief Returns the RGBA 32 color for a given palette color index. + + The object must be properly initialized. + + \param index The palette color index. + \param red Reference to the variable the red component shall be stored + into. + \param green Reference to the variable the green component shall be stored + into. + \param blue Reference to the variable the blue component shall be stored + into. + \param alpha Reference to the variable the alpha component shall be stored + into. +*/ +inline +void +PaletteConverter::RGBA32ColorForIndex(uint8 index, uint8 &red, uint8 &green, + uint8 &blue, uint8 &alpha) const +{ + const rgb_color &color = fColorMap->color_list[index]; + red = color.red; + green = color.green; + blue = color.blue; + alpha = color.alpha; +} + + +/*! \brief Returns the Gray 8 color for a given palette color index. + + The object must be properly initialized. + + \param index The palette color index. + \return The color for the supplied palette color index. +*/ +inline +uint8 +PaletteConverter::GrayColorForIndex(uint8 index) const +{ + const rgb_color &color = fColorMap->color_list[index]; + return brightness_for(color.red, color.green, color.blue); +} + + +// TODO: Remove these and palette_converter() when BScreen is available. +static BLocker gPaletteConverterLock("PalConvLock"); +static PaletteConverter gPaletteConverter; + + +/*! \brief Returns a PaletteConverter using the system color palette. + \return A PaletteConverter. +*/ +static +const PaletteConverter* +palette_converter() +{ + if (gPaletteConverterLock.Lock()) { + if (gPaletteConverter.InitCheck() != B_OK) + gPaletteConverter.SetTo(kSystemPalette); + gPaletteConverterLock.Unlock(); + } + return &gPaletteConverter; +} + + +typedef uint32 (readFunc)(const uint8 **source, int32 index); +typedef void (writeFunc)(uint8 **dest, uint8 *data, int32 index); + + +void +WriteRGB24(uint8 **dest, uint8 *data, int32 index) +{ + (*dest)[0] = data[0]; + (*dest)[1] = data[1]; + (*dest)[2] = data[2]; + *dest += 3; +} + + +uint32 +ReadRGB24(const uint8 **source, int32 index) +{ + uint32 result = (*source)[0] | ((*source)[1] << 8) | ((*source)[2] << 16); + *source += 3; + return result; +} + + +void +WriteGray8(uint8 **dest, uint8 *data, int32 index) +{ + **dest = data[2] * 308 + data[1] * 600 + data[0] * 116 >> 10; + // this would boost the speed but is less accurate: + //*dest = (data[2] << 8) + (data[1] << 9) + (data[0] << 8) >> 10; + (*dest)++; +} + + +uint32 +ReadGray8(const uint8 **source, int32 index) +{ + uint32 result = **source; + (*source)++; + return result; +} + + +void +WriteGray1(uint8 **dest, uint8 *data, int32 index) +{ + int32 shift = 7 - (index % 8); + **dest &= ~(0x01 << shift); + **dest |= (data[2] * 308 + data[1] * 600 + data[0] * 116) >> (17 - shift); + if (shift == 0) + (*dest)++; +} + + +uint32 +ReadGray1(const uint8 **source, int32 index) +{ + int32 shift = 7 - (index % 8); + uint32 result = ((**source >> shift) & 0x01) ? 0xff : 0x00; + if (shift == 0) + (*source)++; + return result; +} + + +void +WriteCMAP8(uint8 **dest, uint8 *data, int32 index) +{ + **dest = gPaletteConverter.IndexForRGB15(*(uint16 *)data); + (*dest)++; +} + + +uint32 +ReadCMAP8(const uint8 **source, int32 index) +{ + uint32 result = gPaletteConverter.RGBA32ColorForIndex(**source); + (*source)++; + return result; +} + + +template +void +ConvertBits(const srcByte *srcBuffer, dstByte *dstBuffer, int32 redShift, + int32 greenShift, int32 blueShift, int32 alphaShift, int32 alphaBits, + uint32 redMask, uint32 greenMask, uint32 blueMask, uint32 alphaMask, + int32 srcBytesPerRow, int32 dstBytesPerRow, int32 srcBitsPerPixel, + int32 dstBitsPerPixel, int32 width, int32 height, bool srcSwap, + bool dstSwap, readFunc *srcFunc, writeFunc *dstFunc) +{ + int32 srcLinePad = ((srcBytesPerRow << 3) - width * srcBitsPerPixel) >> 3; + int32 dstLinePad = ((dstBytesPerRow << 3) - width * dstBitsPerPixel) >> 3; + + register uint32 result; + register uint32 source; + for (int32 i = 0; i < height; i++) { + for (int32 j = 0; j < width; j++) { + if (srcFunc) + source = srcFunc((const uint8 **)&srcBuffer, j); + else { + source = *srcBuffer; + srcBuffer++; + } + + if (srcSwap) + source = (source << 8) | (source >> 8); + + if (redShift > 0) + result = ((source >> redShift) & redMask); + else + result = ((source << -redShift) & redMask); + + if (greenShift > 0) + result |= ((source >> greenShift) & greenMask); + else + result |= ((source << -greenShift) & greenMask); + + if (blueShift > 0) + result |= ((source >> blueShift) & blueMask); + else + result |= ((source << -blueShift) & blueMask); + + if (alphaBits > 0) { + if (alphaShift > 0) + result |= ((source >> alphaShift) & alphaMask); + else + result |= ((source << -alphaShift) & alphaMask); + + // if we only had one alpha bit we want it to be 0/255 + if (alphaBits == 1 && result & alphaMask) + result |= alphaMask; + } else + result |= alphaMask; + + if (dstSwap) + *dstBuffer = (result << 8) | (result >> 8); + + if (dstFunc) + dstFunc((uint8 **)&dstBuffer, (uint8 *)&result, j); + else { + *dstBuffer = result; + dstBuffer++; + } + } + + (char *)srcBuffer += srcLinePad; + (char *)dstBuffer += dstLinePad; + } +} + + +template +status_t +ConvertBits(const srcByte *srcBuffer, void *dstBuffer, int32 redShift, + int32 greenShift, int32 blueShift, int32 alphaShift, int32 alphaBits, + int32 srcBytesPerRow, int32 dstBytesPerRow, int32 srcBitsPerPixel, + color_space dstColorSpace, int32 width, int32 height, bool srcSwap, + readFunc *srcFunc) +{ + switch (dstColorSpace) { + case B_RGBA32: + ConvertBits(srcBuffer, (uint32 *)dstBuffer, redShift - 24, + greenShift - 16, blueShift - 8, alphaShift - 32, alphaBits, + 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, srcBytesPerRow, + dstBytesPerRow, srcBitsPerPixel, 32, width, height, srcSwap, + false, srcFunc, NULL); + break; + + case B_RGBA32_BIG: + ConvertBits(srcBuffer, (uint32 *)dstBuffer, redShift - 16, + greenShift - 24, blueShift - 32, alphaShift - 8, alphaBits, + 0x0000ff00, 0x00ff0000, 0xff000000, 0x00000ff, srcBytesPerRow, + dstBytesPerRow, srcBitsPerPixel, 32, width, height, srcSwap, + false, srcFunc, NULL); + break; + + /* Note: we set the unused alpha to 255 here. This is because BeOS + uses the unused alpha for B_OP_ALPHA even though it should + not care about it. */ + case B_RGB32: + ConvertBits(srcBuffer, (uint32 *)dstBuffer, redShift - 24, + greenShift - 16, blueShift - 8, 0, 0, 0x00ff0000, 0x0000ff00, + 0x000000ff, 0xff000000, srcBytesPerRow, dstBytesPerRow, + srcBitsPerPixel, 32, width, height, srcSwap, false, srcFunc, + NULL); + break; + + case B_RGB32_BIG: + ConvertBits(srcBuffer, (uint32 *)dstBuffer, redShift - 16, + greenShift - 24, blueShift - 32, 0, 0, 0x0000ff00, 0x00ff0000, + 0xff000000, 0x000000ff, srcBytesPerRow, dstBytesPerRow, + srcBitsPerPixel, 32, width, height, srcSwap, false, srcFunc, + NULL); + break; + + case B_RGB24: + ConvertBits(srcBuffer, (uint8 *)dstBuffer, redShift - 24, + greenShift - 16, blueShift - 8, 0, 0, 0xff0000, 0x00ff00, + 0x0000ff, 0x000000, srcBytesPerRow, dstBytesPerRow, + srcBitsPerPixel, 24, width, height, srcSwap, false, srcFunc, + WriteRGB24); + break; + + case B_RGB24_BIG: + ConvertBits(srcBuffer, (uint8 *)dstBuffer, redShift - 8, + greenShift - 16, blueShift - 24, 0, 0, 0x0000ff, 0x00ff00, + 0xff0000, 0x000000, srcBytesPerRow, dstBytesPerRow, + srcBitsPerPixel, 24, width, height, srcSwap, false, srcFunc, + WriteRGB24); + break; + + case B_RGB16: + case B_RGB16_BIG: + ConvertBits(srcBuffer, (uint16 *)dstBuffer, redShift - 16, + greenShift - 11, blueShift - 5, 0, 0, 0xf800, 0x07e0, 0x001f, + 0x0000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 16, + width, height, srcSwap, dstColorSpace == B_RGB16_BIG, srcFunc, + NULL); + break; + + case B_RGBA15: + case B_RGBA15_BIG: + ConvertBits(srcBuffer, (uint16 *)dstBuffer, redShift - 15, + greenShift - 10, blueShift - 5, alphaShift - 16, alphaBits, + 0x7c00, 0x03e0, 0x001f, 0x8000, srcBytesPerRow, dstBytesPerRow, + srcBitsPerPixel, 16, width, height, srcSwap, + dstColorSpace == B_RGBA15_BIG, srcFunc, NULL); + break; + + case B_RGB15: + case B_RGB15_BIG: + ConvertBits(srcBuffer, (uint16 *)dstBuffer, redShift - 15, + greenShift - 10, blueShift - 5, 0, 0, 0x7c00, 0x03e0, 0x001f, + 0x0000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 16, + width, height, srcSwap, dstColorSpace == B_RGB15_BIG, srcFunc, + NULL); + break; + + case B_GRAY8: + ConvertBits(srcBuffer, (uint8 *)dstBuffer, redShift - 24, + greenShift - 16, blueShift - 8, 0, 0, 0x00ff0000, 0x0000ff00, + 0x000000ff, 0x00000000, srcBytesPerRow, dstBytesPerRow, + srcBitsPerPixel, 8, width, height, srcSwap, false, srcFunc, + WriteGray8); + break; + + case B_GRAY1: + ConvertBits(srcBuffer, (uint8 *)dstBuffer, redShift - 24, + greenShift - 16, blueShift - 8, 0, 0, 0x00ff0000, 0x0000ff00, + 0x000000ff, 0x00000000, srcBytesPerRow, dstBytesPerRow, + srcBitsPerPixel, 1, width, height, srcSwap, false, srcFunc, + WriteGray1); + break; + + case B_CMAP8: + palette_converter(); + ConvertBits(srcBuffer, (uint8 *)dstBuffer, redShift - 15, + greenShift - 10, blueShift - 5, 0, 0, 0x7c00, 0x03e0, 0x001f, + 0x0000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 8, + width, height, srcSwap, false, srcFunc, WriteCMAP8); + break; + + default: + return B_BAD_VALUE; + break; + } + + return B_OK; +} + + +/*! \brief Converts a source buffer in one colorspace into a destination + buffer of another colorspace. + + \param srcBuffer The raw source buffer. + \param dstBuffer The raw destination buffer. + \param srcBytesPerRow How many bytes per row the source buffer has got. + \param dstBytesPerRow How many bytes per row the destination buffer has got. + \param srcColorSpace The colorspace the source buffer is in. + \param dstColorSpace The colorspace the buffer shall be converted to. + \param width The width (in pixels) of each row. + \param height The height (in pixels) of the buffers. + \return + - \c B_OK: Indicates success. + - \c B_BAD_VALUE: \c NULL buffer or at least one colorspace is unsupported. +*/ +status_t +ConvertBits(const void *srcBuffer, void *dstBuffer, uint32 srcBytesPerRow, + uint32 dstBytesPerRow, color_space srcColorSpace, + color_space dstColorSpace, int32 width, int32 height) +{ + if (!srcBuffer || !dstBuffer) + return B_BAD_VALUE; + + if (srcColorSpace == dstColorSpace && srcBytesPerRow == dstBytesPerRow) { + memcpy(dstBuffer, srcBuffer, height * srcBytesPerRow); + return B_OK; + } + + switch (srcColorSpace) { + case B_RGBA32: + return ConvertBits((const uint32 *)srcBuffer, dstBuffer, 24, 16, + 8, 32, 8, srcBytesPerRow, dstBytesPerRow, 32, dstColorSpace, + width, height, false, NULL); + break; + + case B_RGBA32_BIG: + return ConvertBits((const uint32 *)srcBuffer, dstBuffer, 16, 24, + 32, 8, 8, srcBytesPerRow, dstBytesPerRow, 32, dstColorSpace, + width, height, false, NULL); + break; + + case B_RGB32: + return ConvertBits((const uint32 *)srcBuffer, dstBuffer, 24, 16, + 8, 0, 0, srcBytesPerRow, dstBytesPerRow, 32, dstColorSpace, + width, height, false, NULL); + break; + + case B_RGB32_BIG: + return ConvertBits((const uint32 *)srcBuffer, dstBuffer, 16, 24, + 32, 0, 0, srcBytesPerRow, dstBytesPerRow, 32, dstColorSpace, + width, height, false, NULL); + break; + + case B_RGB24: + return ConvertBits((const uint8 *)srcBuffer, dstBuffer, 24, 16, 8, + 0, 0, srcBytesPerRow, dstBytesPerRow, 24, dstColorSpace, + width, height, false, ReadRGB24); + break; + + case B_RGB24_BIG: + return ConvertBits((const uint8 *)srcBuffer, dstBuffer, 8, 16, 24, + 0, 0, srcBytesPerRow, dstBytesPerRow, 24, dstColorSpace, + width, height, false, ReadRGB24); + break; + + case B_RGB16: + case B_RGB16_BIG: + return ConvertBits((const uint16 *)srcBuffer, dstBuffer, 16, 11, 5, + 0, 0, srcBytesPerRow, dstBytesPerRow, 16, dstColorSpace, width, + height, srcColorSpace == B_RGB16_BIG, NULL); + break; + + case B_RGBA15: + case B_RGBA15_BIG: + return ConvertBits((const uint16 *)srcBuffer, dstBuffer, 15, 10, 5, + 16, 1, srcBytesPerRow, dstBytesPerRow, 16, dstColorSpace, + width, height, srcColorSpace == B_RGBA15_BIG, NULL); + break; + + case B_RGB15: + case B_RGB15_BIG: + return ConvertBits((const uint16 *)srcBuffer, dstBuffer, 15, 10, 5, + 0, 0, srcBytesPerRow, dstBytesPerRow, 16, dstColorSpace, width, + height, srcColorSpace == B_RGB15_BIG, NULL); + break; + + case B_GRAY8: + return ConvertBits((const uint8 *)srcBuffer, dstBuffer, 8, 8, 8, 0, + 0, srcBytesPerRow, dstBytesPerRow, 8, dstColorSpace, width, + height, false, ReadGray8); + break; + + case B_GRAY1: + return ConvertBits((const uint8 *)srcBuffer, dstBuffer, 8, 8, 8, 0, + 0, srcBytesPerRow, dstBytesPerRow, 1, dstColorSpace, width, + height, false, ReadGray1); + break; + + case B_CMAP8: + palette_converter(); + return ConvertBits((const uint8 *)srcBuffer, dstBuffer, 24, 16, 8, + 32, 8, srcBytesPerRow, dstBytesPerRow, 8, dstColorSpace, width, + height, false, ReadCMAP8); + break; + + default: + return B_BAD_VALUE; + break; + } +} + +} // namespace BPrivate diff --git a/src/kits/interface/Jamfile b/src/kits/interface/Jamfile index 2fd5eb3d02..fbafc77c3f 100644 --- a/src/kits/interface/Jamfile +++ b/src/kits/interface/Jamfile @@ -38,8 +38,9 @@ MergeObject interface_kit.o : ChannelControl.cpp ChannelSlider.cpp CheckBox.cpp - ColorUtils.cc + ColorConversion.cpp ColorControl.cpp + ColorUtils.cc Control.cpp Deskbar.cpp Dragger.cpp