vector image editor enhancements and DataFormat for OpenDocument drawing vector files

This commit is contained in:
Michael Becker 2020-09-20 01:09:56 -04:00
parent 00fbd252af
commit b5fb12fc07
No known key found for this signature in database
GPG Key ID: 506F54899E2BFED7
9 changed files with 390 additions and 7 deletions

View File

@ -23,6 +23,7 @@ using System.Collections.Generic;
using MBS.Framework.Drawing;
using MBS.Framework.UserInterface;
using MBS.Framework.UserInterface.Drawing;
using MBS.Framework.UserInterface.Input.Mouse;
using UniversalEditor.ObjectModels.Multimedia.VectorImage;
using UniversalEditor.ObjectModels.Multimedia.VectorImage.VectorItems;
@ -30,6 +31,12 @@ namespace UniversalEditor.Editors.Multimedia.VectorImage.Controls
{
public class VectorImageControl : CustomControl
{
DragManager dragManager = new DragManager();
public VectorImageControl()
{
dragManager.Register(this);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
@ -46,6 +53,84 @@ namespace UniversalEditor.Editors.Multimedia.VectorImage.Controls
}
}
public VectorItem HitTest(Vector2D point)
{
VectorImageEditor editor = (Parent as VectorImageEditor);
if (editor == null) return null;
VectorImageObjectModel vec = (editor.ObjectModel as VectorImageObjectModel);
if (vec == null) return null;
for (int i = 0; i < vec.Items.Count; i++)
{
if (vec.Items[i].Contains(point))
return vec.Items[i];
}
return null;
}
private VectorItem m_HoverItem = null;
private double dx = 0, dy = 0;
private double cx = 0, cy = 0;
private double gx = 0, gy = 0;
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Buttons == MouseButtons.Primary)
{
m_HoverItem = HitTest(e.Location);
if (m_HoverItem is LineVectorItem)
{
dx = (m_HoverItem as LineVectorItem).X1.GetValue(MeasurementUnit.Pixel);
dy = (m_HoverItem as LineVectorItem).Y1.GetValue(MeasurementUnit.Pixel);
gx = ((m_HoverItem as LineVectorItem).X2.GetValue(MeasurementUnit.Pixel) - (m_HoverItem as LineVectorItem).X1.GetValue(MeasurementUnit.Pixel));
gy = ((m_HoverItem as LineVectorItem).Y2.GetValue(MeasurementUnit.Pixel) - (m_HoverItem as LineVectorItem).Y1.GetValue(MeasurementUnit.Pixel));
}
cx = e.Location.X;
cy = e.Location.Y;
Refresh();
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.Buttons == MouseButtons.None)
{
VectorItem _item = HitTest(e.Location);
if (_item != m_HoverItem)
{
m_HoverItem = _item;
Refresh();
}
if (_item != null)
{
Cursor = Cursors.Move;
}
else
{
Cursor = Cursors.Default;
}
}
else if (e.Buttons == MouseButtons.Primary)
{
if (m_HoverItem != null)
{
if (m_HoverItem is LineVectorItem)
{
Measurement mx = new Measurement(dx + (e.X - cx), MeasurementUnit.Pixel), my = new Measurement(dy + (e.Y - cy), MeasurementUnit.Pixel);
Measurement mgx = new Measurement(gx + (e.X - cx), MeasurementUnit.Pixel), mgy = new Measurement(gy + (e.Y - cy), MeasurementUnit.Pixel);
((LineVectorItem)m_HoverItem).X1 = mx;
((LineVectorItem)m_HoverItem).X2 = mgx;
((LineVectorItem)m_HoverItem).Y1 = my;
((LineVectorItem)m_HoverItem).Y2 = mgy;
}
}
}
}
private void DrawVectorItem(Graphics graphics, VectorItem vectorItem)
{
if (vectorItem is PolygonVectorItem)
@ -67,6 +152,21 @@ namespace UniversalEditor.Editors.Multimedia.VectorImage.Controls
{
graphics.DrawPolygon(new Pen(poly.Style.BorderColor), points);
}
if (m_HoverItem == poly)
{
graphics.DrawPolygon(new Pen(SystemColors.HighlightBackground), points);
}
}
else if (vectorItem is LineVectorItem)
{
LineVectorItem line = (vectorItem as LineVectorItem);
graphics.DrawLine(new Pen(line.Style.BorderColor), line.X1.GetValue(), line.Y1.GetValue(), line.X2.GetValue(), line.Y2.GetValue());
if (m_HoverItem == line)
{
graphics.DrawLine(new Pen(SystemColors.HighlightBackground), line.X1.GetValue(), line.Y1.GetValue(), line.X2.GetValue(), line.Y2.GetValue());
}
}
}
}

