/*! * \brief Turn a bitmap in grayscale * * The output bitmap will be of the same size and will use the same color space * of the original. Currently supports the following color spaces: B_CMAP8, * B_RGB24, B_RGB24_BIG, B_RGB32, B_BRGBA32, B_RGB32_BIG, B_RGBA32_BIG; * transparency is maintained. With all other color spaces, the function will * return a copy of the bitmap (note that B_GRAY8 and B_GRAY1 are already * grayscale). * * \todo Support more color spaces * * @param[in] bitmap The bitmap you want to turn in grayscale * * \return If bitmap is \c NULL or isn't valid, returns \c NULL, or a new * bitmap. It's up to you to delete the bitmap when you are done with * it. */ BBitmap * BitmapUtils::Grayscale(BBitmap *bitmap) { if (bitmap == NULL) return NULL; if (!bitmap->IsValid()) return NULL; // To obtain the disabled bitmap, we turn the original bitmap in // grayscale, converting each pixel from RGB to YCbCr and taking only // the Y component (luminance). int32 x, y, width, height, offset, row_length; unsigned char *i_bits, *o_bits; BBitmap *ret; uint8 Yc; ret = new BBitmap(bitmap->Bounds(), bitmap->ColorSpace()); i_bits = (unsigned char*)bitmap->Bits(); o_bits = (unsigned char*)ret->Bits(); height = bitmap->Bounds().IntegerHeight() + 1; width = bitmap->Bounds().IntegerWidth() + 1; row_length = bitmap->BytesPerRow(); switch (bitmap->ColorSpace()) { // B_CMAP8: each pixel (one byte) is the index of a color in the // system's color table. The table can be obtained from a BScreen // object. case B_CMAP8: { const rgb_color *color; const color_map *map; BScreen screen; map = screen.ColorMap(); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { offset = y * row_length + x; if (i_bits[offset] == B_TRANSPARENT_8_BIT) o_bits[offset] = B_TRANSPARENT_8_BIT; else { color = map->color_list + i_bits[offset]; Yc = __Yc(color->red, color->green, color->blue); o_bits[offset] = screen.IndexForColor(Yc, Yc, Yc); } } } } break; // B_RGB24 = BGR 8:8:8 case B_RGB24: for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { offset = y * row_length + x * 3; Yc = __Yc(i_bits[offset + 2], i_bits[offset + 1], i_bits[offset]); o_bits[offset + 1] = Yc; o_bits[offset + 2] = Yc; o_bits[offset + 3] = Yc; } } break; // B_RGB32 = BGRA 8:8:8:8 // B_RGBA32 = BGRx 8:8:8:8 case B_RGB32: case B_RGBA32: for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { offset = y * row_length + x * 4; Yc = __Yc(i_bits[offset + 2], i_bits[offset + 1], i_bits[offset]); o_bits[offset] = Yc; o_bits[offset + 1] = Yc; o_bits[offset + 2] = Yc; o_bits[offset + 3] = i_bits[offset]; } } break; // B_RGB24_BIG = RGB 8:8:8 case B_RGB24_BIG: for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { offset = y * row_length + x * 3; Yc = __Yc(i_bits[offset], i_bits[offset + 1], i_bits[offset + 2]); o_bits[offset + 1] = Yc; o_bits[offset + 2] = Yc; o_bits[offset + 3] = Yc; } } break; // B_RGB32_BIG = xRGB 8:8:8:8 // B_RGBA32_BIG = ARGB 8:8:8:8 case B_RGB32_BIG: case B_RGBA32_BIG: for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { offset = y * row_length + x * 4; Yc = __Yc(i_bits[offset + 1], i_bits[offset + 2], i_bits[offset + 3]); o_bits[offset] = i_bits[offset]; o_bits[offset + 1] = Yc; o_bits[offset + 2] = Yc; o_bits[offset + 3] = Yc; } } break; default: memcpy(ret->Bits(), bitmap->Bits(), bitmap->BitsLength()); break; } return ret; }