找回密码
 立即注册
首页 业界区 安全 Github Copilot 实战: 从零开始用AI写一个OCR工具 (2) ...

Github Copilot 实战: 从零开始用AI写一个OCR工具 (2)

坟菊 2025-5-30 19:48:49
源码

https://github.com/densen2014/Blazor100/tree/master/AI/MiOcr
点击图片区域不需要选择图片

要移除“点击图片区域选择图片”的功能,只需删除或注释掉 ImageBorder_MouseLeftButtonUp 方法及其在 XAML 中的事件绑定。
操作步骤如下:

  • 删除 C# 事件处理方法
    在 MainWindow.xaml.cs 中,删除如下方法:
  1. // 点击图片区域也可选择图片
  2. private void ImageBorder_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  3. {
  4.     SelectImageButton_Click(sender, e);
  5. }
复制代码

  • 移除 XAML 事件绑定
    在 MainWindow.xaml 中,找到绑定了 MouseLeftButtonUp="ImageBorder_MouseLeftButtonUp" 的控件(通常是  或 <img>),将该属性删除。例如:
  1. [/code]改为:
  2. [code]
复制代码
这样,点击图片区域将不会再弹出选择图片对话框,拖放、粘贴等功能不受影响。
DrawOcrResultsOnImage 画出的区域支持鼠标右键复制文本

先上图:
1.png

要让 DrawOcrResultsOnImage 画出的区域支持鼠标右键复制文本,推荐的 WPF 实现方式如下:

  • 记录每个识别区域的多边形和文本,用于命中测试。
  • 在 MainImage 上监听鼠标右键事件,判断鼠标是否在某个区域内。
  • 弹出右键菜单,点击“复制文本”即可将对应文本复制到剪贴板。
下面是详细实现步骤:

  • 定义识别区域数据结构
    在 MainWindow 类中添加:
  1. private List<(Geometry geometry, string text)> _ocrRegions = new();
复制代码

  • 修改 DrawOcrResultsOnImage,记录区域
  1. private BitmapSource DrawOcrResultsOnImage(BitmapImage? image, PaddleOcrResult result)
  2. {
  3.     if (image == null) return null!;
  4.     int width = image.PixelWidth;
  5.     int height = image.PixelHeight;
  6.     _ocrRegions.Clear(); // 清空旧的区域
  7.     var visual = new DrawingVisual();
  8.     using (var dc = visual.RenderOpen())
  9.     {
  10. <Grid>
  11.     <Image x:Name="MainImage" Stretch="Uniform"
  12.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  13.            MouseMove="MainImage_MouseMove"
  14.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  15.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  16.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  17. </Grid>dc.DrawImage(image, new Rect(0, 0, width, height));
  18. <Grid>
  19.     <Image x:Name="MainImage" Stretch="Uniform"
  20.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  21.            MouseMove="MainImage_MouseMove"
  22.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  23.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  24.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  25. </Grid>var pen = new Pen(Brushes.Red, 2);
  26. <Grid>
  27.     <Image x:Name="MainImage" Stretch="Uniform"
  28.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  29.            MouseMove="MainImage_MouseMove"
  30.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  31.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  32.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  33. </Grid>var typeface = new Typeface("Arial");
  34. <Grid>
  35.     <Image x:Name="MainImage" Stretch="Uniform"
  36.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  37.            MouseMove="MainImage_MouseMove"
  38.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  39.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  40.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  41. </Grid>foreach (var region in result.Regions)
  42. <Grid>
  43.     <Image x:Name="MainImage" Stretch="Uniform"
  44.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  45.            MouseMove="MainImage_MouseMove"
  46.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  47.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  48.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  49. </Grid>{
  50. <Grid>
  51.     <Image x:Name="MainImage" Stretch="Uniform"
  52.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  53.            MouseMove="MainImage_MouseMove"
  54.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  55.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  56.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  57. </Grid>    var vertices = region.Rect.Points();
  58. <Grid>
  59.     <Image x:Name="MainImage" Stretch="Uniform"
  60.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  61.            MouseMove="MainImage_MouseMove"
  62.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  63.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  64.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  65. </Grid>    var points = vertices.Select(p => new System.Windows.Point(p.X, p.Y)).ToArray();
  66. <Grid>
  67.     <Image x:Name="MainImage" Stretch="Uniform"
  68.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  69.            MouseMove="MainImage_MouseMove"
  70.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  71.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  72.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  73. </Grid>    // 绘制多边形
  74. <Grid>
  75.     <Image x:Name="MainImage" Stretch="Uniform"
  76.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  77.            MouseMove="MainImage_MouseMove"
  78.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  79.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  80.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  81. </Grid>    var figure = new PathFigure(points[0], new[] { new PolyLineSegment(points.Skip(1), true) }, true);
  82. <Grid>
  83.     <Image x:Name="MainImage" Stretch="Uniform"
  84.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  85.            MouseMove="MainImage_MouseMove"
  86.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  87.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  88.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  89. </Grid>    var geometry = new PathGeometry(new[] { figure });
  90. <Grid>
  91.     <Image x:Name="MainImage" Stretch="Uniform"
  92.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  93.            MouseMove="MainImage_MouseMove"
  94.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  95.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  96.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  97. </Grid>    dc.DrawGeometry(null, pen, geometry);
  98. <Grid>
  99.     <Image x:Name="MainImage" Stretch="Uniform"
  100.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  101.            MouseMove="MainImage_MouseMove"
  102.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  103.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  104.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  105. </Grid>    // 记录区域和文本
  106. <Grid>
  107.     <Image x:Name="MainImage" Stretch="Uniform"
  108.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  109.            MouseMove="MainImage_MouseMove"
  110.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  111.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  112.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  113. </Grid>    _ocrRegions.Add((geometry, region.Text));
  114. <Grid>
  115.     <Image x:Name="MainImage" Stretch="Uniform"
  116.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  117.            MouseMove="MainImage_MouseMove"
  118.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  119.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  120.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  121. </Grid>    // 绘制文字
  122. <Grid>
  123.     <Image x:Name="MainImage" Stretch="Uniform"
  124.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  125.            MouseMove="MainImage_MouseMove"
  126.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  127.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  128.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  129. </Grid>    var formattedText = new FormattedText(
  130. <Grid>
  131.     <Image x:Name="MainImage" Stretch="Uniform"
  132.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  133.            MouseMove="MainImage_MouseMove"
  134.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  135.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  136.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  137. </Grid><Grid>
  138.     <Image x:Name="MainImage" Stretch="Uniform"
  139.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  140.            MouseMove="MainImage_MouseMove"
  141.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  142.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  143.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  144. </Grid>region.Text,
  145. <Grid>
  146.     <Image x:Name="MainImage" Stretch="Uniform"
  147.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  148.            MouseMove="MainImage_MouseMove"
  149.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  150.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  151.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  152. </Grid><Grid>
  153.     <Image x:Name="MainImage" Stretch="Uniform"
  154.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  155.            MouseMove="MainImage_MouseMove"
  156.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  157.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  158.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  159. </Grid>System.Globalization.CultureInfo.CurrentCulture,
  160. <Grid>
  161.     <Image x:Name="MainImage" Stretch="Uniform"
  162.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  163.            MouseMove="MainImage_MouseMove"
  164.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  165.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  166.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  167. </Grid><Grid>
  168.     <Image x:Name="MainImage" Stretch="Uniform"
  169.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  170.            MouseMove="MainImage_MouseMove"
  171.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  172.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  173.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  174. </Grid>FlowDirection.LeftToRight,
  175. <Grid>
  176.     <Image x:Name="MainImage" Stretch="Uniform"
  177.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  178.            MouseMove="MainImage_MouseMove"
  179.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  180.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  181.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  182. </Grid><Grid>
  183.     <Image x:Name="MainImage" Stretch="Uniform"
  184.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  185.            MouseMove="MainImage_MouseMove"
  186.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  187.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  188.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  189. </Grid>typeface,
  190. <Grid>
  191.     <Image x:Name="MainImage" Stretch="Uniform"
  192.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  193.            MouseMove="MainImage_MouseMove"
  194.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  195.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  196.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  197. </Grid><Grid>
  198.     <Image x:Name="MainImage" Stretch="Uniform"
  199.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  200.            MouseMove="MainImage_MouseMove"
  201.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  202.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  203.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  204. </Grid>20,
  205. <Grid>
  206.     <Image x:Name="MainImage" Stretch="Uniform"
  207.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  208.            MouseMove="MainImage_MouseMove"
  209.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  210.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  211.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  212. </Grid><Grid>
  213.     <Image x:Name="MainImage" Stretch="Uniform"
  214.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  215.            MouseMove="MainImage_MouseMove"
  216.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  217.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  218.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  219. </Grid>Brushes.Yellow,
  220. <Grid>
  221.     <Image x:Name="MainImage" Stretch="Uniform"
  222.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  223.            MouseMove="MainImage_MouseMove"
  224.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  225.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  226.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  227. </Grid><Grid>
  228.     <Image x:Name="MainImage" Stretch="Uniform"
  229.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  230.            MouseMove="MainImage_MouseMove"
  231.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  232.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  233.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  234. </Grid>1.25);
  235. <Grid>
  236.     <Image x:Name="MainImage" Stretch="Uniform"
  237.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  238.            MouseMove="MainImage_MouseMove"
  239.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  240.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  241.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  242. </Grid>    dc.DrawText(formattedText, new System.Windows.Point(region.Rect.Center.X, region.Rect.Center.Y));
  243. <Grid>
  244.     <Image x:Name="MainImage" Stretch="Uniform"
  245.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  246.            MouseMove="MainImage_MouseMove"
  247.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  248.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  249.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  250. </Grid>}
  251.     }
  252.     var bmp = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
  253.     bmp.Render(visual);
  254.     bmp.Freeze();
  255.     return bmp;
  256. }
