有些PDF是透過掃描或者虛擬印表機生成的,這些PDF不可複製裡邊的內容
市面上的工具一般都是收費或者有水印,所以就萌生了自己搞一個的想法:
使用了以下三個開源庫
- PdfiumViewer PDF預覽及可編輯PDF的提取
- PDFsharp 生成PDF
- PaddleSharp 對圖片OCR識別
大概思路是:
用PdfiumViewer 渲染顯示,並轉PDF為圖片;
使用PaddleSharp 對提取圖片的內容及bbox座標;
把座標根據縮放比轉成相對於PDF的座標,並使用PDFsharp 重新生成PDF,如需要保持原有格式需要把1轉成的圖片重新回寫到生成的pdf,文字層為ocg層;
實現雙層pdf的效果;
讀取PDF到到記憶體流:
private PdfDocument OpenDocument(string fileName) { try { return PdfDocument.Load(this, new MemoryStream(File.ReadAllBytes(fileName))); } catch (Exception ex) { MessageBox.Show(this, ex.Message, Text, MessageBoxButtons.OK, MessageBoxIcon.Error); return null; } }
PDF轉圖片:
//圖片dpi要相對大些,這樣ocr識別的更清晰
int dpiX = 96 * 5; int dpiY = 96 * 5; var pdfWidth = (int)document.PageSizes[page].Width * 4 / 3; var pdfHeight = (int)document.PageSizes[page].Height * 4 / 3; var rotate = PdfRotation.Rotate0; var flags = PdfRenderFlags.Annotations | PdfRenderFlags.CorrectFromDpi; using (var image = document.Render(page, pdfWidth, pdfHeight, dpiX, dpiY, rotate, flags)){}
OCR識別:
byte[] sampleImageData = ImageToByte(image); FullOcrModel model = LocalFullModels.ChineseV3; using (PaddleOcrAll all = new PaddleOcrAll(model, PaddleDevice.Mkldnn()) { AllowRotateDetection = true, /* 允許識別有角度的文字 */ Enable180Classification = false, /* 允許識別旋轉角度大於90度的文字 */ }) { // Load local file by following code: using (Mat src = Cv2.ImDecode(sampleImageData, ImreadModes.Color)) { PaddleOcrResult result = all.Run(src); return result; } }
圖片轉成流:
private byte[] ImageToByte(System.Drawing.Image image) { MemoryStream ms = new MemoryStream(); if (image == null) return new byte[ms.Length]; image.Save(ms, System.Drawing.Imaging.ImageFormat.Png); byte[] BPicture = new byte[ms.Length]; BPicture = ms.GetBuffer(); return BPicture; }
轉換bbox座標到PDF座標:bbox座標是相對於圖片的座標,所以縮放比是pdf和圖片的之間的轉換,圖片大小變化,此函式需跟著調整
private System.Drawing.RectangleF ConvertToPDFSize(System.Drawing.RectangleF rectangle, float dpiX, float dpiY, PdfRotation rotate, PdfRenderFlags flags) { var width = rectangle.Width; var height = rectangle.Height; var x = rectangle.X; var y = rectangle.Y; if ((flags & PdfRenderFlags.CorrectFromDpi) != 0) { width = (width / dpiX * 72); height = (height / dpiY * 72); x = (x / dpiX * 72); y = (y / dpiY * 72); } return new RectangleF(x, y, width, height); }
bbox座標框選示例:
由於OCR的限制:轉雙層pdf只能在x64系統執行,不使用OCR可執行x86和x64,
工具功能:
- 可提取和框選提取可複製和不可複製pdf;
- 可轉換不可複製的pdf為雙層可複製pdf;
- 可轉換不可複製的pdf為可複製pdf;
- 載入圖片並提取標註提取內容;
直接下載地址:
https://cloud.189.cn/web/share?code=MZvMb2ZNRbMn(訪問碼:y9st)
也可按照下放程式碼自己編譯使用,遵循MIT協議
歡迎Start、PR
原始碼地址:https://github.com/1000374/HM.PdfOcr