View File

@ -19,6 +19,8 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using MBS.Framework.Drawing;
namespace UniversalEditor.ObjectModels.Multimedia.VectorImage
{
public abstract class VectorItem : ICloneable
@ -28,6 +30,18 @@ namespace UniversalEditor.ObjectModels.Multimedia.VectorImage
}
public Rectangle Bounds { get; set; } = Rectangle.Empty;
public VectorImageStyle Style { get; set; } = new VectorImageStyle();
public abstract object Clone();
protected virtual bool ContainsInternal(Vector2D point)
{
return Bounds.Contains(point);
}
public bool Contains(Vector2D point)
{
return ContainsInternal(point);
}
}
}

View File

@ -0,0 +1,53 @@
//
// LineVectorItem.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using MBS.Framework.Drawing;
namespace UniversalEditor.ObjectModels.Multimedia.VectorImage.VectorItems
{
public class LineVectorItem : VectorItem
{
public Measurement X1 { get; set; } = Measurement.Empty;
public Measurement X2 { get; set; } = Measurement.Empty;
public Measurement Y1 { get; set; } = Measurement.Empty;
public Measurement Y2 { get; set; } = Measurement.Empty;
protected override bool ContainsInternal(Vector2D point)
{
double m = (Y2.GetValue(MeasurementUnit.Pixel) - Y1.GetValue(MeasurementUnit.Pixel)) / (X2.GetValue(MeasurementUnit.Pixel) - X1.GetValue(MeasurementUnit.Pixel));
double b = (Y2.GetValue(MeasurementUnit.Pixel) - (m * (X2.GetValue(MeasurementUnit.Pixel))));
double y = (m * point.X) + b;
double pb = 4;
return (y >= point.Y - pb) && (y <= point.Y + pb);
}
public override object Clone()
{
LineVectorItem clone = new LineVectorItem();
clone.X1 = X1;
clone.X2 = X2;
clone.Y1 = Y1;
clone.Y2 = Y2;
return clone;
}
}
}

View File

