将 FreeText 注释添加到 PDF [英] Adding FreeText annotation to PDF

查看:34
本文介绍了将 FreeText 注释添加到 PDF的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 podofo 进行 PDF 操作,例如根据我的要求添加注释、签名等iOS 应用程序.我首先尝试了 podofo 库可用 的唯一示例,效果很好.但是示例的问题是添加的注释没有显示在任何预览中,例如 GoogleAdobe Reader 等.这是一个问题.

根据 Adob​​e 的一些指南,我发现它需要有 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)b​​Width title:(NSString*)title content:(NSString*)content bOpen:(Boolean)bOpen color:(UIColor*)color {PoDoFo::PdfMemDocument *doc = (PoDoFo::PdfMemDocument *) aDoc;PoDoFo::PdfPage* pPage = doc->GetPage(pageIndex);如果(!pPage){//无法获取该页面返回;}PoDoFo::PdfRect 矩形;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([title UTF8String]));PoDoFo::PdfString sContent(reinterpret_cast([content UTF8String]));PoDoFo::PdfFont* pFont = doc->CreateFont( "Helvetica", new PoDoFo::PdfIdentityEncoding( 0, 0xffff, true ) );std::ostringstream oss;oss<GetIdentifier().GetName()<<" " <<pFont->GetFontSize()<<Tf"<<std::endl;[APDFManager WriteStringToStream:sContent:oss:pFont];oss<GetIdentifier().GetName(), pFont->GetObject()->Reference());PoDoFo::PdfDictionary 资源;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;字符* pBuffer = NULL;std::auto_ptrpFilter = PoDoFo::PdfFilterFactory::Create(PoDoFo::ePdfFilter_ASCIIHexDecode);pFilter->Encode(buffer.GetBuffer(), buffer.GetSize(), &pBuffer, &lLen );oss<<<";oss<

SO Universe 中的任何人都可以告诉我上面的代码有什么问题,以及如何添加正确的 FreeText Annotation 以使其在任何地方都能正确显示.

非常感谢.

解决方案

有问题的注释如下所示:

19 0 对象<</类型/注释/Contents(þÿ M Y A 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<</字体<</Ft18 18 0 R>>>/M(D:20140616141406+05'00')/P 4 0 R/矩形[188.814117 748.970520 467.849731 795.476456]/子类型/自由文本/T(þÿ A n o t a t e P D F)>>结束对象

三个观察:

  1. 它有一个默认外观,但没有外观流.
  2. 默认外观的内容无效.
  3. 默认资源位于错误的对象中.

第 1 项可能会导致外观无法在许多仅显示最终内容(页面内容、注释外观等)但不从 默认外观 创建外观的简单查看器中呈现.因此,您还应该提供外观流.

第 2 项和第 3 项可能会导致外观无法在更复杂的查看器中呈现,这些查看器确实尝试从 默认外观默认资源 创建外观,但希望 DA 正确且 DR 正确定位.因此,您应该更正 DA 并移动 DR.

详细...

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

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

这并不完全令人惊讶:虽然您的 PDF 没有太多可做的事情,但将默认值应用于某些内容可能意味着计算文本的最佳大小以适合某些区域和类似任务.因此,简单、不完整的查看器往往不会实现这一点.

2 - 默认外观内容无效

您的DA 字符串包含BTET 运算符.如果您查看 ISO 32000-1,不过,您会看到在外观创建期间DA 的内容被嵌入到BT .. ET 信封:

<块引用>

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

/Tx BMC % 以标记 Tx 开始标记的内容q % 保存图形状态... 任何所需的图形状态更改,例如剪裁 ...BT % 开始文本对象... 默认外观字符串 ( DA ) ...... 文本定位和文本显示运算符来显示变量文本 ...ET % 结束文本对象Q % 恢复图形状态EMC % 结束标记内容

<块引用>

默认外观字符串 (DA) 包含建立图形状态参数(例如文本大小和颜色)所需的任何图形状态或文本状态运算符,以显示字段的可变文本.只有在文本对象中允许的操作符才会出现在这个字符串中

但是 BTET 不允许在另一个 BT .. ET 文本对象中!

此外,您还可以在 DA 中添加文本内容.如上所示,文本绘制操作紧接着添加到您的 DA 内容之后.因此,您最终会面临重复文本的危险.

3 - 默认资源错位

您在注释字典中有默认资源.但是 Variable Text 部分="noreferrer">ISO 32000-1 上面提到的表示:

<块引用>

指定的 font 值应与默认资源字典的 Font 条目中的资源名称匹配(从交互式表单字典).

因此,您的 DR 将被忽略并在其他地方被预期.所以你选择的字体最多可能会被忽略

I am using podofo for doing PDF operations, like adding annotations, signatures etc as per my requirement in my iOS application. I have first tried the only sample for the podofo library available which works great. But the problem with the sample is the annotations added doesn't show in any preview like Google, Adobe Reader etc. Thats a problem.

As per few guideline from Adobe I found that it requires to have Appearance Key for the FreeText annotation to appear. I have tried analyzing raw pdf file in a text editor to see the difference in the PDF which has correct Annotations, with podofo created PDF annotations. I found there are AP N keys with a stream object that is in encoded form for the annotation, which was missing from podofo sample.

Then after searching I found podofo's own sample and tried to use the code, which seems to be doing correctly, but didn't work either, I know I am missing something, but not sure what, and where, please have a look of the code below

+(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;
}

Any one in SO universe can please tell me what's wrong with above code, and how to add a correct FreeText Annotation so that it appears correctly everywhere.

Many Thanks.

解决方案

The annotation in question looks like this:

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

Three observations:

  1. It has a Default Appearance but not APpearance streams.
  2. The contents of the Default Appearance are invalid.
  3. The Default Resources are in the wrong object.

Item 1 may cause the appearance not to render in many simple viewers which only show finalized stuff (page content, annotation appearances, ...) but don't create appearances from the Default Appearance. You should, therefore, also supply an appearance stream.

Items 2 and 3 may cause the appearance not to render in more complex viewers which do try to create appearances from the Default Appearance and Default Resources but expect the DA to be correct and the DR correctly located. You should, therefore, correct the DA and move the DR.

In detail...

1 - Default Appearance but not APpearance streams

While according to the specification ISO 32000-1 the DA is required for free text annotation and AP is not, simpler PDF viewers may not have built-in code to create an appearance stream from the default appearance.

This is not completely surprising: While in case of your PDF there is not much to do, applying the default to some content can imply calculating the best size for text to fit into some area and similar tasks. Thus, simple, incomplete viewers tend to not implement this.

2 - Default Appearance contents are invalid

Your DA string contains BT and ET operators. If you look at section 12.7.3.3 Variable Text of ISO 32000-1, though, you'll see that during appearance creation the contents of DA are embedded into a BT .. ET envelope:

The appearance stream includes the following section of marked content, which represents the portion of the stream that draws the text:

/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 

The default appearance string (DA) contains any graphics state or text state operators needed to establish the graphics state parameters, such as text size and colour, for displaying the field’s variable text. Only operators that are allowed within text objects shall occur in this string

But BT and ET are not allowed inside another BT .. ET text object!

Furthermore you add the text content inside your DA. As you see above, the text drawing operations are added right after your DA contents. Thus, you're in danger of having duplicate texts eventually.

3 - Default Resources dislocation

You have the Default Resources in the annotation dictionary. But the section 12.7.3.3 Variable Text of ISO 32000-1 mentioned above indicates:

The specified font value shall match a resource name in the Font entry of the default resource dictionary (referenced from the DR entry of the interactive form dictionary).

Thus, your DR will be ignored and are expected elsewhere. So your choice of font may at best be ignored

这篇关于将 FreeText 注释添加到 PDF的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