- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试使用 PoDoFo 库从 PDF 文件中提取文本,它适用于 Tj 运算符,但无法为 (数组)TJ 运算符。我找到了这段代码(经过我的小修改)here :
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<PdfVariant> stack;
while( tokenizer.ReadNext( eType, pszToken, var ) )
{
if( eType == ePdfContentsType_Keyword )
{
// support 'l' and 'm' tokens
_RPT1(_CRT_WARN, " %s\n", 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 R\n",
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<int>(array.GetSize()); i++ )
{
_RPT1(_CRT_WARN, " variant: %s", array[i].GetDataTypeString());
if(array[i].IsHexString()) {
if(!pCurFont) {
_RPT1(_CRT_WARN, " : Could not Get font!!%d\n", i);
}
else {
if(!pCurFont->GetEncoding()) {
_RPT1(_CRT_WARN, ": could not get encoding\n",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, " : %s\n", strlen(szText)> 0? szText: "nothing");
}
}
}
else if(array[i].IsNumber()) {
_RPT1(_CRT_WARN, " : %d\n", 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: %s\n", 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
[<0026>-7<004F>-15<004C>-15<0048>-11<0051>-11<0057>-19<0058>-11<004F>-15<0058>-11<004C>] 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
[<0030>9<0027>-13<002C>-16<0003>1<0026>-13<0032>13<0031>-13<0036>-9<0037>-6<0035>-13<0038>-13<0026>-13<0037>-6<0003>1<0037>-6<0035>-13<0024>-9<0031>-13<0036>-9<0003>1<0028>-9<003B>-9<0033>-9<0028>-9<0035>-13<0037>-6<0003>1<0036>-9<0035>-13<002F>] TJ
ET
最佳答案
1. 中央代码部分是这样的原始问题的答案:
else if( strcmp( pszToken, "TJ" ) == 0 )
{
PdfArray array = stack.top().GetArray();
stack.pop();
for( int i=0; i<static_cast<int>(array.GetSize()); i++ )
{
if( array[i].IsString() )
AddTextElement( dCurPosX, dCurPosY, pCurFont, array[i].GetString() );
}
}
}
问题是:
I've noticed that the the
array[i].IsString()
never gets to be true. Is this the right way to get the text from a TJ operator?
简短的回答:
PoDoFo 中的十六进制字符串 PdfVariants
被IsHexString()
认可而不是 IsString()
.因此,您必须测试两种字符串风格:
if( array[i].IsString() || array[i].IsHexString() )
长答案:
PDF 中有两种基本的字符串风格:
String objects shall be written in one of the following two ways:
As a sequence of literal characters enclosed in parentheses ( ) (using LEFT PARENTHESIS (28h) and RIGHT PARENThESIS (29h)); see 7.3.4.2, "Literal Strings."
As hexadecimal data enclosed in angle brackets < > (using LESS-THAN SIGN (3Ch) and GREATER-THAN SIGN (3Eh)); see 7.3.4.3, "Hexadecimal Strings."
(section 7.3.4 in ISO 32000-1)
PoDoFo 模型均使用 PdfString
在解析上下文中的类通常包含在 PdfVariant
中或更具体地在 PdfObject
中.
但是,在确定其中包含的对象的类型时,PdfVariant
区分文字字符串和十六进制字符串:
/** \returns true if this variant is a string (i.e. GetDataType() == ePdfDataType_String)
*/
inline bool IsString() const { return GetDataType() == ePdfDataType_String; }
/** \returns true if this variant is a hex-string (i.e. GetDataType() == ePdfDataType_HexString)
*/
inline bool IsHexString() const { return GetDataType() == ePdfDataType_HexString; }
PdfString
的类型在 PdfVariant
里面包裹时确定:
PdfVariant::PdfVariant( const PdfString & rsString )
{
Init();
Clear();
m_eDataType = rsString.IsHex() ? ePdfDataType_HexString : ePdfDataType_String;
m_Data.pData = new PdfString( rsString );
}
对于您的 TJ 参数数组组件,相关字符串被读取为十六进制字符串。
因此,在您的代码中,您必须同时考虑 IsHexString()
和 IsString()
:
if( array[i].IsString() || array[i].IsHexString() )
2. 此后,修改代码后使用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, " : %s\n", strlen(szText)> 0? szText: "nothing");
和问题(如评论中所述)
the
s.GetLength()
returns 2 andunicode.GetLength()
returns 0, the conversion didn't work?
示例文档分析 Document2.pdf显示相关文档确实包含文本提取所需的信息。该文档中唯一使用十六进制编码的字体是 /F1,它的字体字典确实包含一个适当的 /ToUnicode 映射,用于可靠的文本提取。
不幸的是,PoDoFo 似乎还没有正确地使用该 map 进行解析。我没有在任何地方看到它检索 /ToUnicode 映射以使包含的信息可用于文本解析。看起来 PoDoFo 无法正确解析使用 Type0 又名复合字体的文档文本。
关于c++ - 使用 PoDoFo 库从 PDF 运算符中的数组 TJ 中提取文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16607094/
我有一个 pdf 文件,我希望从中删除所有图像和其他绘图内容。并将结果另存为新的 pdf。 我知道如何使用 TJ 、 Tj 运算符删除文本,我目前执行的操作如下 op.getOperation().e
如果我们假设一个 PDF 文档“doc.pdf”包含“hello world”作为一个简单的字符串。 让我们考虑一下这段代码: //read the document DDocument do
是否可以确定TJ运算符中的数字是否代表单词之间的空格? 示例:[(Sta)28(ry)-333(Plzenec,)]TJ 数字28空格不够,否则333应该根据实际字号空格。字体大小为 9.96 最佳答
我试图找出在未压缩的 PDF v1.4 文档中使用 Times 字体的位置。 /Font描述 PDF 中 Times 字体的对象是对象 65如下: 65 0 obj > endobj 它指的是 /Fo
我使用 iText 库来创建并操作 PDF 文档。让我们有一个包含简单字符串的文档,例如“Hello world”。所以在pdf文件结构中,我们必须有(Hello world)Tj。问题是我如何通过使
我尝试使用 PDFBox 2.0.0 解析 PDF 的内容流。 这是处理它的代码的一部分: InputStream is; try { is = this.input.getDocumentC
最近我被分配到一个项目,我们必须将旧的 VB3 进程迁移到 C#,这个进程从 Access 97 文件中获取数据并将其插入 SQL Server,问题是一些“天才”调用字段“Ta/Tj”和“/”破坏了
我正在尝试使用 PoDoFo 库从 PDF 文件中提取文本,它适用于 Tj 运算符,但无法为 (数组)TJ 运算符。我找到了这段代码(经过我的小修改)here : const char*
我是否正确理解我不需要在 TypeScript 中使用像 tj/co 这样的库来控制流程,因为我可以使用 async/await?将 promises 与生成器一起使用只是 async/await 的
背景故事,阅读:https://medium.com/code-adventures/4ba9e7f3e52b TJ 说 Node 失败是因为: 您可能会收到重复的回调 您可能根本没有收到回电(迷失方
最近看了TJ的博文:"Farewell Node.js" . 我不太了解 Node 失败部分。在这里: Error-handling in Go is superior in my opinion.
好的,所以我正在解析 PDF 内容流,发现 TJ 回调生成一个字符串数组,所以我捕获它并开始遍历它以获取字符串值,如下所示: static void Op_TJ(CGPDFScannerRef s,
我是一名优秀的程序员,十分优秀!