添加FreeText注释到PDF
Adding FreeText annotation to PDF
我使用podofo做PDF操作,如添加注释,签名等根据我的要求在我的iOS应用程序。我首先尝试了podofo库可用的唯一示例,它工作得很好。但是这个示例的问题是添加的注释没有在任何预览中显示,比如Google
, Adobe Reader
等。这是个问题。
根据Adobe的一些指导方针,我发现它需要Appearance Key
才能出现FreeText annotation
。我尝试在文本编辑器中分析原始pdf文件,以查看具有正确注释的pdf与podofo创建的pdf注释之间的差异。我发现有AP
N
键,stream
对象是编码形式的注释,这是从podofo样本中缺失的。
然后搜索后,我发现了podofo自己的样本,并试图使用代码,这似乎是正确的,但也没有工作,我知道我错过了一些东西,但不确定是什么,在哪里,请看看下面的代码
+(void)createFreeTextAnnotationOnPage:(NSInteger)pageIndex doc:(PdfMemDocument*)aDoc rect:(CGRect)aRect borderWidth:(double)bWidth title:(NSString*)title content:(NSString*)content bOpen:(Boolean)bOpen color:(UIColor*)color {
PoDoFo::PdfMemDocument *doc = (PoDoFo::PdfMemDocument *) aDoc;
PoDoFo::PdfPage* pPage = doc->GetPage(pageIndex);
if (! pPage) {
// couldn't get that page
return;
}
PoDoFo::PdfRect rect;
rect.SetBottom(aRect.origin.y);
rect.SetLeft(aRect.origin.x);
rect.SetHeight(aRect.size.height);
rect.SetWidth(aRect.size.width);
PoDoFo::PdfString sTitle(reinterpret_cast<const PoDoFo::pdf_utf8*>([title UTF8String]));
PoDoFo::PdfString sContent(reinterpret_cast<const PoDoFo::pdf_utf8*>([content UTF8String]));
PoDoFo::PdfFont* pFont = doc->CreateFont( "Helvetica", new PoDoFo::PdfIdentityEncoding( 0, 0xffff, true ) );
std::ostringstream oss;
oss << "BT" << std::endl << "/" << pFont->GetIdentifier().GetName()
<< " " << pFont->GetFontSize()
<< " Tf " << std::endl;
[APDFManager WriteStringToStream:sContent :oss :pFont];
oss << "Tj ET" << std::endl;
PoDoFo::PdfDictionary fonts;
fonts.AddKey(pFont->GetIdentifier().GetName(), pFont->GetObject()->Reference());
PoDoFo::PdfDictionary resources;
resources.AddKey( PoDoFo::PdfName("Fonts"), fonts );
PoDoFo::PdfAnnotation* pAnnotation =
pPage->CreateAnnotation( PoDoFo::ePdfAnnotation_FreeText, rect );
pAnnotation->SetTitle( sTitle );
pAnnotation->SetContents( sContent );
//pAnnotation->SetAppearanceStream( &xObj );
pAnnotation->GetObject()->GetDictionary().AddKey( PoDoFo::PdfName("DA"), PoDoFo::PdfString(oss.str()) );
pAnnotation->GetObject()->GetDictionary().AddKey( PoDoFo::PdfName("DR"), resources );
}
+(void) WriteStringToStream:(const PoDoFo::PdfString & )rsString :(std::ostringstream &) oss :(PoDoFo::PdfFont*) pFont
{
PoDoFo::PdfEncoding* pEncoding = new PoDoFo::PdfIdentityEncoding( 0, 0xffff, true );
PoDoFo::PdfRefCountedBuffer buffer = pEncoding->ConvertToEncoding( rsString, pFont );
PoDoFo::pdf_long lLen = 0;
char* pBuffer = NULL;
std::auto_ptr<PoDoFo::PdfFilter> pFilter = PoDoFo::PdfFilterFactory::Create( PoDoFo::ePdfFilter_ASCIIHexDecode );
pFilter->Encode( buffer.GetBuffer(), buffer.GetSize(), &pBuffer, &lLen );
oss << "<";
oss << std::string( pBuffer, lLen );
oss << ">";
free( pBuffer );
delete pEncoding;
}
任何一个在SO宇宙可以请告诉我上面的代码有什么问题,以及如何添加一个正确的FreeText注释,使其正确地出现在任何地方。
多谢。
注释如下:
19 0 obj
<<
/Type/Annot
/Contents(þÿ M Y A N N O T A T I O N)
/DA(BTn/Ft18 12 Tf n 1 0 0 rg n<002D003900000021002E002E002F0034002100340029002F002E>Tj ETn)
/DR<</Fonts<</Ft18 18 0 R>>>>
/M(D:20140616141406+05'00')
/P 4 0 R
/Rect[ 188.814117 748.970520 467.849731 795.476456]
/Subtype/FreeText
/T(þÿ A n n o t a t e P D F)
>>
endobj
三个观察:
- 它有默认外观但没有外观流。
- Default Appearance内容无效。
- Default Resources在错误的对象中。
Item 1可能会导致外观在许多简单的查看器中不呈现,这些查看器只显示最终的内容(页面内容,注释外观等),但不会从Default appearance 创建外观。因此,您还应该提供一个外观流。
项目2和3可能会导致外观在更复杂的查看器中不呈现,这些查看器确实尝试从默认外观和默认资源创建外观,但期望DA正确且DR正确定位。因此,您应该更正DA并移动DR。
详细…
1 - 默认外观但不外观流
虽然根据ISO 32000-1规范,DA是自由文本注释所必需的,而AP则不是,但简单的PDF查看器可能没有内置代码来从默认外观创建外观流。
这并不完全令人惊讶:虽然在PDF的情况下没有太多要做的事情,但对某些内容应用默认值可能意味着计算适合某些区域的文本的最佳大小和类似的任务。因此,简单的、不完整的查看器往往不会实现这一点。
2 - Default Appearance内容无效
您的DA字符串包含BT和ET操作符。但是,如果您查看ISO 32000-1的12.7.3.3 可变文本部分,您将看到在创建外观时DA的内容被嵌入到BT中。等信封:
外观流包括以下标记内容的部分,它表示绘制文本的流的一部分:
/Tx BMC % Begin marked content with tag Tx
q % Save graphics state
… Any required graphics state changes, such as clipping …
BT % Begin text object
… Default appearance string ( DA ) …
… Text-positioning and text-showing operators to show the variable text …
ET % End text object
Q % Restore graphics state
EMC % End marked content
默认的外观字符串(DA)包含建立图形状态参数(如文本大小和颜色)所需的任何图形状态或文本状态操作符,用于显示字段的可变文本。只有在文本对象中允许的操作符才能出现在这个字符串
中
但是BT和ET不允许在另一个BT内。ET文本对象!
此外,在DA中添加文本内容。正如上面所看到的,文本绘图操作被添加在 DA内容之后。因此,您最终将面临有重复文本的危险。
3 - Default Resources错位
在注释字典中有Default Resources。但是上面提到的ISO 32000-1的12.7.3.3 可变文本部分表明:
因此,您的DR将被忽略,并期望在其他地方使用。所以你选择的字体最好可以忽略指定的font值应匹配默认资源字典 font条目中的资源名称(从交互式表单字典的DR条目引用)。
我也在做类似的事情。我尝试手动生成外观流,但发现很难。实际上,你上面发布的podofo示例代码是有效的,但它在添加外观流的方式上是错误的。你不能使用setappearance ream,这也是错误的。
podofo的PdfPainter可以绘制文本。它生成文本流。它看起来只适用于PdfPage,但实际上它也适用于XObject。这真的是一个隐藏的功能!
我的代码示例:PdfFont *pFont = ...;
// Add XObject
PdfXObject xObj(borderPdfRect, pPdfMemDocument);
PdfPainter painter;
painter.SetPage(&xObj);
painter.Save(); // Save graphics settings
// Draw text
painter.SetFont(pFont);
painter.GetFont()->SetFontSize(fontSize);
painter.SetColor(self.textColor.color.red, self.textColor.color.green, self.textColor.color.blue);
PdfString pdfStr(reinterpret_cast<const pdf_utf8*>([self.text UTF8String]));
painter.DrawMultiLineText(textPdfRect, pdfStr);
painter.Restore();
painter.FinishPage();
// Add xObj as appearance stream. Don't use SetAppearanceStream
PdfDictionary dict;
dict.AddKey("N", xObj.GetObject()->Reference());
pTextAnno->GetObject()->GetDictionary().AddKey("AP", dict);
- Visual Studio 2019:插入多个C++风格的单行注释
- VSCode 中带有 C/C++ 扩展名的多行注释缩进错误
- 如果我注释掉换行符,为什么'string'会成为一个不合格的变量
- 使用 cpprest (Casablanca) 返回 PDF 响应
- 为什么 ## aka 令牌粘贴运算符不适用于 C 和 C++ 中的注释?
- 在 // C++注释中使用 \\ 是否合法?(C++评论中的LaTeX方程)
- 如何使用打印到 PDF 打印机在 MFC 和 CView 中以编程方式打印而不提示输入文件名?
- 注释一行使代码工作,而没有它,代码不起作用
- 使用 Doxygen 在不同文件中注释函数
- 如何设置叮当格式的注释编译指示,以免触及多行doxygen注释?
- Qt - 带有注释的 JSON
- Visual Studio Community 代码分析的质量与 SAL 注释
- 如何阻止 ReSharper 在 C++ 中格式化多行注释
- C++,在多行代码段中注释
- 使用 Python 和正则表达式提取源代码中的C++注释
- 使用 C++ std::sregex_token_iterator 提取 HTML 注释
- C(嵌入式):注释 FreeRTOS 的 RootTask 时代码大小不会缩小
- 在Windows 8.1上使用MuPDF创建pdf的图像注释
- 使用纯 C/C++向 PDF 添加注释
- 添加FreeText注释到PDF