首次提交:本地项目同步到Gitea

This commit is contained in:
zhusenlin
2026-01-24 08:45:54 +08:00
commit 4a6b23db69
256 changed files with 25311 additions and 0 deletions

View File

@@ -0,0 +1,207 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
/// <summary>
/// 枚举转换器
/// 用此类之前必须保证在枚举项中定义了Description
/// </summary>
public class EnumConverter : ExpandableObjectConverter
{
/// <summary>
/// 枚举项集合
/// </summary>
Dictionary<object, string> dic;
/// <summary>
/// 构造函数
/// </summary>
public EnumConverter()
{
dic = new Dictionary<object, string>();
}
/// <summary>
/// 加载枚举项集合
/// </summary>
/// <param name="context"></param>
private void LoadDic(ITypeDescriptorContext context)
{
dic = GetEnumValueDesDic(context.PropertyDescriptor.PropertyType);
}
/// <summary>
/// 是否可从来源转换
/// </summary>
/// <param name="context"></param>
/// <param name="sourceType"></param>
/// <returns></returns>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
/// <summary>
/// 从来源转换
/// </summary>
/// <param name="context"></param>
/// <param name="culture"></param>
/// <param name="value"></param>
/// <returns></returns>
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
//如果是枚举
if (context.PropertyDescriptor.PropertyType.IsEnum)
{
if (dic.Count <= 0)
LoadDic(context);
if (dic.Values.Contains(value.ToString()))
{
foreach (object obj in dic.Keys)
{
if (dic[obj] == value.ToString())
{
return obj;
}
}
}
}
}
return base.ConvertFrom(context, culture, value);
}
/// <summary>
/// 是否可转换
/// </summary>
/// <param name="context"></param>
/// <param name="destinationType"></param>
/// <returns></returns>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return true;
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return true;
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
//ListAttribute listAttribute = (ListAttribute)context.PropertyDescriptor.Attributes[typeof(ListAttribute)];
//StandardValuesCollection vals = new TypeConverter.StandardValuesCollection(listAttribute._lst);
//Dictionary<object, string> dic = GetEnumValueDesDic(typeof(PKGenerator));
//StandardValuesCollection vals = new TypeConverter.StandardValuesCollection(dic.Keys);
if (dic == null || dic.Count <= 0)
LoadDic(context);
StandardValuesCollection vals = new TypeConverter.StandardValuesCollection(dic.Keys);
return vals;
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <param name="culture"></param>
/// <param name="value"></param>
/// <param name="destinationType"></param>
/// <returns></returns>
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
//DescriptionAttribute.GetCustomAttribute(
//EnumDescription
//List<KeyValuePair<Enum, string>> mList = UserCombox.ToListForBind(value.GetType());
//foreach (KeyValuePair<Enum, string> mItem in mList)
//{
// if (mItem.Key.Equals(value))
// {
// return mItem.Value;
// }
//}
//return "Error!";
//绑定控件
// FieldInfo fieldinfo = value.GetType().GetField(value.ToString());
//Object[] objs = fieldinfo.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false);
//if (objs == null || objs.Length == 0)
//{
// return value.ToString();
//}
//else
//{
// System.ComponentModel.DescriptionAttribute da = (System.ComponentModel.DescriptionAttribute)objs[0];
// return da.Description;
//}
if (dic.Count <= 0)
LoadDic(context);
foreach (object key in dic.Keys)
{
if (key.ToString() == value.ToString() || dic[key] == value.ToString())
{
return dic[key].ToString();
}
}
return base.ConvertTo(context, culture, value, destinationType);
}
/// <summary>
/// 记载枚举的值+描述
/// </summary>
/// <param name="enumType"></param>
/// <returns></returns>
public Dictionary<object, string> GetEnumValueDesDic(Type enumType)
{
Dictionary<object, string> dic = new Dictionary<object, string>();
FieldInfo[] fieldinfos = enumType.GetFields();
foreach (FieldInfo field in fieldinfos)
{
if (field.FieldType.IsEnum)
{
Object[] objs = field.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (objs.Length > 0)
{
dic.Add(Enum.Parse(enumType, field.Name), ((DescriptionAttribute)objs[0]).Description);
}
}
}
return dic;
}
}
}

View File

