mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-03-03 00:00:57 +08:00
修复6.0二维码的bug
This commit is contained in:
@@ -91,16 +91,16 @@ namespace AIStudio.Wpf.DiagramApp.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private Models.ColorType _colorObject;
|
||||
private Models.ColorType _colorType;
|
||||
public Models.ColorType ColorType
|
||||
{
|
||||
get
|
||||
{
|
||||
return _colorObject;
|
||||
return _colorType;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _colorObject, value);
|
||||
SetProperty(ref _colorType, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -715,21 +715,128 @@ namespace AIStudio.Wpf.DiagramApp.ViewModels
|
||||
List<Color> result = new List<Color>();
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
//var colors = ColorGallery.GetGradient(ColorGallery.StandardThemeColors[i], 10);
|
||||
//for (var j = 9; j >= 0; j--)
|
||||
//{
|
||||
// result.AddTo(colors[j]);
|
||||
//}
|
||||
var colors = GetGradient(ColorGallery.StandardThemeColors[i], 10);
|
||||
for (var j = 9; j >= 0; j--)
|
||||
{
|
||||
result.Add(colors[j]);
|
||||
}
|
||||
}
|
||||
{
|
||||
//var colors = ColorGallery.GetGradient(Colors.Black, 10);
|
||||
//for (var j = 9; j >= 0; j--)
|
||||
//{
|
||||
// result.AddTo(colors[j]);
|
||||
//}
|
||||
var colors = GetGradient(Colors.Black, 10);
|
||||
for (var j = 9; j >= 0; j--)
|
||||
{
|
||||
result.Add(colors[j]);
|
||||
}
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Gradient Generation
|
||||
|
||||
/// <summary>
|
||||
/// Returns brightness of the given color from 0..1
|
||||
/// </summary>
|
||||
/// <param name="color">Color</param>
|
||||
/// <returns>Brightness of the given color from 0..1</returns>
|
||||
private static double GetBrightness(Color color)
|
||||
{
|
||||
var summ = (double)color.R + color.G + color.B;
|
||||
return summ / (255.0 * 3.0);
|
||||
}
|
||||
|
||||
// Makes the given color lighter
|
||||
private static Color Lighter(Color color, double power)
|
||||
{
|
||||
var totalAvailability = (255.0 * 3.0) - color.R + color.G + color.B;
|
||||
double redAvailability;
|
||||
double greenAvailability;
|
||||
double blueAvailability;
|
||||
double needToBeAdded;
|
||||
|
||||
if (color.R + color.G + color.B == 0)
|
||||
{
|
||||
redAvailability = 1.0 / 3.0;
|
||||
greenAvailability = 1.0 / 3.0;
|
||||
blueAvailability = 1.0 / 3.0;
|
||||
needToBeAdded = power * 255.0 * 3.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
redAvailability = (255.0 - color.R) / totalAvailability;
|
||||
greenAvailability = (255.0 - color.G) / totalAvailability;
|
||||
blueAvailability = (255.0 - color.B) / totalAvailability;
|
||||
needToBeAdded = ((double)color.R + color.G + color.B) * (power - 1);
|
||||
}
|
||||
|
||||
var result = Color.FromRgb(
|
||||
(byte)(color.R + (byte)(redAvailability * needToBeAdded)),
|
||||
(byte)(color.G + (byte)(greenAvailability * needToBeAdded)),
|
||||
(byte)(color.B + (byte)(blueAvailability * needToBeAdded)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Makes the given color darker
|
||||
private static Color Darker(Color color, double power)
|
||||
{
|
||||
var totalAvailability = (double)color.R + color.G + color.B;
|
||||
var redAvailability = color.R / totalAvailability;
|
||||
var greenAvailability = color.G / totalAvailability;
|
||||
var blueAvailability = color.B / totalAvailability;
|
||||
|
||||
var needToBeAdded = (double)color.R + color.G + color.B;
|
||||
needToBeAdded = needToBeAdded - (needToBeAdded * power);
|
||||
|
||||
var result = Color.FromRgb(
|
||||
(byte)(color.R - (byte)(redAvailability * needToBeAdded)),
|
||||
(byte)(color.G - (byte)(greenAvailability * needToBeAdded)),
|
||||
(byte)(color.B - (byte)(blueAvailability * needToBeAdded)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Makes a new color from the given with new brightness
|
||||
private static Color Rebright(Color color, double newBrightness)
|
||||
{
|
||||
var currentBrightness = GetBrightness(color);
|
||||
var power = DoubleUtil.AreClose(currentBrightness, 0.0) == false
|
||||
? newBrightness / currentBrightness
|
||||
: 1.0 + newBrightness;
|
||||
|
||||
// TODO: round power to make nice numbers
|
||||
// ...
|
||||
|
||||
if (power > 1.0)
|
||||
{
|
||||
return Lighter(color, power);
|
||||
}
|
||||
|
||||
return Darker(color, power);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes gradient colors from lighter to darker
|
||||
/// </summary>
|
||||
/// <param name="color">Base color</param>
|
||||
/// <param name="count">Count of items in the gradient</param>
|
||||
/// <returns>Colors from lighter to darker</returns>
|
||||
public static Color[] GetGradient(Color color, int count)
|
||||
{
|
||||
const double lowBrightness = 0.15;
|
||||
const double highBrightness = 0.85;
|
||||
var result = new Color[count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var brightness = lowBrightness + (i * (highBrightness - lowBrightness) / count);
|
||||
result[count - i - 1] = Rebright(color, brightness);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<PackageReference Include="MahApps.Metro.IconPacks" Version="4.8.0" />
|
||||
<PackageReference Include="AIStudio.Wpf.Svg2XamlExtension" Version="1.2.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="ZXing.Net" Version="0.16.8" />
|
||||
<PackageReference Include="ZXing.Net" Version="0.16.9" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -116,6 +116,7 @@ namespace AIStudio.Wpf.DiagramDesigner.Additionals.Controls
|
||||
Margin = 0
|
||||
}
|
||||
};
|
||||
writer.Renderer = new GeometryRenderer();
|
||||
var image = writer.Write(Text ?? "AIStudio画板");
|
||||
imageBarcodeEncoderGeometry.Data = image;
|
||||
#else
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using ZXing.Common;
|
||||
using ZXing.Rendering;
|
||||
using ZXing;
|
||||
using System.Windows;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Renders a barcode into a geometry
|
||||
/// Autor: Rob Fonseca-Ensor
|
||||
/// </summary>
|
||||
public class GeometryRenderer : IBarcodeRenderer<Geometry>
|
||||
{
|
||||
/// <summary>
|
||||
/// Renders the specified matrix.
|
||||
/// </summary>
|
||||
/// <param name="matrix">The matrix.</param>
|
||||
/// <param name="format">The format.</param>
|
||||
/// <param name="content">The content.</param>
|
||||
/// <returns></returns>
|
||||
public Geometry Render(BitMatrix matrix, BarcodeFormat format, string content)
|
||||
{
|
||||
return Render(matrix, format, content, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the specified matrix.
|
||||
/// </summary>
|
||||
/// <param name="matrix">The matrix.</param>
|
||||
/// <param name="format">The format.</param>
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns></returns>
|
||||
public Geometry Render(BitMatrix matrix, BarcodeFormat format, string content, EncodingOptions options)
|
||||
{
|
||||
var edges = new HashSet<Edge>();
|
||||
var edgeMap = new Dictionary<Coordinate, List<Edge>>();
|
||||
var cols = matrix.Width;
|
||||
var rows = matrix.Height;
|
||||
|
||||
for (int c = 0; c <= cols; c++)
|
||||
{
|
||||
for (int r = 0; r <= rows; r++)
|
||||
{
|
||||
var cell = GetCell(c, r, matrix);
|
||||
var westCell = GetCell(c - 1, r, matrix);
|
||||
var northCell = GetCell(c, r - 1, matrix);
|
||||
if (northCell != cell)
|
||||
{
|
||||
AddEdge(new Edge(c, r, c + 1, r), edges, edgeMap);
|
||||
}
|
||||
|
||||
if (westCell != cell)
|
||||
{
|
||||
AddEdge(new Edge(c, r, c, r + 1), edges, edgeMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cycles = new List<List<Coordinate>>();
|
||||
|
||||
while (edges.Count > 0)
|
||||
{
|
||||
var edge = edges.First();
|
||||
RemoveEdge(edge, edges, edgeMap);
|
||||
|
||||
if (IsEdgeLeftHand(matrix, edge))
|
||||
{
|
||||
edge = edge.Reversed();
|
||||
}
|
||||
|
||||
var currentCycle = new List<Coordinate> { edge.From, edge.To };
|
||||
while (edge.To != currentCycle[0])
|
||||
{
|
||||
var moves = from direction in Turns(edge.From - edge.To)
|
||||
let nextCoordinate = direction + edge.To
|
||||
from e in EdgesFrom(edge.To, edgeMap)
|
||||
where e.To == nextCoordinate || e.From == nextCoordinate
|
||||
select e;
|
||||
|
||||
var nextEdge = moves.First();
|
||||
RemoveEdge(nextEdge, edges, edgeMap);
|
||||
edge = nextEdge.To != edge.To ? nextEdge : nextEdge.Reversed();
|
||||
currentCycle.Add(edge.To);
|
||||
}
|
||||
cycles.Add(currentCycle);
|
||||
}
|
||||
|
||||
return new PathGeometry(cycles.Select(x => new PathFigure(x.First().ToPoint(1), x.Skip(1).Select(y => new LineSegment(y.ToPoint(1), true)), true)));
|
||||
|
||||
}
|
||||
|
||||
private static bool IsEdgeLeftHand(BitMatrix b, Edge edge)
|
||||
{
|
||||
var cell = GetCell(edge.From.Col, edge.From.Row, b);
|
||||
return (edge.From.Row < edge.To.Row && cell) || (!(edge.From.Col < edge.To.Col && cell));
|
||||
}
|
||||
|
||||
private static IEnumerable<Edge> EdgesFrom(Coordinate c, Dictionary<Coordinate, List<Edge>> edgeMap)
|
||||
{
|
||||
return edgeMap.ContainsKey(c) ? edgeMap[c] : Enumerable.Empty<Edge>();
|
||||
}
|
||||
|
||||
private static IEnumerable<Coordinate> Turns(Coordinate currentDirection)
|
||||
{
|
||||
int index = Array.IndexOf(Coordinate.Directions, currentDirection);
|
||||
return Coordinate.Directions.Skip(index + 1).Concat(Coordinate.Directions.Take(index));
|
||||
}
|
||||
|
||||
private static bool GetCell(int c, int r, BitMatrix matrix)
|
||||
{
|
||||
if (r < 0 || r >= matrix.Height)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (c < 0 || c >= matrix.Width)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return matrix[c, r];
|
||||
}
|
||||
|
||||
private static void RemoveEdge(Edge e, HashSet<Edge> edges, Dictionary<Coordinate, List<Edge>> edgeMap)
|
||||
{
|
||||
edges.Remove(e);
|
||||
edgeMap[e.From].Remove(e);
|
||||
edgeMap[e.To].Remove(e);
|
||||
}
|
||||
|
||||
private static void AddEdge(Edge e, HashSet<Edge> edges, Dictionary<Coordinate, List<Edge>> edgeMap)
|
||||
{
|
||||
edges.Add(e);
|
||||
AddCoordinate(e.From, e, edgeMap);
|
||||
AddCoordinate(e.To, e, edgeMap);
|
||||
}
|
||||
|
||||
private static void AddCoordinate(Coordinate c, Edge e, Dictionary<Coordinate, List<Edge>> edgeMap)
|
||||
{
|
||||
List<Edge> list;
|
||||
if (!edgeMap.TryGetValue(c, out list))
|
||||
{
|
||||
edgeMap[c] = list = new List<Edge>();
|
||||
}
|
||||
list.Add(e);
|
||||
}
|
||||
|
||||
|
||||
private struct Coordinate
|
||||
{
|
||||
public readonly int Row, Col;
|
||||
|
||||
public Coordinate(int col, int row)
|
||||
{
|
||||
Col = col;
|
||||
Row = row;
|
||||
}
|
||||
|
||||
public bool Equals(Coordinate other)
|
||||
{
|
||||
return other.Row == Row && other.Col == Col;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
return false;
|
||||
if (obj.GetType() != typeof(Coordinate))
|
||||
return false;
|
||||
return Equals((Coordinate)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (Row * 397) ^ Col;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var s = "";
|
||||
if (this == North)
|
||||
s = " n";
|
||||
if (this == West)
|
||||
s = " w";
|
||||
if (this == South)
|
||||
s = " s";
|
||||
if (this == East)
|
||||
s = " e";
|
||||
return String.Format("({0}, {1}{2})", Col, Row, s);
|
||||
}
|
||||
|
||||
public static bool operator ==(Coordinate left, Coordinate right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Coordinate left, Coordinate right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public static Coordinate operator +(Coordinate c1, Coordinate c2)
|
||||
{
|
||||
return new Coordinate(c1.Col + c2.Col, c1.Row + c2.Row);
|
||||
}
|
||||
|
||||
public static Coordinate operator -(Coordinate c1, Coordinate c2)
|
||||
{
|
||||
return new Coordinate(c1.Col - c2.Col, c1.Row - c2.Row);
|
||||
}
|
||||
|
||||
public Point ToPoint(double scale)
|
||||
{
|
||||
return new Point(Col * scale, Row * scale);
|
||||
}
|
||||
|
||||
private static readonly Coordinate West = new Coordinate(-1, 0);
|
||||
private static readonly Coordinate South = new Coordinate(0, 1);
|
||||
private static readonly Coordinate East = new Coordinate(1, 0);
|
||||
private static readonly Coordinate North = new Coordinate(0, -1);
|
||||
|
||||
public static readonly Coordinate[] Directions = new[]
|
||||
{
|
||||
West,
|
||||
South,
|
||||
East,
|
||||
North,
|
||||
};
|
||||
}
|
||||
|
||||
private struct Edge
|
||||
{
|
||||
public readonly Coordinate From, To;
|
||||
|
||||
public Edge(Coordinate from, Coordinate to)
|
||||
{
|
||||
From = from;
|
||||
To = to;
|
||||
}
|
||||
|
||||
public Edge(int fromCol, int fromRow, int toCol, int toRow)
|
||||
: this(new Coordinate(fromCol, fromRow), new Coordinate(toCol, toRow))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public bool Equals(Edge other)
|
||||
{
|
||||
return other.From.Equals(From) && other.To.Equals(To);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
return false;
|
||||
if (obj.GetType() != typeof(Edge))
|
||||
return false;
|
||||
return Equals((Edge)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (From.GetHashCode() * 397) ^ To.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
char angle = ' ';
|
||||
if (From.Col == To.Col)
|
||||
{
|
||||
angle = '|';
|
||||
}
|
||||
if (From.Row == To.Row)
|
||||
{
|
||||
angle = '-';
|
||||
}
|
||||
|
||||
|
||||
return string.Format("[{0} {2} {1}]", From, To, angle);
|
||||
}
|
||||
|
||||
public static bool operator ==(Edge left, Edge right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Edge left, Edge right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public Edge Reversed()
|
||||
{
|
||||
return new Edge(To, From);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,6 +279,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
StreamResourceInfo sri = Application.GetResourceStream(new Uri("pack://application:,,,/AIStudio.Wpf.DiagramDesigner;component/Images/FormatPainter.cur", UriKind.RelativeOrAbsolute));
|
||||
this.Cursor = new Cursor(sri.Stream);
|
||||
|
||||
foreach (SelectableDesignerItemViewModelBase item in _viewModel.Items)
|
||||
{
|
||||
item.IsHitTestVisible = false;
|
||||
|
||||
64
AIStudio.Wpf.DiagramDesigner/Helpers/DoubleUtil.cs
Normal file
64
AIStudio.Wpf.DiagramDesigner/Helpers/DoubleUtil.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
using System;
|
||||
|
||||
public static class DoubleUtil
|
||||
{
|
||||
// Const values come from sdk\inc\crt\float.h
|
||||
#pragma warning disable SA1310 // Field names must not contain underscore
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private const double DBL_EPSILON = 2.2204460492503131e-016; /* smallest such that 1.0+DBL_EPSILON != 1.0 */
|
||||
#pragma warning restore SA1310 // Field names must not contain underscore
|
||||
|
||||
/// <summary>
|
||||
/// AreClose - Returns whether or not two doubles are "close". That is, whether or
|
||||
/// not they are within epsilon of each other. Note that this epsilon is proportional
|
||||
/// to the numbers themselves to that AreClose survives scalar multiplication.
|
||||
/// There are plenty of ways for this to return false even for numbers which
|
||||
/// are theoretically identical, so no code calling this should fail to work if this
|
||||
/// returns false. This is important enough to repeat:
|
||||
/// NB: NO CODE CALLING THIS FUNCTION SHOULD DEPEND ON ACCURATE RESULTS - this should be
|
||||
/// used for optimizations *only*.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// bool - the result of the AreClose comparision.
|
||||
/// </returns>
|
||||
/// <param name="value1"> The first double to compare. </param>
|
||||
/// <param name="value2"> The second double to compare. </param>
|
||||
public static bool AreClose(double value1, double value2)
|
||||
{
|
||||
// in case they are Infinities (then epsilon check does not work)
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||
if (value1 == value2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// This computes (|value1-value2| / (|value1| + |value2| + 10.0)) < DBL_EPSILON
|
||||
var eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON;
|
||||
var delta = value1 - value2;
|
||||
return (-eps < delta) && (eps > delta);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GreaterThan - Returns whether or not the first double is greater than the second double.
|
||||
/// That is, whether or not the first is strictly greater than *and* not within epsilon of
|
||||
/// the other number. Note that this epsilon is proportional to the numbers themselves
|
||||
/// to that AreClose survives scalar multiplication. Note,
|
||||
/// There are plenty of ways for this to return false even for numbers which
|
||||
/// are theoretically identical, so no code calling this should fail to work if this
|
||||
/// returns false. This is important enough to repeat:
|
||||
/// NB: NO CODE CALLING THIS FUNCTION SHOULD DEPEND ON ACCURATE RESULTS - this should be
|
||||
/// used for optimizations *only*.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// bool - the result of the GreaterThan comparision.
|
||||
/// </returns>
|
||||
/// <param name="value1"> The first double to compare. </param>
|
||||
/// <param name="value2"> The second double to compare. </param>
|
||||
public static bool GreaterThan(double value1, double value2)
|
||||
{
|
||||
return (value1 > value2) && !AreClose(value1, value2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,10 +192,6 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsHitTestVisible == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _isSelected;
|
||||
}
|
||||
set
|
||||
|
||||
Reference in New Issue
Block a user