VintaSoft Imaging .NET SDK 14.0: Документация для .NET разработчика
В этом разделе
    Как создать пользовательскую аннотацию метку?
    В этом разделе
    VintaSoft Annotation .NET Plug-in позволяет создавать пользовательские аннотации с нуля, т.е.: Также плагин позволяет использовать любую стандартную аннотацию в качестве базового класса для пользовательских аннотаций, поскольку архитектура SDK является открытой.


    В этой статье описывается, как создать аннотацию метку с нуля. Для выполнения задачи необходимо создать 1 перечисление и 3 класса:

    Перечисление MarkAnnotationType

    Перечисление MarkAnnotationType определяет возможные типы меток: прямоугольник, галочка, звездочка или крест.

    Вот C#/VB.NET код, который демонстрирует, как реализовать перечисление MarkAnnotationType:
    namespace DemosCommonCode.Annotation
    {
        /// <summary>
        /// Specifies the available types of mark annotation.
        /// </summary>
        public enum MarkAnnotationType : int
        {
            /// <summary>
            /// The rectangle.
            /// </summary>
            Rectangle = 0,
    
            /// <summary>
            /// The tick.
            /// </summary>
            Tick = 1,
    
            /// <summary>
            /// The star.
            /// </summary>
            Star = 2,
    
            /// <summary>
            /// The cross.
            /// </summary>
            Cross = 3,
        }
    }
    
    
    Namespace DemosCommonCode.Annotation
        ''' <summary>
        ''' Specifies the available types of mark annotation.
        ''' </summary>
        Public Enum MarkAnnotationType As Integer
            ''' <summary>
            ''' The rectangle.
            ''' </summary>
            Rectangle = 0
    
            ''' <summary>
            ''' The tick.
            ''' </summary>
            Tick = 1
    
            ''' <summary>
            ''' The star.
            ''' </summary>
            Star = 2
    
            ''' <summary>
            ''' The cross.
            ''' </summary>
            Cross = 3
        End Enum
    End Namespace
    
    


    Аласс MarkAnnotationData

    Класс MarkAnnotationData:
    Вот C#/VB.NET код, который демонстрирует, как реализовать класс MarkAnnotationData:
    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Runtime.Serialization;
    using System.Security.Permissions;
    
    using Vintasoft.Imaging;
    using Vintasoft.Imaging.Annotation;
    using Vintasoft.Imaging.Annotation.Rendering;
    
    namespace DemosCommonCode.Annotation
    {
        /// <summary>
        /// Class that holds information about the annotation that displays a mark.
        /// </summary>
        [Serializable]
        public class MarkAnnotationData : AnnotationData
        {
    
            #region Constructors
    
            /// <summary>
            /// Initializes a new instance of the <see cref="MarkAnnotationData"/> class.
            /// </summary>
            public MarkAnnotationData()
                : base()
            {
                FillBrush = new AnnotationSolidBrush(Color.Black);
            }
    
            /// <summary>
            /// Initializes a new instance of the <see cref="AnnotationData"/> class.
            /// </summary>
            /// <param name="info">The SerializationInfo to populate with data.</param>
            /// <param name="context">The destination for this serialization.</param>
            public MarkAnnotationData(SerializationInfo info, StreamingContext context)
                : base(info, context)
            {
                _markType = (MarkAnnotationType)info.GetValue("MarkType", typeof(int));
            }
    
    
            /// <summary>
            /// Initializes the <see cref="MarkAnnotationData"/> class.
            /// </summary>
            static MarkAnnotationData()
            {
                // register renderer form this annotation
                AnnotationRendererFactory.RegisterRendererForAnnotationData(typeof(MarkAnnotationData), typeof(MarkAnnotationRenderer));
            }
    
            #endregion
    
    
    
            #region Properties
    
            MarkAnnotationType _markType = MarkAnnotationType.Tick;
            /// <summary>
            /// Gets or sets a mark type.
            /// </summary>
            [Description("The mark type.")]
            [DefaultValue(MarkAnnotationType.Tick)]
            public MarkAnnotationType MarkType
            {
                get
                {
                    return _markType;
                }
                set
                {
                    if (_markType != value)
                    {
                        ObjectPropertyChangingEventArgs changingArgs =
                            new ObjectPropertyChangingEventArgs("MarkType", _markType, value);
                        if (OnPropertyChanging(changingArgs))
                        {
                            _markType = (MarkAnnotationType)changingArgs.NewValue;
                            OnPropertyChanged(changingArgs.ToChangedEventArgs());
                        }
                    }
                }
            }
    
            #endregion
    
    
    
            #region Methods
    
            /// <summary>
            /// Returns the bounding box of annotation if annotation will have specified location,
            /// size and rotation.
            /// </summary>
            /// <param name="location">Location, in device-independent pixels (1/96th inch),
            /// of annotation.</param>
            /// <param name="size">Size, in device-independent pixels (1/96th inch),
            /// of annotation</param>
            /// <param name="rotation">Rotation, in degrees, of annotation.</param>
            /// <returns>Bounding box of annotation.</returns>
            public override RectangleF GetBoundingBox(PointF location, SizeF size, float rotation)
            {
                PointF[] points = GetReferencePointsInContentSpace();
    
                // rotate
                AnnotationsMath.RotatePointsAt(points, PointF.Empty, Rotation);
                // scale
                AnnotationsMath.ScalePoints(points, size.Width / this.Size.Width, size.Height / this.Size.Height);
                // translate
                AnnotationsMath.TranslatePoints(points, location.X, location.Y);
    
                return AnnotationsMath.GetBoundingBox(points);
            }
    
    
            /// <summary>
            /// Gets an array that contains reference points in content space of this annotation.
            /// </summary>
            /// <returns></returns>
            public virtual PointF[] GetReferencePointsInContentSpace()
            {
                float width = Size.Width;
                float height = Size.Height;
                float w = Math.Min(width / 10, height / 10);
    
                PointF[] points;
                switch (MarkType)
                {
                    case MarkAnnotationType.Rectangle:
                        points = new PointF[]{
                            new PointF(-width / 2, -height/2),
                            new PointF(width / 2, -height/2),
                            new PointF(width / 2, height/2),
                            new PointF(-width / 2, height/2)};
                        break;
    
                    case MarkAnnotationType.Tick:
                        points = new PointF[]{
                            new PointF(-width / 2, 0),
                            new PointF(0, height / 4),
                            new PointF(width / 2, -height / 2),
                            new PointF(0, height / 2),
                            new PointF(-width / 2, 0)};
                        break;
    
                    case MarkAnnotationType.Cross:
                        points = new PointF[]{
                            new PointF(-width / 2, -w),
                            new PointF(-w, -w),
                            new PointF(-w, -height/2),
                            new PointF(w, -height/2),
                            new PointF(w, -w),
                            new PointF(width/2, -w),
                            new PointF(width/2, w),
                            new PointF(w, w),
                            new PointF(w, height/2),
                            new PointF(-w, height/2),
                            new PointF(-w, w),
                            new PointF(-width/2, w)};
                        break;
    
                    case MarkAnnotationType.Star:
                        points = new PointF[]{
                            new PointF(-width / 2, 0),
                            new PointF(-w, -w),
                            new PointF(0, -height/2),
                            new PointF(w, -w),
                            new PointF(width/2, 0),
                            new PointF(w, w),
                            new PointF(0, height/2),
                            new PointF(-w, w),
                            new PointF(-width/2, 0)};
                        break;
    
                    default:
                        throw new NotImplementedException();
                }
    
                AffineMatrix matrix = new AffineMatrix();
                if (HorizontalMirrored)
                    matrix.ScalePrepend(-1, 1);
                if (VerticalMirrored)
                    matrix.ScalePrepend(1, -1);
    
                PointFAffineTransform.TransformPoints(matrix, points);
    
                return points;
            }
    
    
            /// <summary>
            /// Populates a SerializationInfo with the data needed to serialize the target object.
            /// </summary>
            /// <param name="info">The SerializationInfo to populate with data.</param>
            /// <param name="context">The destination for this serialization.</param>
            [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
            public override void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                base.GetObjectData(info, context);
                info.AddValue("MarkType", (int)MarkType);
            }
    
            
            /// <summary>
            /// Creates a new object that is a copy of the current instance.
            /// </summary>
            /// <returns>A new object that is a copy of this instance.</returns>
            public override object Clone()
            {
                MarkAnnotationData data = new MarkAnnotationData();
                CopyTo(data);
                return data;
            }
    
            /// <summary>
            /// Copies the state of the current object to the target object.
            /// </summary>
            /// <param name="target">Object to copy the state of the current object to.</param>
            public override void CopyTo(AnnotationData target)
            {
                base.CopyTo(target);
    
                if (target is MarkAnnotationData)
                {
                    ((MarkAnnotationData)target).MarkType = MarkType;
                }
            }
    
            #endregion
    
        }
    }
    
    
    Imports System.ComponentModel
    Imports System.Drawing
    Imports System.Drawing.Drawing2D
    Imports System.Runtime.Serialization
    Imports System.Security.Permissions
    
    Imports Vintasoft.Imaging
    Imports Vintasoft.Imaging.Annotation
    Imports Vintasoft.Imaging.Annotation.Rendering
    
    Namespace DemosCommonCode.Annotation
        ''' <summary>
        ''' Class that holds information about the annotation that displays a mark.
        ''' </summary>
        <Serializable> _
        Public Class MarkAnnotationData
            Inherits AnnotationData
    
            #Region "Constructors"
    
            ''' <summary>
            ''' Initializes a new instance of the <see cref="MarkAnnotationData"/> class.
            ''' </summary>
            Public Sub New()
                MyBase.New()
                FillBrush = New AnnotationSolidBrush(Color.Black)
            End Sub
    
            ''' <summary>
            ''' Initializes a new instance of the <see cref="AnnotationData"/> class.
            ''' </summary>
            ''' <param name="info">The SerializationInfo to populate with data.</param>
            ''' <param name="context">The destination for this serialization.</param>
            Public Sub New(info As SerializationInfo, context As StreamingContext)
                MyBase.New(info, context)
                _markType = CType(info.GetValue("MarkType", GetType(Integer)), MarkAnnotationType)
            End Sub
    
    
            ''' <summary>
            ''' Initializes the <see cref="MarkAnnotationData"/> class.
            ''' </summary>
            Shared Sub New()
                ' register renderer form this annotation
                AnnotationRendererFactory.RegisterRendererForAnnotationData(GetType(MarkAnnotationData), GetType(MarkAnnotationRenderer))
            End Sub
    
            #End Region
    
    
    
            #Region "Properties"
    
            Private _markType As MarkAnnotationType = MarkAnnotationType.Tick
            ''' <summary>
            ''' Gets or sets a mark type.
            ''' </summary>
            <Description("The mark type.")> _
            <DefaultValue(MarkAnnotationType.Tick)> _
            Public Property MarkType() As MarkAnnotationType
                Get
                    Return _markType
                End Get
                Set
                    If _markType <> value Then
                        Dim changingArgs As New ObjectPropertyChangingEventArgs("MarkType", _markType, value)
                        If OnPropertyChanging(changingArgs) Then
                            _markType = CType(changingArgs.NewValue, MarkAnnotationType)
                            OnPropertyChanged(changingArgs.ToChangedEventArgs())
                        End If
                    End If
                End Set
            End Property
    
            #End Region
    
    
    
            #Region "Methods"
    
            ''' <summary>
            ''' Returns the bounding box of annotation if annotation will have specified location,
            ''' size and rotation.
            ''' </summary>
            ''' <param name="location">Location, in device-independent pixels (1/96th inch),
            ''' of annotation.</param>
            ''' <param name="size">Size, in device-independent pixels (1/96th inch),
            ''' of annotation</param>
            ''' <param name="rotation">Rotation, in degrees, of annotation.</param>
            ''' <returns>Bounding box of annotation.</returns>
            Public Overrides Function GetBoundingBox(location As PointF, size As SizeF, rotation__1 As Single) As RectangleF
                Dim points As PointF() = GetReferencePointsInContentSpace()
    
                ' rotate
                AnnotationsMath.RotatePointsAt(points, PointF.Empty, Rotation)
                ' scale
                AnnotationsMath.ScalePoints(points, size.Width / Me.Size.Width, size.Height / Me.Size.Height)
                ' translate
                AnnotationsMath.TranslatePoints(points, location.X, location.Y)
    
                Return AnnotationsMath.GetBoundingBox(points)
            End Function
    
    
            ''' <summary>
            ''' Gets an array that contains reference points in content space of this annotation.
            ''' </summary>
            ''' <returns></returns>
            Public Overridable Function GetReferencePointsInContentSpace() As PointF()
                Dim width As Single = Size.Width
                Dim height As Single = Size.Height
                Dim w As Single = Math.Min(width / 10, height / 10)
    
                Dim points As PointF()
                Select Case MarkType
                    Case MarkAnnotationType.Rectangle
                        points = New PointF() {New PointF(-width / 2, -height / 2), New PointF(width / 2, -height / 2), New PointF(width / 2, height / 2), New PointF(-width / 2, height / 2)}
                        Exit Select
    
                    Case MarkAnnotationType.Tick
                        points = New PointF() {New PointF(-width / 2, 0), New PointF(0, height / 4), New PointF(width / 2, -height / 2), New PointF(0, height / 2), New PointF(-width / 2, 0)}
                        Exit Select
    
                    Case MarkAnnotationType.Cross
                        points = New PointF() {New PointF(-width / 2, -w), New PointF(-w, -w), New PointF(-w, -height / 2), New PointF(w, -height / 2), New PointF(w, -w), New PointF(width / 2, -w), _
                            New PointF(width / 2, w), New PointF(w, w), New PointF(w, height / 2), New PointF(-w, height / 2), New PointF(-w, w), New PointF(-width / 2, w)}
                        Exit Select
    
                    Case MarkAnnotationType.Star
                        points = New PointF() {New PointF(-width / 2, 0), New PointF(-w, -w), New PointF(0, -height / 2), New PointF(w, -w), New PointF(width / 2, 0), New PointF(w, w), _
                            New PointF(0, height / 2), New PointF(-w, w), New PointF(-width / 2, 0)}
                        Exit Select
                    Case Else
    
                        Throw New NotImplementedException()
                End Select
    
                Dim matrix As New AffineMatrix()
                If HorizontalMirrored Then
                    matrix.ScalePrepend(-1, 1)
                End If
                If VerticalMirrored Then
                    matrix.ScalePrepend(1, -1)
                End If
    
                PointFAffineTransform.TransformPoints(matrix, points)
    
                Return points
            End Function
    
    
            ''' <summary>
            ''' Populates a SerializationInfo with the data needed to serialize the target object.
            ''' </summary>
            ''' <param name="info">The SerializationInfo to populate with data.</param>
            ''' <param name="context">The destination for this serialization.</param>
            <SecurityPermission(SecurityAction.LinkDemand, Flags := SecurityPermissionFlag.SerializationFormatter)> _
            Public Overrides Sub GetObjectData(info As SerializationInfo, context As StreamingContext)
                MyBase.GetObjectData(info, context)
                info.AddValue("MarkType", CInt(MarkType))
            End Sub
    
    
            ''' <summary>
            ''' Creates a new object that is a copy of the current instance.
            ''' </summary>
            ''' <returns>A new object that is a copy of this instance.</returns>
            Public Overrides Function Clone() As Object
                Dim data As New MarkAnnotationData()
                CopyTo(data)
                Return data
            End Function
    
            ''' <summary>
            ''' Copies the state of the current object to the target object.
            ''' </summary>
            ''' <param name="target">Object to copy the state of the current object to.</param>
            Public Overrides Sub CopyTo(target As AnnotationData)
                MyBase.CopyTo(target)
    
                If TypeOf target Is MarkAnnotationData Then
                    DirectCast(target, MarkAnnotationData).MarkType = MarkType
                End If
            End Sub
    
            #End Region
    
        End Class
    End Namespace
    
    


    Класс MarkAnnotationBuilder

    Класс MarkAnnotationBuilder выполняет визуальное построение аннотации.
    Класс MarkAnnotationBuilder:
    Вот C#/VB.NET код, который демонстрирует, как реализовать класс MarkAnnotationBuilder:
    using System.Drawing;
    
    using Vintasoft.Imaging.UI.VisualTools.UserInteraction;
    
    namespace DemosCommonCode.Annotation
    {
        /// <summary>
        /// Interaction controller that builds a mark annotation.
        /// </summary>
        public class MarkAnnotationBuilder : InteractionControllerBase<IRectangularInteractiveObject>
        {
    
            #region Contructors
    
            /// <summary>
            /// Initializes a new instance of the <see cref="MarkAnnotationBuilder"/> class.
            /// </summary>
            /// <param name="view">The mark annotation.</param>
            public MarkAnnotationBuilder(MarkAnnotationView view)
                : base(view)
            {
                // create an interaction area that can be moved, hovered and clicked
                ImageViewerArea buildArea = new ImageViewerArea(
                    InteractionAreaType.Hover | InteractionAreaType.Movable | InteractionAreaType.Clickable);
                // mark that any mouse button can interact with interaction area
                buildArea.AnyActionMouseButton = true;
                // add the interacton area to a list of interaction areas of the interaction controller
                InteractionAreaList.Add(buildArea);
    
                // set initial size of annotation
                _initialSize = view.Size;
            }
    
            #endregion
    
    
    
            #region Properties
            
            SizeF _initialSize;
            /// <summary>
            /// Gets or sets an annotation initial size.
            /// </summary>
            public SizeF InitialSize
            {
                get
                {
                    return _initialSize;
                }
                set
                {
                    _initialSize = value;
                }
            }
    
            #endregion
    
    
    
            #region Methods
    
            /// <summary>
            /// Performs an interaction between user and interaction area.
            /// </summary>
            /// <param name="args">An interaction event args.</param>
            protected override void PerformInteraction(InteractionEventArgs args)
            {
                // set rectangle of annotation
                InteractiveObject.SetRectangle(
                            args.Location.X - _initialSize.Width / 2, args.Location.Y - _initialSize.Height / 2,
                            args.Location.X + _initialSize.Width / 2, args.Location.Y + _initialSize.Height / 2);
    
                // mark that the user interacted with annotation
                args.InteractionOccured(true);
    
                // if any mouse button is clicked
                if (args.Action == InteractionAreaAction.Click)
                    // finish building of annotation
                    args.InteractionFinished = true;
            }
    
            #endregion
    
        }
    }
    
    
    Imports System.Drawing
    
    Imports Vintasoft.Imaging.UI.VisualTools.UserInteraction
    
    Namespace DemosCommonCode.Annotation
        ''' <summary>
        ''' Interaction controller that builds a mark annotation.
        ''' </summary>
        Public Class MarkAnnotationBuilder
            Inherits InteractionControllerBase(Of IRectangularInteractiveObject)
    
            #Region "Contructors"
    
            ''' <summary>
            ''' Initializes a new instance of the <see cref="MarkAnnotationBuilder"/> class.
            ''' </summary>
            ''' <param name="view">The mark annotation.</param>
            Public Sub New(view As MarkAnnotationView)
                MyBase.New(view)
                ' create an interaction area that can be moved, hovered and clicked
                Dim buildArea As New ImageViewerArea(InteractionAreaType.Hover Or InteractionAreaType.Movable Or InteractionAreaType.Clickable)
                ' mark that any mouse button can interact with interaction area
                buildArea.AnyActionMouseButton = True
                ' add the interacton area to a list of interaction areas of the interaction controller
                InteractionAreaList.Add(buildArea)
    
                ' set initial size of annotation
                _initialSize = view.Size
            End Sub
    
            #End Region
    
    
    
            #Region "Properties"
    
            Private _initialSize As SizeF
            ''' <summary>
            ''' Gets or sets an annotation initial size.
            ''' </summary>
            Public Property InitialSize() As SizeF
                Get
                    Return _initialSize
                End Get
                Set
                    _initialSize = value
                End Set
            End Property
    
            #End Region
    
    
    
            #Region "Methods"
    
            ''' <summary>
            ''' Performs an interaction between user and interaction area.
            ''' </summary>
            ''' <param name="args">An interaction event args.</param>
            Protected Overrides Sub PerformInteraction(args As InteractionEventArgs)
                ' set rectangle of annotation
                InteractiveObject.SetRectangle(args.Location.X - _initialSize.Width / 2, args.Location.Y - _initialSize.Height / 2, args.Location.X + _initialSize.Width / 2, args.Location.Y + _initialSize.Height / 2)
    
                ' mark that the user interacted with annotation
                args.InteractionOccured(True)
    
                ' if any mouse button is clicked
                If args.Action = InteractionAreaAction.Click Then
                    ' finish building of annotation
                    args.InteractionFinished = True
                End If
            End Sub
    
            #End Region
    
        End Class
    End Namespace
    
    


    Класс MarkAnnotationView

    Класс MarkAnnotationView:
    Вот C#/VB.NET код, который демонстрирует, как реализовать класс MarkAnnotationView:
    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    
    using Vintasoft.Imaging;
    using Vintasoft.Imaging.Annotation;
    using Vintasoft.Imaging.Annotation.UI;
    using Vintasoft.Imaging.Annotation.UI.VisualTools.UserInteraction;
    using Vintasoft.Imaging.Drawing;
    using Vintasoft.Imaging.UI.VisualTools.UserInteraction;
    
    namespace DemosCommonCode.Annotation
    {
        /// <summary>
        /// Class that determines how to display the annotation that displays a mark
        /// and how user can interact with annotation.
        /// </summary>
        public class MarkAnnotationView : AnnotationView, IRectangularInteractiveObject
        {
    
            #region Constructors
    
            /// <summary>
            /// Initializes a new instance of the <see cref="MarkAnnotationView"/> class.
            /// </summary>
            /// <param name="annotationData">Object that stores the annotation data.</param>
            public MarkAnnotationView(MarkAnnotationData annotationData)
                : base(annotationData)
            {
                SizeF initialSize = Size;
                if (initialSize.IsEmpty)
                {
                    initialSize = new Size(64, 64);
                    Size = initialSize;
                }
                Builder = new MarkAnnotationBuilder(this);
    
                RectangularAnnotationTransformer transformer = new RectangularAnnotationTransformer(this);
                transformer.HideInteractionPointsWhenMoving = true;
                foreach (InteractionPoint point in transformer.ResizePoints)
                    point.FillColor = Color.FromArgb(100, Color.Red);
                Transformer = transformer;
            }
    
            #endregion
    
    
    
            #region Properties
    
            /// <summary>
            /// Gets or sets a mark type.
            /// </summary>
            [Description("The mark type.")]
            [DefaultValue(MarkAnnotationType.Tick)]
            public MarkAnnotationType MarkType
            {
                get
                { 
                    return MarkAnnoData.MarkType;
                }
                set 
                { 
                    MarkAnnoData.MarkType = value;
                }
            }
    
            /// <summary>
            /// Gets an annotation data.
            /// </summary>
            MarkAnnotationData MarkAnnoData
            {
                get 
                { 
                    return (MarkAnnotationData)Data;
                }
            }
    
            /// <summary>
            /// Gets or sets the rotation angle of interactive object.
            /// </summary>
            double IRectangularInteractiveObject.RotationAngle
            {
                get 
                { 
                    return Rotation; 
                }
                set 
                { 
                    Rotation = (float)value;
                }
            }
    
            #endregion
    
    
    
            #region Methods
    
            #region PUBLIC
    
            /// <summary>
            /// Indicates whether the specified point is contained within the annotation.
            /// </summary>
            /// <param name="point">Point in image space.</param>
            /// <returns><b>true</b> if the specified point is contained within the annotation;
            /// otherwise, <b>false</b>.</returns>
            public override bool IsPointOnFigure(PointF point)
            {
                using (IGraphicsPath path = ((MarkAnnotationRenderer)Renderer).GetAsGraphicsPath(DrawingFactory.Default))
                {
                    path.Transform(GetTransformFromContentToImageSpace());
                    using (IDrawingPen pen = DrawingFactory.Default.CreatePen(Outline))
                    {
                        return path.Contains(point) || path.OutlineContains(point, pen);
                    }
                }
            }
    
            /// <summary>
            /// Creates a new object that is a copy of the current
            /// <see cref="MarkAnnotationView"/> instance.
            /// </summary>
            /// <returns>A new object that is a copy of this <see cref="MarkAnnotationView"/>
            /// instance.</returns>
            public override object Clone()
            {
                return new MarkAnnotationView((MarkAnnotationData)this.Data.Clone());
            }
    
            /// <summary>
            /// Returns an annotation selection as <see cref="GraphicsPath"/> in annotation content space.
            /// </summary>
            public override GraphicsPath GetSelectionAsGraphicsPath()
            {
                GraphicsPath path = new GraphicsPath();
                SizeF size = Size;
                path.AddRectangle(new RectangleF(-size.Width / 2, -size.Height / 2, size.Width, size.Height));
                using (Matrix transform = GdiConverter.Convert(GetTransformFromContentToImageSpace()))
                    path.Transform(transform);
                return path;
            }
    
            #endregion
    
    
            #region PROTECTED
    
            /// <summary>
            /// Sets the properties of interaction controller according to the properties of annotation.
            /// </summary>
            /// <param name="controller">The interaction controller.</param>
            protected override void SetInteractionControllerProperties(IInteractionController controller)
            {
                base.SetInteractionControllerProperties(controller);
    
                RectangularObjectTransformer rectangularTransformer = controller as RectangularObjectTransformer;
                if (rectangularTransformer != null)
                {
                    rectangularTransformer.CanMove = Data.CanMove;
                    rectangularTransformer.CanResize = Data.CanResize;
                    rectangularTransformer.CanRotate = Data.CanRotate;
                    return;
                }
            }
    
            /// <summary>
            /// Raises the <see cref="AnnotationView.StateChanged" /> event.
            /// Invoked when the property of annotation is changed.
            /// </summary>
            /// <param name="e">An <see cref="ObjectPropertyChangedEventArgs" />
            /// that contains the event data.</param>
            protected override void OnDataPropertyChanged(ObjectPropertyChangedEventArgs e)
            {
                base.OnDataPropertyChanged(e);
    
                if (e.PropertyName == "Size")
                {
                    if (Builder is MarkAnnotationBuilder)
                        ((MarkAnnotationBuilder)Builder).InitialSize = (SizeF)e.NewValue;
                }
            }
    
            #endregion
    
    
            #region IRectangularInteractiveObject
    
            /// <summary>
            /// Returns a rectangle of interactive object.
            /// </summary>
            /// <param name="x0">Left-top X coordinate of rectangle.</param>
            /// <param name="y0">Left-top Y coordinate of rectangle.</param>
            /// <param name="x1">Right-bottom X coordinate of rectangle.</param>
            /// <param name="y1">Right-bottom Y coordinate of rectangle.</param>
            void IRectangularInteractiveObject.GetRectangle(
                out double x0,
                out double y0,
                out double x1,
                out double y1)
            {
                PointF location = Location;
                SizeF size = Size;
                x0 = location.X - size.Width / 2;
                y0 = location.Y - size.Height / 2;
                x1 = location.X + size.Width / 2;
                y1 = location.Y + size.Height / 2;
                if (Data.HorizontalMirrored)
                {
                    double tmp = x0;
                    x0 = x1;
                    x1 = tmp;
                }
                if (Data.VerticalMirrored)
                {
                    double tmp = y0;
                    y0 = y1;
                    y1 = tmp;
                }
            }
    
            /// <summary>
            /// Sets a rectangle of interactive object.
            /// </summary>
            /// <param name="x0">Left-top X coordinate of rectangle.</param>
            /// <param name="y0">Left-top Y coordinate of rectangle.</param>
            /// <param name="x1">Right-bottom X coordinate of rectangle.</param>
            /// <param name="y1">Right-bottom Y coordinate of rectangle.</param>
            void IRectangularInteractiveObject.SetRectangle(double x0, double y0, double x1, double y1)
            {
                Size = new SizeF((float)Math.Abs(x0 - x1), (float)Math.Abs(y0 - y1));
                Location = new PointF((float)(x0 + x1) / 2, (float)(y0 + y1) / 2);
    
                HorizontalMirrored = x0 > x1;
                VerticalMirrored = y0 > y1;
    
                if (Data.IsInitializing)
                    OnStateChanged();
            }
    
            #endregion
    
            #endregion
    
        }
    }
    
    
    Imports System.ComponentModel
    Imports System.Drawing
    Imports System.Drawing.Drawing2D
    
    Imports Vintasoft.Imaging
    Imports Vintasoft.Imaging.Annotation
    Imports Vintasoft.Imaging.Annotation.UI
    Imports Vintasoft.Imaging.Annotation.UI.VisualTools.UserInteraction
    Imports Vintasoft.Imaging.Drawing
    Imports Vintasoft.Imaging.UI.VisualTools.UserInteraction
    
    Namespace DemosCommonCode.Annotation
        ''' <summary>
        ''' Class that determines how to display the annotation that displays a mark
        ''' and how user can interact with annotation.
        ''' </summary>
        Public Class MarkAnnotationView
            Inherits AnnotationView
            Implements IRectangularInteractiveObject
    
            #Region "Constructors"
    
            ''' <summary>
            ''' Initializes a new instance of the <see cref="MarkAnnotationView"/> class.
            ''' </summary>
            ''' <param name="annotationData">Object that stores the annotation data.</param>
            Public Sub New(annotationData As MarkAnnotationData)
                MyBase.New(annotationData)
                Dim initialSize As SizeF = Size
                If initialSize.IsEmpty Then
                    initialSize = New Size(64, 64)
                    Size = initialSize
                End If
                Builder = New MarkAnnotationBuilder(Me)
    
                Dim transformer__1 As New RectangularAnnotationTransformer(Me)
                transformer__1.HideInteractionPointsWhenMoving = True
                For Each point As InteractionPoint In transformer__1.ResizePoints
                    point.FillColor = Color.FromArgb(100, Color.Red)
                Next
                Transformer = transformer__1
            End Sub
    
            #End Region
    
    
    
            #Region "Properties"
    
            ''' <summary>
            ''' Gets or sets a mark type.
            ''' </summary>
            <Description("The mark type.")> _
            <DefaultValue(MarkAnnotationType.Tick)> _
            Public Property MarkType() As MarkAnnotationType
                Get
                    Return MarkAnnoData.MarkType
                End Get
                Set
                    MarkAnnoData.MarkType = value
                End Set
            End Property
    
            ''' <summary>
            ''' Gets an annotation data.
            ''' </summary>
            Private ReadOnly Property MarkAnnoData() As MarkAnnotationData
                Get
                    Return DirectCast(Data, MarkAnnotationData)
                End Get
            End Property
    
            ''' <summary>
            ''' Gets or sets the rotation angle of interactive object.
            ''' </summary>
            Private Property IRectangularInteractiveObject_RotationAngle() As Double Implements IRectangularInteractiveObject.RotationAngle
                Get
                    Return Rotation
                End Get
                Set
                    Rotation = CSng(value)
                End Set
            End Property
    
            #End Region
    
    
    
            #Region "Methods"
    
            #Region "PUBLIC"
    
            ''' <summary>
            ''' Indicates whether the specified point is contained within the annotation.
            ''' </summary>
            ''' <param name="point">Point in image space.</param>
            ''' <returns><b>true</b> if the specified point is contained within the annotation;
            ''' otherwise, <b>false</b>.</returns>
            Public Overrides Function IsPointOnFigure(point As PointF) As Boolean
                Using path As IGraphicsPath = DirectCast(Renderer, MarkAnnotationRenderer).GetAsGraphicsPath(DrawingFactory.[Default])
                    path.Transform(GetTransformFromContentToImageSpace())
                    Using pen As IDrawingPen = DrawingFactory.[Default].CreatePen(Outline)
                        Return path.Contains(point) OrElse path.OutlineContains(point, pen)
                    End Using
                End Using
            End Function
    
            ''' <summary>
            ''' Creates a new object that is a copy of the current
            ''' <see cref="MarkAnnotationView"/> instance.
            ''' </summary>
            ''' <returns>A new object that is a copy of this <see cref="MarkAnnotationView"/>
            ''' instance.</returns>
            Public Overrides Function Clone() As Object
                Return New MarkAnnotationView(DirectCast(Me.Data.Clone(), MarkAnnotationData))
            End Function
    
            ''' <summary>
            ''' Returns an annotation selection as <see cref="GraphicsPath"/> in annotation content space.
            ''' </summary>
            Public Overrides Function GetSelectionAsGraphicsPath() As GraphicsPath
                Dim path As New GraphicsPath()
                Dim size__1 As SizeF = Size
                path.AddRectangle(New RectangleF(-size__1.Width / 2, -size__1.Height / 2, size__1.Width, size__1.Height))
                Using transform As Matrix = GdiConverter.Convert(GetTransformFromContentToImageSpace())
                    path.Transform(transform)
                End Using
                Return path
            End Function
    
            #End Region
    
    
            #Region "PROTECTED"
    
            ''' <summary>
            ''' Sets the properties of interaction controller according to the properties of annotation.
            ''' </summary>
            ''' <param name="controller">The interaction controller.</param>
            Protected Overrides Sub SetInteractionControllerProperties(controller As IInteractionController)
                MyBase.SetInteractionControllerProperties(controller)
    
                Dim rectangularTransformer As RectangularObjectTransformer = TryCast(controller, RectangularObjectTransformer)
                If rectangularTransformer IsNot Nothing Then
                    rectangularTransformer.CanMove = Data.CanMove
                    rectangularTransformer.CanResize = Data.CanResize
                    rectangularTransformer.CanRotate = Data.CanRotate
                    Return
                End If
            End Sub
    
            ''' <summary>
            ''' Raises the <see cref="AnnotationView.StateChanged" /> event.
            ''' Invoked when the property of annotation is changed.
            ''' </summary>
            ''' <param name="e">An <see cref="ObjectPropertyChangedEventArgs" />
            ''' that contains the event data.</param>
            Protected Overrides Sub OnDataPropertyChanged(e As ObjectPropertyChangedEventArgs)
                MyBase.OnDataPropertyChanged(e)
    
                If e.PropertyName = "Size" Then
                    If TypeOf Builder Is MarkAnnotationBuilder Then
                        DirectCast(Builder, MarkAnnotationBuilder).InitialSize = CType(e.NewValue, SizeF)
                    End If
                End If
            End Sub
    
            #End Region
    
    
            #Region "IRectangularInteractiveObject"
    
            ''' <summary>
            ''' Returns a rectangle of interactive object.
            ''' </summary>
            ''' <param name="x0">Left-top X coordinate of rectangle.</param>
            ''' <param name="y0">Left-top Y coordinate of rectangle.</param>
            ''' <param name="x1">Right-bottom X coordinate of rectangle.</param>
            ''' <param name="y1">Right-bottom Y coordinate of rectangle.</param>
            Private Sub IRectangularInteractiveObject_GetRectangle(ByRef x0 As Double, ByRef y0 As Double, ByRef x1 As Double, ByRef y1 As Double) Implements IRectangularInteractiveObject.GetRectangle
                Dim location__1 As PointF = Location
                Dim size__2 As SizeF = Size
                x0 = location__1.X - size__2.Width / 2
                y0 = location__1.Y - size__2.Height / 2
                x1 = location__1.X + size__2.Width / 2
                y1 = location__1.Y + size__2.Height / 2
                If Data.HorizontalMirrored Then
                    Dim tmp As Double = x0
                    x0 = x1
                    x1 = tmp
                End If
                If Data.VerticalMirrored Then
                    Dim tmp As Double = y0
                    y0 = y1
                    y1 = tmp
                End If
            End Sub
    
            ''' <summary>
            ''' Sets a rectangle of interactive object.
            ''' </summary>
            ''' <param name="x0">Left-top X coordinate of rectangle.</param>
            ''' <param name="y0">Left-top Y coordinate of rectangle.</param>
            ''' <param name="x1">Right-bottom X coordinate of rectangle.</param>
            ''' <param name="y1">Right-bottom Y coordinate of rectangle.</param>
            Private Sub IRectangularInteractiveObject_SetRectangle(x0 As Double, y0 As Double, x1 As Double, y1 As Double) Implements IRectangularInteractiveObject.SetRectangle
                Size = New SizeF(CSng(Math.Abs(x0 - x1)), CSng(Math.Abs(y0 - y1)))
                Location = New PointF(CSng(x0 + x1) / 2, CSng(y0 + y1) / 2)
    
                HorizontalMirrored = x0 > x1
                VerticalMirrored = y0 > y1
    
                If Data.IsInitializing Then
                    OnStateChanged()
                End If
            End Sub
    
            #End Region
    
            #End Region
    
        End Class
    End Namespace
    
    


    Регистрация связи между классами MarkAnnotationData и MarkAnnotationView

    Связь между MarkAnnotationData и Классы MarkAnnotationView должны быть зарегистрированы до создания любого экземпляра класса MarkAnnotationView. Связь между классами MarkAnnotationData и MarkAnnotationView можно зарегистрировать с помощью метода AnnotationViewFactory.RegisterViewForAnnotationData.


    Примеры

    Реализация аннотации метки в C# и VB.NET является частью кода проекта AnnotationDemo и WpfAnnotationDemo.