首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在PDF中添加FreeText注释

在PDF中添加FreeText注释
EN

Stack Overflow用户
提问于 2014-06-13 12:19:24
回答 2查看 2.7K关注 0票数 2

我使用坡多佛进行iOS操作,例如根据我的iOS应用程序的要求添加注释、签名等。我第一次尝试了提供podofo图书馆的唯一示例,它工作得很好。但是这个示例的问题是添加的注释没有显示在任何预览中,比如GoogleAdobe Reader等等。这是一个问题。

根据Adobe的一些指导方针,我发现它需要有Appearance Key才能显示FreeText annotation。我尝试在文本编辑器中分析原始pdf文件,看看PDF中有正确注释的不同之处,而podofo创建了PDF注释。我发现有一个AP N键,其中包含一个stream对象,该对象是为注释编码的,podofo示例中缺少该对象。

搜索后,我找到了podofo自己的示例,并尝试使用代码,这似乎是正确的,但也没有工作,我知道我遗漏了什么,但不确定,在哪里,请看下面的代码

代码语言:javascript
复制
+(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;
}

宇宙中的任何一个人都可以告诉我上面的代码有什么问题,以及如何添加一个正确的FreeText注释,以便它在任何地方都能正确地出现。

非常感谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-06-16 13:54:18

所讨论的注释如下:

代码语言:javascript
复制
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

三项意见:

  1. 它具有默认外观,但不具有Appearance流。
  2. 默认外观的内容无效。
  3. 默认资源位于错误的对象中。

第1项可能导致外观不呈现在许多简单的观众中,只显示最后定稿的内容(页面内容、注释外观、.)但是,不要从默认外观创建外观。因此,您还应该提供一个外观流。

第2项和第3项可能导致外观不呈现在更复杂的查看器中,后者确实试图从默认外观和默认参考资料中创建外观,但希望DA是正确的,而DR定位正确。因此,您应该更正DA并移动DR

详细的..。

1-默认外观,但不是Appearance流

虽然根据规范ISO 32000-1,自由文本注释需要DA,而AP不是,但简单的PDF查看器可能没有内置代码来从默认外观创建外观流。

这并不是完全令人惊讶的:虽然在PDF中没有什么可做的,但是对某些内容应用默认值可能意味着计算文本的最佳大小以适应某些领域和类似的任务。因此,简单、不完整的观众往往不会实现这一点。

2-默认外观内容无效

DA字符串包含、BT、ET运算符。但是,如果您查看ISO 32000-1的12.7.3.3节变量文本,您将看到在外观创建期间,DA的内容被嵌入到BT中。ET信封:

外观流包括标记内容的以下部分,表示流中绘制文本的部分:

代码语言:javascript
复制
/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)包含设置图形状态参数(如文本大小和颜色)所需的任何图形状态或文本状态运算符,以显示字段的可变文本。只有文本对象中允许的运算符才会出现在此字符串中。

BTET不允许进入另一个BT。ET文本对象!

此外,还可以在DA中添加文本内容。正如您在上面看到的,文本绘图操作是在DA内容之后添加的。因此,你最终会有重复文本的危险。

3-默认资源错位

注释字典中有默认的参考资料。但上文提到的ISO 32000-1的12.7.3.3节可变文本表明:

指定的字体值应与默认资源字典的字体条目中的资源名称相匹配(从交互式表单字典的DR条目中引用)。

因此,你的博士将被忽视,并期待在其他地方。因此,您的字体选择最多可以忽略不计。

票数 5
EN

Stack Overflow用户

发布于 2016-03-16 03:29:06

我正在做类似的事情。我尝试手动生成外观流,但发现这很困难。实际上,上面发布的podofo示例代码可以工作,但是添加外观流的方式是错误的。您不能使用SetAppearanceStream,这也是错误的。

podofo的PdfPainter可以绘制文本。它生成文本流。它看起来只适用于PdfPage,但实际上也适用于XObject。这真的是个隐藏的特征!

我的代码示例:

代码语言:javascript
复制
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);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24205137

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档