Browse Source

Render the ColorSpectrum to physical device pixel resolution

pull/8050/head
robloo 4 years ago
parent
commit
d9ef01acfc
  1. 46
      src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs

46
src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs

@ -10,6 +10,7 @@ using Avalonia.Controls.Metadata;
using Avalonia.Controls.Shapes; using Avalonia.Controls.Shapes;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Threading; using Avalonia.Threading;
@ -587,8 +588,10 @@ namespace Avalonia.Controls.Primitives
return; return;
} }
double xPosition = point.Position.X; // Remember the bitmap size follows physical device pixels
double yPosition = point.Position.Y; var scale = LayoutHelper.GetLayoutScale(this);
double xPosition = point.Position.X * scale;
double yPosition = point.Position.Y * scale;
double radius = Math.Min(_imageWidthFromLastBitmapCreation, _imageHeightFromLastBitmapCreation) / 2; double radius = Math.Min(_imageWidthFromLastBitmapCreation, _imageHeightFromLastBitmapCreation) / 2;
double distanceFromRadius = Math.Sqrt(Math.Pow(xPosition - radius, 2) + Math.Pow(yPosition - radius, 2)); double distanceFromRadius = Math.Sqrt(Math.Pow(xPosition - radius, 2) + Math.Pow(yPosition - radius, 2));
@ -819,8 +822,10 @@ namespace Avalonia.Controls.Primitives
yPosition = (Math.Sin((thetaValue * Math.PI / 180.0) + Math.PI) * radius * rValue) + radius; yPosition = (Math.Sin((thetaValue * Math.PI / 180.0) + Math.PI) * radius * rValue) + radius;
} }
Canvas.SetLeft(_selectionEllipsePanel, xPosition - (_selectionEllipsePanel.Width / 2)); // Remember the bitmap size follows physical device pixels
Canvas.SetTop(_selectionEllipsePanel, yPosition - (_selectionEllipsePanel.Height / 2)); var scale = LayoutHelper.GetLayoutScale(this);
Canvas.SetLeft(_selectionEllipsePanel, (xPosition / scale) - (_selectionEllipsePanel.Width / 2));
Canvas.SetTop(_selectionEllipsePanel, (yPosition / scale) - (_selectionEllipsePanel.Height / 2));
// We only want to bother with the color name tool tip if we can provide color names. // We only want to bother with the color name tool tip if we can provide color names.
if (IsFocused && if (IsFocused &&
@ -969,7 +974,14 @@ namespace Avalonia.Controls.Primitives
List<byte> bgraMaxPixelData = new List<byte>(); List<byte> bgraMaxPixelData = new List<byte>();
List<Hsv> newHsvValues = new List<Hsv>(); List<Hsv> newHsvValues = new List<Hsv>();
var pixelCount = (int)(Math.Round(minDimension) * Math.Round(minDimension)); // 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; var pixelDataSize = pixelCount * 4;
bgraMinPixelData.Capacity = pixelDataSize; bgraMinPixelData.Capacity = pixelDataSize;
@ -986,8 +998,6 @@ namespace Avalonia.Controls.Primitives
bgraMaxPixelData.Capacity = pixelDataSize; bgraMaxPixelData.Capacity = pixelDataSize;
newHsvValues.Capacity = pixelCount; newHsvValues.Capacity = pixelCount;
int minDimensionInt = (int)Math.Round(minDimension);
await Task.Run(() => await Task.Run(() =>
{ {
// As the user perceives it, every time the third dimension not represented in the ColorSpectrum changes, // As the user perceives it, every time the third dimension not represented in the ColorSpectrum changes,
@ -1006,12 +1016,12 @@ namespace Avalonia.Controls.Primitives
// but the running time savings after that are *huge* when we can just set an opacity instead of generating a brand new bitmap. // 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) if (shape == ColorSpectrumShape.Box)
{ {
for (int x = minDimensionInt - 1; x >= 0; --x) for (int x = pixelDimension - 1; x >= 0; --x)
{ {
for (int y = minDimensionInt - 1; y >= 0; --y) for (int y = pixelDimension - 1; y >= 0; --y)
{ {
FillPixelForBox( FillPixelForBox(
x, y, hsv, minDimensionInt, components, minHue, maxHue, minSaturation, maxSaturation, minValue, maxValue, x, y, hsv, pixelDimension, components, minHue, maxHue, minSaturation, maxSaturation, minValue, maxValue,
bgraMinPixelData, bgraMiddle1PixelData, bgraMiddle2PixelData, bgraMiddle3PixelData, bgraMiddle4PixelData, bgraMaxPixelData, bgraMinPixelData, bgraMiddle1PixelData, bgraMiddle2PixelData, bgraMiddle3PixelData, bgraMiddle4PixelData, bgraMaxPixelData,
newHsvValues); newHsvValues);
} }
@ -1019,12 +1029,12 @@ namespace Avalonia.Controls.Primitives
} }
else else
{ {
for (int y = 0; y < minDimensionInt; ++y) for (int y = 0; y < pixelDimension; ++y)
{ {
for (int x = 0; x < minDimensionInt; ++x) for (int x = 0; x < pixelDimension; ++x)
{ {
FillPixelForRing( FillPixelForRing(
x, y, minDimensionInt / 2.0, hsv, components, minHue, maxHue, minSaturation, maxSaturation, minValue, maxValue, x, y, pixelDimension / 2.0, hsv, components, minHue, maxHue, minSaturation, maxSaturation, minValue, maxValue,
bgraMinPixelData, bgraMiddle1PixelData, bgraMiddle2PixelData, bgraMiddle3PixelData, bgraMiddle4PixelData, bgraMaxPixelData, bgraMinPixelData, bgraMiddle1PixelData, bgraMiddle2PixelData, bgraMiddle3PixelData, bgraMiddle4PixelData, bgraMaxPixelData,
newHsvValues); newHsvValues);
} }
@ -1034,8 +1044,8 @@ namespace Avalonia.Controls.Primitives
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() =>
{ {
int pixelWidth = (int)Math.Round(minDimension); int pixelWidth = pixelDimension;
int pixelHeight = (int)Math.Round(minDimension); int pixelHeight = pixelDimension;
ColorSpectrumComponents components2 = Components; ColorSpectrumComponents components2 = Components;
@ -1066,8 +1076,8 @@ namespace Avalonia.Controls.Primitives
_shapeFromLastBitmapCreation = Shape; _shapeFromLastBitmapCreation = Shape;
_componentsFromLastBitmapCreation = Components; _componentsFromLastBitmapCreation = Components;
_imageWidthFromLastBitmapCreation = minDimension; _imageWidthFromLastBitmapCreation = pixelDimension;
_imageHeightFromLastBitmapCreation = minDimension; _imageHeightFromLastBitmapCreation = pixelDimension;
_minHueFromLastBitmapCreation = MinHue; _minHueFromLastBitmapCreation = MinHue;
_maxHueFromLastBitmapCreation = MaxHue; _maxHueFromLastBitmapCreation = MaxHue;
_minSaturationFromLastBitmapCreation = MinSaturation; _minSaturationFromLastBitmapCreation = MinSaturation;
@ -1086,7 +1096,7 @@ namespace Avalonia.Controls.Primitives
double x, double x,
double y, double y,
Hsv baseHsv, Hsv baseHsv,
double minDimension, int minDimension,
ColorSpectrumComponents components, ColorSpectrumComponents components,
double minHue, double minHue,
double maxHue, double maxHue,

Loading…
Cancel
Save