@ -20,23 +20,18 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using MBS.Framework.Drawing;
namespace UniversalEditor.ObjectModels.Multimedia.VectorImage.VectorItems
{
public class PolygonVectorItem : VectorItem
{
public double X { get; set; } = 0;
public double Y { get; set; } = 0;
public VectorImageStyle Style { get; set; } = new VectorImageStyle();
public List<PositionVector2> Points { get; } = new List<PositionVector2>();
public override object Clone()
{
PolygonVectorItem clone = new PolygonVectorItem();
clone.X = X;
clone.Y = Y;
clone.Bounds = Bounds;
clone.Style = Style.Clone() as VectorImageStyle;
for (int i = 0; i < Points.Count; i++)
{

View File

@ -341,6 +341,7 @@
<Compile Include="ObjectModels\Multimedia\VectorImage\VectorItems\PolygonVectorItem.cs" />
<Compile Include="ObjectModels\Multimedia\VectorImage\VectorImageStyle.cs" />
<Compile Include="DataFormats\Multimedia\VectorImage\SVG\SVGDataFormat.cs" />
<Compile Include="ObjectModels\Multimedia\VectorImage\VectorItems\LineVectorItem.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\UniversalEditor.Compression\UniversalEditor.Compression.csproj">

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" ?>
<UniversalEditor Version="4.0">
<Associations>
<Association>
<Filters>
<Filter Title="OpenDocument Drawing vector image">
<FileNameFilters>
<FileNameFilter>*.odg</FileNameFilter>
</FileNameFilters>
<MagicByteSequences>
<MagicByteSequence>
<MagicByte Type="String">PK</MagicByte>
</MagicByteSequence>
</MagicByteSequences>
</Filter>
</Filters>
<ObjectModels>
<ObjectModel TypeName="UniversalEditor.ObjectModels.Multimedia.VectorImage.VectorImageObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.Plugins.Office.DataFormats.VectorImage.OpenDocument.OpenDocumentVectorImageDataFormat" />
</DataFormats>
</Association>
</Associations>
</UniversalEditor>

View File

@ -0,0 +1,151 @@
//
// OpenDocumentVectorImageDataFormat.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using MBS.Framework.Drawing;
using UniversalEditor.Accessors;
using UniversalEditor.DataFormats.Markup.XML;
using UniversalEditor.DataFormats.Package.OpenDocument;
using UniversalEditor.ObjectModels.FileSystem;
using UniversalEditor.ObjectModels.Markup;
using UniversalEditor.ObjectModels.Multimedia.VectorImage;
using UniversalEditor.ObjectModels.Package;
namespace UniversalEditor.Plugins.Office.DataFormats.VectorImage.OpenDocument
{
public class OpenDocumentVectorImageDataFormat : OpenDocumentDataFormat
{
private static DataFormatReference _dfr = null;
protected override DataFormatReference MakeReferenceInternal()
{
if (_dfr == null)
{
_dfr = new DataFormatReference(GetType());
_dfr.Capabilities.Add(typeof(VectorImageObjectModel), DataFormatCapabilities.All);
}
return _dfr;
}
protected override void BeforeLoadInternal(Stack<ObjectModel> objectModels)
{
objectModels.Push(new PackageObjectModel());
base.BeforeLoadInternal(objectModels);
}
protected override void AfterLoadInternal(Stack<ObjectModel> objectModels)
{
base.AfterLoadInternal(objectModels);
PackageObjectModel package = (objectModels.Pop() as PackageObjectModel);
if (package == null) throw new ObjectModelNotSupportedException();
VectorImageObjectModel vec = (objectModels.Pop() as VectorImageObjectModel);
if (vec == null) throw new ObjectModelNotSupportedException();
XMLDataFormat xdf = new XMLDataFormat();
MarkupObjectModel mom_content = new MarkupObjectModel();
File file_content_xml = package.FileSystem.Files["content.xml"];
if (file_content_xml == null)
throw new InvalidDataFormatException("content.xml not found in root directory");
Document.Load(mom_content, xdf, new EmbeddedFileAccessor(file_content_xml));
MarkupTagElement tagContent = mom_content.FindElementUsingSchema(OpenDocumentXMLSchemas.Office, "document-content") as MarkupTagElement;
if (tagContent == null)
throw new InvalidDataFormatException("content.xml does not contain a top-level document-content tag");
MarkupTagElement tagBody = tagContent.FindElementUsingSchema(OpenDocumentXMLSchemas.Office, "body") as MarkupTagElement;
if (tagBody != null)
{
MarkupTagElement tagDrawing = tagBody.FindElementUsingSchema(OpenDocumentXMLSchemas.Office, "drawing") as MarkupTagElement;
if (tagDrawing != null)
{
MarkupTagElement tagPage = tagDrawing.FindElementUsingSchema(OpenDocumentXMLSchemas.Draw, "page") as MarkupTagElement;
if (tagPage != null)
{
MarkupAttribute attName = tagPage.FindAttributeUsingSchema(OpenDocumentXMLSchemas.Draw, "name");
if (attName != null)
{
}
for (int i = 0; i < tagPage.Elements.Count; i++)
{
MarkupTagElement tag = tagPage.Elements[i] as MarkupTagElement;
if (tag == null) continue;
if (tag.Name == "line" && tag.XMLSchema == OpenDocumentXMLSchemas.Draw)
{
MarkupAttribute attX1 = tag.FindAttributeUsingSchema(OpenDocumentXMLSchemas.Svg, "x1");
MarkupAttribute attY1 = tag.FindAttributeUsingSchema(OpenDocumentXMLSchemas.Svg, "y1");
MarkupAttribute attX2 = tag.FindAttributeUsingSchema(OpenDocumentXMLSchemas.Svg, "x2");
MarkupAttribute attY2 = tag.FindAttributeUsingSchema(OpenDocumentXMLSchemas.Svg, "y2");
if (attX1 == null || attY1 == null || attX2 == null || attY2 == null)
{
continue;
}
UniversalEditor.ObjectModels.Multimedia.VectorImage.VectorItems.LineVectorItem lvi = new UniversalEditor.ObjectModels.Multimedia.VectorImage.VectorItems.LineVectorItem();
// if stroke color is null
lvi.Style.BorderColor = Colors.Black; // Colors.CornflowerBlue;
lvi.X1 = Measurement.Parse(attX1.Value);
lvi.X2 = Measurement.Parse(attX2.Value);
lvi.Y1 = Measurement.Parse(attY1.Value);
lvi.Y2 = Measurement.Parse(attY2.Value);
lvi.Bounds = new Rectangle(lvi.X1.GetValue(MeasurementUnit.Pixel), lvi.Y1.GetValue(MeasurementUnit.Pixel), lvi.X2.GetValue(MeasurementUnit.Pixel) - lvi.X1.GetValue(MeasurementUnit.Pixel), lvi.Y2.GetValue(MeasurementUnit.Pixel) - lvi.Y1.GetValue(MeasurementUnit.Pixel));
vec.Items.Add(lvi);
}
else if (tag.Name == "custom-shape" && tag.XMLSchema == OpenDocumentXMLSchemas.Draw)
{
MarkupAttribute attX = tag.FindAttributeUsingSchema(OpenDocumentXMLSchemas.Svg, "x");
MarkupAttribute attY = tag.FindAttributeUsingSchema(OpenDocumentXMLSchemas.Svg, "y");
MarkupAttribute attWidth = tag.FindAttributeUsingSchema(OpenDocumentXMLSchemas.Svg, "width");
MarkupAttribute attHeight = tag.FindAttributeUsingSchema(OpenDocumentXMLSchemas.Svg, "height");
MarkupTagElement tagEnhancedGeometry = tag.FindElementUsingSchema(OpenDocumentXMLSchemas.Draw, "enhanced-geometry") as MarkupTagElement;
if (tagEnhancedGeometry != null)
{
MarkupAttribute attType = tagEnhancedGeometry.FindAttributeUsingSchema(OpenDocumentXMLSchemas.Draw, "type");
if (attType != null)
{
}
}
}
}
}
}
}
}
protected override void BeforeSaveInternal(Stack<ObjectModel> objectModels)
{
base.BeforeSaveInternal(objectModels);
VectorImageObjectModel vec = (objectModels.Pop() as VectorImageObjectModel);
if (vec == null) throw new ObjectModelNotSupportedException();
PackageObjectModel package = new PackageObjectModel();
objectModels.Push(package);
}
}
}

View File

@ -0,0 +1,30 @@
//
// OpenDocumentSchemas.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.Plugins.Office.DataFormats.VectorImage.OpenDocument
{
public static class OpenDocumentXMLSchemas
{
public const string Office = "urn:oasis:names:tc:opendocument:xmlns:office:1.0";
public const string Draw = "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0";
public const string Svg = "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0";
}
}

View File

@ -46,6 +46,8 @@
<Compile Include="ObjectModels\Spreadsheet\Column.cs" />
<Compile Include="ObjectModels\Spreadsheet\Row.cs" />
<Compile Include="ObjectModels\Spreadsheet\Sheet.cs" />
<Compile Include="DataFormats\VectorImage\OpenDocument\OpenDocumentVectorImageDataFormat.cs" />
<Compile Include="DataFormats\VectorImage\OpenDocument\OpenDocumentXMLSchemas.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="ObjectModels\" />
@ -57,6 +59,9 @@
<Folder Include="DataFormats\Presentation\HyperCard\Internal\STAK\" />
<Folder Include="Associations\" />
<Folder Include="ObjectModels\Spreadsheet\" />
<Folder Include="DataFormats\VectorImage\" />
<Folder Include="DataFormats\VectorImage\OpenDocument\" />
<Folder Include="Associations\VectorImage\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\UniversalEditor.Core\UniversalEditor.Core.csproj">
@ -67,9 +72,18 @@
<Project>{30467E5C-05BC-4856-AADC-13906EF4CADD}</Project>
<Name>UniversalEditor.Essential</Name>
</ProjectReference>
<ProjectReference Include="..\UniversalEditor.Plugins.Multimedia\UniversalEditor.Plugins.Multimedia.csproj">
<Project>{BE4D0BA3-0888-42A5-9C09-FC308A4509D2}</Project>
<Name>UniversalEditor.Plugins.Multimedia</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\MBS.Framework\MBS.Framework\MBS.Framework.csproj">
<Project>{00266B21-35C9-4A7F-A6BA-D54D7FDCC25C}</Project>
<Name>MBS.Framework</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Associations\Presentation\HyperCardDataFormat.uexml" />
<EmbeddedResource Include="Associations\VectorImage\OpenDocumentVectorImageDataFormat.uexml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>