C# - Конвертиране на ARGB цвят в RGB555

Имам алгоритъм, който преобразува 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;
    }
}

person Vorspire    schedule 24.03.2013    source източник
comment
какво ще кажете за ToArgb   -  person Chase Florell    schedule 24.03.2013
comment
Първата стъпка би била да го разберем. Ако не можете да разберете преместването на битове и нямате желание да го направите, не заслужавате да използвате този код.   -  person Jonathon Reinhart    schedule 24.03.2013
comment
Наясно сте, че не можете да върнете точните данни, тъй като изхвърляте данни, нали?   -  person boxed    schedule 24.03.2013
comment
@JonathonReinhart е прав. Вземете цялостната идея, която се опитвате да постигнете, и не я усложнявайте. Цветовете не са трудни за разгадаване в голямата схема на нещата.   -  person Chase Florell    schedule 24.03.2013
comment
@Chase Florell - Търся да конвертирам ARGB в RGB555, методът, който публикувах, вече прави това, което предлагате.   -  person Vorspire    schedule 24.03.2013
comment
@Jonathon Reinhart - Не си спомням да съм казвал нещо за това, че не искам да уча, следователно даването на съвети за разбирането му би било глътка свеж въздух - не като че очаквам някой да дойде и да го направи вместо мен. Аз не съм просто копи-пейст програмист, така се случи, че най-накрая ми се наложи да задам въпрос на публичен уебсайт, след като 10 години съм измислял сам нещата.   -  person Vorspire    schedule 24.03.2013
comment
Всъщност, след като прочетох отново коментара на @JonathonReinhart, бих искал да отменя своя вот за. Пропуснах да прочета, не заслужавам да използвам този код, трябва да помисля за нещо друго... честно казано, не прочетох след първия ред. Моя грешка. Мисля, че има много начини да одреш котка и ако искаш да се научиш, това е страхотно. Ще кажа, че тъй като вашият метод използва FromArgb, тогава е логично обратното да бъде ToArgb. Нямам своя IDE пред мен, за да се забърквам с него, но трябва да е добра отправна точка.   -  person Chase Florell    schedule 24.03.2013
comment
@ChaseFlorell След като прочетох отново собствения си коментар, съгласен съм, че беше малко груб. Твърде често на този сайт потребители с 1 повторение питат, моля, дайте ми въпроси за кодовете. Но общото ми послание е същото: Първата стъпка за обръщане на този алгоритъм би била да го разберем. Казваш, че побитовото изместване е малко над главата ми - така че мисля, че първата стъпка би била да разбера двоичните числа и битовото изместване. Тогава ще видите, че функцията извлича 5-битови числа от 16-битовия вход. Вие наистина не сте показали никакво усилие в този въпрос, което стимулира моя разочарован коментар.   -  person Jonathon Reinhart    schedule 24.03.2013
comment
@JonathonReinhart - Напълно разбирам вашето разочарование, разбирам как работи побитовото преместване, но когато се опитам да сложа писалка на хартия, числата ме объркват. Въпреки това съм изключително склонен да уча, просто отнема малко повече време от повечето, когато става въпрос за математика.   -  person Vorspire    schedule 24.03.2013
comment
Когато казвате обръщане на този код, какво имате предвид? Бихте ли предоставяли само цветове, които са резултат от този код, или бихте искали функция, която се занимава с всички цветове? Във втория случай трябва също да помислите как искате да боравите с цветовете, които не съответстват точно.   -  person jswolf19    schedule 24.03.2013
comment
@jswolf19 - Желаният резултат би бил Color555 да бъде посредник между UInt16 и System.Drawing.Color - Пр. var c = new Color555(Color.Green); Казвам „обратно“, защото по същество е обратното на метода „ToColor“.   -  person Vorspire    schedule 24.03.2013


Отговори (2)


Color използва 32 бита на пиксел: по 8 бита за алфа, червени, зелени и сини стойности. (Това означава, че стойностите за всеки компонент могат да варират от 0 до 255.)

Цвят RGB555 използва 5 бита на пиксел (и има без алфа канал), така че червеното, зеленото и синьото могат да приемат стойност от 0-31.

За да преобразуваме от едно в друго, трябва да съпоставим стойностите 0-255 към стойностите 0-31. Това очевидно ще бъде процес със загуби; ние просто не можем да представим всички възможни Color и много различни Color стойности ще бъдат картографирани към едно и също Color555.

Най-простото картографиране е просто отрязване, където делим на 8 и изхвърляме остатъка. Това преобразува 0-7 в 0, 8-15 в 1, ..., 248-255 в 31. Това може да се запише като изместване на бита надясно с три бита.

След това трябва да комбинираме стойностите в една 16-битова стойност, което се постига чрез изместване на червения и зеления компонент наляво.

(Вашият примерен код изглежда настройва алфа канала въз основа на високия бит, така че можем да конвертираме алфа канала обратно по същия начин. В този случай трябва да съпоставим 256 възможни стойности към 2: 0 или 1. I Избрах да разделя алфа канала точно наполовина; има и други възможни съпоставяния.)

Събирайки всичко заедно, трябва да изглежда така:

public Color555(Color color)
{
    _Value = (ushort) ((color.A >= 128 ? 0x8000 : 0x0000) |
        ((color.R & 0xF8) << 7) | ((color.G & 0xF8) << 2) | (color.B >> 3));
}
person Bradley Grainger    schedule 24.03.2013
comment
Предоставеният код изглежда използва най-значимия бит като алфа флаг, колкото си струва. - person jswolf19; 24.03.2013

Защо не използвате това?

{
    Color c = ColorTranslator.FromHtml("#555");
    string s = ColorTranslator.ToHtml(c);
}
person Alina B.    schedule 24.03.2013
comment
Ще разгледам добре ColorTranslator, благодаря, че го споделихте. Но като гледам документацията, не съм сигурен дали ще даде желаните резултати - ще трябва да направя някои тестове. - person Vorspire; 24.03.2013
comment
RGB 555 е много МНОГО различно от ...Html('#555'); - person Chase Florell; 24.03.2013
comment
@user2203880 погледнете тази връзка за качествена информация за това, което се опитвате да направите. msdn.microsoft.com/en -us/library/windows/desktop/ - person Chase Florell; 24.03.2013