Fix omissions in text appearance generation

When generating appearance streams for variable text annotations,
properly handle the cases of there being no appearance dictionary, no
appearance stream, or an appearance stream with no BMC..EMC marker.
This commit is contained in:
Jay Berkenbilt 2019-01-20 21:52:44 -05:00
parent 65ef0bf313
commit 930eade6d3
7 changed files with 10225 additions and 13 deletions

View File

@ -1,5 +1,10 @@
2019-01-20 Jay Berkenbilt <ejb@ql.org>
* When generating appearance streams for variable text
annotations, properly handle the cases of there being no
appearance dictionary, no appearance stream, or an appearance
stream with no BMC..EMC marker.
* When flattening annotations, remove annotations from the file
that don't have appearance streams. These were previously being
preserved, but since they are invisible, there is no reason to

View File

@ -506,6 +506,7 @@ class ValueSetter: public QPDFObjectHandle::TokenFilter
{
}
virtual void handleToken(QPDFTokenizer::Token const&);
virtual void handleEOF();
void writeAppearance();
private:
@ -515,6 +516,7 @@ class ValueSetter: public QPDFObjectHandle::TokenFilter
double tf;
QPDFObjectHandle::Rectangle bbox;
enum { st_top, st_bmc, st_emc, st_end } state;
bool replaced;
};
ValueSetter::ValueSetter(std::string const& DA, std::string const& V,
@ -525,7 +527,8 @@ ValueSetter::ValueSetter(std::string const& DA, std::string const& V,
opt(opt),
tf(tf),
bbox(bbox),
state(st_top)
state(st_top),
replaced(false)
{
}
@ -575,8 +578,22 @@ ValueSetter::handleToken(QPDFTokenizer::Token const& token)
}
}
void ValueSetter::writeAppearance()
void
ValueSetter::handleEOF()
{
if (! this->replaced)
{
QTC::TC("qpdf", "QPDFFormFieldObjectHelper replaced BMC at EOF");
write("/Tx BMC\n");
writeAppearance();
}
}
void
ValueSetter::writeAppearance()
{
this->replaced = true;
// This code does not take quadding into consideration because
// doing so requires font metric information, which we don't
// have in many cases.
@ -768,6 +785,29 @@ QPDFFormFieldObjectHelper::generateTextAppearance(
QPDFAnnotationObjectHelper& aoh)
{
QPDFObjectHandle AS = aoh.getAppearanceStream("/N");
if (AS.isNull())
{
QTC::TC("qpdf", "QPDFFormFieldObjectHelper create AS from scratch");
QPDFObjectHandle::Rectangle rect = aoh.getRect();
QPDFObjectHandle::Rectangle bbox(
0, 0, rect.urx - rect.llx, rect.ury - rect.lly);
QPDFObjectHandle dict = QPDFObjectHandle::parse(
"<< /Resources << /ProcSet [ /PDF /Text ] >>"
" /Type /XObject /Subtype /Form >>");
dict.replaceKey("/BBox", QPDFObjectHandle::newFromRectangle(bbox));
AS = QPDFObjectHandle::newStream(
this->oh.getOwningQPDF(), "/Tx BMC\nEMC\n");
AS.replaceDict(dict);
QPDFObjectHandle AP = aoh.getAppearanceDictionary();
if (AP.isNull())
{
QTC::TC("qpdf", "QPDFFormFieldObjectHelper create AP from scratch");
aoh.getObjectHandle().replaceKey(
"/AP", QPDFObjectHandle::newDictionary());
AP = aoh.getAppearanceDictionary();
}
AP.replaceKey("/N", AS);
}
if (! AS.isStream())
{
aoh.getObjectHandle().warnIfPossible(

View File

@ -422,3 +422,6 @@ qpdf bytes fallback warning 0
qpdf invalid utf-8 in auto 0
qpdf input password hex-bytes 0
QPDFPageDocumentHelper ignore annotation with no appearance 0
QPDFFormFieldObjectHelper create AS from scratch 0
QPDFFormFieldObjectHelper create AP from scratch 0
QPDFFormFieldObjectHelper replaced BMC at EOF 0

View File

@ -261,18 +261,29 @@ $td->runtest("compare files",
show_ntests();
# ----------
$td->notify("--- Appearance Streams ---");
$n_tests += 4;
$n_tests += 8;
$td->runtest("generate appearances and flatten",
{$td->COMMAND =>
"qpdf --qdf --no-original-object-ids --static-id" .
" --generate-appearances --flatten-annotations=all" .
" need-appearances.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("compare files",
{$td->FILE => "a.pdf"},
{$td->FILE => "appearances-a.pdf"});
foreach my $f ('need-appearances',
'need-appearances-more',
'need-appearances-more2')
{
$td->runtest("generate appearances and flatten ($f)",
{$td->COMMAND =>
"qpdf --qdf --no-original-object-ids --static-id" .
" --generate-appearances --flatten-annotations=all" .
" $f.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
my $exp = 'appearances-a';
if ($f =~ m/appearances(-.*)$/)
{
$exp .= $1;
}
$exp .= '.pdf';
$td->runtest("compare files",
{$td->FILE => "a.pdf"},
{$td->FILE => $exp});
}
$td->runtest("more choices",
{$td->COMMAND =>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff