diff --git a/NewWorldCompanion.Entities/OcrMapping.cs b/NewWorldCompanion.Entities/OcrMapping.cs new file mode 100644 index 0000000..4d16a80 --- /dev/null +++ b/NewWorldCompanion.Entities/OcrMapping.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NewWorldCompanion.Entities +{ + public class OcrMapping + { + public string key { get; set; } = string.Empty; + public string value { get; set; } = string.Empty; + } +} diff --git a/NewWorldCompanion.Services/OcrHandler.cs b/NewWorldCompanion.Services/OcrHandler.cs index 247667e..10079c1 100644 --- a/NewWorldCompanion.Services/OcrHandler.cs +++ b/NewWorldCompanion.Services/OcrHandler.cs @@ -1,8 +1,13 @@ -using NewWorldCompanion.Events; +using NewWorldCompanion.Entities; +using NewWorldCompanion.Events; using NewWorldCompanion.Interfaces; using Prism.Events; using System; +using System.Collections.Generic; using System.Drawing; +using System.IO; +using System.Linq; +using System.Text.Json; using TesserNet; namespace NewWorldCompanion.Services @@ -12,6 +17,8 @@ public class OcrHandler : IOcrHandler private readonly IEventAggregator _eventAggregator; private readonly IScreenProcessHandler _screenProcessHandler; + private List _ocrMappings = new List(); + private bool _isBusy = false; private string _ocrText = string.Empty; @@ -28,6 +35,8 @@ public OcrHandler(IEventAggregator eventAggregator, IScreenProcessHandler screen // Init services _screenProcessHandler = screenProcessHandler; + // Init ocr mappings + UpdateOcrMappings(); } #endregion @@ -55,7 +64,9 @@ private void HandleOcrImageReadyEvent() { Image image = Image.FromFile(@"ocrimages\itemname.png"); Tesseract tesseract = new Tesseract(); - OcrText = tesseract.Read(image).Trim().Replace('\n', ' '); + string ocrText = tesseract.Read(image).Trim().Replace('\n', ' '); + var mapping = _ocrMappings.FirstOrDefault(m => m.key.Equals(ocrText), new OcrMapping{ key = ocrText, value = ocrText }); + OcrText = mapping.value; image.Dispose(); tesseract.Dispose(); @@ -78,6 +89,21 @@ private void HandleOcrImageReadyEvent() #region Methods + private void UpdateOcrMappings() + { + try + { + _ocrMappings.Clear(); + string fileName = "Config/OcrMappings.json"; + if (File.Exists(fileName)) + { + using FileStream stream = File.OpenRead(fileName); + _ocrMappings = JsonSerializer.Deserialize>(stream) ?? new List(); + } + } + catch (Exception){} + } + #endregion } } diff --git a/NewWorldCompanion.Services/OverlayHandler.cs b/NewWorldCompanion.Services/OverlayHandler.cs index c12d108..085687c 100644 --- a/NewWorldCompanion.Services/OverlayHandler.cs +++ b/NewWorldCompanion.Services/OverlayHandler.cs @@ -201,7 +201,6 @@ private void Timer_Tick(object? sender, EventArgs e) private void HandleOcrTextReadyEvent() { _itemName = _ocrHandler.OcrText; - //TODO Cleanup name. For example Toilvium -> Tolvium if (!_itemName.Equals(_itemNamePrevious)) { _priceManager.UpdatePriceData(_itemName); diff --git a/NewWorldCompanion.Services/ScreenProcessHandler.cs b/NewWorldCompanion.Services/ScreenProcessHandler.cs index d07073b..37faaec 100644 --- a/NewWorldCompanion.Services/ScreenProcessHandler.cs +++ b/NewWorldCompanion.Services/ScreenProcessHandler.cs @@ -179,7 +179,7 @@ private void ProcessImage(Mat img) ( rectangleList[0].MinAreaRect().X + rectangleList[0].MinAreaRect().Width + 5, rectangleList[0].MinAreaRect().Y, - (int)(rectangleList[0].MinAreaRect().Width * 3.25), + (int)(rectangleList[0].MinAreaRect().Width * 3.30), rectangleList[0].MinAreaRect().Height - 25 ); @@ -191,6 +191,9 @@ private void ProcessImage(Mat img) try { + // Validate width + roiRectangle.Width = (roiRectangle.X + roiRectangle.Width) <= img.Width ? roiRectangle.Width : roiRectangle.Width - (roiRectangle.X + roiRectangle.Width - img.Width); + crop = new Mat(img, roiRectangle); RoiImage = crop.ToBitmap(); _eventAggregator.GetEvent().Publish(); diff --git a/NewWorldCompanion/Config/OcrMappings.json b/NewWorldCompanion/Config/OcrMappings.json new file mode 100644 index 0000000..9df953f --- /dev/null +++ b/NewWorldCompanion/Config/OcrMappings.json @@ -0,0 +1,30 @@ +[ + { + "key": "Giintstrands", + "value": "Glintstrands" + }, + { + "key": "Hearty Meai", + "value": "Hearty Meal" + }, + { + "key": "Orichaleum", + "value": "Orichalcum" + }, + { + "key": "Recipe: Meatioaf", + "value": "Recipe: Meatloaf" + }, + { + "key": "Schematic: lron-bound Wall-mounted Lantern", + "value": "Schematic: Iron-bound Wall-mounted Lantern" + }, + { + "key": "Schematic: Maple Smail Table", + "value": "Schematic: Maple Small Table" + }, + { + "key": "Toilvium", + "value": "Tolvium" + } +] \ No newline at end of file diff --git a/NewWorldCompanion/NewWorldCompanion.csproj b/NewWorldCompanion/NewWorldCompanion.csproj index 05bb595..1cc7219 100644 --- a/NewWorldCompanion/NewWorldCompanion.csproj +++ b/NewWorldCompanion/NewWorldCompanion.csproj @@ -52,4 +52,14 @@ + + + + + + + Always + + + diff --git a/NewWorldCompanion/ViewModels/Tabs/CraftingViewModel.cs b/NewWorldCompanion/ViewModels/Tabs/CraftingViewModel.cs index 04055f0..8822907 100644 --- a/NewWorldCompanion/ViewModels/Tabs/CraftingViewModel.cs +++ b/NewWorldCompanion/ViewModels/Tabs/CraftingViewModel.cs @@ -74,6 +74,7 @@ public CraftingViewModel(IEventAggregator eventAggregator, ICraftingRecipeManage // Init View commands CraftingRecipeLearnedCommand = new DelegateCommand(CraftingRecipeLearnedExecute); VisitNwdbCommand = new DelegateCommand(VisitNwdbExecute); + CopyRecipeNameCommand = new DelegateCommand(CopyRecipeNameExecute); // Init filter views CreateCraftingRecipesFilteredView(); @@ -98,6 +99,7 @@ public CraftingViewModel(IEventAggregator eventAggregator, ICraftingRecipeManage public DelegateCommand CraftingRecipeLearnedCommand { get; } public DelegateCommand VisitNwdbCommand { get; } + public DelegateCommand CopyRecipeNameCommand { get; } public ObservableCollection CraftingRecipes { get => _craftingRecipes; set => _craftingRecipes = value; } public ListCollectionView? CraftingRecipesFiltered { get; private set; } @@ -247,8 +249,6 @@ private void HandleOcrTextReadyEvent() // As the view is accessed by the UI it will need to be created on the UI thread Application.Current?.Dispatcher?.Invoke(() => { - //TODO Cleanup name. For example Toilvium -> Tolvium - // Only set filter for recipe items. if (CraftingRecipes.Any(recipe => recipe.Localisation.StartsWith(_ocrHandler.OcrText))) { @@ -274,6 +274,21 @@ private void VisitNwdbExecute(object url) Process.Start(new ProcessStartInfo(url as string ?? string.Empty) { UseShellExecute = true }); } + private void CopyRecipeNameExecute(object obj) + { + // Note: New World does not accept the following special characters when using copy/paste: ':', '''. + try + { + var recipe = (CraftingRecipe)obj; + string recipeName = recipe.Localisation.Contains(':') ? + recipe.Localisation.Substring(recipe.Localisation.IndexOf(':') + 1) : + recipe.Localisation; + + System.Windows.Clipboard.SetText(recipeName.Trim()); + } + catch (Exception) { } + } + private void CreateCraftingRecipesFilteredView() { // As the view is accessed by the UI it will need to be created on the UI thread diff --git a/NewWorldCompanion/Views/Tabs/CooldownView.xaml b/NewWorldCompanion/Views/Tabs/CooldownView.xaml index a14abe8..1493478 100644 --- a/NewWorldCompanion/Views/Tabs/CooldownView.xaml +++ b/NewWorldCompanion/Views/Tabs/CooldownView.xaml @@ -60,13 +60,13 @@ - - - diff --git a/NewWorldCompanion/Views/Tabs/CraftingView.xaml b/NewWorldCompanion/Views/Tabs/CraftingView.xaml index c5ce8f1..ccc0116 100644 --- a/NewWorldCompanion/Views/Tabs/CraftingView.xaml +++ b/NewWorldCompanion/Views/Tabs/CraftingView.xaml @@ -3,6 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" xmlns:local="clr-namespace:NewWorldCompanion.Views.Tabs" xmlns:converters="clr-namespace:NewWorldCompanion.Converters" xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" @@ -108,10 +109,15 @@ Orientation="Vertical" Margin="5" Visibility="{Binding SelectedCraftingRecipe, Converter={StaticResource EmptyToVisibilityConverter}}"> - + + +