首页 > 其他分享 >文本pdf转epub的一点体会

文本pdf转epub的一点体会

时间:2023-02-05 02:55:20浏览次数:44  
标签:string left new pdf 文本 epub 图片

文本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

相关文章

  • 解决vuepdf不显示章印问题
    找到node_modules/pdfjs-dist/es5/build/pdf.worker.js这个目录if(data.fieldType==="Sig"){data.fieldValue=null;//pdf预览不显示红章问题......
  • Android集成mupdf,实现手写笔签字,手指翻页的java代码
    importandroid.graphics.Bitmap;importandroid.graphics.Color;importandroid.graphics.RectF;importandroid.util.Log;importjava.util.LinkedList;importc......
  • 第24章 使用正则表达式解析文本文件
    第24章使用正则表达式解析文本文件正则表达式(regularexpression,或regex)能够非常有效地进行文本解析,你经常会在UNIX或Linux操作系统中用到。24.2正则表达式入门......
  • 使用pdfobject预览pdf
    之前写过一篇预览pdf的,​​Vue使用vue-pdf实现PDF文件预览​​ ,大家按需所用一般项目中在上传文件之前可能会有先预览一下,看是否符合要求,符合再上传,这里先说了pdf文件,使用......
  • c++ 一键提取pdf文件图片工具
    日常工作的时候,有时候需要将一个pdf文件中的图片全部提取出来使用,那么这时候就需要一个简单的方法来做这个事情,而不是一个一个图片截图做操作。效果如下:工具下载地址:​​pdf......
  • 百度富文本编辑器ueditor上传图片宽度设置
    分两步1.ueditor的themes文件夹下有个iframe.css加入以下代码,设置样式,保存(原先的css文件是空的)img{max-width:330;/*图片自适应宽度,这里设置为宽330px,高度......
  • CSS 实现文本装饰效果
    使用CSS实现文本装饰效果主要有以下几种方式:text-shadow:为文本添加阴影效果。text-decoration:为文本添加下划线、删除线、上划线等装饰效果。letter-spacing:调......
  • wangeditor富文本编辑和vue3
    官网:wangEditor  https://www.wangeditor.com/v5/为啥用这个富文本编辑器(我觉得官网写自己优势已经非常好了没有啥可补充的了) 文档特别的全和友好安装yarnadd......
  • 使用itext7进行pdf签名印章
    ......
  • #Python 文本包含pandas的 Series.str.contains函数
    一:基础的函数组成’’‘Series.str.contains(pat,case=True,flags=0,na=nan,regex=True)’’'测试pattern或regex是否包含在Series或Index的字符串中。返回布尔值系列......