通过您提供的代码片段,我可以意识到您应该解决的几个警告:
首先,作为red
一个严格小于 7 的整数,red = ((red/7) * 31)
将始终导致 0,这是因为这样编写,您指示编译器执行整数除法,然后执行整数乘法,即忽略小数部分。
现在关于您在第 68 行提供的示例,我相信color = (0xFFFF & (((red << 11) & RED_5_6_5) & ((green << 5) & GRN_5_6_5) & (blue & BLU_5_6_5)));
也将始终导致 0,即假设RED_5_6_5 & GRN_5_6_5 & BLU_5_6_5 = 0 = 0
应该如此。我相信你的意思是color = (0xFFFF & (((red << 11) & RED_5_6_5) | ((green << 5) & GRN_5_6_5) | (blue & BLU_5_6_5)));
这里。
此外,您将unsigned short
其用作“std::uint16_t”unsigned int
的同义词,同样用作“std::uint32_t”的同义词,不需要在每个平台上保存,甚至不需要在同一平台上的不同编译器版本之间保存,所以我会强烈建议使用上述固定大小的整数,可以在 .
通过您在整个代码中大量使用常量,以及大量的代码重复,我可以预见,几乎可以肯定,您很快就会遇到很多困难来维护您的代码甚至让它工作。也就是说,我希望这听起来不是我的傲慢,但我冒昧地向您提出了一种处理这些像素抽象的全新方法,除了解决您来这里寻求建议的具体问题。
在下面的代码片段中,我重写了用于处理 RGB 像素的 api,通过使用元编程将代码重复保持在我认为的最低限度。例如,您会意识到我不必专门处理该类template<...> struct Pixel
来处理像素格式和深度的每种可能组合,因为我将血淋淋的细节留在了一个帮助类template<...> struct pixel_tools
中,该类适用于给定像素格式的任何可能的深度,从而减少代码的复制。
我不会假装我的解决方案在这种情况下是最好的,事实上我很确定它不是,但我相信它在代码维护方面比你的解决方案有所改进。从现在开始,如果你决定采纳我的任何建议,我相信将这个想法扩展到你正在使用的其他像素抽象上是很简单的。
注意:这个代码片段很可能包含错误,请原谅,但我没有时间彻底检查它。
#include <cstddef>
#include <cstdint>
#include <iostream>
template <std::size_t bit_depth>
struct underlying_type;
template <>
struct underlying_type<8U>
{
typedef std::uint8_t type;
};
template <>
struct underlying_type<16U>
{
typedef std::uint16_t type;
};
template <>
struct underlying_type<32U>
{
typedef std::uint32_t type;
};
enum class COLOR
{
RED = 0,
GREEN = 1,
BLUE = 2,
ALPHA = 3
};
enum class PIXEL_FORMAT : char
{
PALETTE,
RGB,
RGBA
};
template<PIXEL_FORMAT fmt>
struct pixel_tools;
template<>
struct pixel_tools<PIXEL_FORMAT::RGB>
{
//this metafunction avoids the use of #defines, which do get nasty quickly and should be avoided at all costs
//luckly c++ has strong metaprogramming idioms and boost is your best friend
//the third argument is necessary because total template specialization is not allowed inside templated structures
template <COLOR color, std::size_t bit_depth, typename _ = void>
struct color_mask;
template <typename _>
struct color_mask<COLOR::RED, 8U, _>
{
static typename underlying_type<8U>::type const value = 0xE0;
};
template <typename _>
struct color_mask<COLOR::GREEN, 8U, _>
{
static typename underlying_type<8U>::type const value = 0x1C;
};
template <typename _>
struct color_mask<COLOR::BLUE, 8U, _>
{
static typename underlying_type<8U>::type const value = 0x03;
};
template <typename _>
struct color_mask<COLOR::RED, 16U, _>
{
static typename underlying_type<16U>::type const value = 0xF800;
};
template <typename _>
struct color_mask<COLOR::GREEN, 16U, _>
{
static typename underlying_type<16U>::type const value = 0x07E0;
};
template <typename _>
struct color_mask<COLOR::BLUE, 16U, _>
{
static typename underlying_type<16U>::type const value = 0x001F;
};
template <typename _>
struct color_mask<COLOR::RED, 32U, _>
{
static typename underlying_type<32U>::type const value = 0xFFC00000;
};
template <typename _>
struct color_mask<COLOR::GREEN, 32U, _>
{
static typename underlying_type<32U>::type const value = 0x003FF000;
};
template <typename _>
struct color_mask<COLOR::BLUE, 32U, _>
{
static typename underlying_type<32U>::type const value = 0x00000FFC;
};
//the third argument is necessary because total template specialization is not allowed inside templated structures
template <COLOR color, std::size_t bit_depth, typename _ = void>
struct color_offset_mask;
template <typename _>
struct color_offset_mask<COLOR::RED, 8U, _>
{
static typename underlying_type<8U>::type const value = 0x05;
};
template <typename _>
struct color_offset_mask<COLOR::GREEN, 8U, _>
{
static typename underlying_type<8U>::type const value = 0x02;
};
template <typename _>
struct color_offset_mask<COLOR::BLUE, 8U, _>
{
static typename underlying_type<8U>::type const value = 0x00;
};
template <typename _>
struct color_offset_mask<COLOR::RED, 16U, _>
{
static typename underlying_type<16U>::type const value = 0x000B;
};
template <typename _>
struct color_offset_mask<COLOR::GREEN, 16U, _>
{
static typename underlying_type<16U>::type const value = 0x0005;
};
template <typename _>
struct color_offset_mask<COLOR::BLUE, 16U, _>
{
static typename underlying_type<16U>::type const value = 0x0000;
};
template <typename _>
struct color_offset_mask<COLOR::RED, 32U, _>
{
static typename underlying_type<32U>::type const value = 0x00000016;
};
template <typename _>
struct color_offset_mask<COLOR::GREEN, 32U, _>
{
static typename underlying_type<32U>::type const value = 0x0000000C;
};
template <typename _>
struct color_offset_mask<COLOR::BLUE, 32U, _>
{
static typename underlying_type<32U>::type const value = 0x00000002;
};
template <COLOR color, std::size_t from, std::size_t to>
struct depth_conversion_factor
{
static constexpr double const value =
double(color_mask<color, to>::value >> color_offset_mask<color, to>::value)/
double(color_mask<color, from>::value >> color_offset_mask<color, from>::value);
};
template <COLOR color, std::size_t bit_depth>
static typename underlying_type<bit_depth>::type get_color(typename underlying_type<bit_depth>::type pixel)
{
return (color_mask<color, bit_depth>::value & pixel) >> color_offset_mask<color, bit_depth>::value;
}
template <COLOR color, std::size_t bit_depth>
static void set_color(typename underlying_type<bit_depth>::type& pixel, typename underlying_type<bit_depth>::type clr)
{
//erase current color
pixel &= ~color_mask<color, bit_depth>::value;
//set new value
pixel |= (clr << color_offset_mask<color, bit_depth>::value) & color_mask<color, bit_depth>::value;
}
template <std::size_t from, std::size_t to>
static typename underlying_type<to>::type convert_depth(typename underlying_type<from>::type pixel)
{
typename underlying_type<to>::type const converted_red = double(get_color<COLOR::RED, from>(pixel))*depth_conversion_factor<COLOR::RED, from, to>::value;
typename underlying_type<to>::type const converted_green = double(get_color<COLOR::GREEN, from>(pixel))*depth_conversion_factor<COLOR::GREEN, from, to>::value;
typename underlying_type<to>::type const converted_blue = double(get_color<COLOR::BLUE, from>(pixel))*depth_conversion_factor<COLOR::BLUE, from, to>::value;
typename underlying_type<to>::type converted_pixel(0);
set_color<COLOR::RED, to>(converted_pixel, converted_red);
set_color<COLOR::GREEN, to>(converted_pixel, converted_green);
set_color<COLOR::BLUE, to>(converted_pixel, converted_blue);
return converted_pixel;
}
template <std::size_t bit_depth>
static typename underlying_type<bit_depth>::type convert_depth(typename underlying_type<bit_depth>::type pixel)
{
return pixel;
}
};
template<std::size_t bit_depth, PIXEL_FORMAT fmt>
struct Pixel
{
typename underlying_type<bit_depth>::type color;
Pixel(typename underlying_type<bit_depth>::type red, typename underlying_type<bit_depth>::type green, typename underlying_type<bit_depth>::type blue)
: color(0)
{
pixel_tools<fmt>::template set_color<COLOR::RED, bit_depth>(this->color, red);
pixel_tools<fmt>::template set_color<COLOR::BLUE, bit_depth>(this->color, blue);
pixel_tools<fmt>::template set_color<COLOR::GREEN, bit_depth>(this->color, green);
}
Pixel(typename underlying_type<bit_depth>::type clr)
{
//always a good idea to guarantee a valid value
pixel_tools<fmt>::template set_color<COLOR::RED, bit_depth>(this->color, pixel_tools<fmt>::template get_color<COLOR::RED, bit_depth>(clr));
pixel_tools<fmt>::template set_color<COLOR::BLUE, bit_depth>(this->color, pixel_tools<fmt>::template get_color<COLOR::BLUE, bit_depth>(clr));
pixel_tools<fmt>::template set_color<COLOR::GREEN, bit_depth>(this->color, pixel_tools<fmt>::template get_color<COLOR::GREEN, bit_depth>(clr));
}
template<std::size_t new_bit_depth>
Pixel<new_bit_depth, fmt> convert_depth() const
{
return Pixel<new_bit_depth, fmt>(pixel_tools<fmt>::template convert_depth<bit_depth, new_bit_depth>(this->color));
}
};
template<typename char_t, typename char_traits, std::size_t bit_depth, PIXEL_FORMAT fmt>
std::basic_ostream<char_t, char_traits>& operator << (std::basic_ostream<char_t, char_traits>& o, Pixel<bit_depth, fmt> const& pixel)
{
o << '<'
<< std::uint32_t(pixel_tools<fmt>::template get_color<COLOR::RED, bit_depth>(pixel.color)) << ", "
<< std::uint32_t(pixel_tools<fmt>::template get_color<COLOR::GREEN, bit_depth>(pixel.color)) << ", "
<< std::uint32_t(pixel_tools<fmt>::template get_color<COLOR::BLUE, bit_depth>(pixel.color))
<< '>';
}
int main()
{
Pixel<16U, PIXEL_FORMAT::RGB> p16(2U, 5U, 4U);
Pixel<32U, PIXEL_FORMAT::RGB> p32 = p16.convert_depth<32U>();
//should output <2, 5, 4> <66, 81, 132> <2, 4, 4> <0, 0, 0>
std::cout << std::endl << p16 << ' ' << p32 << ' ' << p32.convert_depth<16>() << ' ' << p16.convert_depth<8>() << std::endl;
return 0;
}
注意:在 Archlinux x64 机器上使用 gcc GCC 4.8.1 20130725 (prerelease) 编译和测试。