C++ 向PDF添加FreeText批注

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示例中

我正在使用它执行PDF操作,如根据我在iOS应用程序中的要求添加批注、签名等。我第一次尝试了唯一一个非常有效的样品。但是这个示例的问题是添加的注释没有显示在任何预览中,比如
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)包含建立图形状态参数(如文本大小和颜色)所需的任何图形状态或文本状态运算符,用于显示字段的可变文本。此字符串中只能出现文本对象中允许的运算符

但是BTET不允许在另一个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);