using ComDocumentAIKit; using ComPDFKit.PDFDocument; using ComPDFKit.PDFPage; using ComPDFKit.PDFPage.Edit; using ComPDFKitViewer; using ComPDFKitViewer.PdfViewer; using PDF_Master.EventAggregators; using PDF_Master.Helper; using PDF_Master.Model; using Prism.Commands; using Prism.Events; using Prism.Mvvm; using Prism.Regions; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Threading; namespace PDF_Master.ViewModels.Scan { class ScanViwerViewModel : BindableBase, INavigationAware { private CPDFViewer PDFViewer; private ViewContentViewModel viewContentViewModel; private WriteableBitmap bgImage; public WriteableBitmap BgImage { get { return bgImage; } set { SetProperty(ref bgImage, value); } } private List> textRectList; public List> TextRectList { get { return textRectList; } set { SetProperty(ref textRectList, value); } } private bool isEnhanced; /// /// 当前是否为增强扫描状态 /// public bool IsEnhanced { get { return isEnhanced; } set { SetProperty(ref isEnhanced, value); } } private bool isShowRect; public bool IsShowRect { get { return isShowRect; } set { SetProperty(ref isShowRect, value); } } private COCRLanguage language = COCRLanguage.COCRLanguageEnglish; /// /// 增强扫描结果路径 /// public List EnhancedFilePathList; /// /// OCR结果路径 /// private Dictionary>> cacahe; private Visibility showTooltip = Visibility.Collapsed; public Visibility ShowTooltip { get { return showTooltip; } set { SetProperty(ref showTooltip, value); } } public DelegateCommand CloseTooltipCommand { get; set; } public DelegateCommand CancelEnhancedCommand { get; set; } public bool IsNavigationTarget(NavigationContext navigationContext) { return true; } public void OnNavigatedFrom(NavigationContext navigationContext) { return; } public void OnNavigatedTo(NavigationContext navigationContext) { navigationContext.Parameters.TryGetValue(ParameterNames.ViewContentViewModel, out viewContentViewModel); if (viewContentViewModel == null) { return; } navigationContext.Parameters.TryGetValue(ParameterNames.PDFViewer, out PDFViewer); if (PDFViewer == null) { return; } else { PDFViewer.InfoChanged += PDFViewer_InfoChanged; PDFViewer.ChangeViewMode(ViewMode.Single); //第一次进入获取当前预览显示内容 CPDFPage pdfPage = PDFViewer.Document.PageAtIndex(PDFViewer.CurrentIndex); float zoom = (float)(DpiHelpers.Dpi / 72D); int renderWidth = (int)(pdfPage.PageSize.Width * zoom); int renderHeight = (int)(pdfPage.PageSize.Height * zoom); byte[] renderData = new byte[renderWidth * renderHeight * 4]; pdfPage.RenderPageBitmapWithMatrix(zoom, new Rect(0, 0, renderWidth, renderHeight), 0xFFFFFFFF, renderData, 0); BgImage = new WriteableBitmap(renderWidth, renderHeight, DpiHelpers.Dpi, DpiHelpers.Dpi, PixelFormats.Bgra32, null); BgImage.WritePixels(new Int32Rect(0, 0, renderWidth, renderHeight), renderData, BgImage.BackBufferStride, 0); } } private void PDFViewer_InfoChanged(object sender, KeyValuePair e) { if (e.Key == "PageNum") { RenderData renderData = e.Value as RenderData; if (renderData != null) { if (IsEnhanced) { BitmapImage image = new BitmapImage(new Uri(EnhancedFilePathList[PDFViewer.CurrentIndex])); BgImage = new WriteableBitmap(image); } else { CPDFPage pdfPage = PDFViewer.Document.PageAtIndex(renderData.PageIndex - 1); float zoom = (float)(DpiHelpers.Dpi / 72D); int renderWidth = (int)(pdfPage.PageSize.Width * zoom); int renderHeight = (int)(pdfPage.PageSize.Height * zoom); byte[] Data = new byte[renderWidth * renderHeight * 4]; pdfPage.RenderPageBitmapWithMatrix(zoom, new Rect(0, 0, renderWidth, renderHeight), 0xFFFFFFFF, Data, 0); BgImage = new WriteableBitmap(renderWidth, renderHeight, DpiHelpers.Dpi, DpiHelpers.Dpi, PixelFormats.Bgra32, null); BgImage.WritePixels(new Int32Rect(0, 0, renderWidth, renderHeight), Data, BgImage.BackBufferStride, 0); } if (cacahe.Count > 0) { if (cacahe.ContainsKey(renderData.PageIndex - 1)) { TextRectList = cacahe[renderData.PageIndex - 1]; } else { TextRectList = null; } } ClearDraw(); } } } private void ClearDraw() { //笨办法,有好方案随时能换,目前是以触发属性改变事件的方式激活清空 IsShowRect = !IsShowRect; IsShowRect = !IsShowRect; } public ScanViwerViewModel(IEventAggregator eventAggregator) { CloseTooltipCommand = new DelegateCommand(CloseTooltip); CancelEnhancedCommand = new DelegateCommand(CancelEnhanced); EnhancedFilePathList = new List(); eventAggregator.GetEvent().Subscribe(ChangeScanMode, e => e.Unicode == App.mainWindowViewModel.SelectedItem.Unicode); cacahe = new Dictionary>>(); } /// /// 区域识别 /// public void AreaProcess(Rect AreaRect, Rect ImageRect) { COCREngine imEngine = new COCREngine(App.modelFolderPath); string path = App.CachePath.MergeFilePath; string name = Guid.NewGuid().ToString(); path = Path.Combine(path, name); Directory.CreateDirectory(path); CPDFDocument CurrentDoc = PDFViewer.Document; Task.Run(() => { CErrorCode error = imEngine.SetModel(language); cacahe.Remove(PDFViewer.CurrentIndex); string pageImagePath = Path.Combine(path, "Area"); Directory.CreateDirectory(pageImagePath); pageImagePath = Path.Combine(pageImagePath, PDFViewer.CurrentIndex.ToString()); if (IsEnhanced) { BitmapImage image = new BitmapImage(new Uri(EnhancedFilePathList[PDFViewer.CurrentIndex])); BgImage = new WriteableBitmap(image); double zoomWidth = AreaRect.Width / ImageRect.Width; double zoomHeight = AreaRect.Height / ImageRect.Height; double zoomX = (AreaRect.X - ImageRect.X) / ImageRect.Width; double zoomY = (AreaRect.Y - ImageRect.Y) / ImageRect.Height; Int32Rect rect = new Int32Rect((int)(BgImage.Width * zoomX), (int)(BgImage.Height * zoomY), (int)(BgImage.Width * zoomWidth), (int)(BgImage.Height * zoomHeight)); byte[] renderData = new byte[(int)(BgImage.Width * BgImage.Height * 4)]; BgImage.CopyPixels(rect, renderData, BgImage.BackBufferStride, 0); WriteableBitmap bitmap = new WriteableBitmap(rect.Width, rect.Height, DpiHelpers.Dpi, DpiHelpers.Dpi, PixelFormats.Bgra32, null); bitmap.WritePixels(new Int32Rect(0, 0, rect.Width, rect.Height), renderData, BgImage.BackBufferStride, 0); BitmapEncoder encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmap)); using (FileStream imageStream = File.Create(pageImagePath)) { encoder.Save(imageStream); imageStream.Flush(); } error = imEngine.Process(pageImagePath); if (imEngine.OCRResultList == null) return; List> RectList = new List>(); foreach (COCRResult ocrResult in imEngine.OCRResultList) { List rectPoints = new List(); for (int j = 0; j < ocrResult.position.Length; j += 2) { rectPoints.Add(new Point(ocrResult.position[j], ocrResult.position[j + 1])); } int left = (int)rectPoints.AsEnumerable().Min(x => x.X); int right = (int)rectPoints.AsEnumerable().Max(x => x.X); int top = (int)rectPoints.AsEnumerable().Min(x => x.Y); int bottom = (int)rectPoints.AsEnumerable().Max(x => x.Y); RectList.Add(new KeyValuePair(new Rect(left + BgImage.Width * zoomX, top + BgImage.Height * zoomY, right - left, bottom - top), ocrResult.text)); } cacahe.Add(PDFViewer.CurrentIndex, RectList); if (cacahe.Count > 0) { if (cacahe.ContainsKey(PDFViewer.CurrentIndex)) { TextRectList = cacahe[PDFViewer.CurrentIndex]; } else { TextRectList = null; } } } else { CPDFPage pdfPage = CurrentDoc.PageAtIndex(PDFViewer.CurrentIndex); double zoomWidth = AreaRect.Width / ImageRect.Width; double zoomHeight = AreaRect.Height / ImageRect.Height; double zoomX = (AreaRect.X - ImageRect.X) / ImageRect.Width; double zoomY = (AreaRect.Y - ImageRect.Y) / ImageRect.Height; float zoom = (float)(DpiHelpers.Dpi / 72D); int renderWidth = (int)(pdfPage.PageSize.Width * zoomWidth * zoom); int renderHeight = (int)(pdfPage.PageSize.Height * zoomHeight * zoom); int renderX = (int)(pdfPage.PageSize.Width * zoomX * zoom); int renderY = (int)(pdfPage.PageSize.Height * zoomY * zoom); byte[] renderData = new byte[renderWidth * renderHeight * 4]; pdfPage.RenderPageBitmapWithMatrix(zoom, new Rect(renderX, renderY, renderWidth, renderHeight), 0xFFFFFFFF, renderData, 0); WriteableBitmap bitmap = new WriteableBitmap(renderWidth, renderHeight, DpiHelpers.Dpi, DpiHelpers.Dpi, PixelFormats.Bgra32, null); bitmap.WritePixels(new Int32Rect(0, 0, renderWidth, renderHeight), renderData, bitmap.BackBufferStride, 0); BitmapEncoder encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmap)); using (FileStream imageStream = File.Create(pageImagePath)) { encoder.Save(imageStream); imageStream.Flush(); } error = imEngine.Process(pageImagePath); if (imEngine.OCRResultList == null) return; List> RectList = new List>(); foreach (COCRResult ocrResult in imEngine.OCRResultList) { List rectPoints = new List(); for (int j = 0; j < ocrResult.position.Length; j += 2) { rectPoints.Add(new Point(ocrResult.position[j], ocrResult.position[j + 1])); } int left = (int)rectPoints.AsEnumerable().Min(x => x.X); int right = (int)rectPoints.AsEnumerable().Max(x => x.X); int top = (int)rectPoints.AsEnumerable().Min(x => x.Y); int bottom = (int)rectPoints.AsEnumerable().Max(x => x.Y); RectList.Add(new KeyValuePair(new Rect(left + renderX, top + renderY, right - left, bottom - top), ocrResult.text)); } cacahe.Add(PDFViewer.CurrentIndex, RectList); if (cacahe.Count > 0) { if (cacahe.ContainsKey(PDFViewer.CurrentIndex)) { TextRectList = cacahe[PDFViewer.CurrentIndex]; } else { TextRectList = null; } } } imEngine.Release(); }); ClearDraw(); } private void CancelEnhanced() { ShowTooltip = Visibility.Collapsed; IsEnhanced = false; CPDFPage pdfPage = PDFViewer.Document.PageAtIndex(PDFViewer.CurrentIndex); float zoom = (float)(DpiHelpers.Dpi / 72D); int renderWidth = (int)(pdfPage.PageSize.Width * zoom); int renderHeight = (int)(pdfPage.PageSize.Height * zoom); byte[] Data = new byte[renderWidth * renderHeight * 4]; pdfPage.RenderPageBitmapWithMatrix(zoom, new Rect(0, 0, renderWidth, renderHeight), 0xFFFFFFFF, Data, 0); BgImage = new WriteableBitmap(renderWidth, renderHeight, DpiHelpers.Dpi, DpiHelpers.Dpi, PixelFormats.Bgra32, null); BgImage.WritePixels(new Int32Rect(0, 0, renderWidth, renderHeight), Data, BgImage.BackBufferStride, 0); if (cacahe.Count > 0) { if (cacahe.ContainsKey(PDFViewer.CurrentIndex)) { TextRectList = cacahe[PDFViewer.CurrentIndex]; } else { TextRectList = null; } } } private void CloseTooltip() { ShowTooltip = Visibility.Collapsed; } /// /// 根据Vm事件通知处理OCR与区域识别或者增强扫描事件 /// /// private void ChangeScanMode(ScanEventArgs e) { IsShowRect = false; switch (e.Mode) { case ScanMode.Unknown: break; case ScanMode.Enhanced: EnhancedProcess(e); IsEnhanced = true; break; case ScanMode.OCR: if (IsEnhanced) { EnhancedOCRProcess(e); } else { OCRProcess(e); } break; case ScanMode.Area: language = (COCRLanguage)e.ScanLanguage; IsShowRect = true; break; default: break; } } /// /// 增强扫描 /// private void EnhancedProcess(ScanEventArgs args) { CPDFDocument CurrentDoc = PDFViewer.Document; string path = App.CachePath.MergeFilePath; string name = Guid.NewGuid().ToString(); path = Path.Combine(path, name); string EnhancePath = Path.Combine(path, "Enhance"); Directory.CreateDirectory(path); Directory.CreateDirectory(EnhancePath); Task.Run(() => { CIMEngine imEngine = new CIMEngine(App.modelFolderPath); CErrorCode error = imEngine.SetModel(); if (error!= CErrorCode.E_DA_SUCCESS) { return; } //显示进度条 App.mainWindowViewModel.IsProcessVisible = Visibility.Visible; App.mainWindowViewModel.MaxValue = CurrentDoc.PageCount; for (int i = 0; i < CurrentDoc.PageCount; i++) { //刷新进度 App.Current.Dispatcher.Invoke(async () => { App.mainWindowViewModel.Value = i; await Task.Delay(5); }); string pageImagePath = Path.Combine(path, i.ToString()); string pageEnhancePath = Path.Combine(EnhancePath, i.ToString() + ".png"); try { CPDFPage pdfPage = CurrentDoc.PageAtIndex(i); float zoom = (float)(DpiHelpers.Dpi / 72D); int renderWidth = (int)(pdfPage.PageSize.Width * zoom); int renderHeight = (int)(pdfPage.PageSize.Height * zoom); byte[] renderData = new byte[renderWidth * renderHeight * 4]; pdfPage.RenderPageBitmapWithMatrix(zoom, new Rect(0, 0, renderWidth, renderHeight), 0xFFFFFFFF, renderData, 0); WriteableBitmap bitmap = new WriteableBitmap(renderWidth, renderHeight, DpiHelpers.Dpi, DpiHelpers.Dpi, PixelFormats.Bgra32, null); bitmap.WritePixels(new Int32Rect(0, 0, renderWidth, renderHeight), renderData, bitmap.BackBufferStride, 0); BitmapEncoder encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmap)); using (FileStream imageStream = File.Create(pageImagePath)) { encoder.Save(imageStream); imageStream.Flush(); } //File.Create(pageEnhancePath); error = imEngine.Process(pageImagePath, pageEnhancePath); EnhancedFilePathList.Add(pageEnhancePath); } catch { } } Application.Current.Dispatcher.Invoke(() => { BitmapImage image = new BitmapImage(new Uri(EnhancedFilePathList[PDFViewer.CurrentIndex])); BgImage = new WriteableBitmap(image); }); imEngine.Release(); ShowTooltip = Visibility.Visible; //隐藏进度条 App.mainWindowViewModel.IsProcessVisible = Visibility.Collapsed; App.mainWindowViewModel.MaxValue = 0; App.mainWindowViewModel.Value = 0; }); } /// /// 使用当前文档OCR /// /// private void OCRProcess(ScanEventArgs args) { Task.Run(() => { COCREngine imEngine = new COCREngine(App.modelFolderPath); string path = App.CachePath.MergeFilePath; string name = Guid.NewGuid().ToString(); path = Path.Combine(path, name); Directory.CreateDirectory(path); CPDFDocument CurrentDoc = PDFViewer.Document; CErrorCode error = imEngine.SetModel((COCRLanguage)args.ScanLanguage); if (error != CErrorCode.E_DA_SUCCESS) { return; } cacahe.Clear(); //显示进度条 App.mainWindowViewModel.IsProcessVisible = Visibility.Visible; App.mainWindowViewModel.MaxValue = args.PageRange.Count; for (int i = 0; i < args.PageRange.Count; i++) { //刷新进度 App.Current.Dispatcher.Invoke(async () => { App.mainWindowViewModel.Value = i; await Task.Delay(5); }); string pageImagePath = Path.Combine(path, args.PageRange[i].ToString()); CPDFPage pdfPage = CurrentDoc.PageAtIndex(args.PageRange[i]); float zoom = (float)(DpiHelpers.Dpi / 72D); int renderWidth = (int)(pdfPage.PageSize.Width * zoom); int renderHeight = (int)(pdfPage.PageSize.Height * zoom); byte[] renderData = new byte[renderWidth * renderHeight * 4]; pdfPage.RenderPageBitmapWithMatrix(zoom, new Rect(0, 0, renderWidth, renderHeight), 0xFFFFFFFF, renderData, 0); WriteableBitmap bitmap = new WriteableBitmap(renderWidth, renderHeight, DpiHelpers.Dpi, DpiHelpers.Dpi, PixelFormats.Bgra32, null); bitmap.WritePixels(new Int32Rect(0, 0, renderWidth, renderHeight), renderData, bitmap.BackBufferStride, 0); BitmapEncoder encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmap)); using (FileStream imageStream = File.Create(pageImagePath)) { encoder.Save(imageStream); imageStream.Flush(); } error = imEngine.Process(pageImagePath); if (imEngine.OCRResultList == null) { App.mainWindowViewModel.IsProcessVisible = Visibility.Collapsed; App.mainWindowViewModel.MaxValue = 0; App.mainWindowViewModel.Value = 0; return; } List> RectList = new List>(); foreach (COCRResult ocrResult in imEngine.OCRResultList) { List rectPoints = new List(); for (int j = 0; j < ocrResult.position.Length; j += 2) { rectPoints.Add(new Point(ocrResult.position[j], ocrResult.position[j + 1])); } int left = (int)rectPoints.AsEnumerable().Min(x => x.X); int right = (int)rectPoints.AsEnumerable().Max(x => x.X); int top = (int)rectPoints.AsEnumerable().Min(x => x.Y); int bottom = (int)rectPoints.AsEnumerable().Max(x => x.Y); RectList.Add(new KeyValuePair(new Rect(left, top, right - left, bottom - top), ocrResult.text)); } cacahe.Add(args.PageRange[i], RectList); } if (cacahe.Count > 0) { if (cacahe.ContainsKey(PDFViewer.CurrentIndex)) { TextRectList = cacahe[PDFViewer.CurrentIndex]; } else { TextRectList = null; } } imEngine.Release(); //隐藏进度条 App.mainWindowViewModel.IsProcessVisible = Visibility.Collapsed; App.mainWindowViewModel.MaxValue = 0; App.mainWindowViewModel.Value = 0; }); } /// /// 使用增强扫描结果进行OCR /// /// private void EnhancedOCRProcess(ScanEventArgs args) { Task.Run(() => { COCREngine imEngine = new COCREngine(App.modelFolderPath); CErrorCode error = imEngine.SetModel((COCRLanguage)args.ScanLanguage); cacahe.Clear(); for (int i = 0; i < args.PageRange.Count; i++) { error = imEngine.Process(EnhancedFilePathList[args.PageRange[i]]); if (imEngine.OCRResultList == null) return; List> RectList = new List>(); foreach (COCRResult ocrResult in imEngine.OCRResultList) { List rectPoints = new List(); for (int j = 0; j < ocrResult.position.Length; j += 2) { rectPoints.Add(new Point(ocrResult.position[j], ocrResult.position[j + 1])); } int left = (int)rectPoints.AsEnumerable().Min(x => x.X); int right = (int)rectPoints.AsEnumerable().Max(x => x.X); int top = (int)rectPoints.AsEnumerable().Min(x => x.Y); int bottom = (int)rectPoints.AsEnumerable().Max(x => x.Y); RectList.Add(new KeyValuePair(new Rect(left, top, right - left, bottom - top), ocrResult.text)); } cacahe.Add(args.PageRange[i], RectList); } if (cacahe.Count > 0) { if (cacahe.ContainsKey(PDFViewer.CurrentIndex)) { TextRectList = cacahe[PDFViewer.CurrentIndex]; } else { TextRectList = null; } } imEngine.Release(); }); } public void Save() { for (int i = 0; i < PDFViewer.Document.PageCount; i++) { if (cacahe.ContainsKey(i)) { CPDFPage pdfPage = PDFViewer.Document.PageAtIndex(i); CPDFEditPage editPage = pdfPage.GetEditPage(); //2023.2.17版本的SDK不能使用EditText枚举,会有内存问题 editPage.BeginEdit(CPDFEditType.EditImage); for (int y = textRectList.Count - 1; y >= 0; y--) { KeyValuePair textBlock = textRectList[y]; int fontSize = 1; Rect pdfRect = DpiHelpers.GetRawRect(textBlock.Key); for (; fontSize < 100; fontSize++) { Rect cmpRect = pdfPage.GetTextContentRect(fontSize, "Helvetica", textBlock.Value); if (cmpRect.Width > pdfRect.Width || cmpRect.Height > pdfRect.Height) { fontSize -= 1; break; } } //字体 CPDFEditTextArea editArea = editPage.CreateNewTextArea(pdfRect, "Helvetica", fontSize, new byte[] { 0, 0, 0 }); //透明度 editArea.SetCharsFontTransparency(0); bool x = editArea.SetTextAreaAlign(TextAlignType.AlignChar); editArea.InsertText(textBlock.Value); } editPage.EndEdit(); } } } } }