复制代码

  • 监听 MainImage 的鼠标右键事件
    在 MainWindow.xaml 的  增加:
  1. [/code][list=1]
  2. [*]实现右键菜单和复制逻辑
  3. 在 MainWindow.xaml.cs 添加:
  4. [/list][code]private void MainImage_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
  5. {
  6.     var pos = e.GetPosition(MainImage);
  7.     // 需要将控件坐标映射到图片像素坐标
  8.     if (_currentImage == null || _ocrRegions.Count == 0) return;
  9.     // 计算缩放比例和偏移
  10.     var imgRect = new Rect(0, 0, _currentImage.PixelWidth, _currentImage.PixelHeight);
  11.     var ctrlRect = new Rect(0, 0, MainImage.ActualWidth, MainImage.ActualHeight);
  12.     var scale = Math.Min(ctrlRect.Width / imgRect.Width, ctrlRect.Height / imgRect.Height);
  13.     var offsetX = (ctrlRect.Width - imgRect.Width * scale) / 2;
  14.     var offsetY = (ctrlRect.Height - imgRect.Height * scale) / 2;
  15.     var imgX = (pos.X - offsetX) / scale;
  16.     var imgY = (pos.Y - offsetY) / scale;
  17.     var imgPoint = new System.Windows.Point(imgX, imgY);
  18.     // 命中测试
  19.     foreach (var (geometry, text) in _ocrRegions)
  20.     {
  21. <Grid>
  22.     <Image x:Name="MainImage" Stretch="Uniform"
  23.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  24.            MouseMove="MainImage_MouseMove"
  25.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  26.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  27.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  28. </Grid>if (geometry.FillContains(imgPoint))
  29. <Grid>
  30.     <Image x:Name="MainImage" Stretch="Uniform"
  31.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  32.            MouseMove="MainImage_MouseMove"
  33.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  34.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  35.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  36. </Grid>{
  37. <Grid>
  38.     <Image x:Name="MainImage" Stretch="Uniform"
  39.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  40.            MouseMove="MainImage_MouseMove"
  41.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  42.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  43.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  44. </Grid>    // 弹出右键菜单
  45. <Grid>
  46.     <Image x:Name="MainImage" Stretch="Uniform"
  47.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  48.            MouseMove="MainImage_MouseMove"
  49.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  50.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  51.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  52. </Grid>    var menu = new ContextMenu();
  53. <Grid>
  54.     <Image x:Name="MainImage" Stretch="Uniform"
  55.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  56.            MouseMove="MainImage_MouseMove"
  57.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  58.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  59.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  60. </Grid>    var item = new MenuItem { Header = "复制文本" };
  61. <Grid>
  62.     <Image x:Name="MainImage" Stretch="Uniform"
  63.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  64.            MouseMove="MainImage_MouseMove"
  65.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  66.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  67.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  68. </Grid>    item.Click += (s, args) => Clipboard.SetText(text);
  69. <Grid>
  70.     <Image x:Name="MainImage" Stretch="Uniform"
  71.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  72.            MouseMove="MainImage_MouseMove"
  73.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  74.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  75.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  76. </Grid>    menu.Items.Add(item);
  77. <Grid>
  78.     <Image x:Name="MainImage" Stretch="Uniform"
  79.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  80.            MouseMove="MainImage_MouseMove"
  81.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  82.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  83.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  84. </Grid>    menu.IsOpen = true;
  85. <Grid>
  86.     <Image x:Name="MainImage" Stretch="Uniform"
  87.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  88.            MouseMove="MainImage_MouseMove"
  89.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  90.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  91.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  92. </Grid>    break;
  93. <Grid>
  94.     <Image x:Name="MainImage" Stretch="Uniform"
  95.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  96.            MouseMove="MainImage_MouseMove"
  97.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  98.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  99.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  100. </Grid>}
  101.     }
  102. }
复制代码
说明
•        支持图片缩放/居中情况下的坐标映射。
•        只在点击到识别区域时弹出“复制文本”菜单。
•        复制后可直接粘贴到其他地方。
如需支持多语言或批量复制,可扩展菜单项。此方案适用于 WPF,且不会影响拖放、粘贴等原有功能。
支持鼠标左键按下拖动多选区域复制文本

效果图:
2.png

你可以通过以下方式支持鼠标左键拖动框选多个 OCR 区域并复制文本:

  • 鼠标左键按下时记录起点,拖动时绘制选框,松开时判断与哪些 OCR 区域相交,弹出菜单可复制所有命中的文本。
  • 需要在 MainWindow 中维护选框状态,并在 MainImage 上处理相关事件。

  • 字段定义
    在 MainWindow 类中添加
  1. private System.Windows.Point? _selectStart;
  2. private System.Windows.Point? _selectEnd;
  3. private Rectangle _selectionRect = new Rectangle();
  4. private List<string> _selectedTexts = new();
