Closed aaronfranke closed 2 years ago
@aaronfranke: By the way, even if there is no color type implemented for .NET Core, we should still deprecate
System.Drawing.Color
.@tannergooding: What would be the reason for deprecating System.Drawing.Color? It is still used for its intended purpose, with System.Drawing; which itself is based on GDI+ and is actively supported on both Unix and Windows.
@nxrighthere: There's no point to deprecate it without a replacement. It makes sense to update/improve it, but not just leaving behind.
As a follow-up to this discussion, another reason for deprecating System.Drawing.Color
is that it's extremely inefficient. As explained at the top of #48615, System.Drawing.Color
contains extra metadata that makes it unusable in interop scenarios and inefficient in arrays. It contains a nullable string for the name (>= 64 bits on a 64-bit system), the color value is stored in a 64-bit long
despite the fact that only the first 32 bits are used, and it also stores two 16-bit short
values. This means that System.Drawing.Color
is at a minimum 160 bits, which is more than the proposed HDR Color
type (128 bits in total), and despite all 160 of those bits it can only store colors as precisely as the proposed Color8
type (32 bits in total).
namespace System.Drawing
{
public readonly struct Color : IEquatable<Color>
{
private readonly string? name;
private readonly long value;
private readonly short knownColor;
private readonly short state;
}
}
I still think that this proposal is the best idea, or at least something similar (names are up for debate). Lots of things need a general-purpose color type. It would make things easier both in .NET itself and in user-made .NET programs for .NET to have a general-purpose color type.
For concerns about how we can't make a solution general enough to satisfy all use cases, I still disagree that we need to do this - if it satisfies simple use cases such as the ones inside .NET itself and the ones in programs such as Unity and Godot and Stride, that's plenty good, and programs such as Paint.NET that need more specialization can continue to use their own color types.
For concerns about the details such as which color space to use, I suggest we look at color spaces that existing ones such as System.Drawing.Color
and System.Windows.Media.Color
use, and use that. We don't need a solution general enough that it has support for different color spaces. Even if an end-user program ends up using a different color space, it can still use the proposed Color type for interoperability with itself, since it's just writing some value defined in one space and reading it as the same space.
For concerns about the proposed Color
type being inefficient since it stores 32 bits per channel, 1) there is the proposed Color8
type available (which could be renamed to Color
if we decide that), and 2) per the above comment, it's more efficient than the existing System.Drawing.Color
which needs to be replaced.
We are going with the approach described in https://github.com/dotnet/runtime/issues/48615 instead.
There will be very basic interchange types covering two of the most common formats (Argb<T>
and Rgba<T>
) and that are inline with the general SIMD accelerated/Graphics oriented types already exposed by System.Numerics and that are inline with what similar libraries (DX Math, GL Math, XNA, MonoGame, etc) have exposed.
At most, there may be a few simple SIMD accelerated operations in the future for the core APIs that the same similar libraries expose. This would include basic vector ops, an interpolate, adjust contrast, and adjust saturation function, plus basic conversion to/from the "core" color spaces (sRGB - IEC 61966-2-1:1999, CIE XYZ, IUT-R BT.601/CCIR 601, IUT-R BT.709, and IUT-R BT.2020)
Some of these are iffy and if you want more extensive functionality you could build it on top of these interchange types and/or use a more advanced and dedicated Image Processing library. We explicitly want to keep this scoped down and to only cover the core needs.
Going to close this one since #48615 is the direction we're taking.
As discussed in https://github.com/dotnet/runtime/issues/14825, the existing
System.Drawing.Color
type is not ideal for all use cases and .NET Core could benefit from new color types.This proposal includes two new types:
Color
andColor8
, in theSystem.Numerics
namespace in a new folder (library? package?) calledSystem.Numerics.Colors
.Rationale and usage
The new
Color8
type uses fourbyte
values. This is intended to be the computationally-cheap color type. It is fairly similar toSystem.Drawing.Color
. TheColor8
type is not suitable to use for HDR color math, including on high-end displays or in VR, but theColor8
type is ideal to use on computers which display 8 bits per channel, without having any unnecessary bits. A color type using bytes can also be accelerated on GPUs when used on vertices.The new
Color
type uses fourfloat
values. This is intended to be the fully capable color type, even if it's slower thanColor8
and takes up four times the space in memory. The reason this is calledColor
with no suffix is because it should be presented to users as the default choice, since it is the most capable. This type can be used for HDR color math, since it supports values outside of the normal [0, 1] range, and it supports much higher color precision thanColor8
. HDR implementations typically need 10, 12, or 16 bits per channel, floats have 23 bits of mantissa which is plenty. A color type using floats is also ideal when exposed to shaders (GLSL or similar).Both of these types have properties for setting with the other's member type (
R8
/G8
/B8
/A8
/Rf
/Gf
/Bf
/Af
), as well as operators and constructors to convert between them, so it is easy to interchange these types, including the ability to do high precision color math and store it in a low precision (byte
) context, or vice versa.Additionally, this proposal includes
H
/S
/V
properties for getting and setting hue, saturation, and value. This is a very common workflow for colors, especially when getting values from user input.Finally, there are
Colors
andColors8
static classes which have preset colors. The existingSystem.Drawing.Color
places these as static members of that struct, but it is quite useful to have these separate to distinguish them from other static members (such asFromHSV
and any others we wish to have).The uses of these types are too broad to include specific code examples. See the above text for information on how these types are expected to be used.
Proposed API
None of the properties listed below are auto-properties, all non-static properties read/write from the fields.
The proposed code for this API is collapsed, just expand it to view the code.
Details
While making this proposal, I referenced several open source color types:
Of course,
System.Drawing.Color
(see docs). Some things fromSystem.Drawing.Color
were not included or implemented differently. For example, instead ofGetHue
etc methods,H
etc properties were used.Godot's
Color
type (see non-C# docs), MIT license. It usesfloat
RGBA, and is very similar to the proposedColor
type. Godot's strategy is to have one universal Color type that's used everywhere.Stride's color types (formerly Xenko), MIT license. Stride's strategy is to have tons of types and write tons of code for every use case, and there's a point of bloat and diminishing returns here. Stride has
Color
as using fourbyte
values andColor4
as using fourfloat
values, among several other types, but this isn't ideal and they have expressed that they're open to changing this.The proposed
Color
type is also very similar to MAUI'sColor
type, which uses floats, has methods to convert between byte and HSV representations, and has a static classColors
with preset colors. It's also similar to Unity'sColor
type, though this one is closed-source.When it comes to internal memory representation, string parsing, and importing from
uint
/ulong
, these types use RGBA order. Traditionally, Microsoft APIs such as DirectX andSystem.Drawing
use ARGB, but the rest of the world uses RGBA. Using RGBA order everywhere helps fit with the goal if "Semantic parity with CSS".Open Questions
Are there any common use cases that these color types are unsuitable for?
Are there any other methods or properties which should be added?
What are some good test cases to add?
Pull Request
None so far, but see https://github.com/dotnet/corefx/pull/40733 for a closed proposed (and outdated) implementation.
Updates
None so far.