@@ -0,0 +1,78 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
/// <summary>
/// 椭圆弧
/// </summary>
public class ShapeArc : ShapeRectangle
{
public ShapeArc()
{
// 设置默认的角度
StartAngle = 0;
SweepAngle = 90;
}
[DescriptionAttribute("弧线的起始角度"), DisplayName("弧线的起始角度"), CategoryAttribute("外观")]
public float StartAngle { get; set; }
[DescriptionAttribute("startAngle 和弧线末尾之间的角度"), DisplayName("夹角"), CategoryAttribute("外观")]
public float SweepAngle { get; set; }
public override ShapeEle DeepClone()
{
// 这里用json的方式
string json = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject<ShapeArc>(json);
//throw new NotImplementedException();
}
public override System.Drawing.RectangleF GetBounds(Matrix matrix)
{
// 这个实际上是矩形的
GraphicsPath path = base.GetGraphicsPathWithAngle();
// 这里加上旋转
Matrix matrix1 = new Matrix();
// 这里按照中心点旋转,
var rect = path.GetBounds();
var centerPoint = new PointF() { X = rect.X + rect.Width / 2, Y = rect.Y + rect.Height / 2 };
matrix1.RotateAt(Angle, centerPoint);
Matrix matrix2 = matrix.Clone();
matrix2.Multiply(matrix1);
// 应用这个转换
path.Transform(matrix2);
return path.GetBounds();
//return base.GetBounds(matrix);
}
public override GraphicsPath GetGraphicsPathWithAngle()
{
GraphicsPath path = new GraphicsPath();
var rect = new System.Drawing.RectangleF()
{
X = getX(),
Y = getY(),
Width = getWidth(),
Height = getHeight(),
};
var rect2 = correctRectangle(rect);
path.AddArc(
rect2,
StartAngle,
SweepAngle);
return path;
//return base.GetGraphicsPathWithAngle();
}
}
}

View File

@@ -0,0 +1,162 @@
using Io.Github.Kerwinxu.LibShapes.Core.Converter;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using ZXing;
using ZXing.Common;
using ZXing.QrCode;
using ZXing.QrCode.Internal;
using ZXing.Rendering;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
public class ShapeBarcode : ShapeVar
{
/// <summary>
/// 构造函数
/// </summary>
public ShapeBarcode()
{
QrCodeErrorLevel = "容错7%"; // 默认这个
Encoding = "CODE_39"; // 默认编码
StaticText = "690123456789"; // 默认数字
isIncludeLabel = true; // 默认包含标签。
IsFill = true;
Font = new Font("Arial", 8); // 默认的字体
}
#region
/// <summary>
/// qr二维码的容错率
/// </summary>
[TypeConverter(typeof(QrCodeErrorCorrectionLevelConverter)), DescriptionAttribute("QR Code编码的容错率"), DisplayName("QR Code容错率"), CategoryAttribute("条形码设置")]
public string QrCodeErrorLevel { get; set; }
/// <summary>
/// 编码类型
/// </summary>
[TypeConverter(typeof(BarcodeEncodingConverter)), DescriptionAttribute("编码"), DisplayName("编码"), CategoryAttribute("条形码设置")]
public string Encoding { get; set; }
/// <summary>
/// 字体
/// </summary>
[DescriptionAttribute("请注意,这个字体是打印机上实际的字体,在界面上不会放大缩小。"), DisplayName("字体"), CategoryAttribute("字体")]
public Font Font { get; set; }
[DescriptionAttribute("是否包含标签"), DisplayName("包含标签"), CategoryAttribute("条形码设置")]
public bool isIncludeLabel { get; set; }
#endregion
public override ShapeEle DeepClone()
{
// 这里用json的方式
string json = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject<ShapeBarcode>(json);
//throw new NotImplementedException();
}
public override void Draw(Graphics g, Matrix matrix)
{
// 请注意,我这个算法是有瑕疵的,
// 这个角度实际上应该是最小内接矩形的角度,
// 这个是个小项目,应用场景是简单的图形操作,
// 如果群组里套图形加上群组有角度,会产生偏差。
// 1.0首先取得没有变换前的坐标
var path = GetGraphicsPath(matrix);
var rect = path.GetBounds(); // 外接矩形,如果是内接矩形是最准的。
// 这里需要将尺寸单位更改一下我的画布是mm而这个zxing估计是像素吧
var rect2 = new Rectangle()
{
//X = (int)(rect.X / 25.4 * g.DpiX),
//Y = (int)(rect.Y / 25.4 * g.DpiY),
Width = (int)(rect.Width / 25.4 * g.DpiX),
Height = (int)(rect.Height / 25.4 * g.DpiX),
};
// 我这里改成一开始就是1比1
// 中心点的坐标
var centerPoint = new PointF()
{
X = rect.X + rect.Width / 2,
Y = rect.Y + rect.Height / 2
};
// 2. 取得条形码图像
BarcodeWriter writer = new BarcodeWriter() {
Renderer = new BitmapRenderer() {
DpiX = g.DpiX,
DpiY = g.DpiY,
TextFont = this.Font,
}
};
writer.Format = BarcodeEncodingConverter.dictBarcode[Encoding]; // 编码
EncodingOptions options = new EncodingOptions()
{
Width = rect2.Width, // 图像的宽和高
Height = rect2.Height,
PureBarcode = !isIncludeLabel, // 是否包括标签。
Margin = 2,
};
if (Encoding == "QR_CODE")
{
options = new QrCodeEncodingOptions() {
Width = (int)rect2.Width, // 图像的宽和高
Height = (int)rect2.Height,
PureBarcode = !isIncludeLabel, // 是否包括标签。
Margin = 2,
ErrorCorrection=QrCodeErrorCorrectionLevelConverter.level[QrCodeErrorLevel],
};
}
writer.Options = options;
var text = getText();
if (string.IsNullOrEmpty(text))
{
// 如果没有,就话一个矩形吧。就什么都不做。
}
else
{
var bitmap = writer.Write(text); // 生成条形码图像。
if (bitmap != null)
{
// 3. 转换。
Matrix matrix1 = new Matrix();
matrix1.RotateAt(this.Angle, centerPoint);
g.Transform = matrix1; // 应用这个变换。
// 4.
g.DrawImage(bitmap, rect.X, rect.Y, rect.Width, rect.Height);
//5.
g.ResetTransform(); // 取消这个变换
}
}
//base.Draw(g, matrix);
}
public override GraphicsPath GetGraphicsPathWithAngle()
{
// 这个直接是返回父类的,
return base.GetGraphicsPathWithAngle();
}
}
}

