C# - 将ARGB颜色转换为RGB555

时间:2013-03-24 05:19:57

标签: c# .net colors converter bit-shift

我有一个算法将RGB555值转换为System.Drawing.Color对象;

public static Color ToColor(ushort color)
{
    int a = color & 0x8000;
    int r = color & 0x7C00;
    int g = color & 0x03E0;
    int b = color & 0x1F;
    int rgb = (r << 9) | (g << 6) | (b << 3);

    return Color.FromArgb((a * 0x1FE00) | rgb | ((rgb >> 5) & 0x070707));
}

一位朋友为我写了这个方法(按位移位有点过头了),反转这段代码最有效的方法是什么?

感谢您的任何建议,我一直在努力寻找答案,所以任何见解都会让我感到清新!

修改

这个问题已经解决了一段时间,但我想我会回来并用最终结果更新我的帖子 - 感谢所有回答的人!

public struct Color555 : IEquatable<Color555>, IComparable<Color555>, IEquatable<ushort>, IComparable<ushort>
{
    public static readonly Color555 MinValue = ushort.MinValue;
    public static readonly Color555 MaxValue = ushort.MaxValue;

    private readonly ushort _Value;

    public Color555(Color value)
    {
        uint c = (uint)value.ToArgb();
        _Value = (ushort)(((c >> 16) & 0x8000 | (c >> 9) & 0x7C00 | (c >> 6) & 0x03E0 | (c >> 3) & 0x1F));
    }

    public Color555(ushort value)
    {
        _Value = value;
    }

    public override int GetHashCode()
    {
        return _Value.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        return (obj is ushort && Equals((ushort)obj)) || (obj is Color555 && Equals((Color555)obj));
    }

    public bool Equals(ushort other)
    {
        return _Value == other;
    }

    public bool Equals(Color555 other)
    {
        return _Value == other._Value;
    }

    public int CompareTo(Color555 other)
    {
        return _Value.CompareTo(other._Value);
    }

    public int CompareTo(ushort other)
    {
        return _Value.CompareTo(other);
    }

    public override string ToString()
    {
        return String.Format("{0}", _Value);
    }

    public string ToString(string format)
    {
        return String.Format(format, _Value);
    }

    public string ToString(IFormatProvider provider)
    {
        return String.Format(provider, "{0}", _Value);
    }

    public string ToString(string format, IFormatProvider provider)
    {
        return String.Format(provider, format, _Value);
    }

    public int ToArgb()
    {
        return ToColor().ToArgb();
    }

    public Color ToColor()
    {
        int a = _Value & 0x8000;
        int r = _Value & 0x7C00;
        int g = _Value & 0x03E0;
        int b = _Value & 0x1F;
        int rgb = (r << 9) | (g << 6) | (b << 3);

        return Color.FromArgb((a * 0x1FE00) | rgb | ((rgb >> 5) & 0x070707));
    }

    public static bool operator ==(Color555 l, Color555 r)
    {
        return l.Equals(r);
    }

    public static bool operator !=(Color555 l, Color555 r)
    {
        return !l.Equals(r);
    }

    public static implicit operator Color555(Color value)
    {
        return new Color555(value);
    }

    public static implicit operator Color555(ushort value)
    {
        return new Color555(value);
    }

    public static implicit operator ushort(Color555 value)
    {
        return value._Value;
    }
}

2 个答案:

答案 0 :(得分:2)

Color每像素使用32位:每个8位用于alpha,红色,绿色和蓝色值。 (这意味着每个组件的值范围为0到255.)

RGB555颜色每像素使用5位(并且没有alpha通道),因此红色,绿色和蓝色都可以取0-31的值。

要从一个转换为另一个,我们需要将值0-255映射到值0-31。这显然是一个有损的过程;我们根本无法代表所有可能的Color,并且许多不同的Color值将映射到相同的Color555

最简单的映射就是截断,我们除以8并丢弃余数。这将0-7映射到0,8-15到1,...,248-255到31.这可以写为右向位移三位。

然后我们需要将这些值组合成一个16位值,这是通过将红色和绿色组件向左移动来实现的。

(您的示例代码似乎是基于高位设置Alpha通道,因此我们可以以相同的方式向后转换Alpha通道。在这种情况下,我们需要将256个可能的值映射到2:0或1.我选择将alpha通道分成两半;还有其他可能的映射。)

总而言之,它应该看起来像:

public Color555(Color color)
{
    _Value = (ushort) ((color.A >= 128 ? 0x8000 : 0x0000) |
        ((color.R & 0xF8) << 7) | ((color.G & 0xF8) << 2) | (color.B >> 3));
}

答案 1 :(得分:-1)

为什么不使用它?

{
    Color c = ColorTranslator.FromHtml("#555");
    string s = ColorTranslator.ToHtml(c);
}