Ответ 1
То, что вы хотите, невозможно. У вас есть растровое изображение, и оно не волшебным образом известно о тексте в нем, и ничего не изменится. Хотя это не то, что вы ничего не можете с этим поделать. У меня нет времени, чтобы предоставить полное решение, но я могу дать пошаговую инструкцию по достижению наилучшего возможного решения.
Что вы можете сделать:
-
Определение размеров текста. Создайте элемент управления с сеткой, наложенной на изображение с редактируемым шагом и смещением по оси X и Y. Затем вы сможете откалибровать сетку с помощью строк текста (Y). И ширина символа (X). Что-то в этом роде должно (я думаю, вы получите общую идею):
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); } }
-
Выбор текста. Все, что вам нужно сделать, это добавить "привязать к сетке" возможность вашего контроля. Опять же, только для справки:
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 прямоугольника: от точки завершения выборки до нужной точки соответствующей текстовой строки, topleft point следующей строки, чтобы прямая точка линии до последней выбранной и переполненной точки последней строки до прямой выбор
- Получить текст. Получить частичные текстовые данные из этих прямоугольников и присоединиться.