View File

@@ -0,0 +1,357 @@
using Io.Github.Kerwinxu.LibShapes.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
/// <summary>
/// 形状的基类
/// </summary>
public abstract class ShapeEle
{
/// <summary>
/// 构造函数
/// </summary>
public ShapeEle()
{
// 提供一些默认的参数
PenWidth = 1;
PenColor = Color.Black;
}
#region
#region
/// <summary>
/// 唯一的标识符
/// </summary>
[CategoryAttribute("设计")]
public int ID { get; set; }
#endregion
#region
[CategoryAttribute("布局")]
public float X { get; set; }
[CategoryAttribute("布局")]
public float Y { get; set; }
[DescriptionAttribute("宽度"), DisplayName("宽度"), CategoryAttribute("布局")]
public float Width { get; set; }
[DescriptionAttribute("高度"), DisplayName("高度"), CategoryAttribute("布局")]
public float Height { get; set; }
[DescriptionAttribute("角度"), DisplayName("角度"), CategoryAttribute("外观")]
public float Angle { get; set; }
#endregion
#region
[DescriptionAttribute("边框颜色"), DisplayName("边框颜色"), CategoryAttribute("外观")]
public Color PenColor { get; set; }
[DescriptionAttribute("边框粗细"), DisplayName("边框粗细"), CategoryAttribute("外观")]
public float PenWidth { get; set; }
[DescriptionAttribute("虚线的样式"), DisplayName("虚线的样式"), CategoryAttribute("外观")]
public DashStyle PenDashStyle { get; set; }
[DescriptionAttribute("是否填充"), DisplayName("是否填充"), CategoryAttribute("外观")]
public bool IsFill { get; set; }
[DescriptionAttribute("填充颜色"), DisplayName("填充颜色"), CategoryAttribute("外观")]
public Color FillColor { get; set; }
#region
float x_add, y_add, width_add, height_add;
#endregion
#endregion
#endregion
#region
public virtual void Draw(Graphics g, Matrix matrix) {
// 首先取得绘图路径
try
{
var path = GetGraphicsPath(matrix);
// 定义画笔
Pen pen = new Pen(PenColor);
pen.Width = PenWidth; // 画笔的粗细
pen.DashStyle = PenDashStyle; // 虚线的样式
g.DrawPath(pen, path); // 画边框
if (IsFill) // 如果填充
{
Brush brush = new SolidBrush(FillColor);
g.FillPath(brush, path);
}
path.Dispose();
}
catch (Exception ex)
{
//throw;
}
}
/// <summary>
/// 这个返回的是屏幕画布上的真实的坐标体系
/// </summary>
/// <param name="matrix"></param>
/// <returns></returns>
public virtual GraphicsPath GetGraphicsPath(Matrix matrix)
{
GraphicsPath path = null;
if (getWidth() == 0 || getHeight() == 0)
{
// 这里表示只是一条线段或者一个点了
path = new GraphicsPath();
path.AddLine(new PointF(getX(), getY()), new PointF(getX() + getWidth(), getY() + getHeight()));
}
else
{
path = GetGraphicsPathWithAngle();
}
// 这里加上旋转
Matrix matrix1 = new Matrix();
// 这里按照中心点旋转,
var rect = path.GetBounds();
var centerPoint = new PointF() { X = rect.X + rect.Width / 2, Y = rect.Y + rect.Height / 2 };
matrix1.RotateAt(Angle, centerPoint);
Matrix matrix2 = matrix.Clone();
matrix2.Multiply(matrix1);
// 应用这个转换
path.Transform(matrix2);
// 返回这个路径
return path;
}
/// <summary>
/// 矫正矩形,宽和高都不能是复数
/// </summary>
/// <param name="rect"></param>
/// <returns></returns>
protected RectangleF correctRectangle(RectangleF rect)
{
RectangleF rect2 = new RectangleF() {
X = rect.X,
Y = rect.Y,
Width = rect.Width,
Height = rect.Height,
};
if (rect2.Width < 0)
{
rect2.X += rect2.Width;
rect2.Width = -rect2.Width;
}
if (rect2.Height < 0)
{
rect2.Y += rect2.Height;
rect2.Height = -rect2.Height;
}
return rect2;
}
/// <summary>
/// 返回不包括旋转的路径,且这个是虚拟世界的坐标,不用考虑画布中实际的坐标。
/// </summary>
/// <returns></returns>
public virtual GraphicsPath GetGraphicsPathWithAngle()
{
GraphicsPath path = new GraphicsPath();
var rect = new System.Drawing.RectangleF()
{
X = getX(),
Y = getY(),
Width = getWidth(),
Height = getHeight()
};
var rect2 = correctRectangle(rect);
path.AddRectangle(rect2);
return path;
}
/// <summary>
/// 返回外接矩形
/// </summary>
/// <returns></returns>
public virtual RectangleF GetBounds(Matrix matrix)
{
// 请注意,这里是以旋转后的。
return GetGraphicsPath(matrix).GetBounds();
}
/// <summary>
/// 选择的容忍度
/// </summary>
private Pen pen_select_tolerance = new Pen(Color.White) {
Width = DistanceCalculation.select_tolerance
};
/// <summary>
/// 这个点是否在这个图形的轮廓上
/// </summary>
/// <param name="mousePointF"></param>
/// <returns></returns>
public virtual bool isOutlineVisible(Matrix matrix, PointF mousePointF)
{
var pen = new Pen(new SolidBrush(this.PenColor), this.PenWidth);
return GetGraphicsPath(matrix).IsOutlineVisible(mousePointF, pen);
//return GetGraphicsPath(matrix).IsVisible(mousePointF);
}
/// <summary>
/// 这个点是否在这个图形的的内部
/// </summary>
/// <param name="mousePointF"></param>
/// <returns></returns>
public virtual bool isVisible(Matrix matrix, PointF mousePointF)
{
return GetGraphicsPath(matrix).IsVisible(mousePointF);
//return GetGraphicsPath(matrix).IsVisible(mousePointF);
}
/// <summary>
/// 这个表示是否被包含在这个矩形内
/// </summary>
/// <param name="rect"></param>
/// <returns></returns>
public virtual bool isBeContains(Matrix matrix, RectangleF rect)
{
var rect2 = GetBounds(matrix);
return rect.Contains(rect2);
}
public virtual void setVals(Dictionary<string, string> vars)
{
// 什么都不做,子类如果需要,就自己实现。
}
/// <summary>
/// 根据这个矩形更改
/// </summary>
/// <param name="rect"></param>
public void Change(RectangleF rect)
{
x_add = rect.X;
y_add = rect.Y;
width_add = rect.Width;
height_add = rect.Height;
}
public virtual void ChangeComplated()
{
// 将更改固定下来
X += x_add;
Y += y_add;
Width += width_add;
Height += height_add;
// 清零
x_add = 0;
y_add = 0;
width_add = 0;
height_add = 0;
// 这里要注意矫正 todo
if (Width < 0)
{
X += Width;
Width = -Width;
}
if (Height < 0)
{
Y += Height;
Height = -Height;
}
}
/// <summary>
/// 深度拷贝
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public abstract ShapeEle DeepClone();
public override bool Equals(object obj)
{
// 首先判断是否是
var shape = obj as ShapeEle;
if (shape == null) return false; // 转换失败就是不同啦
return this.X == shape.X &&
this.Y == shape.Y &&
this.Width == shape.Width &&
this.Height == shape.Height &&
this.Angle == shape.Angle &&
this.ID == shape.ID &&
this.PenColor == shape.PenColor &&
this.PenWidth == shape.PenWidth &&
this.PenDashStyle == shape.PenDashStyle &&
this.IsFill == shape.IsFill &&
this.FillColor == shape.FillColor;
//return base.Equals(obj);
}
#region add后的参数
protected float getX()
{
return X + x_add;
}
protected float getY()
{
return Y + y_add;
}
protected float getWidth()
{
return Width + width_add;
}
protected float getHeight()
{
return Height + height_add;
}
#endregion
#endregion
public override int GetHashCode()
{
return ID * base.GetHashCode();
//return base.GetHashCode();
}
}
}