复制代码

  • XAML 增加 Canvas 覆盖层
    在 MainWindow.xaml 的图片区域外包一层 Grid,并在其上放置一个 Canvas 用于绘制选框:
  1. <Grid>
  2.     <Image x:Name="MainImage" Stretch="Uniform"
  3.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  4.            MouseMove="MainImage_MouseMove"
  5.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  6.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  7.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  8. </Grid>
复制代码

  • 鼠标事件实现
    在 MainWindow.xaml.cs 添加:
  1. private void MainImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e){    if (_currentImage == null) return;    _selectStart = e.GetPosition(MainImage);    _selectEnd = null;    _selectedTexts.Clear();    OverlayCanvas.Children.Clear();    MainImage.CaptureMouse();}private void MainImage_MouseMove(object sender, MouseEventArgs e){    if (_selectStart.HasValue && e.LeftButton == MouseButtonState.Pressed)    {<Grid>
  2.     <Image x:Name="MainImage" Stretch="Uniform"
  3.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  4.            MouseMove="MainImage_MouseMove"
  5.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  6.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  7.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  8. </Grid>_selectEnd = e.GetPosition(MainImage);<Grid>
  9.     <Image x:Name="MainImage" Stretch="Uniform"
  10.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  11.            MouseMove="MainImage_MouseMove"
  12.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  13.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  14.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  15. </Grid>DrawSelectionRectangle();    }}private void MainImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e){    if (_selectStart.HasValue && _selectEnd.HasValue)    {<Grid>
  16.     <Image x:Name="MainImage" Stretch="Uniform"
  17.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  18.            MouseMove="MainImage_MouseMove"
  19.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  20.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  21.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  22. </Grid>var rect = GetImageRectFromControlRect(new Rect(_selectStart.Value, _selectEnd.Value));<Grid>
  23.     <Image x:Name="MainImage" Stretch="Uniform"
  24.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  25.            MouseMove="MainImage_MouseMove"
  26.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  27.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  28.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  29. </Grid>_selectedTexts = _ocrRegions<Grid>
  30.     <Image x:Name="MainImage" Stretch="Uniform"
  31.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  32.            MouseMove="MainImage_MouseMove"
  33.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  34.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  35.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  36. </Grid>    .Where(r => r.geometry.Bounds.IntersectsWith(rect))<Grid>
  37.     <Image x:Name="MainImage" Stretch="Uniform"
  38.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  39.            MouseMove="MainImage_MouseMove"
  40.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  41.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  42.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  43. </Grid>    .Select(r => r.text)<Grid>
  44.     <Image x:Name="MainImage" Stretch="Uniform"
  45.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  46.            MouseMove="MainImage_MouseMove"
  47.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  48.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  49.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  50. </Grid>    .ToList();<Grid>
  51.     <Image x:Name="MainImage" Stretch="Uniform"
  52.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  53.            MouseMove="MainImage_MouseMove"
  54.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  55.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  56.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  57. </Grid>if (_selectedTexts.Count > 0)<Grid>
  58.     <Image x:Name="MainImage" Stretch="Uniform"
  59.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  60.            MouseMove="MainImage_MouseMove"
  61.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  62.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  63.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  64. </Grid>{<Grid>
  65.     <Image x:Name="MainImage" Stretch="Uniform"
  66.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  67.            MouseMove="MainImage_MouseMove"
  68.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  69.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  70.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  71. </Grid>    var menu = new ContextMenu();<Grid>
  72.     <Image x:Name="MainImage" Stretch="Uniform"
  73.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  74.            MouseMove="MainImage_MouseMove"
  75.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  76.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  77.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  78. </Grid>    var item = new MenuItem { Header = $"复制所选文本({_selectedTexts.Count})" };<Grid>
  79.     <Image x:Name="MainImage" Stretch="Uniform"
  80.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  81.            MouseMove="MainImage_MouseMove"
  82.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  83.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  84.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  85. </Grid>    item.Click += (s, args) => Clipboard.SetText(string.Join(Environment.NewLine, _selectedTexts));<Grid>
  86.     <Image x:Name="MainImage" Stretch="Uniform"
  87.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  88.            MouseMove="MainImage_MouseMove"
  89.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  90.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  91.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  92. </Grid>    menu.Items.Add(item);<Grid>
  93.     <Image x:Name="MainImage" Stretch="Uniform"
  94.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  95.            MouseMove="MainImage_MouseMove"
  96.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  97.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  98.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  99. </Grid>    menu.IsOpen = true;<Grid>
  100.     <Image x:Name="MainImage" Stretch="Uniform"
  101.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  102.            MouseMove="MainImage_MouseMove"
  103.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  104.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  105.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  106. </Grid>}    }    _selectStart = null;    _selectEnd = null;    OverlayCanvas.Children.Clear();    MainImage.ReleaseMouseCapture();}private void DrawSelectionRectangle(){    OverlayCanvas.Children.Clear();    if (_selectStart.HasValue && _selectEnd.HasValue)    {<Grid>
  107.     <Image x:Name="MainImage" Stretch="Uniform"
  108.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  109.            MouseMove="MainImage_MouseMove"
  110.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  111.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  112.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  113. </Grid>var rect = new Rect(_selectStart.Value, _selectEnd.Value);<Grid>
  114.     <Image x:Name="MainImage" Stretch="Uniform"
  115.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  116.            MouseMove="MainImage_MouseMove"
  117.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  118.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  119.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  120. </Grid>var r = new System.Windows.Shapes.Rectangle<Grid>
  121.     <Image x:Name="MainImage" Stretch="Uniform"
  122.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  123.            MouseMove="MainImage_MouseMove"
  124.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  125.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  126.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  127. </Grid>{<Grid>
  128.     <Image x:Name="MainImage" Stretch="Uniform"
  129.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  130.            MouseMove="MainImage_MouseMove"
  131.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  132.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  133.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  134. </Grid>    Stroke = Brushes.Blue,<Grid>
  135.     <Image x:Name="MainImage" Stretch="Uniform"
  136.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  137.            MouseMove="MainImage_MouseMove"
  138.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  139.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  140.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  141. </Grid>    StrokeThickness = 2,<Grid>
  142.     <Image x:Name="MainImage" Stretch="Uniform"
  143.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  144.            MouseMove="MainImage_MouseMove"
  145.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  146.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  147.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  148. </Grid>    Fill = new SolidColorBrush(Color.FromArgb(40, 0, 0, 255)),<Grid>
  149.     <Image x:Name="MainImage" Stretch="Uniform"
  150.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  151.            MouseMove="MainImage_MouseMove"
  152.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  153.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  154.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  155. </Grid>    Width = rect.Width,<Grid>
  156.     <Image x:Name="MainImage" Stretch="Uniform"
  157.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  158.            MouseMove="MainImage_MouseMove"
  159.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  160.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  161.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  162. </Grid>    Height = rect.Height<Grid>
  163.     <Image x:Name="MainImage" Stretch="Uniform"
  164.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  165.            MouseMove="MainImage_MouseMove"
  166.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  167.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  168.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  169. </Grid>};<Grid>
  170.     <Image x:Name="MainImage" Stretch="Uniform"
  171.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  172.            MouseMove="MainImage_MouseMove"
  173.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  174.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  175.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  176. </Grid>Canvas.SetLeft(r, rect.Left);<Grid>
  177.     <Image x:Name="MainImage" Stretch="Uniform"
  178.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  179.            MouseMove="MainImage_MouseMove"
  180.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  181.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  182.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  183. </Grid>Canvas.SetTop(r, rect.Top);<Grid>
  184.     <Image x:Name="MainImage" Stretch="Uniform"
  185.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  186.            MouseMove="MainImage_MouseMove"
  187.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  188.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  189.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  190. </Grid>OverlayCanvas.Children.Add(r);    }}
