WPF: Use the custom text editor for editing text of text annotation in annotation viewer.

Code samples for VintaSoft Annotation .NET Plug-in. Here you can request a code sample.

Moderator: Alex

Post Reply
Alex
Site Admin
Posts: 1589
Joined: Thu Jul 10, 2008 2:21 pm

WPF: Use the custom text editor for editing text of text annotation in annotation viewer.

Post by Alex » Fri Mar 03, 2017 12:52 pm

This topic contains a code snippet that shows how to use the custom text editor for editing the text of text annotation in WPF annotation viewer:

Code: Select all

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

using Vintasoft.Imaging;
using Vintasoft.Imaging.Annotation;
using Vintasoft.Imaging.Annotation.Wpf.UI;
using Vintasoft.Imaging.Annotation.Wpf.UI.VisualTools;
using Vintasoft.Imaging.Annotation.Wpf.UI.VisualTools.UserInteraction;
using Vintasoft.Imaging.Wpf;
using Vintasoft.Imaging.Wpf.UI;
using Vintasoft.Imaging.Wpf.UI.VisualTools.UserInteraction;
using Vintasoft.Imaging.Wpf.Utils;


namespace WpfApplication1
{
    /// <summary>
    /// Main window.
    /// </summary>
    public partial class Window1 : Window
    {

        #region Fields

        /// <summary>
        /// Determines that the building process of annotation is finished.
        /// </summary>
        bool _isAnnotationBuildingFinished = false;

        /// <summary>
        /// Determines that the text editing must be started when text annotation is created.
        /// </summary>
        bool _startTextEditingWhenTextAnnotationIsCreated = false;

        #endregion



        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Window1"/> class.
        /// </summary>
        public Window1()
        {
            InitializeComponent();

            WpfAnnotationVisualTool annotationTool = annotationViewer.AnnotationVisualTool;

            annotationTool.AnnotationBuildingFinished +=
                new EventHandler<WpfAnnotationViewEventArgs>(annotationTool_AnnotationBuildingFinished);
            annotationTool.ActiveInteractionControllerChanged +=
                new PropertyChangedEventHandler<IWpfInteractionController>(annotationTool_ActiveInteractionControllerChanged);
        }

        #endregion



        #region Methods

        /// <summary>
        /// Raizes event <see cref="E:System.Windows.Window.Closed" />.
        /// </summary>
        protected override void OnClosed(EventArgs e)
        {
            annotationViewer.Images.ClearAndDisposeItems();

            base.OnClosed(e);
        }