View File

@@ -0,0 +1,41 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
/// <summary>
/// 椭圆
/// </summary>
public class ShapeEllipse : ShapeEle
{
public override ShapeEle DeepClone()
{
// 这里用json的方式
string json = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject<ShapeEllipse>(json);
}
public override GraphicsPath GetGraphicsPathWithAngle()
{
GraphicsPath path = new GraphicsPath();
var rect = new System.Drawing.RectangleF()
{
X = getX(),
Y = getY(),
Width = getWidth(),
Height = getHeight()
};
var rect2 = correctRectangle(rect);
path.AddEllipse(rect2); // 跟矩形不同的是这里的是AddEllipse
return path;
//return base.GetGraphicsPathWithAngle();
}
}
}

View File

@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
public class ShapeGroup : ShapeMulti
{
/// <summary>
/// 这个重新是因为这个要真正的绘制而ShapeMultiSelect不需要ShapeMultiSelect里保存的只是多个形状的引用。
/// </summary>
/// <param name="g"></param>
/// <param name="matrix"></param>
public override void Draw(Graphics g, Matrix matrix)
{
// 这里首先要注意的是这个可以旋转的
Matrix matrix1 = matrix.Clone();
var rect = GetGraphicsPathWithAngle().GetBounds();
var centerPoint = new PointF() {
X = rect.X + rect.Width / 2,
Y = rect.Y + rect.Height / 2
};
matrix1.RotateAt(Angle, centerPoint);
foreach (var item in shapes)
{
item.Draw(g, matrix1);
}
}
/// <summary>
/// 这个其实是取得了含有角度的。
/// </summary>
/// <returns></returns>
public override GraphicsPath GetGraphicsPathWithAngle()
{
// 这个不需要返回什么。
return null;
}
public override ShapeEle DeepClone()
{
// 首先组建一个新的
ShapeGroup group = new ShapeGroup();
if (shapes != null)
{
foreach (var item in shapes)
{
group.shapes.Add(item.DeepClone());
}
}
return group;
//throw new NotImplementedException();
}
public override bool Equals(object obj)
{
var shape = obj as ShapeGroup;
if (shape == null) return false; // 转换失败就是不同啦
// 群组,需要判断每一个是否相同。
if (shapes.Count != shape.shapes.Count) return false;
for (int i = 0; i < shapes.Count; i++)
{
if (shapes[i] != shape.shapes[i])
{
return false;
}
}
return true;
//return base.Equals(obj);
}
public override int GetHashCode()
{
return this.ID;
return base.GetHashCode();
}
}
}