复制代码

  • 坐标映射辅助方法
    添加一个方法,将控件坐标的选框映射到图片像素坐标:
  1. private Rect GetImageRectFromControlRect(Rect ctrlRect)
  2. {
  3.     if (_currentImage == null) return Rect.Empty;
  4.     var imgRect = new Rect(0, 0, _currentImage.PixelWidth, _currentImage.PixelHeight);
  5.     var ctrlActual = new Rect(0, 0, MainImage.ActualWidth, MainImage.ActualHeight);
  6.     var scale = Math.Min(ctrlActual.Width / imgRect.Width, ctrlActual.Height / imgRect.Height);
  7.     var offsetX = (ctrlActual.Width - imgRect.Width * scale) / 2;
  8.     var offsetY = (ctrlActual.Height - imgRect.Height * scale) / 2;
  9.     // 映射到图片坐标
  10.     double x1 = (ctrlRect.Left - offsetX) / scale;
  11.     double y1 = (ctrlRect.Top - offsetY) / scale;
  12.     double x2 = (ctrlRect.Right - offsetX) / scale;
  13.     double y2 = (ctrlRect.Bottom - offsetY) / scale;
  14.     return new Rect(new System.Windows.Point(x1, y1), new System.Windows.Point(x2, y2));
  15. }
复制代码

  • 说明
    •        支持拖动框选,松开后弹出菜单复制所有命中的文本。
    •        支持图片缩放和居中。
    •        右键单选依然可用。
