Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to select or highlight the text on mouse move event in WritableBitmap in wpf c#

Tags:

c#

wpf

pdftron

I have WritableBitmap image and I have set in image control src. I am creating rectangle when user move on the selected text area.I am also using PDFtron SDK to get selected text from the PDF document. we are getting WritableBitmap image from PDF. We have to select text on line wise.

I am using this code to draw the screen:

System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle((int)Math.Min(_downX, x),
                             (int)Math.Min(_downY, y),
                             (int)Math.Abs(_downX - x),
                             (int)Math.Abs(_downY - y));

System.Drawing.Bitmap myBitmap = new System.Drawing.Bitmap(@"D:\PDF\ScreenDraw\WpfApplication1\WpfApplication1\Image\Capture.PNG");

using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(myBitmap))
{
    System.Drawing.Color customColor = System.Drawing.Color.FromArgb(50, System.Drawing.Color.Red);
    System.Drawing.SolidBrush shadowBrush = new System.Drawing.SolidBrush(customColor);
    g.FillRectangles(shadowBrush, new System.Drawing.Rectangle[] { rectangle });
}

//myBitmap.Save(@"D:\PDF\abc.png");
//bitmapSource = new BitmapImage(new Uri(@"D:\PDF\abc.png", UriKind.Absolute));

using (var memory = new System.IO.MemoryStream())
{
    myBitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
    memory.Position = 0;

    var bitmapImage = new BitmapImage();
    bitmapImage.BeginInit();
    bitmapImage.StreamSource = memory;
    bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
    bitmapImage.EndInit();
    Img.Source = bitmapImage;
}

How can I select the text with line wise not a Rect wise?enter image description here

I have to select text as shown in the above image.

like image 859
Jitendra singh Avatar asked Jul 23 '15 05:07

Jitendra singh


1 Answers

What you want is impossible. You have a bitmap and it is not magically aware of the text in it and nothing will change that. Although it's not that there is nothing you can do about it. I don't have time to provide complete solution, but I can provide step-by-step instruction how to achieve the best possible solution.