View File

@@ -0,0 +1,155 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Text;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
/// <summary>
/// 图片
/// </summary>
public class ShapeImage : ShapeVar
{
public ShapeImage()
{
IsFill = true; // 这样可以方便的选择。
}
// 这个不用ShapeVar中的StaticText是因为我不想显示并且也不用GetText是因为这个默认情况下变量意味着路径而Img意味着静态的图片。
[Browsable(false)]//不在PropertyGrid上显示
public string Img { get; set; }
public override ShapeEle DeepClone()
{
// 这里用json的方式
string json = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject<ShapeImage>(json);
}
public override void Draw(Graphics g, Matrix matrix)
{
// 请注意,我这个算法是有瑕疵的,
// 这个角度实际上应该是最小内接矩形的角度,
// 这个是个小项目,应用场景是简单的图形操作,
// 如果群组里套图形加上群组有角度,会产生偏差。
// 1.0首先取得没有变换前的坐标
var path = GetGraphicsPath(matrix);
var rect = path.GetBounds(); // 外接矩形,如果是内接矩形是最准的。
var centerPoint = new PointF() // 中心点的坐标
{
X = rect.X + rect.Width/2,
Y= rect.Y + rect.Height/2
};
// 2. 取得图片对象
var bitmap = getImg();
if (bitmap != null)
{
// 3. 转换。
Matrix matrix1 = new Matrix();
matrix1.RotateAt(this.Angle, centerPoint);
g.Transform = matrix1; // 应用这个变换。
// 4.
// todo 以后添加上拉伸的判断。
g.DrawImage(bitmap, rect.X, rect.Y, rect.Width, rect.Height);
//5.
g.ResetTransform(); // 取消这个变换
}
//base.Draw(g, matrix);
}
private Bitmap getImg()
{
try
{
if (string.IsNullOrEmpty(this.VarName))
{
return Base64StringToImage(this.Img);
}
else
{
// 这里表示是有路径
if (File.Exists(this.VarValue))
{
// 如果路径存在
return (Bitmap)Image.FromFile(this.VarValue);
}
return null;
}
}
catch (Exception)
{
//throw;
}
return null;
}
public override GraphicsPath GetGraphicsPathWithAngle()
{
return base.GetGraphicsPathWithAngle();
}
#region
public static string ImgToBase64String(Bitmap bmp)
{
try
{
//如下是为了预防GDI一般性错误而深度复制
Bitmap bmp2 = new Bitmap(bmp);
MemoryStream ms = new MemoryStream();
bmp2.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] arr = new byte[ms.Length];
ms.Position = 0;
ms.Read(arr, 0, (int)ms.Length);
ms.Close();
String strbaser64 = Convert.ToBase64String(arr);
bmp2.Dispose();
return strbaser64;
}
catch (Exception ex)
{
return "";
}
}
//base64编码的文本 转为图片
public static Bitmap Base64StringToImage(string strbaser64)
{
try
{
byte[] arr = Convert.FromBase64String(strbaser64);
MemoryStream ms = new MemoryStream(arr);
Bitmap bmp = new Bitmap(ms);
ms.Close();
return bmp;
}
catch (Exception ex)
{
return new Bitmap(10, 10);
}
}
#endregion
}
}

