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?
I have to select text as shown in the above image.
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:
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);
}
}
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();
}
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With