如需高亮选中区域,可在 DrawOcrResultsOnImage 中根据 _selectedTexts 高亮对应区域。此方案适用于 WPF,且不会影响原有功能。
如何在选框内显示选中的文本内容?

图同上
在 WPF 中,如果你想在拖动选框时在选框内实时显示选中的文本内容,可以在 DrawSelectionRectangle 方法中,除了绘制矩形,还绘制文本。
实现思路如下:



  • 实时获取选框内的文本
    在 DrawSelectionRectangle 方法中,获取当前选框对应图片区域的文本:
  1. private void DrawSelectionRectangle(){    OverlayCanvas.Children.Clear();    if (_selectStart.HasValue && _selectEnd.HasValue)    {<Grid>
  2.     <Image x:Name="MainImage" Stretch="Uniform"
  3.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  4.            MouseMove="MainImage_MouseMove"
  5.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  6.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  7.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  8. </Grid>var rect = new Rect(_selectStart.Value, _selectEnd.Value);<Grid>
  9.     <Image x:Name="MainImage" Stretch="Uniform"
  10.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  11.            MouseMove="MainImage_MouseMove"
  12.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  13.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  14.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  15. </Grid>var r = new System.Windows.Shapes.Rectangle<Grid>
  16.     <Image x:Name="MainImage" Stretch="Uniform"
  17.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  18.            MouseMove="MainImage_MouseMove"
  19.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  20.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  21.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  22. </Grid>{<Grid>
  23.     <Image x:Name="MainImage" Stretch="Uniform"
  24.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  25.            MouseMove="MainImage_MouseMove"
  26.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  27.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  28.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  29. </Grid>    Stroke = Brushes.Blue,<Grid>
  30.     <Image x:Name="MainImage" Stretch="Uniform"
  31.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  32.            MouseMove="MainImage_MouseMove"
  33.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  34.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  35.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  36. </Grid>    StrokeThickness = 2,<Grid>
  37.     <Image x:Name="MainImage" Stretch="Uniform"
  38.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  39.            MouseMove="MainImage_MouseMove"
  40.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  41.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  42.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  43. </Grid>    Fill = new SolidColorBrush(Color.FromArgb(40, 0, 0, 255)),<Grid>
  44.     <Image x:Name="MainImage" Stretch="Uniform"
  45.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  46.            MouseMove="MainImage_MouseMove"
  47.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  48.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  49.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  50. </Grid>    Width = rect.Width,<Grid>
  51.     <Image x:Name="MainImage" Stretch="Uniform"
  52.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  53.            MouseMove="MainImage_MouseMove"
  54.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  55.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  56.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  57. </Grid>    Height = rect.Height<Grid>
  58.     <Image x:Name="MainImage" Stretch="Uniform"
  59.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  60.            MouseMove="MainImage_MouseMove"
  61.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  62.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  63.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  64. </Grid>};<Grid>
  65.     <Image x:Name="MainImage" Stretch="Uniform"
  66.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  67.            MouseMove="MainImage_MouseMove"
  68.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  69.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  70.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  71. </Grid>Canvas.SetLeft(r, rect.Left);<Grid>
  72.     <Image x:Name="MainImage" Stretch="Uniform"
  73.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  74.            MouseMove="MainImage_MouseMove"
  75.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  76.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  77.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  78. </Grid>Canvas.SetTop(r, rect.Top);<Grid>
  79.     <Image x:Name="MainImage" Stretch="Uniform"
  80.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  81.            MouseMove="MainImage_MouseMove"
  82.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  83.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  84.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  85. </Grid>OverlayCanvas.Children.Add(r);<Grid>
  86.     <Image x:Name="MainImage" Stretch="Uniform"
  87.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  88.            MouseMove="MainImage_MouseMove"
  89.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  90.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  91.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  92. </Grid>// 获取选框对应图片坐标的区域<Grid>
  93.     <Image x:Name="MainImage" Stretch="Uniform"
  94.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  95.            MouseMove="MainImage_MouseMove"
  96.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  97.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  98.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  99. </Grid>var imgRect = GetImageRectFromControlRect(rect);<Grid>
  100.     <Image x:Name="MainImage" Stretch="Uniform"
  101.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  102.            MouseMove="MainImage_MouseMove"
  103.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  104.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  105.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  106. </Grid>var selectedTexts = _ocrRegions<Grid>
  107.     <Image x:Name="MainImage" Stretch="Uniform"
  108.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  109.            MouseMove="MainImage_MouseMove"
  110.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  111.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  112.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  113. </Grid>    .Where(region => region.geometry.Bounds.IntersectsWith(imgRect))<Grid>
  114.     <Image x:Name="MainImage" Stretch="Uniform"
  115.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  116.            MouseMove="MainImage_MouseMove"
  117.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  118.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  119.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  120. </Grid>    .Select(region => region.text)<Grid>
  121.     <Image x:Name="MainImage" Stretch="Uniform"
  122.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  123.            MouseMove="MainImage_MouseMove"
  124.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  125.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  126.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  127. </Grid>    .ToList();<Grid>
  128.     <Image x:Name="MainImage" Stretch="Uniform"
  129.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  130.            MouseMove="MainImage_MouseMove"
  131.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  132.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  133.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  134. </Grid>if (selectedTexts.Count > 0)<Grid>
  135.     <Image x:Name="MainImage" Stretch="Uniform"
  136.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  137.            MouseMove="MainImage_MouseMove"
  138.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  139.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  140.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  141. </Grid>{<Grid>
  142.     <Image x:Name="MainImage" Stretch="Uniform"
  143.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  144.            MouseMove="MainImage_MouseMove"
  145.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  146.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  147.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  148. </Grid>    // 在选框内绘制文本<Grid>
  149.     <Image x:Name="MainImage" Stretch="Uniform"
  150.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  151.            MouseMove="MainImage_MouseMove"
  152.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  153.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  154.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  155. </Grid>    var text = string.Join(Environment.NewLine, selectedTexts);<Grid>
  156.     <Image x:Name="MainImage" Stretch="Uniform"
  157.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  158.            MouseMove="MainImage_MouseMove"
  159.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  160.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  161.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  162. </Grid>    var tb = new TextBlock<Grid>
  163.     <Image x:Name="MainImage" Stretch="Uniform"
  164.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  165.            MouseMove="MainImage_MouseMove"
  166.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  167.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  168.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  169. </Grid>    {<Grid>
  170.     <Image x:Name="MainImage" Stretch="Uniform"
  171.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  172.            MouseMove="MainImage_MouseMove"
  173.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  174.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  175.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  176. </Grid><Grid>
  177.     <Image x:Name="MainImage" Stretch="Uniform"
  178.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  179.            MouseMove="MainImage_MouseMove"
  180.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  181.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  182.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  183. </Grid>Text = text,<Grid>
  184.     <Image x:Name="MainImage" Stretch="Uniform"
  185.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  186.            MouseMove="MainImage_MouseMove"
  187.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  188.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  189.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  190. </Grid><Grid>
  191.     <Image x:Name="MainImage" Stretch="Uniform"
  192.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  193.            MouseMove="MainImage_MouseMove"
  194.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  195.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  196.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  197. </Grid>Foreground = Brushes.Black,<Grid>
  198.     <Image x:Name="MainImage" Stretch="Uniform"
  199.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  200.            MouseMove="MainImage_MouseMove"
  201.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  202.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  203.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  204. </Grid><Grid>
  205.     <Image x:Name="MainImage" Stretch="Uniform"
  206.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  207.            MouseMove="MainImage_MouseMove"
  208.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  209.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  210.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  211. </Grid>Background = new SolidColorBrush(Color.FromArgb(180, 255, 255, 255)),<Grid>
  212.     <Image x:Name="MainImage" Stretch="Uniform"
  213.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  214.            MouseMove="MainImage_MouseMove"
  215.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  216.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  217.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  218. </Grid><Grid>
  219.     <Image x:Name="MainImage" Stretch="Uniform"
  220.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  221.            MouseMove="MainImage_MouseMove"
  222.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  223.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  224.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  225. </Grid>FontSize = 16,<Grid>
  226.     <Image x:Name="MainImage" Stretch="Uniform"
  227.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  228.            MouseMove="MainImage_MouseMove"
  229.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  230.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  231.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  232. </Grid><Grid>
  233.     <Image x:Name="MainImage" Stretch="Uniform"
  234.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  235.            MouseMove="MainImage_MouseMove"
  236.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  237.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  238.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  239. </Grid>TextWrapping = TextWrapping.Wrap,<Grid>
  240.     <Image x:Name="MainImage" Stretch="Uniform"
  241.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  242.            MouseMove="MainImage_MouseMove"
  243.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  244.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  245.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  246. </Grid><Grid>
  247.     <Image x:Name="MainImage" Stretch="Uniform"
  248.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  249.            MouseMove="MainImage_MouseMove"
  250.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  251.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  252.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  253. </Grid>Width = r.Width - 8,<Grid>
  254.     <Image x:Name="MainImage" Stretch="Uniform"
  255.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  256.            MouseMove="MainImage_MouseMove"
  257.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  258.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  259.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  260. </Grid><Grid>
  261.     <Image x:Name="MainImage" Stretch="Uniform"
  262.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  263.            MouseMove="MainImage_MouseMove"
  264.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  265.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  266.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  267. </Grid>Padding = new Thickness(4)<Grid>
  268.     <Image x:Name="MainImage" Stretch="Uniform"
  269.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  270.            MouseMove="MainImage_MouseMove"
  271.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  272.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  273.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  274. </Grid>    };<Grid>
  275.     <Image x:Name="MainImage" Stretch="Uniform"
  276.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  277.            MouseMove="MainImage_MouseMove"
  278.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  279.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  280.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  281. </Grid>    Canvas.SetLeft(tb, rect.Left + 4);<Grid>
  282.     <Image x:Name="MainImage" Stretch="Uniform"
  283.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  284.            MouseMove="MainImage_MouseMove"
  285.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  286.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  287.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  288. </Grid>    Canvas.SetTop(tb, rect.Top + 4);<Grid>
  289.     <Image x:Name="MainImage" Stretch="Uniform"
  290.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  291.            MouseMove="MainImage_MouseMove"
  292.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  293.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  294.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  295. </Grid>    OverlayCanvas.Children.Add(tb);<Grid>
  296.     <Image x:Name="MainImage" Stretch="Uniform"
  297.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  298.            MouseMove="MainImage_MouseMove"
  299.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  300.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  301.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  302. </Grid>}    }}
