check point

This commit is contained in:
meelstorm
2025-07-14 12:03:59 +02:00
commit d3cb790bd9
431 changed files with 44078 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
namespace Hawkeye.VisionBuilder.Features.ImagePreview;
public enum EControlMode
{
Preview,
Creation
}

View File

@@ -0,0 +1,37 @@
namespace Hawkeye.VisionBuilder.Features.ImagePreview
{
partial class ImagePreviewControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
}
#endregion
}
}

View File

@@ -0,0 +1,329 @@
using System.Drawing;
using System.Drawing.Drawing2D;
using Hawkeye.VisionBuilder.Workflow;
using Hawkeye.VisionBuilder.Workflow.Datatypes;
using Hawkeye.VisionBuilder.Workflow.Datatypes.Elements;
using Hawkeye.VisionBuilder.Workflow.Datatypes.Elements.Origin;
using Hawkeye.VisionBuilder.Workflow.Datatypes.Elements.Poly;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using Point = System.Drawing.Point;
using PointF = System.Drawing.PointF;
using Matrix = Hawkeye.VisionBuilder.Workflow.Matrix;
using Vector2 = Hawkeye.VisionBuilder.Workflow.Vector2;
namespace Hawkeye.VisionBuilder.Features.ImagePreview
{
public partial class ImagePreviewControl : UserControl,ICanvas
{
private Bitmap _backBuffer;
public List<IGraphicsElement> GraphicsElements { get; set; }=new List<IGraphicsElement>();
public EControlMode Mode { get; set; } = EControlMode.Preview;
public Hawkeye.VisionBuilder.Workflow.Datatypes.HawkeyeImage Image
{
get => _image;
set
{
var needsCentering = _image == null;
_image = value;
if(needsCentering) CenterImage();
}
}
public void CenterImage()
{
TransformationMatrix= Workflow.Matrix.Identity;
var hRatio = Width/ (float)_image.ImageData.Width;
var vRatio = Height / (float) _image.ImageData.Height;
TransformationMatrix*=Matrix.CreateScale(Math.Min(hRatio,vRatio));
var shift = new Vector2(Width,Height)- Vector2.Transform(new Vector2(_image.ImageData.Width, _image.ImageData.Height),
TransformationMatrix);
TransformationMatrix *= Matrix.CreateTranslation(shift.X / 2f, shift.Y / 2f, 0);
}
public ImagePreviewControl()
{
InitializeComponent();
_backBuffer = new Bitmap(Width, Height);
MouseWheel += ZoomPictureBoxWheel_MouseWheel;
DoubleClick += ZoomPictureBoxWheel_DoubleClick;
DoubleBuffered = true;
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
private void ZoomPictureBoxWheel_DoubleClick(object sender, EventArgs e)
{
Invalidate();
}
private float _zoom = 1;
private void ZoomPictureBoxWheel_MouseWheel(object sender, MouseEventArgs e)
{
_zoom *= (e.Delta > 0) ? 0.9f : (1f / 0.9f);
TransformationMatrix = TransformationMatrix
* Matrix.CreateTranslation(-_lastMousePosition.X, -_lastMousePosition.Y, 0)
* Matrix.CreateScale((e.Delta > 0) ? 0.9f : (1f / 0.9f))
* Matrix.CreateTranslation(_lastMousePosition.X, _lastMousePosition.Y, 0);
Invalidate();
}
public void FitToScreen()
{
if (Image == null) return;
var width = Image.ImageData.Width;
var height = Image.ImageData.Height;
var aspectRatio = (float)width / height;
var screenAspectRatio = (float)Width / Height;
if (aspectRatio > screenAspectRatio)
{
_zoom = Width / (float)width;
TransformationMatrix = Matrix.Identity;
TransformationMatrix *= Matrix.CreateScale(_zoom);
var shift = new Vector2(Width, Height) - Vector2.Transform(new Vector2(width, height),
TransformationMatrix);
TransformationMatrix *= Matrix.CreateTranslation(shift.X / 2f, shift.Y / 2f, 0);
}
else
{
_zoom = Height / (float)height;
TransformationMatrix = Matrix.Identity;
TransformationMatrix *= Matrix.CreateScale(_zoom);
var shift = new Vector2(Width, Height) - Vector2.Transform(new Vector2(width, height),
TransformationMatrix);
TransformationMatrix *= Matrix.CreateTranslation(shift.X / 2f, shift.Y / 2f, 0);
}
Invalidate();
}
private MouseButtons _mouseButton = MouseButtons.None;
public Matrix TransformationMatrix { get; set; }=Matrix.Identity;
private Vector2 _lastMousePosition;
private const float NODE_SIZE = 10;
protected override void OnMouseDown(MouseEventArgs e)
{
_mouseButton = e.Button;
_lastMousePosition = new Vector2(e.X, e.Y);
var threshold = NODE_SIZE / _zoom ;
var inverted = Matrix.Invert(TransformationMatrix);
var imageCoords = Vector2.Transform(new Vector2(e.X, e.Y), inverted);
_selectedNode=GraphicsElements.Where(x=>x.Editable).Select(x => x.GetNode(imageCoords, threshold)).FirstOrDefault(x => x != null);
}
protected override void OnMouseUp(MouseEventArgs e)
{
_mouseButton = MouseButtons.None;
}
ToolTip _toolTip = new ToolTip();
static bool RectangleContainsPoint(int x, int y, int width, int height, int px, int py)
{
return px >= x && px <= x + width && py >= y && py <= y + height;
}
protected override void OnMouseLeave(EventArgs e)
{
_toolTip.Hide(this);
}
string GetContourInfo(Mat image, int x, int y)
{
var contours = image.FindContoursAsArray(RetrievalModes.List, ContourApproximationModes.ApproxSimple);
var contour = contours.FirstOrDefault(c => Cv2.PointPolygonTest(c, new Point2f(x, y), false) >= 0);
if (contour == null) return "No contour";
var area = Cv2.ContourArea(contour);
var rect = Cv2.BoundingRect(contour);
var width = rect.Width;
var height = rect.Height;
return $"Area: {area}, Width: {width}, Height: {height}";
}
protected override void OnMouseMove(MouseEventArgs e)
{
// if Ctrl is pressed
if ((ModifierKeys & Keys.Control) != 0&&_mouseButton == MouseButtons.None)
{
if(Image==null||Image.ImageData==null) return;
var inverted = Matrix.Invert(TransformationMatrix);
var imageCoords = Vector2.Transform(new Vector2(e.X, e.Y), inverted);
if(!RectangleContainsPoint(0,0,Image.ImageData.Width,Image.ImageData.Height,(int)imageCoords.X,(int)imageCoords.Y)) return;
if (Image.ImageData.Type() == MatType.CV_8UC3)
{
var pixel = Image.ImageData.Get<Vec3b>((int)imageCoords.Y,(int)imageCoords.X);
_toolTip.Show($"R:{pixel.Item0} G:{pixel.Item1} B:{pixel.Item2}", this, e.X + 15, e.Y + 15, 5000);
return;
}
if (Image.ImageData.Type() == MatType.CV_8UC1)
{
var pixel = Image.ImageData.Get<byte>((int)imageCoords.Y,(int)imageCoords.X);
var info= GetContourInfo(Image.ImageData, (int)imageCoords.X, (int)imageCoords.Y);
_toolTip.Show($"Gray:{pixel}\n"+info, this, e.X+15, e.Y+15,5000);
return;
}
return;
}
if (Mode == EControlMode.Preview)
{
if (_mouseButton == MouseButtons.Middle)
{
TransformationMatrix *=
Matrix.CreateTranslation(e.X - _lastMousePosition.X, e.Y - _lastMousePosition.Y, 0);
}
}
_mouseShift = new Vector2(e.X, e.Y) - _lastMousePosition;
if (_mouseButton == MouseButtons.Left&& _selectedNode != null)
{
var inverted = Matrix.Invert(TransformationMatrix);
var transformed = Vector2.Transform(new Vector2(e.X, e.Y), inverted);
_selectedNode.SetPosition(transformed);
}
_lastMousePosition = new Vector2(e.X, e.Y);
Invalidate();
}
private Graphics _currentGraphics;
private Workflow.Datatypes.HawkeyeImage? _image;
private Vector2 _mouseShift;
private INode _selectedNode;
protected override void OnPaint(PaintEventArgs pe)
{
if (Image == null)
{
pe.Graphics.Clear(Color.Black);
return;
}
try
{
using (Graphics g = Graphics.FromImage(_backBuffer))
{
_currentGraphics = g;
g.Clear(Color.Black);
var img = Image.ImageData.ToBitmap();
var pos = Vector2.Transform(new Vector2(0, 0), TransformationMatrix);
var size = Vector2.Transform(new Vector2(img.Width, img.Height), TransformationMatrix);
g.DrawImage(img, pos.X, pos.Y, size.X - pos.X, size.Y - pos.Y);
foreach (IGraphicsElement element in GraphicsElements)
{
element.Draw(this);
}
}
pe.Graphics.DrawImage(_backBuffer, 0, 0);
}
catch
{
}
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
//base.OnPaintBackground(pevent);
}
protected override void OnResize(EventArgs e)
{
if (Width == 0) return;
_backBuffer = new Bitmap(Width, Height);
}
public void DrawNode(Vector2 location)
{
var imageCoordSpace = Vector2.Transform(location, TransformationMatrix);
var start = imageCoordSpace - new Vector2(NODE_SIZE/2, NODE_SIZE / 2);
var end = (imageCoordSpace + new Vector2(NODE_SIZE / 2, NODE_SIZE / 2))-start;
_currentGraphics.FillRectangle(Brushes.White,start.X,start.Y,end.X,end.Y);
_currentGraphics.DrawRectangle(Pens.Black,start.X,start.Y,end.X,end.Y);
}
public void DrawArrow(Vector2 location, Vector2 direction)
{
var imageCoordSpaceLocation = Vector2.Transform(location, TransformationMatrix);
var imageCoordSpaceSize = Vector2.Transform(location + direction, TransformationMatrix);
var arrowPen = new Pen(Color.Aqua, 2);
arrowPen.EndCap = LineCap.Custom;
arrowPen.CustomEndCap = new AdjustableArrowCap(5,5,true);
_currentGraphics.DrawLine(arrowPen, imageCoordSpaceLocation.X, imageCoordSpaceLocation.Y, imageCoordSpaceSize.X, imageCoordSpaceSize.Y);
}
public void DrawRectangle(Vector2 start, Vector2 size, bool isGood)
{
var imageCoordSpaceLocation = Vector2.Transform(start, TransformationMatrix);
var imageCoordSpaceSize = Vector2.Transform(start+size, TransformationMatrix)-imageCoordSpaceLocation;
var pen = new Pen(isGood ? Color.Green : Color.Red, 2);
_currentGraphics.DrawRectangle(pen, imageCoordSpaceLocation.X, imageCoordSpaceLocation.Y, imageCoordSpaceSize.X, imageCoordSpaceSize.Y);
}
public void DrawLine(Vector2 start, Vector2 end,LineType type)
{
var coordStart = Vector2.Transform(start, TransformationMatrix);
var coordEnd = Vector2.Transform(end, TransformationMatrix);
var pen = new Pen(type ==LineType.Good? Color.Green:(type==LineType.Bad? Color.Red:Color.Aqua),2);
_currentGraphics.DrawLine(pen,coordStart.X,coordStart.Y,coordEnd.X,coordEnd.Y);
}
public void DrawPoly(Vector2[] points, bool isGood)
{
var pen = new Pen(isGood ? Color.Green : Color.Red, 3);
var coords = points.Select(x=> Vector2.Transform(x, TransformationMatrix)).Select(x => new PointF(x.X, x.Y)).ToArray();
_currentGraphics.DrawPolygon(pen, coords);
}
public void DrawCross(Vector2 location)
{
var startH=Vector2.Transform(location-new Vector2(10,0),TransformationMatrix);
var endH = Vector2.Transform(location+new Vector2(10,0), TransformationMatrix);
var startV =Vector2.Transform(location-new Vector2(0,20), TransformationMatrix);
var endV =Vector2.Transform(location+new Vector2(0,20), TransformationMatrix);
var pen = new Pen(Color.Aqua, 1);
_currentGraphics.DrawLine(pen, startH.X, startH.Y, endH.X, endH.Y);
_currentGraphics.DrawLine(pen, startV.X, startV.Y, endV.X, endV.Y);
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,77 @@
namespace Hawkeye.VisionBuilder.Features.ImagePreview
{
partial class ImagePreviewPanel
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImagePreviewPanel));
toolStrip1 = new ToolStrip();
btnFit = new ToolStripButton();
toolStrip1.SuspendLayout();
SuspendLayout();
//
// toolStrip1
//
toolStrip1.Items.AddRange(new ToolStripItem[] { btnFit });
toolStrip1.Location = new Point(0, 0);
toolStrip1.Name = "toolStrip1";
toolStrip1.Size = new Size(800, 25);
toolStrip1.TabIndex = 0;
toolStrip1.Text = "toolStrip1";
//
// btnFit
//
btnFit.DisplayStyle = ToolStripItemDisplayStyle.Text;
btnFit.Image = (Image)resources.GetObject("btnFit.Image");
btnFit.ImageTransparentColor = Color.Magenta;
btnFit.Name = "btnFit";
btnFit.Size = new Size(24, 22);
btnFit.Text = "Fit";
btnFit.Click += btnFit_Click;
//
// ImagePreviewPanel
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(toolStrip1);
DoubleBuffered = true;
Name = "ImagePreviewPanel";
Text = "Image Preview";
toolStrip1.ResumeLayout(false);
toolStrip1.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
#endregion
private ImagePreviewControl imagePreviewControl;
private ToolStrip toolStrip1;
private ToolStripButton btnFit;
}
}

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Hawkeye.VisionBuilder.Panels;
using Hawkeye.VisionBuilder.Workflow.Datatypes;
using Hawkeye.VisionBuilder.Workflow.Datatypes.Elements;
namespace Hawkeye.VisionBuilder.Features.ImagePreview
{
public partial class ImagePreviewPanel : BasePannel
{
public ImagePreviewPanel()
{
InitializeComponent();
imagePreviewControl = new ImagePreviewControl()
{
Dock = DockStyle.Fill
};
this.Controls.Add(imagePreviewControl);
imagePreviewControl.BringToFront();
}
public Workflow.Datatypes.HawkeyeImage CurrentImage { get; set; }
public void SetImage(Workflow.Datatypes.HawkeyeImage image)
{
if (image == null) return;
imagePreviewControl.Image = image;
CurrentImage = image;
imagePreviewControl.Invalidate();
}
public void ClearGraphics()
{
imagePreviewControl.GraphicsElements.Clear();
}
public void AddGraphics(IGraphicsElement element)
{
imagePreviewControl.GraphicsElements.Add(element);
}
private void btnFit_Click(object sender, EventArgs e)
{
imagePreviewControl.FitToScreen();
}
}
}

View File

@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="btnFit.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACRSURBVDhPY/j27dt/SjDYACcnJ7IwigEf3n8kCZNswPNb
J/+f6DYF0yA+yQac6Db5f6hWCmwIiE+mC0wIu2DS2Vf/F1x6DefjwlgNyNr34r/0wkdgTMgQDAOQNRNj
CIoBOg0rMTTDMLIhIHbriZeYBmDTiIxBGkEYxge5liQDsGGQqykyAISpZwAlmIEywMAAAAc1/Jwvt6sN
AAAAAElFTkSuQmCC
</value>
</data>
</root>