Skip to content

Commit

Permalink
Fix picking color from reference
Browse files Browse the repository at this point in the history
  • Loading branch information
Equbuxu committed Dec 7, 2021
1 parent 1e5c9cd commit 640db35
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 53 deletions.
30 changes: 9 additions & 21 deletions PixiEditor/Models/ImageManipulation/BitmapUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
Expand Down Expand Up @@ -126,29 +125,18 @@ public static WriteableBitmap GeneratePreviewBitmap(IEnumerable<SerializableLaye
return result;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Color BlendColor(Color previousColor, Color color, float opacity)
public static SKColor BlendColors(SKColor bottomColor, SKColor topColor)
{
if ((color.A < 255 && color.A > 0) || (opacity < 1f && opacity > 0 && color.A > 0))
if ((topColor.Alpha < 255 && topColor.Alpha > 0))
{
byte pixelA = (byte)(color.A * opacity);
byte r = (byte)((color.R * pixelA / 255) + (previousColor.R * previousColor.A * (255 - pixelA) / (255 * 255)));
byte g = (byte)((color.G * pixelA / 255) + (previousColor.G * previousColor.A * (255 - pixelA) / (255 * 255)));
byte b = (byte)((color.B * pixelA / 255) + (previousColor.B * previousColor.A * (255 - pixelA) / (255 * 255)));
byte a = (byte)(pixelA + (previousColor.A * (255 - pixelA) / 255));
color = Color.FromArgb(a, r, g, b);
}
else
{
color = Color.FromArgb(color.A, color.R, color.G, color.B);
}

if (color.A > 0)
{
return color;
byte r = (byte)((topColor.Red * topColor.Alpha / 255) + (bottomColor.Red * bottomColor.Alpha * (255 - topColor.Alpha) / (255 * 255)));
byte g = (byte)((topColor.Green * topColor.Alpha / 255) + (bottomColor.Green * bottomColor.Alpha * (255 - topColor.Alpha) / (255 * 255)));
byte b = (byte)((topColor.Blue * topColor.Alpha / 255) + (bottomColor.Blue * bottomColor.Alpha * (255 - topColor.Alpha) / (255 * 255)));
byte a = (byte)(topColor.Alpha + (bottomColor.Alpha * (255 - topColor.Alpha) / 255));
return new SKColor(r, g, b, a);
}

return previousColor;
return topColor.Alpha == 255 ? topColor : bottomColor;
}

private static WriteableBitmap GeneratePreviewBitmap(
Expand Down Expand Up @@ -193,7 +181,7 @@ private static Color BlendColor(Color previousColor, Color color, float opacity)
int newWidth = width >= height ? maxPreviewWidth : (int)Math.Ceiling(width / ((float)height / maxPreviewHeight));
int newHeight = height > width ? maxPreviewHeight : (int)Math.Ceiling(height / ((float)width / maxPreviewWidth));
return previewBitmap.Resize(newWidth, newHeight, WriteableBitmapExtensions.Interpolation.NearestNeighbor);*/
return previewBitmap.Redesize(newWidth, newHeight, WriteableBitmapExtensions.Interpolation.NearestNeighbor);*/
}
}
}
105 changes: 73 additions & 32 deletions PixiEditor/Models/Tools/Tools/ColorPickerTool.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using PixiEditor.Models.Controllers;
using PixiEditor.Models.DataHolders;
using PixiEditor.Models.ImageManipulation;
using PixiEditor.Models.Layers;
using PixiEditor.Models.Position;
using PixiEditor.Models.Services;
Expand All @@ -17,22 +18,23 @@ public class ColorPickerTool : ReadonlyTool
{
private readonly DocumentProvider _docProvider;
private readonly BitmapManager _bitmapManager;
private readonly string defaultActionDisplay = "Click to pick colors from the canvas. Hold Ctrl to pick from the reference layer. Hold Ctrl and Alt to blend the reference and canvas color";

public ColorPickerTool(DocumentProvider documentProvider, BitmapManager bitmapManager)
{
ActionDisplay = "Press on a pixel to make it the primary color. Hold Ctrl to pick from the reference. Hold Ctrl and Alt to blend the reference and canvas color";
ActionDisplay = defaultActionDisplay;
_docProvider = documentProvider;
_bitmapManager = bitmapManager;
}

public override bool HideHighlight => true;

public override string Tooltip => "Swaps primary color with selected on canvas. (O)";
public override string Tooltip => "Picks the primary color from the canvas. (O)";

public override void Use(List<Coordinates> coordinates)
{
var coords = coordinates.First();
var doc = _docProvider.GetSurface();
var doc = _docProvider.GetDocument();
if (coords.X < 0 || coords.Y < 0 || coords.X >= doc.Width || coords.Y >= doc.Height)
return;

Expand All @@ -41,34 +43,73 @@ public override void Use(List<Coordinates> coordinates)

public SKColor GetColorAt(int x, int y)
{
SKColor? color = null;
Document activeDocument = _docProvider.GetDocument();
Layer referenceLayer;
Layer referenceLayer = _docProvider.GetReferenceLayer();

if ((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
&& (referenceLayer = _docProvider.GetReferenceLayer()) is not null)
if (referenceLayer != null && (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
{
double actualX = activeDocument.MouseXOnCanvas * referenceLayer.Width / activeDocument.Width;
double actualY = activeDocument.MouseYOnCanvas * referenceLayer.Height / activeDocument.Height;
double preciseX = _docProvider.GetDocument().MouseXOnCanvas;
double preciseY = _docProvider.GetDocument().MouseYOnCanvas;

if ((Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt)))
{
return GetCombinedColor(x, y, preciseX, preciseY);
}
return GetReferenceColor(preciseX, preciseY);
}

return GetCanvasColor(x, y);
}

private SKColor GetCombinedColor(int x, int y, double preciseX, double preciseY)
{
SKColor top = GetCanvasColor(x, y);
SKColor bottom = GetReferenceColor(preciseX, preciseY);
return BitmapUtils.BlendColors(bottom, top);
}

private SKColor GetCanvasColor(int x, int y)
{
return _docProvider.GetRenderer()?.FinalSurface.GetSRGBPixel(x, y) ?? SKColors.Transparent;
}

x = (int)Round(actualX, MidpointRounding.ToZero);
y = (int)Round(actualY, MidpointRounding.ToZero);
private SKColor GetReferenceColor(double x, double y)
{
Document activeDocument = _docProvider.GetDocument();
Layer referenceLayer = _docProvider.GetReferenceLayer();
Coordinates refPos = CanvasSpaceToReferenceSpace(
x, y,
activeDocument.Width, activeDocument.Height,
referenceLayer.Width, referenceLayer.Height);

if (refPos.X >= 0 && refPos.Y >= 0 && refPos.X < referenceLayer.Width && refPos.Y < referenceLayer.Height)
return referenceLayer.LayerBitmap.GetSRGBPixel(refPos.X, refPos.Y);
return SKColors.Transparent;
}

color = referenceLayer.LayerBitmap.GetSRGBPixel(x, y);
private Coordinates CanvasSpaceToReferenceSpace(double canvasX, double canvasY, int canvasW, int canvasH, int referenceW, int referenceH)
{
double canvasRatio = canvasW / (double)canvasH;
double referenceRatio = referenceW / (double)referenceH;
bool blackBarsAreOnTopAndBottom = referenceRatio > canvasRatio;
if (blackBarsAreOnTopAndBottom)
{
double combinedBlackBarsHeight = (1 - canvasRatio / referenceRatio) * canvasH;
double refScale = referenceH / ((double)canvasH - combinedBlackBarsHeight);

int outX = (int)Math.Floor(canvasX * referenceW / canvasW);
int outY = (int)Math.Floor((canvasY - combinedBlackBarsHeight / 2) * refScale);

//if ((Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt)) && color != null)
//{
// // TODO: Blend colors
// throw new NotImplementedException();
// //SKColor? canvasColor = _docProvider.GetRenderer()?.FinalSurface.GetSRGBPixel(x, y);
//}
return new Coordinates(outX, outY);
}
else
{
color = _docProvider.GetRenderer()?.FinalSurface.GetSRGBPixel(x, y);
}
double combinedBlackBarsWidth = (1 - referenceRatio / canvasRatio) * canvasW;
double refScale = referenceW / ((double)canvasW - combinedBlackBarsWidth);

return color ?? SKColors.Transparent;
int outX = (int)Math.Floor((canvasX - combinedBlackBarsWidth / 2) * refScale);
int outY = (int)Math.Floor(canvasY * referenceH / canvasH);
return new Coordinates(outX, outY);
}
}

public override void OnKeyDown(KeyEventArgs e)
Expand All @@ -94,25 +135,25 @@ public override void OnDeselected()

private void UpdateActionDisplay()
{
if (Keyboard.IsKeyDown(Key.LeftCtrl) /*|| Keyboard.IsKeyDown(Key.RightCtrl)*/)
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{
//if (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt))
//{
// _bitmapManager.HideReferenceLayer = false;
// _bitmapManager.OnlyReferenceLayer = false;
// ActionDisplay = "Press on a pixel to make the blend of the reference and canvas the primary color. Release Ctrl and Alt to pick from the canvas. Release just Alt to pick from the reference";
// return;
//}
if (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt))
{
_bitmapManager.HideReferenceLayer = false;
_bitmapManager.OnlyReferenceLayer = false;
ActionDisplay = "Click to pick colors from both the canvas and the reference layer blended together. Release Ctrl and Alt to pick from the canvas. Release just Alt to pick from the reference layer";
return;
}

_bitmapManager.HideReferenceLayer = false;
_bitmapManager.OnlyReferenceLayer = true;
ActionDisplay = "Press on a pixel on the reference to make it the primary color. Release Ctrl to pick from the canvas. Hold Ctrl and Alt to blend the reference and canvas color";
ActionDisplay = "Click to pick colors from the reference layer. Release Ctrl to pick from the canvas. Hold Ctrl and Alt to blend the reference and canvas color";
}
else
{
_bitmapManager.HideReferenceLayer = true;
_bitmapManager.OnlyReferenceLayer = false;
ActionDisplay = "Press on a pixel to make it the primary color. Hold Ctrl to pick from the reference.";
ActionDisplay = defaultActionDisplay;
}
}
}
Expand Down

0 comments on commit 640db35

Please sign in to comment.