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

浙公网安备 33010602011771号