        /// <summary>
        /// Loads images to viewer.
        /// </summary>
        private void loadImage_Click(object sender, RoutedEventArgs e)
        {
            // if building of annotation is not finished
            if (!_isAnnotationBuildingFinished)
            {
                WpfAnnotationVisualTool annotationTool = annotationViewer.AnnotationVisualTool;
                annotationTool.CancelAnnotationBuilding();
            }

            // remove all images
            annotationViewer.Images.ClearAndDisposeItems();

            Microsoft.Win32.OpenFileDialog dialog = new Microsoft.Win32.OpenFileDialog();
            dialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
            dialog.Filter = "Jpeg file|*.jpg;*.jpeg|Tiff file|*.tiff;*.tif|Png file|*.png|Bmp file|*.bmp";
            if (dialog.ShowDialog(this) == true)
            {
                try
                {
                    // load images
                    annotationViewer.Images.Add(dialog.FileName);
                }
                catch (Exception exc)
                {
                    MessageBox.Show(exc.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }

            addTextAnnotation.IsEnabled = annotationViewer.Image != null;
        }

        /// <summary>
        /// Adds text annotation.
        /// </summary>
        private void addTextAnnotation_Click(object sender, RoutedEventArgs e)
        {
            WpfAnnotationVisualTool annotationTool = annotationViewer.AnnotationVisualTool;

            // if building of annotation is not finished
            if (!_isAnnotationBuildingFinished)
                annotationTool.CancelAnnotationBuilding();

            _isAnnotationBuildingFinished = false;
            // create text annotation
            TextAnnotationData textAnnotation = new TextAnnotationData();

            textAnnotation.Text = "Text";
            textAnnotation.FontBrush = new AnnotationSolidBrush(System.Drawing.Color.DarkGreen);
            textAnnotation.FillBrush = new AnnotationSolidBrush(System.Drawing.Color.LightGray);
            textAnnotation.Border = true;
            textAnnotation.Outline.Width = 5;
            textAnnotation.Outline.Brush = new AnnotationSolidBrush(System.Drawing.Color.Blue);

            // build annotation
            annotationTool.AddAndBuildAnnotation(textAnnotation);
        }

        private void startTextEditingCheckBox_Checked(object sender, RoutedEventArgs e)
        {
            _startTextEditingWhenTextAnnotationIsCreated = (bool)startTextEditingCheckBox.IsChecked;
        }


        /// <summary>
        /// Building of annotation is finished.
        /// </summary>
        private void annotationTool_AnnotationBuildingFinished(object sender, WpfAnnotationViewEventArgs e)
        {
            _isAnnotationBuildingFinished = true;

            if (_startTextEditingWhenTextAnnotationIsCreated &&
                e.AnnotationView is WpfTextAnnotationView)
            {
                e.AnnotationView.InteractionControllerChanged +=
                    new PropertyChangedEventHandler<IWpfInteractionController>(TextAnnotation_InteractionControllerChanged);
            }
        }

        /// <summary>
        /// The interaction controller of text annotation is changed.
        /// </summary>
        void TextAnnotation_InteractionControllerChanged(object sender, PropertyChangedEventArgs<IWpfInteractionController> e)
        {
            WpfRectangularTextAnnotationTransformer transformer =
                e.NewValue as WpfRectangularTextAnnotationTransformer;
            if (transformer != null)
            {
                WpfAnnotationView view = (WpfAnnotationView)sender;
                transformer.ShowTextBox(annotationViewer, new Point(0, 0));

                TextBox textBox = transformer.TextBox;
                textBox.Focus();
                textBox.Select(textBox.Text.Length, 0);
                textBox.ScrollToEnd();
                view.InteractionControllerChanged -=
                    new PropertyChangedEventHandler<IWpfInteractionController>(TextAnnotation_InteractionControllerChanged);
            }
        }

        /// <summary>
        /// The interaction controller of annotation is changed.
        /// </summary>
        private void annotationTool_ActiveInteractionControllerChanged(object sender,
            PropertyChangedEventArgs<IWpfInteractionController> e)
        {
            if (e.OldValue is WpfRectangularTextAnnotationTransformer)
            {
                WpfRectangularTextAnnotationTransformer transformer =
                    (WpfRectangularTextAnnotationTransformer)e.OldValue;

                transformer.TextBoxTransformer.TextBoxUpdated -=
                    new EventHandler<WpfTextObjectTextBoxTransformerEventArgs>(TextBoxTransformer_TextBoxUpdated);
            }

            if (e.NewValue is WpfRectangularTextAnnotationTransformer)
            {
                WpfRectangularTextAnnotationTransformer transformer =
                    (WpfRectangularTextAnnotationTransformer)e.NewValue;

                WpfTextObjectTextBoxTransformer textBoxTransformer = transformer.TextBoxTransformer;

                if (startTextEditingOneClickRadioButton.IsChecked == true)
                    textBoxTransformer.ActivateClickCount = 1;
                else if (startTextEditingDoubleClickRadioButton.IsChecked == true)
                    textBoxTransformer.ActivateClickCount = 2;

                textBoxTransformer.TextBoxUpdated +=
                    new EventHandler<WpfTextObjectTextBoxTransformerEventArgs>(TextBoxTransformer_TextBoxUpdated);
            }
        }

        /// <summary>
        /// Updates the text box of text annotation.
        /// </summary>
        void TextBoxTransformer_TextBoxUpdated(object sender, WpfTextObjectTextBoxTransformerEventArgs e)
        {
            TextBox textBox = e.TextBox;
            WpfTextAnnotationView annotationView = (WpfTextAnnotationView)e.TextObject;

            Scale scaleToImage = e.Viewer.ViewerState.ScaleToImage;
            Resolution imageResolution = e.Viewer.Image.Resolution;

            Scale textBoxScale = new Scale(
                (float)(scaleToImage.Horizontal * (imageResolution.Horizontal / 96.0)),
                (float)(scaleToImage.Vertical * (imageResolution.Vertical / 96.0)));

            // update colors of text box
            UpdateTextBoxColors(textBox, annotationView, textBoxScale);
            // update font of text box
            UpdateTextBoxFontStyle(textBox, annotationView, textBoxScale);
            // update location and size of text box
            UpdateTextBoxLocationAndSize(textBox, annotationView, e.Viewer, textBoxScale);
        }

        /// <summary>
        /// Updates colors of the text box.
        /// </summary>
        /// <param name="textBox">The text box.</param>
        /// <param name="annotationView">The annotation view.</param>
        /// <param name="textBoxScale">The scale of the text box.</param>
        private void UpdateTextBoxColors(TextBox textBox, WpfTextAnnotationView annotationView, Scale textBoxScale)
        {
            // if background color is solid
            if (annotationView.FillBrush is AnnotationSolidBrush)
            {
                // get brush
                AnnotationSolidBrush solidBrush = (AnnotationSolidBrush)annotationView.FillBrush;
                // create solid brush
                textBox.Background = new SolidColorBrush(WpfObjectConverter.CreateWindowsColor(solidBrush.Color));
            }
            else
                throw new NotImplementedException();

            // if font color is solid
            if (annotationView.FontBrush is AnnotationSolidBrush)
            {
                // get brush
                AnnotationSolidBrush solidBrush = (AnnotationSolidBrush)annotationView.FontBrush;
                // create solid brush
                textBox.Foreground = new SolidColorBrush(WpfObjectConverter.CreateWindowsColor(solidBrush.Color));
            }
            else
                throw new NotImplementedException();

            // create thickness of border
            Thickness borderThickness = new Thickness();
            // create brush of border
            SolidColorBrush borderBrush = new SolidColorBrush(Colors.Transparent);
            // if border is visible
            if (annotationView.Border)
            {
                // create brush
                borderBrush = new SolidColorBrush(
                    WpfObjectConverter.CreateWindowsColor(annotationView.Outline.Color));

                // get border width
                double width = annotationView.Outline.Width;
                // create thickness of border
                borderThickness = new Thickness(
                    width * textBoxScale.Horizontal,
                    width * textBoxScale.Vertical,
                    width * textBoxScale.Horizontal,
                    width * textBoxScale.Vertical);
            }
            // update thickness of border
            textBox.BorderThickness = borderThickness;
            // update brush of border
            textBox.BorderBrush = borderBrush;
        }

        /// <summary>
        /// Updates font style of the text box.
        /// </summary>
        /// <param name="textBox">The text box.</param>
        /// <param name="annotationView">The annotation view.</param>
        /// <param name="textBoxScale">The scale of the text box.</param>
        private void UpdateTextBoxFontStyle(
            TextBox textBox,
            WpfTextAnnotationView annotationView,
            Scale textBoxScale)
        {
            AnnotationFont font = annotationView.Font;

            // create font family of text
            textBox.FontFamily = new FontFamily(font.FamilyName);

            // calculate font size
            double fontSize = font.Size * textBoxScale.Horizontal;
            // convert font size to device independent pixels
            switch (font.Unit)
            {
                case AnnotationFontUnit.Display:
                    fontSize *= 96.0 / ImagingEnvironment.ScreenDpiX;
                    break;

                case AnnotationFontUnit.Document:
                    fontSize *= 96.0 / 300;
                    break;

                case AnnotationFontUnit.Inch:
                    fontSize *= 96.0;
                    break;

                case AnnotationFontUnit.Millimeter:
                    fontSize *= 96.0 / 25.4;
                    break;

                case AnnotationFontUnit.Point:
                    fontSize *= 96.0 / 72;
                    break;
            }
            textBox.FontSize = fontSize;

            // if font is italic
            if (font.Italic)
                textBox.FontStyle = FontStyles.Italic;

            // if font is bold
            if (font.Bold)
                textBox.FontWeight = FontWeights.Bold;

            // if font is strikeout
            if (font.Strikeout)
            {
                TextDecoration strikeout = new TextDecoration();
                strikeout.Location = TextDecorationLocation.Strikethrough;
                textBox.TextDecorations.Add(strikeout);
            }

            // if font is underline
            if (font.Underline)
            {
                TextDecoration underline = new TextDecoration();
                underline.Location = TextDecorationLocation.Underline;
                textBox.TextDecorations.Add(underline);
            }
        }

        /// <summary>
        /// Updates the size and location of the text box.
        /// </summary>
        /// <param name="textBox">The text box.</param>
        /// <param name="annotationView">The annotation view.</param>
        /// <param name="viewer">The viewer.</param>
        /// <param name="textBoxScale">The scale of the text box.</param>
        private void UpdateTextBoxLocationAndSize(
            TextBox textBox,
            WpfTextAnnotationView annotationView,
            WpfImageViewer viewer,
            Scale textBoxScale)
        {
            // update horizontal alignment of text
            switch (annotationView.TextHorizontalAlignment)
            {
                case AlignmentX.Center:
                    textBox.HorizontalContentAlignment = HorizontalAlignment.Center;
                    break;

                case AlignmentX.Left:
                    textBox.HorizontalContentAlignment = HorizontalAlignment.Left;
                    break;

                case AlignmentX.Right:
                    textBox.HorizontalContentAlignment = HorizontalAlignment.Right;
                    break;
            }

            // update vertical alignment of text
            switch (annotationView.TextVerticalAlignment)
            {
                case AlignmentY.Bottom:
                    textBox.VerticalContentAlignment = VerticalAlignment.Bottom;
                    break;

                case AlignmentY.Center:
                    textBox.VerticalContentAlignment = VerticalAlignment.Center;
                    break;

                case AlignmentY.Top:
                    textBox.VerticalContentAlignment = VerticalAlignment.Top;
                    break;
            }

            // get point transform of the annotation for image viewer
            WpfPointTransform transform = annotationView.GetPointTransform(viewer);

            // location of annotation
            Point location = annotationView.Location;
            // size of annotation
            Size size = annotationView.Size;

            // calculate top-left point of annotation
            Point topLeftPoint = new Point(location.X - size.Width / 2, location.Y - size.Height / 2);
            topLeftPoint = transform.TransformPoint(topLeftPoint);

            // calculate bottom-right point of annotation
            Point bottomRightPoint = new Point(location.X + size.Width / 2, location.Y + size.Height / 2);
            bottomRightPoint = transform.TransformPoint(bottomRightPoint);

            // calculate bounding box of text box
            double textBoxX = topLeftPoint.X;
            double textBoxY = topLeftPoint.Y;
            double textBoxWidth = bottomRightPoint.X - topLeftPoint.X;
            double textBoxHeight = bottomRightPoint.Y - topLeftPoint.Y;

            if (textBoxWidth <= 0)
                textBoxWidth = 0;
            if (textBoxHeight <= 0)
                textBoxHeight = 0;

            // update location and size of text box
            Canvas.SetLeft(textBox, textBoxX);
            Canvas.SetTop(textBox, textBoxY);
            textBox.Width = textBoxWidth;
            textBox.Height = textBoxHeight;

            // calculate padding of text
            double textPaddingLeft = annotationView.TextPadding.Left * textBoxScale.Horizontal;
            double textPaddingTop = annotationView.TextPadding.Top * textBoxScale.Vertical;
            double textPaddingRight = annotationView.TextPadding.Right * textBoxScale.Horizontal;
            double textPaddingBottom = annotationView.TextPadding.Bottom * textBoxScale.Vertical;

            // if border is not visible
            if (!annotationView.Border)
            {
                double borderHorizontal = annotationView.Outline.Width * textBoxScale.Horizontal;
                double borderVertical = annotationView.Outline.Width * textBoxScale.Vertical;

                // update padding of text
                textPaddingLeft += borderHorizontal;
                textPaddingTop += borderVertical;
                textPaddingRight += borderHorizontal;
                textPaddingBottom += borderVertical;
            }

            textBox.Padding = new Thickness(
                textPaddingLeft,
                textPaddingTop,
                textPaddingRight,
                textPaddingBottom);

            // if annotation is mirrored
            if (annotationView.HorizontalMirrored ||
                annotationView.VerticalMirrored)
            {
                // create transform
                TransformGroup layoutTransform = new TransformGroup();
                // if annotation is horizontal mirrored
                if (annotationView.HorizontalMirrored)
                    layoutTransform.Children.Add(new ScaleTransform(-1, 1));
                // if annotation is vertical mirrored
                if (annotationView.VerticalMirrored)
                    layoutTransform.Children.Add(new ScaleTransform(1, -1));
                textBox.LayoutTransform = layoutTransform;
            }

            // if annotation is rotated
            if (annotationView.Rotation != 0)
            {
                // rotate annotation at center of annotation
                textBox.RenderTransformOrigin = new Point(0.5, 0.5);
                // rotate annotation
                textBox.RenderTransform = new RotateTransform(annotationView.Rotation);
            }
        }
        
        private void startTextEditingClickRadioButton_Checked(object sender, RoutedEventArgs e)
        {
            if (annotationViewer == null)
                return;

            IWpfInteractionController controller =
                annotationViewer.AnnotationVisualTool.ActiveInteractionController;

            if (controller is WpfRectangularTextAnnotationTransformer)
            {
                WpfRectangularTextAnnotationTransformer transformer =
                    (WpfRectangularTextAnnotationTransformer)controller;

                WpfTextObjectTextBoxTransformer textBoxTransformer = transformer.TextBoxTransformer;

                if (startTextEditingOneClickRadioButton.IsChecked == true)
                    textBoxTransformer.ActivateClickCount = 1;
                else if (startTextEditingDoubleClickRadioButton.IsChecked == true)
                    textBoxTransformer.ActivateClickCount = 2;
            }
        }

        #endregion

    }
}

Source codes of WPF application for VintaSoft Imaging .NET SDK v8.7 can be downloaded here.

gpbabu
Posts: 16
Joined: Wed Dec 14, 2016 9:01 pm

Re: WPF: Use the custom text editor for editing text of text annotation in annotation viewer.

Post by gpbabu » Mon Apr 16, 2018 9:06 pm

Hi Alex,

We have been trying to use custom text editor example. When we set a large font size with transparent background, we see annotation text in the back shifted. We tried various padding and margin options for the text box. However, none of them helped. If you can provide some input on this issue that will be great.

Thanks
Babu

Changed made to reproduce this ghost text issue:

Code: Select all

private void addTextAnnotation_Click(object sender, RoutedEventArgs e)
{
    WpfAnnotationVisualTool annotationTool = annotationViewer.AnnotationVisualTool;

    // if building of annotation is not finished
    if (!_isAnnotationBuildingFinished)
        annotationTool.CancelAnnotationBuilding();

    _isAnnotationBuildingFinished = false;
    // create text annotation
    TextAnnotationData textAnnotation = new TextAnnotationData();

    textAnnotation.Text = "Text";
    textAnnotation.FontBrush = new AnnotationSolidBrush(System.Drawing.Color.DarkGreen);
    //textAnnotation.FillBrush = new AnnotationSolidBrush(System.Drawing.Color.LightGray);
    textAnnotation.FillBrush = new AnnotationSolidBrush(System.Drawing.Color.FromArgb(0xA0, 200, 200, 200));
    textAnnotation.Border = true;
    textAnnotation.Outline.Width = 5;
    textAnnotation.Outline.Brush = new AnnotationSolidBrush(System.Drawing.Color.Blue);
    textAnnotation.Font.Size = 40;

    // build annotation
    annotationTool.AddAndBuildAnnotation(textAnnotation);
}

Alex
Site Admin
Posts: 1589
Joined: Thu Jul 10, 2008 2:21 pm

Re: WPF: Use the custom text editor for editing text of text annotation in annotation viewer.

Post by Alex » Thu Apr 19, 2018 9:55 am

Hello,

In our example the TextBox control is used for editing the annotation text. Example shows the TextBox over the annotation and you see the text, which is drawn by TextBox. Also SDK draws the updated annotation text when you editing the annotation text. You do not see the updated annotation text, which is drawn by SDK, because the text is located under the TextBox.

You will see the text, which is drawn by SDK, and the text, which is drawn by TextBox, if you use the transparent background in TextBox. The drawn texts may be different because SDK does not know the exact algorithm, which is used for drawing the text in TextBox. This is the reason of your problem.

For solving the problem you can go by 2 ways.

WAY 1: Use TextBox with not transparent background.

WAY 2: Create custom algorithm, which allows to draw and edit annotation text without TextBox.

Best regards, Alexander

Post Reply