1

我有一个将 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;
    }
}
4

2 回答 2

2

AColor每个像素使用 32 位:alpha、红色、绿色和蓝色值各 8 位。(这意味着每个组件的值可以在 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));
}
于 2013-03-24T06:06:42.403 回答
-1

为什么不使用这个?

{
    Color c = ColorTranslator.FromHtml("#555");
    string s = ColorTranslator.ToHtml(c);
}
于 2013-03-24T05:27:32.997 回答