c++ - 向 PDF 添加 FreeText 注释

标签 c++ ios pdf annotations podofo

我正在使用podofo用于执行 PDF 操作,例如根据我在 iOS 应用程序中的要求添加注释、签名等。我首先尝试了 podofo library available 的唯一样本效果很好。但该示例的问题是添加的注释不会显示在任何预览中,例如 GoogleAdobe Reader 等。这是一个问题。

根据 Adob​​e 的一些指南,我发现需要有 Appearance Key 才能显示 FreeText 注释。我尝试在文本编辑器中分析原始 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(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. 它具有默认外观,但没有外观流
  2. 默认外观的内容无效。
  3. 默认资源位于错误的对象中。

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

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

详细...

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

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

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

2 - 默认外观内容无效

您的DA字符串包含BTET运算符。不过,如果您查看 ISO 32000-1 的第 12.7.3.3 节变量文本,您会发现在外观创建过程中,DA 的内容被嵌入到 BT 中。 .ET信封:

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

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

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

3 - 默认资源错位

注释字典中有默认资源。但上面提到的 ISO 32000-1 的 12.7.3.3 Variable Text 部分表明:

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).

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

关于c++ - 向 PDF 添加 FreeText 注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24205137/

相关文章:

c++ - 使用 `size_t` 长度会影响编译器优化吗?

c++ - 从转发声明的类的函数获取返回类型

ios - 当在 vscode 上按 Swift 代码运行时,它会显示此错误 :

objective-c - 删除照片后 UIImagePickerController 崩溃

c# - PDFreactor 交互式 PDF <选择> 框处于非事件状态?

c++ - 在指定的位偏移处读/写一个值

c++ - GTKMM::在 GTk::Drawing 区域中使用单个 Gdk::PixBuf 绘制多个图像

ios - 如何在 ios 中使用 SWRevealViewcontroller 导航到 sw_front View ?

xml - 如何使用 perl 将 ZUGFeRD-XML 附加到 PDF?

php - 使用 php 将生成的输出 html/css 转换为 pdf - 2017 年