View File

@@ -0,0 +1,50 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
/// <summary>
/// 线段
/// </summary>
public class ShapeLine : ShapeEle
{
public override ShapeEle DeepClone()
{
// 这里用json的方式
string json = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject<ShapeLine>(json);
//throw new NotImplementedException();
}
public override GraphicsPath GetGraphicsPathWithAngle()
{
GraphicsPath path = new GraphicsPath();
path.AddLine(getX(), getY(), getX()+getWidth(), getY()+getHeight());
return path;
//throw new NotImplementedException();
}
///// <summary>
///// 是否取得线段的。
///// </summary>
///// <param name="matrix"></param>
///// <param name="mousePointF"></param>
///// <returns></returns>
//public override bool isContains(Matrix matrix, PointF mousePointF)
//{
// // 这里用点到线段的距离来判断的,
// var path = GetGraphicsPath(matrix);// 取得路径
// var points = path.PathPoints; // 取得路径上的点
// bool b = SelectStrategy.isNear(mousePointF, points[0], points[1]);
// return b;
// //return base.isContains(matrix, mousePointF);
//}
}
}

View File

@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
/// <summary>
/// 多个形状的集合
/// </summary>
public class ShapeMulti:ShapeEle
{
public List<ShapeEle> shapes = new List<ShapeEle>();
public override ShapeEle DeepClone()
{
// 首先组建一个新的
ShapeMulti group = new ShapeMulti();
if (shapes != null)
{
foreach (var item in shapes)
{
group.shapes.Add(item.DeepClone());
}
}
return group;
//throw new NotImplementedException();
}
/// <summary>
/// 取得
/// </summary>
/// <param name="matrix"></param>
/// <returns></returns>
public override GraphicsPath GetGraphicsPath(Matrix matrix)
{
// 这里要先算子形状的所有的路径
GraphicsPath path = new GraphicsPath();
foreach (var item in shapes)
{
path.AddPath(item.GetGraphicsPath(matrix), false);
}
// 然后对这个进行旋转
var rect = path.GetBounds();
var centerPoints = new PointF()
{
X = rect.X + rect.Width / 2,
Y = rect.Y + rect.Height / 2
};
Matrix matrix1 = new Matrix();
matrix1.RotateAt(Angle, centerPoints);
path.Transform(matrix1);
return path;
}
public override bool Equals(object obj)
{
var shape = obj as ShapeMulti;
if (shape == null) return false; // 转换失败就是不同啦
// 群组,需要判断每一个是否相同。
if (shapes.Count != shape.shapes.Count) return false;
for (int i = 0; i < shapes.Count; i++)
{
if (shapes[i] != shape.shapes[i])
{
return false;
}
}
return true;
//return base.Equals(obj);
}
public override int GetHashCode()
{
return this.ID;
return base.GetHashCode();
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
/// <summary>
/// 选择了多个形状后,就放在这里边。
/// </summary>
public class ShapeMultiSelect: ShapeMulti
{
public override ShapeEle DeepClone()
{
// 首先组建一个新的
ShapeMultiSelect group = new ShapeMultiSelect();
if (shapes != null)
{
foreach (var item in shapes)
{
group.shapes.Add(item.DeepClone());
}
}
return group;
//return base.DeepClone();
}
}
}

View File

@@ -0,0 +1,48 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
/// <summary>
/// 扇形,跟弧度的区别是没有那个边框吧。
/// </summary>
public class ShapePie : ShapeArc
{
public override ShapeEle DeepClone()
{
// 这里用json的方式
string json = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject<ShapePie>(json);
}
public override GraphicsPath GetGraphicsPathWithAngle()
{
GraphicsPath path = new GraphicsPath();
var rect = new System.Drawing.RectangleF()
{
X = getX(),
Y = getY(),
Width = getWidth(),
Height = getHeight(),
};
var rect2 = correctRectangle(rect);
path.AddPie(
rect2.X,
rect2.Y,
rect2.Width,
rect2.Height,
StartAngle,
SweepAngle);
return path;
//return base.GetGraphicsPathWithAngle();
}
}
}

