Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 65 additions & 64 deletions platforms/windows/WriteBench/Services/OCR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,69 +5,70 @@
using System.Windows.Media.Imaging;
using Microsoft.Win32;
using Tesseract;
namespace WriteBench;

public sealed partial class MainWindow
{
async Task ImportImages(bool answer)
{
if (grading)
return;
var dialog = new OpenFileDialog { Title = answer ? "导入手写稿" : "导入题目", Filter = "图片|*.png;*.jpg;*.jpeg;*.bmp;*.tif;*.tiff", Multiselect = true };
if (dialog.ShowDialog(this) != true)
return;
if (dialog.FileNames.Length > 12)
{
Message("每次最多导入 12 页。");
return;
}
try
{
foreach (var p in dialog.FileNames)
if (new FileInfo(p).Length > 25_000_000)
throw new Exception("每张图片不得超过 25 MB");
var recognized = await Task.Run(() => { using var engine = new TesseractEngine(Path.Combine(AppContext.BaseDirectory, "tessdata"), "eng+chi_sim", EngineMode.Default); return dialog.FileNames.Select(path => { using var image = Pix.LoadFromFile(path); using var page = engine.Process(image); return page.GetText(); }).ToArray(); });
ConfirmOCR(dialog.FileNames, recognized, answer);
}
catch (Exception e) { Message("本机图片识别未完成。请检查图像清晰度与 OCR 运行库。\n" + e.Message); }
}
void ConfirmOCR(string[] files, string[] texts, bool answer)
{
var window = new Window { Owner = this, Title = "校对识别结果", Width = 1050, Height = 760, WindowStartupLocation = WindowStartupLocation.CenterOwner };
var root = new DockPanel { Margin = new Thickness(24) };
var footer = new StackPanel { Orientation = System.Windows.Controls.Orientation.Horizontal, Margin = new Thickness(0, 20, 0, 0) };
var checkedAll = new CheckBox { Content = "我已对照原图核对所有页面", VerticalAlignment = VerticalAlignment.Center, Margin = new Thickness(0, 0, 20, 0) };
footer.Children.Add(checkedAll);
var confirm = Button(answer ? "确认并评卷" : "确认填入题目", () => { if (answer) { essay = string.Join("\n\n", texts); inputMode = "handwritten"; } else question = string.Join("\n\n", texts); SaveDraft(); window.Close(); Render(); if (answer) _ = Submit(); }, true);
confirm.IsEnabled = false;
checkedAll.Checked += (_, _) => confirm.IsEnabled = true;
checkedAll.Unchecked += (_, _) => confirm.IsEnabled = false;
footer.Children.Add(confirm);
DockPanel.SetDock(footer, Dock.Bottom);
root.Children.Add(footer);
var tabs = new TabControl();
for (int i = 0; i < files.Length; i++)
{
int index = i;
var grid = new Grid();
grid.ColumnDefinitions.Add(new());
grid.ColumnDefinitions.Add(new());
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(files[i]);
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
var image = new Image { Source = bitmap, Stretch = Stretch.Uniform, Margin = new Thickness(12) };
grid.Children.Add(new ScrollViewer { Content = image });
var editor = Input(texts[i]);
editor.AcceptsReturn = true;
editor.TextChanged += (_, _) => texts[index] = editor.Text;
Grid.SetColumn(editor, 1);
grid.Children.Add(editor);
tabs.Items.Add(new TabItem { Header = $"第 {i + 1} 页", Content = grid });
}
root.Children.Add(tabs);
window.Content = root;
window.ShowDialog();
namespace WriteBench;

public sealed partial class MainWindow
{
async Task ImportImages(bool answer)
{
if (grading)
return;
var dialog = new OpenFileDialog { Title = answer ? "导入手写稿" : "导入题目", Filter = "图片|*.png;*.jpg;*.jpeg;*.bmp;*.tif;*.tiff", Multiselect = true };
if (dialog.ShowDialog(this) != true)
return;
if (dialog.FileNames.Length > 12)
{
Message("每次最多导入 12 页。");
return;
}
try
{
foreach (var p in dialog.FileNames)
if (new FileInfo(p).Length > 25_000_000)
throw new Exception("每张图片不得超过 25 MB");
var recognized = await Task.Run(() => { using var engine = new TesseractEngine(Path.Combine(AppContext.BaseDirectory, "tessdata"), "eng+chi_sim", EngineMode.Default); return dialog.FileNames.Select(path => { using var image = Pix.LoadFromFile(path); using var page = engine.Process(image); return page.GetText(); }).ToArray(); });
ConfirmOCR(dialog.FileNames, recognized, answer);
}
catch (Exception e) { Message("本机图片识别未完成。请检查图像清晰度与 OCR 运行库。\n" + e.Message); }
}
void ConfirmOCR(string[] files, string[] texts, bool answer)
{
var workArea = SystemParameters.WorkArea;
var window = new Window { Owner = this, Title = "校对识别结果", Width = Math.Min(1050, Math.Max(1, workArea.Width - 16)), Height = Math.Min(760, Math.Max(1, workArea.Height - 16)), WindowStartupLocation = WindowStartupLocation.CenterOwner };
var root = new DockPanel { Margin = new Thickness(24) };
var footer = new StackPanel { Orientation = System.Windows.Controls.Orientation.Horizontal, Margin = new Thickness(0, 20, 0, 0) };
var checkedAll = new CheckBox { Content = "我已对照原图核对所有页面", VerticalAlignment = VerticalAlignment.Center, Margin = new Thickness(0, 0, 20, 0) };
footer.Children.Add(checkedAll);
var confirm = Button(answer ? "确认并评卷" : "确认填入题目", () => { if (answer) { essay = string.Join("\n\n", texts); inputMode = "handwritten"; } else question = string.Join("\n\n", texts); SaveDraft(); window.Close(); Render(); if (answer) _ = Submit(); }, true);
confirm.IsEnabled = false;
checkedAll.Checked += (_, _) => confirm.IsEnabled = true;
checkedAll.Unchecked += (_, _) => confirm.IsEnabled = false;
footer.Children.Add(confirm);
DockPanel.SetDock(footer, Dock.Bottom);
root.Children.Add(footer);
var tabs = new TabControl();
for (int i = 0; i < files.Length; i++)
{
int index = i;
var grid = new Grid();
grid.ColumnDefinitions.Add(new());
grid.ColumnDefinitions.Add(new());
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(files[i]);
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
var image = new Image { Source = bitmap, Stretch = Stretch.Uniform, Margin = new Thickness(12) };
grid.Children.Add(new ScrollViewer { Content = image });
var editor = Input(texts[i]);
editor.AcceptsReturn = true;
editor.TextChanged += (_, _) => texts[index] = editor.Text;
Grid.SetColumn(editor, 1);
grid.Children.Add(editor);
tabs.Items.Add(new TabItem { Header = $"第 {i + 1} 页", Content = grid });
}
root.Children.Add(tabs);
window.Content = root;
window.ShowDialog();
}
}
12 changes: 8 additions & 4 deletions platforms/windows/WriteBench/Views/MainWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ public MainWindow(bool preview = false)
store = new LocalStore(preview ? Path.Combine(Path.GetTempPath(), "WriteBench-preview-" + Guid.NewGuid()) : null);
credentials = new Credentials(preview ? Path.Combine(Path.GetTempPath(), "WriteBench-preview-credentials-" + Guid.NewGuid()) : null);
Title = "WriteBench";
Width = 1320;
Height = 870;
MinWidth = 960;
MinHeight = 650;
var workArea = SystemParameters.WorkArea;
double availableWidth = Math.Max(1, workArea.Width - 16);
double availableHeight = Math.Max(1, workArea.Height - 16);
Width = Math.Min(1320, availableWidth);
Height = Math.Min(870, availableHeight);
MinWidth = Math.Min(960, availableWidth);
MinHeight = Math.Min(650, availableHeight);
WindowStartupLocation = WindowStartupLocation.CenterScreen;
Icon = new BitmapImage(new Uri("pack://application:,,,/Assets/Icon.png"));
settings = store.Read<Settings>("settings.json") ?? new();
Expand Down Expand Up @@ -120,6 +123,7 @@ void Render()
{
var b = Button(exam, () => SelectTask(ExamTask.All.First(t => t.Exam == exam)), task.Exam == exam);
b.Content = ExamLabel(exam, task.Exam == exam);
System.Windows.Automation.AutomationProperties.SetName(b, exam);
tabs.Children.Add(b);
}
DockPanel.SetDock(tabs, Dock.Top);
Expand Down
Loading