private async void CreateBitmapsAndColorMap()

in src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs [1042:1231]


        private async void CreateBitmapsAndColorMap()
        {
            if (_layoutRoot == null ||
                _sizingPanel == null ||
                _inputTarget == null ||
                _spectrumRectangle == null ||
                _spectrumEllipse == null ||
                _spectrumOverlayRectangle == null ||
                _spectrumOverlayEllipse == null
                /*|| SharedHelpers.IsInDesignMode*/)
            {
                return;
            }

            // We want ColorSpectrum to always be a square, so we'll take the smaller of the dimensions
            // and size the sizing panel to that.
            double minDimension = Math.Min(_layoutRoot.Bounds.Width, _layoutRoot.Bounds.Height);

            if (minDimension == 0)
            {
                return;
            }

            _sizingPanel.Width = minDimension;
            _sizingPanel.Height = minDimension;
            _inputTarget.Width = minDimension;
            _inputTarget.Height = minDimension;
            _spectrumRectangle.Width = minDimension;
            _spectrumRectangle.Height = minDimension;
            _spectrumEllipse.Width = minDimension;
            _spectrumEllipse.Height = minDimension;
            _spectrumOverlayRectangle.Width = minDimension;
            _spectrumOverlayRectangle.Height = minDimension;
            _spectrumOverlayEllipse.Width = minDimension;
            _spectrumOverlayEllipse.Height = minDimension;

            HsvColor hsvColor = HsvColor;
            int minHue = MinHue;
            int maxHue = MaxHue;
            int minSaturation = MinSaturation;
            int maxSaturation = MaxSaturation;
            int minValue = MinValue;
            int maxValue = MaxValue;
            ColorSpectrumShape shape = Shape;
            ColorSpectrumComponents components = Components;

            // If min >= max, then by convention, min is the only number that a property can have.
            if (minHue >= maxHue)
            {
                maxHue = minHue;
            }

            if (minSaturation >= maxSaturation)
            {
                maxSaturation = minSaturation;
            }

            if (minValue >= maxValue)
            {
                maxValue = minValue;
            }

            Hsv hsv = new Hsv(hsvColor);
            
            // In Avalonia, Bounds returns the actual device-independent pixel size of a control.
            // However, this is not necessarily the size of the control rendered on a display.
            // A desktop or application scaling factor may be applied which must be accounted for here.
            // Remember bitmaps in Avalonia are rendered mapping to actual device pixels, not the device-
            // independent pixels of controls.
            var scale = LayoutHelper.GetLayoutScale(this);
            int pixelDimension = (int)Math.Round(minDimension * scale);
            var pixelCount = pixelDimension * pixelDimension;
            var pixelDataSize = pixelCount * 4;
            // We'll only save pixel data for the middle bitmaps if our third dimension is hue.
            var middleBitmapsSize =
                components is ColorSpectrumComponents.ValueSaturation or ColorSpectrumComponents.SaturationValue
                    ? pixelDataSize : 0;

            var newHsvValues = new List<Hsv>(pixelCount);
            using var bgraMinPixelData = new PooledList<byte>(pixelDataSize, ClearMode.Never);
            using var bgraMaxPixelData = new PooledList<byte>(pixelDataSize, ClearMode.Never);
            // The middle 4 are only needed and used in the case of hue as the third dimension.
            // Saturation and luminosity need only a min and max.
            using var bgraMiddle1PixelData = new PooledList<byte>(middleBitmapsSize, ClearMode.Never);
            using var bgraMiddle2PixelData = new PooledList<byte>(middleBitmapsSize, ClearMode.Never);
            using var bgraMiddle3PixelData = new PooledList<byte>(middleBitmapsSize, ClearMode.Never);
            using var bgraMiddle4PixelData = new PooledList<byte>(middleBitmapsSize, ClearMode.Never);

            await Task.Run(() =>
            {
                // As the user perceives it, every time the third dimension not represented in the ColorSpectrum changes,
                // the ColorSpectrum will visually change to accommodate that value.  For example, if the ColorSpectrum handles hue and luminosity,
                // and the saturation externally goes from 1.0 to 0.5, then the ColorSpectrum will visually change to look more washed out
                // to represent that third dimension's new value.
                // Internally, however, we don't want to regenerate the ColorSpectrum bitmap every single time this happens, since that's very expensive.
                // In order to make it so that we don't have to, we implement an optimization where, rather than having only one bitmap,
                // we instead have multiple that we blend together using opacity to create the effect that we want.
                // In the case where the third dimension is saturation or luminosity, we only need two: one bitmap at the minimum value
                // of the third dimension, and one bitmap at the maximum.  Then we set the second's opacity at whatever the value of
                // the third dimension is - e.g., a saturation of 0.5 implies an opacity of 50%.
                // In the case where the third dimension is hue, we need six: one bitmap corresponding to red, yellow, green, cyan, blue, and purple.
                // We'll then blend between whichever colors our hue exists between - e.g., an orange color would use red and yellow with an opacity of 50%.
                // This optimization does incur slightly more startup time initially since we have to generate multiple bitmaps at once instead of only one,
                // but the running time savings after that are *huge* when we can just set an opacity instead of generating a brand new bitmap.
                if (shape == ColorSpectrumShape.Box)
                {
                    for (int x = pixelDimension - 1; x >= 0; --x)
                    {
                        for (int y = pixelDimension - 1; y >= 0; --y)
                        {
                            FillPixelForBox(
                                x, y, hsv, pixelDimension, components, minHue, maxHue, minSaturation, maxSaturation, minValue, maxValue,
                                bgraMinPixelData, bgraMiddle1PixelData, bgraMiddle2PixelData, bgraMiddle3PixelData, bgraMiddle4PixelData, bgraMaxPixelData,
                                newHsvValues);
                        }
                    }
                }
                else
                {
                    for (int y = 0; y < pixelDimension; ++y)
                    {
                        for (int x = 0; x < pixelDimension; ++x)
                        {
                            FillPixelForRing(
                                x, y, pixelDimension / 2.0, hsv, components, minHue, maxHue, minSaturation, maxSaturation, minValue, maxValue,
                                bgraMinPixelData, bgraMiddle1PixelData, bgraMiddle2PixelData, bgraMiddle3PixelData, bgraMiddle4PixelData, bgraMaxPixelData,
                                newHsvValues);
                        }
                    }
                }
            });

            await Dispatcher.UIThread.InvokeAsync(() =>
            {
                int pixelWidth = pixelDimension;
                int pixelHeight = pixelDimension;

                ColorSpectrumComponents components2 = Components;

                _minBitmap = ColorPickerHelpers.CreateBitmapFromPixelData(bgraMinPixelData, pixelWidth, pixelHeight);
                _maxBitmap = ColorPickerHelpers.CreateBitmapFromPixelData(bgraMaxPixelData, pixelWidth, pixelHeight);

                switch (components2)
                {
                    case ColorSpectrumComponents.HueValue:
                    case ColorSpectrumComponents.ValueHue:
                        _saturationMinimumBitmap?.Dispose();
                        _saturationMinimumBitmap = _minBitmap;
                        _saturationMaximumBitmap?.Dispose();
                        _saturationMaximumBitmap = _maxBitmap;
                        break;
                    case ColorSpectrumComponents.HueSaturation:
                    case ColorSpectrumComponents.SaturationHue:
                        _valueBitmap?.Dispose();
                        _valueBitmap = _maxBitmap;
                        break;
                    case ColorSpectrumComponents.ValueSaturation:
                    case ColorSpectrumComponents.SaturationValue:
                        _hueRedBitmap?.Dispose();
                        _hueRedBitmap = _minBitmap;
                        _hueYellowBitmap?.Dispose();
                        _hueYellowBitmap = ColorPickerHelpers.CreateBitmapFromPixelData(bgraMiddle1PixelData, pixelWidth, pixelHeight);
                        _hueGreenBitmap?.Dispose();
                        _hueGreenBitmap = ColorPickerHelpers.CreateBitmapFromPixelData(bgraMiddle2PixelData, pixelWidth, pixelHeight);
                        _hueCyanBitmap?.Dispose();
                        _hueCyanBitmap = ColorPickerHelpers.CreateBitmapFromPixelData(bgraMiddle3PixelData, pixelWidth, pixelHeight);
                        _hueBlueBitmap?.Dispose();
                        _hueBlueBitmap = ColorPickerHelpers.CreateBitmapFromPixelData(bgraMiddle4PixelData, pixelWidth, pixelHeight);
                        _huePurpleBitmap?.Dispose();
                        _huePurpleBitmap = _maxBitmap;
                        break;
                }

                _shapeFromLastBitmapCreation = Shape;
                _componentsFromLastBitmapCreation = Components;
                _imageWidthFromLastBitmapCreation = pixelDimension;
                _imageHeightFromLastBitmapCreation = pixelDimension;
                _minHueFromLastBitmapCreation = MinHue;
                _maxHueFromLastBitmapCreation = MaxHue;
                _minSaturationFromLastBitmapCreation = MinSaturation;
                _maxSaturationFromLastBitmapCreation = MaxSaturation;
                _minValueFromLastBitmapCreation = MinValue;
                _maxValueFromLastBitmapCreation = MaxValue;

                _hsvValues = newHsvValues;

                UpdateBitmapSources();
                UpdateEllipse();
            });
        }