я использую podofo для выполнения операций PDF, таких как добавление аннотаций, подписей и т. д. согласно моему требованию в моем приложении iOS. Я впервые попробовал единственный образец для библиотека подофо доступна который прекрасно работает Но проблема с образцом в том, что добавленные аннотации не отображаются ни в одном предварительном просмотре, как Google
, Adobe Reader
и т.д. Это проблема.
Согласно нескольким рекомендациям от Adobe, я обнаружил, что для этого требуется 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)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 Universe, может сообщить мне, что не так с приведенным выше кодом, и как добавить правильную аннотацию 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 могут привести к тому, что внешний вид не будет визуализироваться в более сложных средствах просмотра, которые пытаются создать внешний вид из Внешний вид по умолчанию а также Ресурсы по умолчанию но ожидать DA быть правильным и DR правильно расположен. Поэтому вы должны исправить DA и переместить DR.
В деталях…
Хотя согласно спецификации ISO 32000-1 DA требуется для свободной текстовой аннотации и AP Это не так, более простые средства просмотра PDF могут не иметь встроенного кода для создания потока внешнего вида из внешнего вида по умолчанию.
В этом нет ничего удивительного: хотя в случае с вашим PDF не так много дел, применение значения по умолчанию к некоторому контенту может подразумевать вычисление наилучшего размера текста, подходящего для некоторой области и аналогичных задач. Таким образом, простые, неполные зрители склонны не реализовывать это.
Ваш DA строка содержит BT а также ET операторы. Если вы посмотрите на раздел 12.7.3.3 Переменный текст из ISO 32000-1, тем не менее, вы увидите, что при создании внешнего вида содержимое DA встроены в BT .. ET конверт:
Поток внешнего вида включает в себя следующий раздел отмеченного содержимого, представляющий часть потока, который рисует текст:
/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) содержит любые операторы графического состояния или состояния текста, необходимые для установки параметров графического состояния, таких как размер и цвет текста, для отображения переменного текста поля. В этой строке должны присутствовать только те операторы, которые разрешены в текстовых объектах
Но BT а также ET не допускаются внутри другого BT .. ET текстовый объект!
Кроме того, вы добавляете текстовое содержимое в свой DA. Как вы видите выше, добавляются операции рисования текста сразу после ваш DA содержание. Таким образом, вы рискуете получить дубликаты текстов в конце концов.
У тебя есть Ресурсы по умолчанию в аннотационном словаре. Но раздел 12.7.3.3 Переменный текст из ISO 32000-1 упомянутое выше указывает:
Указанный шрифт значение должно соответствовать имени ресурса в Шрифт запись словаря ресурсов по умолчанию (ссылка на DR запись словаря интерактивной формы).
Таким образом, ваш DR будут игнорироваться и ожидаются в другом месте. Таким образом, ваш выбор шрифта может в лучшем случае игнорироваться
Я работаю над подобными вещами. Я попытался создать поток внешнего вида вручную, но оказалось, что это сложно. На самом деле пример кода podofo, который вы публикуете выше, работает, но это неправильно в плане добавления потока внешнего вида. Вы не можете использовать SetAppearanceStream, что тоже неправильно.
PdfPainter podofo может рисовать текст. Он генерирует текстовый поток. Это похоже на работу только для 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);