文本pdf,指的是相对扫描版的pdf而言,可以拷贝文本。文本pdf又有人称为矢量pdf或者印前pdf。这里不包括那种经过ocr处理的所谓双层pdf,即看上去是扫描的图像,但又可以拷贝文本的那种pdf。
pdf不适合在电纸书上看,因为无法调整字体以及根据屏幕大小自动调整排版,除非是大屏(8吋以上),否则最多只能勉强横着看。所以想把pdf转成epub。
epub实质上是打包的html。所以需要提取出pdf中的文本和图片,然后组合成html,再制作元数据文件.ncx和.opf等,压缩成zip就可以了。
转换的大致步骤可分为:1.提取文本和图片 2.根据章节拆分组合成多个html 3.制作元数据文件 4.打包成zip。
提取pdf的文本有多种方法。1. Acrobat有将pdf另存为txt或html的功能,其它类似的软件如pdf-XChange等也有此功能。2.直接打开pdf,然后Ctrl-A, Ctrl-C 3.用代码实现
这三种方法不能绝对说哪种最好。第1种方法比较方便,但是发现有的pdf转换后会丢失文本,不清楚什么原因,也许跟字体有关。第2种方法也很方便,但是会保留原书的排版比如换行等,需要手工或者编程调整。不过,碰到过一本书,用第1种方法提取文本有缺失,用第2种方法却没有,同样不清楚原因。第3种方法最麻烦,但也最灵活。
使用itextsharp,大致的代码是
PdfReader reader = new PdfReader("foo.pdf"); int pages = reader.NumberOfPages; var st = new SimpleTextExtractionStrategy(); for (int i = 1; i <= pages ; i++) { string str = PdfTextExtractor.GetTextFromPage(reader, i, st);//每一页的文本 }
可以根据自己的需要实现ITextExtractionStrategy这个接口(下文会提到),实现特殊的处理。
提取图片,大致也有3种方法。1.Acrobat有将pdf另存为图片的功能。2.其他软件如pdfToy,pdf补丁丁等也有类似功能。3.编程实现。
同样不能说哪种方法一定最好。第1种方法比较方便,但是某些特殊的文本和图片组合成的“图片”难以批量导出(下文会讨论),而且很多图片是不需要的,要手工或者编程删除。第2种方法的处理速度较快,尤其是批量处理时。但是转换图片的选项不如直接用Acrobat丰富。比如Acrobat可以另存为单色的png,而pdfToy和pdf补丁丁都没有这个选项。其他软件没有试过。第3种方法比较麻烦,但是最灵活,可以处理上面说的特殊图片。
处理一本象棋书时,发现棋图不是单纯的图片,而是文本和图片组合成的(用Acrobat的Edit Text & Images就可以发现),怎么将棋图提取出来呢?
也许有人马上会想到截屏,但截屏有个很大的缺点,就是除非是高清显示屏(我还无福消受),否则缺省的分辨率只有96dpi,太低了。另外,还有个坐标的问题。
开始想先确定图片的坐标位置,然后将整个页面另存为图片,然后根据坐标再去抠图。发现每张棋图下固定有“九八七六五四三二一”的文字,而这个字符串只出现在棋图下面,所以确定了这个字符串的坐标,就可以得到棋图的坐标,代码是:
public class MyTextExtractionStrategy : ITextExtractionStrategy { public void BeginTextBlock() { } public void EndTextBlock() { } public void RenderImage(ImageRenderInfo info) { } StringBuilder sb = new StringBuilder(); private string preTxt = null; private string prepreTxt = null; private string fontName = ""; private float left = 0; private float bottom = 0; //上面三个是接口的方法,可以留空,下面这个方法返回页面的文本 public virtual String GetResultantText() { string result = sb.ToString(); sb.Length = 0; return result; } public void RenderText(TextRenderInfo info) { var txt = info.GetText(); if (txt == "九") { Vector curBaseline = info.GetBaseline().GetStartPoint(); Vector topRight = info.GetAscentLine().GetEndPoint(); iTextSharp.text.Rectangle rect = new iTextSharp.text.Rectangle(curBaseline[Parser.Vector.I1], curBaseline[Parser.Vector.I2], topRight[Parser.Vector.I1], topRight[Parser.Vector.I2]); left = rect.Bottom; bottom = rect.Left; } else if (txt == "七" && preTxt == "八" && prepreTxt == "九") { sb.Append(left.ToString() + "," + bottom.ToString() + "|"); } if (prepreTxt == null) { prepreTxt = txt; } else { if (preTxt == null) { preTxt = txt; } else { prepreTxt = preTxt; preTxt = txt; } } } }
实际上不需要检测“九八七六五四三二一”,只要检测到“九八七”三个连续的字符,就可以断定上面就是图片,用left和bottom记录图片左下角的坐标x,y。因为每张棋图的长度和宽度都是一样的,所以不需要每次都检测,调试后把值直接写在后续的处理代码里。
但是,这个取得的图片坐标,仅仅是pdf自己定义的坐标,和截图所需要的屏幕坐标完全是两回事。如何转化?查了不少资料,有个软件提供了api,但需要付钱。自己试了下,找不到合适的方法(其实是由于对pdf理解不深)。最后偶然找到pdf的cropbox资料,才豁然开朗。于是先把pdf的每一页提取出来,保存为单独的pdf文件0001.pdf, 0002.pdf, 0003.pdf......,然后用下面的代码截图:
PdfReader reader = new PdfReader("foo.pdf"); int serail = 1;
string fileName = "0001.pdf"; int pages = reader.NumberOfPages; var st = new MyTextExtractionStrategy(); for (int i = 1; i <= pages ; i++) { string str = PdfTextExtractor.GetTextFromPage(reader, i, st); if (!String.IsNullOrWhiteSpace(str))
continue; string[] coordinates = str.Split('|');
foreach (string item in coordinates)
{
string[] leftBottom = item.Split(',');
PdfReader reader2 = new PdfReader(fileName);
float left = float.Parse(leftBottom[0]);
float bottom = float.Parse(leftBottom[1]);
PdfRectangle rect = new PdfRectangle(left, bottom - 162.075f, left + 120.627f, bottom);//长度和宽度数据预先调试好的
PdfDictionary pageDict = reader.GetPageN(1);
pageDict.Put(PdfName.CROPBOX, rect);
string serialStr = String.Format("{0:0000}crop.pdf", serial);
PdfStamper stamper = new PdfStamper(reader, File.Open(serialStr, FileMode.Create, FileAccess.Write));
stamper.Close();
reader.Close();
serial++;
fileName = String.Format("{0:0000}.pdf", serial);
}
}
得到截图后的pdf,再批量转成图片,就得到了所需要的结果。批量转换使用Acrobat的Action功能,虽然速度很慢,但是可以选择单色png。(待续)
标签:string,left,new,pdf,文本,epub,图片 From: https://www.cnblogs.com/badnumber/p/17092781.html