PDF文档中表格以及形状解析

我们在做PDF文档解析时有时需要解析PDF文档中的表格、形状等数据。跟解析文本类似的常见的解决方案也是两种。文档解析跟ocr技术处理。下面我们来看看使用文档解析的方案来做PDF文档中的表格、图形解析(使用pdfium库)。
表格解析:

在pdfium库中在解析表格时是将表格的线解析成单独的对象。所以我们在解析时只需要遍历页面中的所有线条,拿到线条之后再进行表格结构的重新组装即可。

以下为读取页面中线的相关代码:

cpp 复制代码
std::string strPdfPath = "pdf.pdf";
//初始化库
FPDF_InitLibrary();
//加载文档
FPDF_DOCUMENT document = FPDF_LoadDocument(strPdfPath.c_str(), nullptr);
if (!document)
{
    //load error
}
//获取页数
int page_count = FPDF_GetPageCount(document);
//此处我们只演示处理第一页
FPDF_PAGE page = FPDF_LoadPage(document, 0); // 加载第一页 (索引 0)
if (page)
{
    int objCount = FPDFPage_CountObjects(page); //获取当前页的对象数
    for (int i = 0; i < objCount; ++i)
    {
        FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
        int nObjType = FPDFPageObj_GetType(obj);//对象类型
        switch (nObjType)
        {
            case FPDF_PAGEOBJ_UNKNOWN:
                break;
            case FPDF_PAGEOBJ_PATH: 
            {
                int nSegments = FPDFPath_CountSegments(obj); //
                std::vector<CPoint> vecPts;
                for (int j = 0; j < nSegments; j++)
                {
                    FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(obj, j);
                    int nSegType = FPDFPathSegment_GetType(segment);//线段类型
                    switch (nSegType)
                    {
                        case FPDF_SEGMENT_UNKNOWN:
                            break;
                        case FPDF_SEGMENT_LINETO:
                        {
                            float x, y;
                            FPDFPathSegment_GetPoint(segment, &x, &y);
                            CPoint pt(x, y);
                            vecPts.push_back(pt);                                                   
                        }
                        break;
                        case FPDF_SEGMENT_BEZIERTO:
                        {
                            //                        
                        }
                        break;
                        case FPDF_SEGMENT_MOVETO:
                        {
                            float x, y;
                            FPDFPathSegment_GetPoint(segment, &x, &y);    
                            CPoint pt(x, y);
                            vecPts.push_back(pt);                        
                        }
                        break;
                        default:
                            break;                   
                    }                
                }            
            }     
            break;   
            default:
                break;                               
        }    
    }
}
FPDF_ClosePage(page);

通过上述代码我们获取Path对象中的数据即可拿到表格的线条,需要的注意的时如果只拿表格的线的话需要对线的数量做判断,如果对象只有两个点则为表格的线。这里拿到的线是整体的线。

比如上边的表格拿到的线数量为8条线段。

如果需要将线组成一个表格结构那我们需要自己做处理。大致的处理思路是将长线段打断为短线段然后再将短的线段组合成一个个的小多边形,根据多边形的上下左右共边关系生成一个表格结构。至于这里为什么要生成一个多边形,是为了后续做文本跟表格关联做准备。

根据之前文本解析文章中我们可以看到在获取文本信息时也能拿到文本的位置、大小等信息。所以我们在进行文本表格关联时只需要判断文本位置的那个点是否在表格的多边形内即可,如果在多边形内则说明PDF中该文本为表格中该单元格的数据。这样我们就可以生成一个虚拟的表格数据了。对于图片也是这样处理,拿到图片的中心点如果该点在多边形内则该图片为该表格中的数据。

形状解析:

读取代码跟读取线的代码一样,只是在读取形状时线的数量大于2。如果是圆、半圆之类的则其中一些点为贝塞尔曲线。我在测试时即使形状是线在解析时拿到的线的数量也是4个(一个闭合的多边形)。其他的形状经过测试也是一个闭合的多边形。

比如Word中的这些线条在解析出来后每个对象都是一些线段跟贝塞尔曲线组合成的一个闭合区域。

相关推荐
黄雪超31 分钟前
JVM——对象模型:JVM对象的内部机制和存在方式是怎样的?
java·开发语言·jvm
爱学习的capoo1 小时前
matlab自控仿真【第一弹】❀传递函数和输出时域表达式
开发语言·matlab
EverBule1 小时前
Python 训练 day46
开发语言·python
a.3021 小时前
C++ 时间处理指南:深入剖析<ctime>库
数据结构·c++·算法
Dave_Young2 小时前
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
c++·设计模式
蓝婷儿2 小时前
6个月Python学习计划 Day 18 - 项目实战 · 学生成绩管理系统(OOP版)
开发语言·python·学习
HINOTOR_2 小时前
DAY 25 异常处理
开发语言·python
yorushika_2 小时前
python打卡训练营打卡记录day49
开发语言·python·tensorboard·cbam
至善迎风2 小时前
Windows系统中如何使用符号链接将.vscode等配置文件夹迁移到D盘(附 CMD & PowerShell 双版本命令)
ide·windows·vscode
old_power2 小时前
在 Windows 系统下配置 VSCode + CMake + Ninja 进行 C++ 或 Qt 开发
c++·windows·vscode·cmake·ninja