C++ 向PDF添加FreeText批注
我正在使用它执行PDF操作,如根据我在iOS应用程序中的要求添加批注、签名等。我第一次尝试了唯一一个非常有效的样品。但是这个示例的问题是添加的注释没有显示在任何预览中,比如C++ 向PDF添加FreeText批注,c++,ios,pdf,annotations,podofo,C++,Ios,Pdf,Annotations,Podofo,我正在使用它执行PDF操作,如根据我在iOS应用程序中的要求添加批注、签名等。我第一次尝试了唯一一个非常有效的样品。但是这个示例的问题是添加的注释没有显示在任何预览中,比如Google,adobereader等等。这是个问题 根据Adobe的一些指导原则,我发现它需要有Appearance键,才能显示FreeText注释。我曾尝试在文本编辑器中分析原始pdf文件,以查看pdf中正确注释与podofo创建的pdf注释之间的差异。我发现有APN键具有注释的编码形式的流对象,该对象在podofo示例中
Google
,adobereader
等等。这是个问题
根据Adobe的一些指导原则,我发现它需要有Appearance键
,才能显示FreeText注释
。我曾尝试在文本编辑器中分析原始pdf文件,以查看pdf中正确注释与podofo创建的pdf注释之间的差异。我发现有AP
N
键具有注释的编码形式的流
对象,该对象在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;
}
+(void)CreateFreeTextAnnotationPage:(NSInteger)pageIndex文档:(PdfMemDocument*)aDoc rect:(cRect)aRect borderWidth:(double)bWidth title:(NSString*)title content:(NSString*)content bOpen bOpen:(Boolean)bOpen color:(UIColor*)color{
PoDoFo::PdfMemDocument*doc=(PoDoFo::PdfMemDocument*)aDoc;
PoDoFo::PdfPage*pPage=doc->GetPage(页面索引);
如果(!pPage){
//找不到那一页
返回;
}
PoDoFo::PdfRect rect;
立根圆(aRect.origin.y);
矩形设置左(aRect.origin.x);
垂直设置高度(垂直尺寸高度);
矩形设置宽度(矩形大小宽度);
PoDoFo::PdfString缝合线(重新解释投射([标题UTF8String]);
PoDoFo::PdfString scocontent(重新解释cast([content UTF8String]);
PoDoFo::PdfFont*pFont=doc->CreateFont(“Helvetica”,新的PoDoFo::PdfIdentityEncoding(0,0xffff,true));
std::ostringstream oss;
oss GetObject()->GetDictionary().AddKey(PoDoFo::PdfName(“DA”),PoDoFo::PdfString(oss.str());
pAnnotation->GetObject()->GetDictionary().AddKey(PoDoFo::PdfName(“DR”),参考资料);
}
+(void)WriteStringToStream:(const-PoDoFo::PdfString&)rsString:(std::ostringstream&)oss:(PoDoFo::PdfFont*)pFont
{
PoDoFo::PdfEncoding*pEncoding=新的PoDoFo::PdfIdentityEncoding(0,0xffff,true);
PoDoFo::PdfRefCountedBuffer=pEncoding->ConvertToEncoding(rsString,pFont);
PoDoFo::pdf_long lLen=0;
char*pBuffer=NULL;
std::auto_ptr pFilter=PoDoFo::PdfFilterFactory::Create(PoDoFo::epdfilter_ascihExdecode);
pFilter->Encode(buffer.GetBuffer(),buffer.GetSize(),&pBuffer,&lLen);
oss所讨论的注释如下所示:
19 0 obj
<<
/Type/Annot
/Contents(þÿ M Y A N N O T A T I O N)
/DA(BT\n/Ft18 12 Tf \n 1 0 0 rg \n<002D003900000021002E002E002F0034002100340029002F002E>Tj ET\n)
/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
默认外观字符串(DA)包含建立图形状态参数(如文本大小和颜色)所需的任何图形状态或文本状态运算符,用于显示字段的可变文本。此字符串中只能出现文本对象中允许的运算符
但是BT和ET不允许在另一个BT..ET文本对象内
此外,您还可以在DA中添加文本内容。如上所述,文本绘制操作是在DA内容之后添加的。因此,您最终会面临重复文本的危险
3-默认资源错位
您在注释字典中有默认资源。但上述第12.7.3.3节变量文本指出:
指定的字体值应与默认资源词典的font条目中的资源名称相匹配(参考交互式表单词典的DR条目)
因此,您的DR将被忽略,并在其他地方被期待。因此,您对字体的选择充其量可能被忽略我正在处理类似的事情。我尝试手动生成外观流,但发现很难。实际上,您上面发布的podofo示例代码可以工作,但在添加外观流的方式上是错误的。Y您不能使用SetAppearanceStream,这也是错误的
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);
PdfFont*pFont=。。。;
//添加XObject
pdfxobjectxobj(borderPdfRect、pPdfMemDocument);
PDF油漆工;
painter.SetPage(&xObj);
painter.Save();//保存图形设置
//绘制文本
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([self.text UTF8String]);
painter.DrawMultiLineText(textPdfRect,pdfStr);
画家。还原();
painter.FinishPage();
//将xObj添加为外观流。不要使用SetAppearanceStream
PDF字典;
dict.AddKey(“N”,xObj.GetObject()->Reference());
pTextAnno->GetObject()->GetDictionary().AddKey(“AP”,dict);
Between你能提供一个由你的代码生成的示例PDF吗?我自己并没有使用PoDoFo,但我可以看看结果中缺少了什么,并导致了你的问题。@mkl是的,请在这里找到PDF注释只有在Mac Preview
和PoDoFo
中才能看到。但它不会显示在Google
,Adobe Reader <代码> >你可以找到名字的注释<代码>我的注释< /代码>但是它不显示给谷歌、Adobe Reader等我下载了它并看它。但是对于Adobe Reader的哪一个版本没有注释?我可以在Adobe Reader席Xi和Adobe AcROTAT 5.5上看到MS Windows上的它。我会尽快调查并让你知道。
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);