c# 使用Spire.Pdf为pdf批量整理书签目录,图片ocr转文字,自动生成markdown

捣鼓半天iText没搞定,就用了 Spire.Pdf 了

场景:
捡到一本没有书签目录的pdf,再从淘宝简介页搞到了目录,目录是带有页码的
于是想自动化的把书签匹配进去

瞎敲一顿搞完就结束,粘贴备份一下

目录整理

    public class Page
    {
        public Page(string title, int realPageNumber)
        {
            Title = title;
            PageNumber = realPageNumber;
        }

        public string Title { get; set; }

        /// <summary>
        /// 书本上正文的页数
        /// </summary>
        public int PageNumber { get; set; }


        public override string ToString()
        {
            return $"{Title} {PageNumber}";
        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            var pdfFile = @"Q:\学习\编译原理\编译器设计 第2版.pdf";
            //加载文档 
            PdfDocument pdf = new PdfDocument();
            pdf.LoadFromFile(pdfFile);

            //清空原有书签
            pdf.Bookmarks.Clear();

            Console.WriteLine($"实际页数: {pdf.Pages.Count}");

            //解析文本得到标题和页码
            var pages = ParsePageAndTitles();
            foreach (var kv in pages)
            {
                //添加大章节
                var bigTitle = kv.Key;
                //Console.WriteLine(bigTitle.Title);
                PdfBookmark bookmark = pdf.Bookmarks.Add(bigTitle.Title);
                //设置书签指向的页面和位置 
                //内容实际从n开始 
                int startPage = 14;
                var index = bigTitle.PageNumber - 1 + startPage;
                bookmark.Destination = new PdfDestination(pdf.Pages[index]);
                bookmark.Destination.Location = new PointF(0, 0);
                //添加小章节
                var subTitles = kv.Value;
                for (int i = 0; i < subTitles.Count; i++)
                {
                    //这里只能添加字符串标题
                    bookmark.Add(subTitles[i].Title);
                    //然后使用索引去修改
                    index = subTitles[i].PageNumber - 1 + startPage;
                    bookmark[i].Destination = new PdfDestination(pdf.Pages[index]);
                }
            }
            //保存文档 
            pdf.SaveToFile(pdfFile + "-目录.pdf");
            //
            Console.WriteLine("END");
            Console.ReadLine();

            Console.Read();
        }



        private static Dictionary<Page, List<Page>> ParsePageAndTitles()
        {
            /* 目录文件txt结构如下
第1章 编译概观 1
1.1 简介 1
1.2 编译器结构 4
1.3 转换概述 7
1.3.1 前端 8
1.3.2 优化器 10
1.3.3 后端 11
1.4 小结和展望 15
第2章 词法分析器 17
2.1 简介 17
2.2 识别单词 18
*/
            var result = new Dictionary<Page, List<Page>>();
            var file = @"Q:\学习\编译原理\编译器设计 第2版-目录.txt";
            var lines = File.ReadAllLines(file);
            Page lastBigPage = null;
            foreach (var line in lines)
            {
                if (line.StartsWith("第"))
                {
                    ParseLine(line, out string chapter, out string title, out int pageNumber);
                    lastBigPage = new Page($"{chapter} {title} {pageNumber}", pageNumber);
                    result.Add(lastBigPage, new List<Page>());
                }
                else
                {
                    var subPages = result[lastBigPage];
                    ParseLine(line, out string chapter, out string title, out int pageNumber);
                    subPages.Add(new Page($"{chapter} {title} {pageNumber}", pageNumber));
                }
            }
            return result;
        }

        private static void ParseLine(string input, out string chapter, out string title, out int pageNumber)
        {
            var arr = input.Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            if (arr.Length != 3)
            {
                throw new Exception($"解析出错: '{input}'");
            }
            chapter = arr[0];
            title = arr[1];
            pageNumber = int.Parse(arr[2]);
        }
    }

图片转文字

发现一个不错的工具,也是c#写的,本地ocr识别标准书籍文字还不错,
后续也许可以搞成批量识别转换的,在处理成markdown
https://gitee.com/wanglifree/tianruoocr-cl

MainOCRQuickScreenShots 为双击启动截图识别方法
modeFlag被赋值为 "识别"
将跳转到最后一栏 else if (image_screen != null) 本地ocr
再跳转到 Main_OCR_Thread 方法,再调用 SougouOCR()方法, ocrResult.StrRes是返回的结果
整理后,直接可用的代码

private static string DoOcr(string[] files)
        {
            //初始引擎
            if (ocrEngin == null)
            {
                ocrEngin = new OcrLite();
                //安装模型
                string appPath = AppDomain.CurrentDomain.BaseDirectory;
                string modelsDir = appPath + "models" + "\\" + "cl-ocr";
                string detPath = modelsDir + "\\" + "dbnet.onnx";
                string clsPath = modelsDir + "\\" + "angle_net.onnx";
                string recPath = modelsDir + "\\" + "crnn_lite_lstm.onnx";
                string keysPath = modelsDir + "\\" + "keys.txt";
                int valuetemp = 4;
                ocrEngin.InitModels(detPath, clsPath, recPath, keysPath, valuetemp);
            }
            var results = new List<string>();
            foreach (var file in files)
            {
                Console.WriteLine($"图片路径:{file}");
                var image_screen = new Bitmap(file);

                //识别
                var padding = 10;
                var maxSideLen = 2048;
                float boxScoreThresh = 0.618f;
                float boxThresh = 0.3f;
                var unClipRatio = 2;
                var doAngle = true;
                var mostAngle = true;
                OcrLiteLib.OcrResult ocrResult = ocrEngin.Detect(((Bitmap)image_screen).ToImage<Bgr, Byte>().Mat, padding, maxSideLen, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle);
                var result = ocrResult.StrRes.Trim()
                 .Replace("\r", "")
                 .Replace("\n", "")
                 ;
                image_screen.Dispose();
                results.Add(result);
                Console.WriteLine($"-->{result}<--");
            }
            //
            Console.WriteLine($"-->所有结果<--");
            var allResult = string.Join("\r\n\r\n", results);
            Console.WriteLine(allResult);
            return allResult;
        }

OCR不能处理段落

一开始我想做一个手动划矩形的工具来区分段落
后来一看这书是从下往下排的,不需要划矩形,只需要划横线就完成切割了,我给这个项目命名为古筝计划🙃

posted @ 2023-02-16 15:57  trykle  阅读(769)  评论(0)    收藏  举报