What you can do is:

  1. Text dimensions definition - Create control with grid overlaid on the image with editable X- and Y-axis step and offset. Then you will be able to calibrate the grid with the lines of text (Y). And character width (X). Something like that should do (I think you will get the general idea):

    public int XGridStep
    {
        get { return (int)base.GetValue(XGridStepProperty); }
        set
        {
            base.SetValue(XGridStepProperty, value);
            RepaintGrid();
        }
    }
    
    public static readonly DependencyProperty XGridStepProperty = DependencyProperty.Register("XGridStepProperty", typeof(int), typeof(PlanLayout), new PropertyMetadata(100));
    
    public int XGridOffset
    {
        get { return (int)base.GetValue(XGridOffsetProperty); }
        set
        {
            base.SetValue(XGridOffsetProperty, value);
            RepaintGrid();
        }
    }
    
    public static readonly DependencyProperty XGridOffsetProperty = DependencyProperty.Register("XGridOffsetProperty", typeof(int), typeof(PlanLayout), new PropertyMetadata(0));
    
    public bool XGridVisible
    {
        get { return (bool)base.GetValue(XGridVisibleProperty); }
        set
        {
            base.SetValue(XGridVisibleProperty, value);
            RepaintGrid();
        }
    }
    
    public static readonly DependencyProperty XGridVisibleProperty = DependencyProperty.Register("XGridVisibleProperty", typeof(bool), typeof(PlanLayout), new PropertyMetadata(false));
    
    public int YGridStep
    {
        get { return (int)base.GetValue(YGridStepProperty); }
        set
        {
            base.SetValue(YGridStepProperty, value);
            RepaintGrid();
        }
    }
    
    public static readonly DependencyProperty YGridStepProperty = DependencyProperty.Register("YGridStepProperty", typeof(int), typeof(PlanLayout), new PropertyMetadata(100));
    
    public int YGridOffset
    {
        get { return (int)base.GetValue(YGridOffsetProperty); }
        set
        {
            base.SetValue(YGridOffsetProperty, value);
            RepaintGrid();
        }
    }
    
    public static readonly DependencyProperty YGridOffsetProperty = DependencyProperty.Register("YGridOffsetProperty", typeof(int), typeof(PlanLayout), new PropertyMetadata(0));
    
    public bool YGridVisible
    {
        get { return (bool)base.GetValue(YGridVisibleProperty); }
        set
        {
            base.SetValue(YGridVisibleProperty, value);
            RepaintGrid();
        }
    }
    
    public static readonly DependencyProperty YGridVisibleProperty = DependencyProperty.Register("YGridVisibleProperty", typeof(bool), typeof(PlanLayout), new PropertyMetadata(false));
    
    private void RepaintGrid()
    {
        if (!IsEditable)
            return;
    
        foreach (Line l in _gridXLines)
            content.Children.Remove(l);
        _gridXLines.Clear();
        if (XGridVisible)
            for (int i = XGridOffset; i < content.ActualWidth; i += XGridStep)
            {
                Line line = new Line();
                line.IsHitTestVisible = false;
                line.Stroke = Brushes.Black;
                line.Y1 = 0;
                line.Y2 = content.ActualHeight;
                line.X1 = line.X2 = i;
                if (Math.Abs(line.X1 - content.ActualWidth) < XGridStep * 0.5 || line.X1 < XGridStep * 0.5)
                    continue;
                _gridXLines.Add(line);
                content.Children.Add(line);
                Canvas.SetZIndex(line, 0);
            }
    
        foreach (Line l in _gridYLines)
            content.Children.Remove(l);
        _gridYLines.Clear();
        if (YGridVisible)
            for (int i = YGridOffset; i < content.ActualHeight; i += YGridStep)
            {
                Line line = new Line();
                line.IsHitTestVisible = false;
                line.Stroke = Brushes.Black;
                line.X1 = 0;
                line.X2 = content.ActualWidth;
                line.Y1 = line.Y2 = i;
                if (Math.Abs(line.Y1 - content.ActualHeight) < YGridStep * 0.5 || line.Y1 < YGridStep * 0.5)
                    continue;
                _gridYLines.Add(line);
                content.Children.Add(line);
                Canvas.SetZIndex(line, 0);
            }
    }
    
  2. Text selection - All you have to do now is add "Snap to grid" ability to your control. Again, just for reference:

    private void elementWrapper_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
    {
        if (_mouseHandlingMode != MouseHandlingMode.Dragging)
            return;
    
        SelectableElement element = (SelectableElement)sender;
    
        Point curContentPoint = e.GetPosition(content);
        //Vector elementDragVector = curContentPoint - _origContentMouseDownPoint;
    
        _origContentMouseDownPoint = curContentPoint;
    
        //double destinationLeft = Canvas.GetLeft(element) + elementDragVector.X;
        //double destinationTop = Canvas.GetTop(element) + elementDragVector.Y;
        double destinationLeft = curContentPoint.X - element.ActualWidth / 2;
        double destinationTop = curContentPoint.Y - element.ActualHeight / 2;
    
        if (SnapToGrid)
        {
            if (XGridVisible)
            {
                foreach (Line l in _gridXLines)
                    l.StrokeThickness = 1;
    
                Line nearest = GetNearestXGridLine((int)curContentPoint.X);
    
                if (Math.Abs(curContentPoint.X - nearest.X1) < XGridStep * 0.2)
                {
                    destinationLeft = nearest.X1 - element.ActualWidth / 2;
                    nearest.StrokeThickness = 3;
                }
            }
    
            if (YGridVisible)
            {
                foreach (Line l in _gridYLines)
                    l.StrokeThickness = 1;
    
                Line nearest = GetNearestYGridLine((int)curContentPoint.Y);
    
                if (Math.Abs(curContentPoint.Y - nearest.Y1) < YGridStep * 0.2)
                {
                    destinationTop = nearest.Y1 - element.ActualHeight / 2;
                    nearest.StrokeThickness = 3;
                }
            }
        }
    
        if (destinationLeft < 0)
            destinationLeft = 0;
    
        if (destinationLeft > content.ActualWidth - element.ActualWidth)
            destinationLeft = content.ActualWidth - element.ActualWidth;
    
        if (destinationTop < 0)
            destinationTop = 0;
    
        if (destinationTop > content.ActualHeight - element.ActualHeight)
            destinationTop = content.ActualHeight - element.ActualHeight;
    
        Canvas.SetLeft(element, destinationLeft);
        Canvas.SetTop(element, destinationTop);
    
        element.ElementContent.Position.X = curContentPoint.X;
        element.ElementContent.Position.Y = curContentPoint.Y;
    
        e.Handled = true;
    }
    
    private Line GetNearestXGridLine(int xpos)
    {
        return _gridXLines.OrderBy(gl => Math.Abs((int)gl.X1 - xpos)).First();
    }
    
    private Line GetNearestYGridLine(int Ypos)
    {
        return _gridYLines.OrderBy(gl => Math.Abs((int)gl.Y1 - Ypos)).First();
    }
    
  3. Graphical representation of the selection - Now draw (up to) 3 rectangles: from topleft point of the selection to bottomright point of the relevant text line, topleft point of the next line to bottomright point of the line before the last selected and topleft point of the last line to bottomright of selection

  4. Get text - Get partial text data from these rectangles and join.
like image 93
Peuczynski Avatar answered Sep 24 '22 23:09

Peuczynski