我正在尝试使用PoDoFo库从PDF文件中提取文本,它正在为Tj运算符工作,并且无法为(数组) TJ运算符执行此操作。 我在这里找到了这段代码(我的小修改):
const char* pszToken = NULL; PdfVariant var; EPdfContentsType eType; PdfContentsTokenizer tokenizer( pPage ); double dCurPosX = 0.0; double dCurPosY = 0.0; double dCurFontSize = 0.0; bool bTextBlock = false; PdfFont* pCurFont = NULL; std::stack stack; while( tokenizer.ReadNext( eType, pszToken, var ) ) { if( eType == ePdfContentsType_Keyword ) { // support 'l' and 'm' tokens _RPT1(_CRT_WARN, " %sn", pszToken); if( strcmp( pszToken, "l" ) == 0 || strcmp( pszToken, "m" ) == 0 ) { dCurPosX = stack.top().GetReal(); stack.pop(); dCurPosY = stack.top().GetReal(); stack.pop(); } else if (strcmp(pszToken, "Td") == 0) { dCurPosY = stack.top().GetReal(); stack.pop(); dCurPosX = stack.top().GetReal(); stack.pop(); } else if (strcmp(pszToken, "Tm") == 0) { dCurPosY = stack.top().GetReal(); stack.pop(); dCurPosX = stack.top().GetReal(); stack.pop(); } else if( strcmp( pszToken, "BT" ) == 0 ) { bTextBlock = true; // BT does not reset font // dCurFontSize = 0.0; // pCurFont = NULL; } else if( strcmp( pszToken, "ET" ) == 0 ) { if( !bTextBlock ) fprintf( stderr, "WARNING: Found ET without BT!n" ); } if( bTextBlock ) { if( strcmp( pszToken, "Tf" ) == 0 ) { dCurFontSize = stack.top().GetReal(); stack.pop(); PdfName fontName = stack.top().GetName(); PdfObject* pFont = pPage->GetFromResources( PdfName("Font"), fontName ); if( !pFont ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "Cannot create font!" ); } pCurFont = pDocument->GetFont( pFont ); if( !pCurFont ) { fprintf( stderr, "WARNING: Unable to create font for object %i %i Rn", pFont->Reference().ObjectNumber(), pFont->Reference().GenerationNumber() ); } } else if( strcmp( pszToken, "Tj" ) == 0 || strcmp( pszToken, "'" ) == 0 ) { AddTextElement( dCurPosX, dCurPosY, pCurFont, stack.top().GetString() ); stack.pop(); } else if( strcmp( pszToken, """ ) == 0 ) { AddTextElement( dCurPosX, dCurPosY, pCurFont, stack.top().GetString() ); stack.pop(); stack.pop(); // remove char spacing from stack stack.pop(); // remove word spacing from stack } else if( strcmp( pszToken, "TJ" ) == 0 ) { PdfArray array = stack.top().GetArray(); stack.pop(); for( int i=0; i<static_cast(array.GetSize()); i++ ) { _RPT1(_CRT_WARN, " variant: %s", array[i].GetDataTypeString()); if(array[i].IsHexString()) { if(!pCurFont) { _RPT1(_CRT_WARN, " : Could not Get font!!%dn", i); } else { if(!pCurFont->GetEncoding()) { _RPT1(_CRT_WARN, ": could not get encodingn",0); } else { PdfString s = array[i].GetString(); _RPT1(_CRT_WARN, " : valid :%s ", s.IsValid()?"yes":"not"); _RPT1(_CRT_WARN, " ;hex :%s ", s.IsHex()?"yes":"not"); _RPT1(_CRT_WARN, " ;unicode: %s ", s.IsUnicode()?"yes":"not"); PdfString unicode = pCurFont->GetEncoding()->ConvertToUnicode(s,pCurFont); const char* szText = unicode.GetStringUtf8().c_str(); _RPT1(_CRT_WARN, " : %sn", strlen(szText)> 0? szText: "nothing"); } } } else if(array[i].IsNumber()) { _RPT1(_CRT_WARN, " : %dn", array[i].GetNumber()); } if( array[i].IsString() )//|| array[i].IsHexString()) AddTextElement( dCurPosX, dCurPosY, pCurFont, array[i].GetString() ); } } } } else if ( eType == ePdfContentsType_Variant ) { stack.push( var ); _RPT1(_CRT_WARN, " variant: %sn", var.GetDataTypeString()); } else { // Impossible; type must be keyword or variant PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } }
并为代码我得到这个输出:
BT variant: Name variant: Real Tf variant: Number variant: Number variant: Number rg variant: Real variant: Number variant: Number variant: Number variant: Real variant: Real Tm variant: Array TJ variant: HexString : valid :yes ;hex :yes ;unicode: not : nothing variant: Number : -7 variant: HexString : valid :yes ;hex :yes ;unicode: not : nothing variant: Number : -15 variant: HexString : valid :yes ;hex :yes ;unicode: not : nothing variant: Number : -15 variant: HexString : valid :yes ;hex :yes ;unicode: not : nothing variant: Number : -11 variant: HexString : valid :yes ;hex :yes ;unicode: not : nothing variant: Number : -11 variant: HexString : valid :yes ;hex :yes ;unicode: not : nothing variant: Number : -19 variant: HexString : valid :yes ;hex :yes ;unicode: not : nothing variant: Number : -11 variant: HexString : valid :yes ;hex :yes ;unicode: not : nothing variant: Number : -15 variant: HexString : valid :yes ;hex :yes ;unicode: not : nothing variant: Number : -11 variant: HexString : valid :yes ;hex :yes ;unicode: not : nothing ET
PDF流对象会喜欢这个(对不起但我不允许给你pdf文件):
q Q q Q q q q 1 0 0 1 37.68 785.28 cm 91.92 0 0 31.44 0 0 cm /Img1 Do Q Q q q 1 0 0 1 431.28 780.24 cm 42.72 0 0 7.2 0 0 cm /Img2 Do Q Q q BT /F1 8.88 Tf 0 0 0 rg 0.9998 0 0 1 377.28 704.4 Tm [-7-15-15-11-11-19-11-15-11] TJ ET Q q 1 0 0 1 0 0 cm 0.4799 w 0 0 0 RG 377.28 703.44 m 415.2 703.44 l S Q q BT /F1 8.16 Tf 0 0 0 rg 0.9998 0 0 1 377.28 687.36 Tm [9-13-161-1313-13-9-6-13-13-13-61-6-13-9-13-91-9-9-9-9-13-61-9-13] TJ ET
PDF文件应该在这里或这里找到
1.原始问题的答案,中央代码部分是这样的:
else if( strcmp( pszToken, "TJ" ) == 0 ) { PdfArray array = stack.top().GetArray(); stack.pop(); for( int i=0; i(array.GetSize()); i++ ) { if( array[i].IsString() ) AddTextElement( dCurPosX, dCurPosY, pCurFont, array[i].GetString() ); } } }
问题是:
我注意到
array[i].IsString()
永远不会成为现实。 这是从TJ运算符获取文本的正确方法吗?
简短的回答:
PoDoFo PdfVariants
中的hex字符串由IsHexString()
而不是IsString()
识别。 因此,您必须测试两种字符串风格:
if( array[i].IsString() || array[i].IsHexString() )
答案很长:
PDF中有两种基本的字符串:
字符串对象应使用以下两种方式之一编写:
( ISO 32000-1中的 7.3.4节)
PoDoFo模型都使用PdfString
类,它在解析的上下文中经常被包装在PdfVariant
,甚至更具体地包含在PdfObject
。
但是,在确定其中包含的对象的类型时, PdfVariant
区分文字字符串和hex字符串:
/** returns true if this variant is a string (ie GetDataType() == ePdfDataType_String) */ inline bool IsString() const { return GetDataType() == ePdfDataType_String; } /** returns true if this variant is a hex-string (ie GetDataType() == ePdfDataType_HexString) */ inline bool IsHexString() const { return GetDataType() == ePdfDataType_HexString; }
( PdfVariant.h )
PdfString
的类型在包装时确定:
PdfVariant::PdfVariant( const PdfString & rsString ) { Init(); Clear(); m_eDataType = rsString.IsHex() ? ePdfDataType_HexString : ePdfDataType_String; m_Data.pData = new PdfString( rsString ); }
( PdfVariant.cpp )
对于TJ参数数组组件,有问题的字符串将被读取为hex字符串。
因此,在您的代码中,您必须同时考虑IsHexString()
和IsString()
:
if( array[i].IsString() || array[i].IsHexString() )
2.此后,在修改代码以使用IsHexString(),
进行检查后IsHexString(),
问题集中在
PdfString s = array[i].GetString(); _RPT1(_CRT_WARN, " : valid :%s ", s.IsValid()?"yes":"not"); _RPT1(_CRT_WARN, " ;hex :%s ", s.IsHex()?"yes":"not"); _RPT1(_CRT_WARN, " ;unicode: %s ", s.IsUnicode()?"yes":"not"); PdfString unicode = pCurFont->GetEncoding()->ConvertToUnicode(s,pCurFont); const char* szText = unicode.GetStringUtf8().c_str(); _RPT1(_CRT_WARN, " : %sn", strlen(szText)> 0? szText: "nothing");
和问题(如评论中所述)
s.GetLength()
返回2并且unicode.GetLength()
返回0,转换不起作用?
对示例文档Document2.pdf的分析表明,所讨论的文档确实包含文本提取所需的信息。 该文档中唯一使用hex编码的字体是/ F1 ,其字体字典确实包含适当的/ ToUnicode映射,用于可靠的文本提取。
不幸的是,PoDoFo似乎还没有正确地使用该映射进行解析。 我没有看到它在任何地方检索/ ToUnicode映射以使包含的信息可用于文本解析。 看起来PoDoFo不能用于使用Type0 aka复合字体正确解析文档文本。
以上就是c/c++开发分享使用PoDoFo lib从PDF运算符中的数组TJ中提取文本相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/562682.html