【问题标题】:C# - Convert ARGB Color to RGB555C# - 将 ARGB 颜色转换为 RGB555
【发布时间】:2013-03-13 19:00:39
【问题描述】:

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

【问题讨论】:

  • ToArgb 怎么样
  • 第一步是理解它。如果您无法掌握位移,并且没有这样做的愿望,那么您不应该使用此代码。
  • 您知道您在丢弃数据后无法取回准确的数据吗?
  • @JonathonReinhart 是对的。采取你想要完成的整体想法,不要过度复杂化。颜色并不难在事物的宏伟计划中弄清楚。
  • @Jonathon Reinhart - 我不记得说过不想学习的话,因此提出任何关于理解它的建议将是一股新鲜空气 - 不像我期待有人来并为我做。我不只是一个复制粘贴开发者,碰巧我在为自己弄清楚了 10 年之后终于需要在公共网站上提问。

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


【解决方案1】:

为什么不用这个?

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

【讨论】:

  • 我要好好看看 ColorTranslator,谢谢分享。但是查看文档,我不确定它是否会产生预期的结果 - 必须进行一些测试。
  • RGB 555...Html('#555'); 非常不同
  • @user2203880 查看此链接以获取有关您正在尝试执行的操作的一些质量信息。 msdn.microsoft.com/en-us/library/windows/desktop/…
【解决方案2】:

Color 每个像素使用 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));
}

【讨论】:

  • 提供的代码似乎使用最高有效位作为 alpha 标志,这是值得的。
猜你喜欢
  • 2015-06-02
  • 2022-01-22
  • 1970-01-01
  • 2017-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-29
  • 2016-04-17
相关资源
最近更新 更多