xamarin UIColorPickerViewController正在轻微更改输入颜色

7vux5j2d  于 2022-12-07  发布在  其他
关注(0)|答案(1)|浏览(128)

我需要允许用户在iOS上选择颜色。我使用以下代码启动颜色选择器:

var picker = new UIColorPickerViewController();
    picker.SupportsAlpha = true;
    picker.Delegate = this;
    picker.SelectedColor = color.ToUIColor();   

    PresentViewController(picker, true, null);

当颜色选择器显示时,颜色总是略微偏离。例如:

input RGBA: (220, 235, 92, 255)

颜色选择器中的初始颜色可以是:

selected color: (225, 234, 131, 255)

(这些都是来自测试的真实的值)。离得不远...但如果你正在寻找它,足以注意到。
我想知道颜色选择器网格是否强制颜色为最近的颜色条目-但如果是真的,您会期望某些颜色保持固定(即,如果输入颜色与网格颜色之一完全匹配,它应该保持不变)。
另外,我使用简单的RGBA值以跨平台方式存储颜色。ToUIColor使用

new UIColor((nfloat)rgb.r, (nfloat)rgb.g, (nfloat)rgb.b, (nfloat)rgb.a);
gjmwrych

gjmwrych1#

From the hints in comments by @DonMag, I've got some way towards an answer, and also a set of resources that can help if you are struggling with this.
The key challenge is that mac and iOS use displayP3 as the ColorSpace, but most people use default {UI,NS,CG}Color objects, which use the sRGB ColorSpace (actually... technically they are Extended sRGB so they can cover the wider gamut of DisplayP3). If you want to know the difference between these three - there's resources below.
When you use the UIColorPickerViewController, it allows the user to choose colors in DisplayP3 color space (I show an image of the picker below, and you can see the "Display P3 Hex Colour" at the bottom).
If you give it a color in sRGB, I think it gets converted to DisplayP3. When you read the color, you need to convert back to sRGB, which is the step I missed.
However I found that using CGColor.CreateByMatchingToColorSpace, to convert from DisplayP3 to sRGB never quite worked. In the code below I convert to and from DisplayP3 and should have got back my original color, but I never did. I tried removing Gamma by converting to a Linear space on the way but that didn't help.

cg = new CGColor(...values...); // defaults to sRGB

    // sRGB to DisplayP3
    tmp = CGColor.CreateByMatchingToColorSpace(
        CGColorSpace.CreateWithName("kCGColorSpaceDisplayP3"),
        CGColorRenderingIntent.Default, cg, null);

    //  DisplayP3 to sRGB
    cg2 = CGColor.CreateByMatchingToColorSpace(
        CGColorSpace.CreateWithName("kCGColorSpaceExtendedSRGB"),
        CGColorRenderingIntent.Default, tmp, null);

Then I found an excellent resource: http://endavid.com/index.php?entry=79 that included a set of matrices that can perform the conversions. And that seems to work.
So now I have extended CGColor as follows:

public static CGColor FromExtendedsRGBToDisplayP3(this CGColor c)
    {
        if (c.ColorSpace.Name != "kCGColorSpaceExtendedSRGB")
            throw new Exception("Bad color space");

        var mat = LinearAlgebra.Matrix<float>.Build.Dense(3, 3, new float[] { 0.8225f, 0.1774f, 0f, 0.0332f, 0.9669f, 0, 0.0171f, 0.0724f, 0.9108f });
        var vect = LinearAlgebra.Vector<float>.Build.Dense(new float[] { (float)c.Components[0], (float)c.Components[1], (float)c.Components[2] });
        vect = vect * mat;
        var cg = new CGColor(CGColorSpace.CreateWithName("kCGColorSpaceDisplayP3"), new nfloat[] { vect[0], vect[1], vect[2], c.Components[3] });
        return cg;
    }

    public static CGColor FromP3ToExtendedsRGB(this CGColor c)
    {
        if (c.ColorSpace.Name != "kCGColorSpaceDisplayP3")
            throw new Exception("Bad color space");

        var mat = LinearAlgebra.Matrix<float>.Build.Dense(3, 3, new float[] { 1.2249f, -0.2247f, 0f, -0.0420f, 1.0419f, 0f, -0.0197f, -0.0786f, 1.0979f });
        var vect = LinearAlgebra.Vector<float>.Build.Dense(new float[] { (float)c.Components[0], (float)c.Components[1], (float)c.Components[2] });
        vect = vect * mat;
        var cg = new CGColor(CGColorSpace.CreateWithName("kCGColorSpaceExtendedSRGB"), new nfloat[] { vect[0], vect[1], vect[2], c.Components[3] });
        return cg;
    }

Note: there's lots of assumptions in the matrices w.r.t white point and gammas. But it works for me. Let me know if there are better approaches out there, or if you can tell me why my use of CGColor.CreateByMatchingToColorSpace didn't quite work.

Reading Resources: Reading this: https://stackoverflow.com/a/49040628/6257435 then this: https://bjango.com/articles/colourmanagementgamut/ are essential starting points.
Image of the iOS Color Picker:

相关问题