View File

@@ -0,0 +1,36 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
/// <summary>
/// 矩形
/// </summary>
public class ShapeRectangle : ShapeEle
{
// 我将这个部分移动到ShapeEle部分了,默认情况下就是这种。
//public override GraphicsPath GetGraphicsPathWithAngle()
//{
// GraphicsPath path = new GraphicsPath();
// path.AddRectangle(new System.Drawing.RectangleF() {
// X = getX(),
// Y = getY(),
// Width = getWidth(),
// Height = getHeight()
// });
// return path;
// //throw new NotImplementedException();
//}
public override ShapeEle DeepClone()
{
string json = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject<ShapeRectangle>(json);
//throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,70 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Drawing;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
/// <summary>
/// 圆角矩形
/// </summary>
public class ShapeRoundedRectangle : ShapeEle
{
[DescriptionAttribute("圆角半径"), DisplayName("圆角半径"), CategoryAttribute("布局")]
public float Radius { get; set; }
/// <summary>
/// 构造函数
/// </summary>
public ShapeRoundedRectangle()
{
// 有些参数默认不能是0
Radius = 2;
}
public override ShapeEle DeepClone()
{
// 这里用json的方式
string json = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject<ShapeRoundedRectangle>(json);
//throw new NotImplementedException();
}
public override GraphicsPath GetGraphicsPathWithAngle()
{
var _x = getX();
var _y = getY();
var _width = getWidth();
var _height = getHeight();
var path = new GraphicsPath();
// 这里要注意判断圆角半径可能是0的情况。
path.StartFigure();
// 上边
path.AddLine(new PointF(_x + Radius, _y), new PointF(_x + _width - Radius, _y));
// 右上角
if(Radius > 0) path.AddArc(new RectangleF(_x + _width - Radius * 2 , _y, Radius* 2, Radius * 2), 270, 90);
// 右边
path.AddLine(new PointF(_x + _width, _y + Radius), new PointF(_x + _width, _y + _height - Radius));
// 右下角
if (Radius > 0) path.AddArc(new RectangleF(_x + _width - Radius * 2, _y + _height - Radius * 2, Radius*2, Radius*2), 0, 90);
// 下边
path.AddLine(new PointF(_x + Radius, _y + _height), new PointF(_x + _width - Radius , _y + _height));
// 右下角
if (Radius > 0) path.AddArc(new RectangleF(_x, _y + _height - Radius*2, Radius*2, Radius*2), 90, 90);
// 左边
path.AddLine(new PointF(_x, _y + Radius ), new PointF(_x, _y + _height - Radius));
// 左上角
if (Radius > 0) path.AddArc(new RectangleF(_x, _y, Radius*2, Radius*2), 180, 90);
path.CloseFigure();
return path;
//return base.GetGraphicsPathWithAngle();
}
}
}

View File

@@ -0,0 +1,29 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
/// <summary>
/// 拉伸
/// </summary>
public class ShapeStretch : ShapeEle
{
[DescriptionAttribute("拉伸"), DisplayName("拉伸"), CategoryAttribute("外观")]
public bool isStretch { get; set; }
public override ShapeEle DeepClone()
{
// 这里用json的方式
string json = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject<ShapeStretch>(json);
//throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,171 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
// todo 这个以后支持拉伸。
/// <summary>
/// 文本
/// </summary>
public class ShapeText : ShapeVar
{
#region
[DescriptionAttribute("前缀"), DisplayName("前缀"), CategoryAttribute("文本")]
public string Piefix { get; set; }
[DescriptionAttribute("后缀"), DisplayName("后缀"), CategoryAttribute("文本")]
public string Suffix { get; set; }
#endregion
#region
[DescriptionAttribute("字体"), DisplayName("字体"), CategoryAttribute("字体")]
public Font Font { get; set; }
[DescriptionAttribute("水平对齐方式"), DisplayName("水平对齐方式"), CategoryAttribute("字体")]
public StringAlignment Alignment { get; set; }
[DescriptionAttribute("垂直对齐方式"), DisplayName("垂直对齐方式"), CategoryAttribute("字体")]
public StringAlignment LineAlignment { get; set; }
#endregion
public ShapeText() : base()
{
// 设置摩尔默认的字体。
Font = new Font("Arial", 8);
Piefix = "前缀";
StaticText = "文本";
Suffix = "后缀";
PenWidth = 0;
IsFill = true;
FillColor = Color.Black;
}
public override ShapeEle DeepClone()
{
// 这里用json的方式
string json = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject<ShapeText>(json);
//throw new NotImplementedException();
}
public override string getText()
{
return Piefix + (string.IsNullOrEmpty(this.VarName) ? StaticText : this.VarValue) + Suffix;
}
public override bool isVisible(Matrix matrix, PointF mousePointF)
{
// todo 这个是判断文本框的内部。
return base.isVisible(matrix, mousePointF);
}
public override bool isOutlineVisible(Matrix matrix, PointF mousePointF)
{
// 这个会
return base.isOutlineVisible(matrix, mousePointF) || isVisible(matrix, mousePointF);
}
public override GraphicsPath GetGraphicsPathWithAngle()
{
GraphicsPath path = new GraphicsPath();
var rect = new RectangleF()
{
X = getX(),
Y = getY(),
Width = getWidth(),
Height = getWidth(),
};
path.AddString(
getText(),
Font.FontFamily,
(int)Font.Style,
Font.Size,
rect,
new StringFormat() { Alignment=Alignment, LineAlignment=LineAlignment}
);
return path;
//throw new NotImplementedException();
}
public override bool isBeContains(Matrix matrix, RectangleF rect)
{
// 这个要判断是否整个文本内容是否在这个矩形内,而不是单独的看这个文本的框。
// 这里要判断是否有文字,有时候没有文字,就按照基类的吧
RectangleF rect2;
if(getText() != string.Empty)
{
// 如果有文字,返回文字的范围
rect2 = GetTrueBounds(matrix);
}
else
{
// 如果没有文字,就选择外边边框的范围
rect2 = GetBounds(matrix);
}
return rect.Contains(rect2);
//return base.isBeContains(matrix, rect);
}
/// <summary>
/// 这个返回的是矩形边框
/// </summary>
/// <param name="matrix"></param>
/// <returns></returns>
public override RectangleF GetBounds(Matrix matrix)
{
// 这里不用这个文本图形的GetGraphicsPathWithAngle而是调用矩形的。
GraphicsPath path = base.GetGraphicsPathWithAngle();
// 这里加上旋转
Matrix matrix1 = new Matrix();
// 这里按照中心点旋转,
var rect = path.GetBounds();
var centerPoint = new PointF() { X = rect.X + rect.Width / 2, Y = rect.Y + rect.Height / 2 };
matrix1.RotateAt(Angle, centerPoint);
Matrix matrix2 = matrix.Clone();
matrix2.Multiply(matrix1);
// 应用这个转换
path.Transform(matrix2);
// 返回这个矩形
return path.GetBounds();
//return base.GetBounds(matrix);
}
/// <summary>
/// 返回的是实际文字的边框
/// </summary>
/// <param name="matrix"></param>
/// <returns></returns>
public RectangleF GetTrueBounds(Matrix matrix)
{
GraphicsPath path = GetGraphicsPathWithAngle();
// 这里加上旋转
Matrix matrix1 = new Matrix();
// 这里按照中心点旋转,
var rect = path.GetBounds();
// 我这里做一个判断如果这里上边的全是0那么就手动计算宽度和高度吧
var centerPoint = new PointF() { X = rect.X + rect.Width / 2, Y = rect.Y + rect.Height / 2 };
matrix1.RotateAt(Angle, centerPoint);
Matrix matrix2 = matrix.Clone();
matrix2.Multiply(matrix1);
// 应用这个转换
path.Transform(matrix2);
// 返回这个路径
return path.GetBounds();
//return base.GetBounds(matrix);
}
}
}

View File

@@ -0,0 +1,70 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace Io.Github.Kerwinxu.LibShapes.Core.Shape
{
/// <summary>
/// 变量,主要是支持外部输入变量
/// </summary>
public class ShapeVar : ShapeStretch
{
[DescriptionAttribute("对应excel中的一列数据"), DisplayName("变量名"), CategoryAttribute("变量")]
public string VarName { get; set; }
[Browsable(false)]//不在PropertyGrid上显示
public string VarValue { get; set; }
[DescriptionAttribute("没有指定变量时的文本"), DisplayName("文本"), CategoryAttribute("文本")]
public string StaticText { get; set; }
public override ShapeEle DeepClone()
{
// 这里用json的方式
string json = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject<ShapeVar>(json);
//throw new NotImplementedException();
}
public override void setVals(Dictionary<string, string> vars)
{
if (VarName != null)
{
//首先判断是否有这个
if (vars.ContainsKey(VarName))
{
VarValue = vars[VarName]; // 这个变量的值
}
else
{
VarValue = string.Empty; // 没有是空字符串。
}
}
}
/// <summary>
/// 取得文本
/// </summary>
/// <returns></returns>
public virtual string getText()
{
return string.IsNullOrEmpty(this.VarName) ? StaticText : this.VarValue;
}
public override bool Equals(object obj)
{
var shape = obj as ShapeVar;
if (shape == null) return false; // 转换失败就是不同啦
return base.Equals(obj) && this.VarName == shape.VarName;
}
}
}