复制代码

  • 说明
    •        这样拖动时,选框内会实时显示所有被选中的文本内容。
    •        TextBlock 的宽度和位置做了适当缩进,避免与边框重叠。
    •        若文本较多,TextWrapping 可自动换行。
  • 注意事项
    •        如果选框很小,文本可能显示不全,可根据需要调整字体或最小宽高。
    •        若要美观,可进一步美化 TextBlock 的样式。
在执行ocr之前显示图片, 然后显示一个正在处理的提示, 提升客户体验

效果图:

你可以在执行 OCR 前先显示图片,然后在图片上方显示一个“正在处理...”的提示,OCR 完成后再隐藏提示。
推荐做法是在 XAML 中添加一个覆盖层(如 TextBlock 或 Border),通过代码控制其可见性。



  • XAML 增加处理提示层
    在 MainWindow.xaml 的图片区域 Grid 内,<img> 和  之后添加:
  1. [/code][list=1]
  2. [*]C# 控制提示显示/隐藏
  3. 在 MainWindow.xaml.cs 的 RunOcrAndDraw 前后控制提示:
  4. [/list][code]private async Task RunOcrAndDraw(byte[] imageBytes){    // 先显示图片    ProcessingText.Visibility = Visibility.Visible;    await Task.Delay(100); // 确保UI刷新    var ocr = new PaddleOCRService();    var results = await ocr.StartOCR(imageBytes);    ProcessingText.Visibility = Visibility.Collapsed;    if (results.strings == null || results.strings.Count == 0)    {<Grid>
  5.     <Image x:Name="MainImage" Stretch="Uniform"
  6.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  7.            MouseMove="MainImage_MouseMove"
  8.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  9.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  10.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  11. </Grid>OcrTextBox.Text = "未识别到文本";<Grid>
  12.     <Image x:Name="MainImage" Stretch="Uniform"
  13.            MouseLeftButtonDown="MainImage_MouseLeftButtonDown"
  14.            MouseMove="MainImage_MouseMove"
  15.            MouseLeftButtonUp="MainImage_MouseLeftButtonUp"
  16.            MouseRightButtonUp="MainImage_MouseRightButtonUp"/>
  17.     <Canvas x:Name="OverlayCanvas" IsHitTestVisible="False"/>
  18. </Grid>return;    }    OcrTextBox.Text = string.Join(Environment.NewLine, results.result.Regions.Select(r => r.Text));    var drawed = DrawOcrResultsOnImage(_currentImage, results.result);    MainImage.Source = drawed;}
