OcrExtensions.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections.Generic; 7 using System.Drawing; 8 using System.Drawing.Imaging; 9 using System.IO; 10 using System.Text; 11 using System.Text.RegularExpressions; 12 using System.Threading.Tasks; 13 using System.Windows; 14 using System.Windows.Media; 15 16 using PowerOCR.Models; 17 using Windows.Globalization; 18 using Windows.Graphics.Imaging; 19 using Windows.Media.Ocr; 20 21 namespace PowerOCR.Helpers 22 { 23 internal static class OcrExtensions 24 { 25 public static void GetTextFromOcrLine(this OcrLine ocrLine, bool isSpaceJoiningOCRLang, StringBuilder text) 26 { 27 // (when OCR language is zh or ja) 28 // matches words in a space-joining language, which contains: 29 // - one letter that is not in "other letters" (CJK characters are "other letters") 30 // - one number digit 31 // - any words longer than one character 32 // Chinese and Japanese characters are single-character words 33 // when a word is one punctuation/symbol, join it without spaces 34 if (isSpaceJoiningOCRLang) 35 { 36 text.AppendLine(ocrLine.Text); 37 } 38 else 39 { 40 bool isFirstWord = true; 41 bool isPrevWordSpaceJoining = false; 42 43 Regex regexSpaceJoiningWord = new(@"(^[\p{L}-[\p{Lo}]]|\p{Nd}$)|.{2,}"); 44 45 foreach (OcrWord ocrWord in ocrLine.Words) 46 { 47 string wordString = ocrWord.Text; 48 49 bool isThisWordSpaceJoining = regexSpaceJoiningWord.IsMatch(wordString); 50 51 if (isFirstWord || (!isThisWordSpaceJoining && !isPrevWordSpaceJoining)) 52 { 53 _ = text.Append(wordString); 54 } 55 else 56 { 57 _ = text.Append(' ').Append(wordString); 58 } 59 60 isFirstWord = false; 61 isPrevWordSpaceJoining = isThisWordSpaceJoining; 62 } 63 } 64 } 65 66 public static async Task<string> GetRegionsTextAsTableAsync(OCROverlay passedWindow, Rectangle regionScaled, Language? language) 67 { 68 if (language is null) 69 { 70 return string.Empty; 71 } 72 73 Bitmap bmp = ImageMethods.GetRegionAsBitmap(passedWindow, regionScaled); 74 75 bool scaleBMP = true; 76 77 if (bmp.Width * 1.5 > OcrEngine.MaxImageDimension) 78 { 79 scaleBMP = false; 80 } 81 82 using Bitmap scaledBitmap = scaleBMP ? ImageMethods.ScaleBitmapUniform(bmp, 1.5) : ImageMethods.ScaleBitmapUniform(bmp, 1.0); 83 DpiScale dpiScale = VisualTreeHelper.GetDpi(passedWindow); 84 85 OcrResult ocrResult = await GetOcrResultFromImageAsync(scaledBitmap, language); 86 List<WordBorder> wordBorders = ResultTable.ParseOcrResultIntoWordBorders(ocrResult, dpiScale); 87 return ResultTable.GetWordsAsTable(wordBorders, dpiScale, LanguageHelper.IsLanguageSpaceJoining(language)); 88 } 89 90 internal static async Task<OcrResult> GetOcrResultFromImageAsync(Bitmap bmp, Language language) 91 { 92 await using MemoryStream memoryStream = new(); 93 using WrappingStream wrappingStream = new(memoryStream); 94 95 bmp.Save(wrappingStream, ImageFormat.Bmp); 96 wrappingStream.Position = 0; 97 98 BitmapDecoder bmpDecoder = await BitmapDecoder.CreateAsync(wrappingStream.AsRandomAccessStream()); 99 SoftwareBitmap softwareBmp = await bmpDecoder.GetSoftwareBitmapAsync(); 100 101 await memoryStream.DisposeAsync(); 102 await wrappingStream.DisposeAsync(); 103 104 OcrEngine ocrEngine = OcrEngine.TryCreateFromLanguage(language); 105 return await ocrEngine.RecognizeAsync(softwareBmp); 106 } 107 } 108 }