复制代码

  • 说明
    •        这样图片会立即显示,提示“正在处理...”会覆盖在图片上,OCR 完成后自动隐藏。
    •        await Task.Delay(100); 可确保 UI 有机会刷新,防止提示未及时显示。
    •        你可以根据需要调整提示样式和位置。
这样即可显著提升用户体验,避免界面卡顿或无响应的错觉。
在选框内绘制文本 出现了错误  System.ArgumentException:““-8”不是属性“Width”的有效值。”

你遇到的错误:
System.ArgumentException: “-8”不是属性“Width”的有效值。
原因是:
当选框很小时,r.Width - 8 变成了负数,TextBlock.Width 不能为负。


解决方法
在设置 TextBlock.Width 时,确保其为正数(最小为 1 或 0),可用 Math.Max:
  1. Width = Math.Max(1, r.Width - 8),
复制代码
修正后的代码片段:
  1. var tb = new TextBlock
  2. {
  3.     Text = text,
  4.     Foreground = Brushes.Black,
  5.     Background = new SolidColorBrush(Color.FromArgb(180, 255, 255, 255)),
  6.     FontSize = 16,
  7.     TextWrapping = TextWrapping.Wrap,
  8.     Width = Math.Max(1, r.Width - 8),
  9.     Padding = new Thickness(4)
  10. };
复制代码
建议:
你也可以判断选框宽高过小时不显示文本,避免体验异常。
这样即可避免该异常,选框很小时不会再报错。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册