Commit 2d32f4db8fd125f2481ecf767d9f6506e80481f6
1 parent
9cb59987
Handle fallback font size in text appearances
If we end up using our fallback font size when generating appearances for text fields, reflect that in the Tf operator used in the appearance stream.
Showing
5 changed files
with
393 additions
and
355 deletions
ChangeLog
| 1 | 2019-01-20 Jay Berkenbilt <ejb@ql.org> | 1 | 2019-01-20 Jay Berkenbilt <ejb@ql.org> |
| 2 | 2 | ||
| 3 | + * Tweak the content code generated for variable text fields to | ||
| 4 | + better handle font sizes and multi-line text. | ||
| 5 | + | ||
| 3 | * When generating appearance streams for variable text | 6 | * When generating appearance streams for variable text |
| 4 | annotations, properly handle the cases of there being no | 7 | annotations, properly handle the cases of there being no |
| 5 | appearance dictionary, no appearance stream, or an appearance | 8 | appearance dictionary, no appearance stream, or an appearance |
libqpdf/QPDFFormFieldObjectHelper.cc
| @@ -715,17 +715,23 @@ class TfFinder: public QPDFObjectHandle::TokenFilter | @@ -715,17 +715,23 @@ class TfFinder: public QPDFObjectHandle::TokenFilter | ||
| 715 | virtual void handleToken(QPDFTokenizer::Token const&); | 715 | virtual void handleToken(QPDFTokenizer::Token const&); |
| 716 | double getTf(); | 716 | double getTf(); |
| 717 | std::string getFontName(); | 717 | std::string getFontName(); |
| 718 | + std::string getDA(); | ||
| 718 | 719 | ||
| 719 | private: | 720 | private: |
| 720 | double tf; | 721 | double tf; |
| 722 | + size_t tf_idx; | ||
| 721 | std::string font_name; | 723 | std::string font_name; |
| 722 | double last_num; | 724 | double last_num; |
| 725 | + size_t last_num_idx; | ||
| 723 | std::string last_name; | 726 | std::string last_name; |
| 727 | + std::vector<std::string> DA; | ||
| 724 | }; | 728 | }; |
| 725 | 729 | ||
| 726 | TfFinder::TfFinder() : | 730 | TfFinder::TfFinder() : |
| 727 | tf(11.0), | 731 | tf(11.0), |
| 728 | - last_num(0.0) | 732 | + tf_idx(0), |
| 733 | + last_num(0.0), | ||
| 734 | + last_num_idx(0) | ||
| 729 | { | 735 | { |
| 730 | } | 736 | } |
| 731 | 737 | ||
| @@ -734,11 +740,13 @@ TfFinder::handleToken(QPDFTokenizer::Token const& token) | @@ -734,11 +740,13 @@ TfFinder::handleToken(QPDFTokenizer::Token const& token) | ||
| 734 | { | 740 | { |
| 735 | QPDFTokenizer::token_type_e ttype = token.getType(); | 741 | QPDFTokenizer::token_type_e ttype = token.getType(); |
| 736 | std::string value = token.getValue(); | 742 | std::string value = token.getValue(); |
| 743 | + DA.push_back(token.getRawValue()); | ||
| 737 | switch (ttype) | 744 | switch (ttype) |
| 738 | { | 745 | { |
| 739 | case QPDFTokenizer::tt_integer: | 746 | case QPDFTokenizer::tt_integer: |
| 740 | case QPDFTokenizer::tt_real: | 747 | case QPDFTokenizer::tt_real: |
| 741 | last_num = strtod(value.c_str(), 0); | 748 | last_num = strtod(value.c_str(), 0); |
| 749 | + last_num_idx = DA.size() - 1; | ||
| 742 | break; | 750 | break; |
| 743 | 751 | ||
| 744 | case QPDFTokenizer::tt_name: | 752 | case QPDFTokenizer::tt_name: |
| @@ -754,6 +762,7 @@ TfFinder::handleToken(QPDFTokenizer::Token const& token) | @@ -754,6 +762,7 @@ TfFinder::handleToken(QPDFTokenizer::Token const& token) | ||
| 754 | // insane things or suffering from over/underflow | 762 | // insane things or suffering from over/underflow |
| 755 | tf = last_num; | 763 | tf = last_num; |
| 756 | } | 764 | } |
| 765 | + tf_idx = last_num_idx; | ||
| 757 | font_name = last_name; | 766 | font_name = last_name; |
| 758 | break; | 767 | break; |
| 759 | 768 | ||
| @@ -769,6 +778,30 @@ TfFinder::getTf() | @@ -769,6 +778,30 @@ TfFinder::getTf() | ||
| 769 | } | 778 | } |
| 770 | 779 | ||
| 771 | std::string | 780 | std::string |
| 781 | +TfFinder::getDA() | ||
| 782 | +{ | ||
| 783 | + std::string result; | ||
| 784 | + size_t n = this->DA.size(); | ||
| 785 | + for (size_t i = 0; i < n; ++i) | ||
| 786 | + { | ||
| 787 | + std::string cur = this->DA.at(i); | ||
| 788 | + if (i == tf_idx) | ||
| 789 | + { | ||
| 790 | + double delta = strtod(cur.c_str(), 0) - this->tf; | ||
| 791 | + if ((delta > 0.001) || (delta < -0.001)) | ||
| 792 | + { | ||
| 793 | + // tf doesn't match the font size passed to Tf, so | ||
| 794 | + // substitute. | ||
| 795 | + QTC::TC("qpdf", "QPDFFormFieldObjectHelper fallback Tf"); | ||
| 796 | + cur = QUtil::double_to_string(tf); | ||
| 797 | + } | ||
| 798 | + } | ||
| 799 | + result += cur; | ||
| 800 | + } | ||
| 801 | + return result; | ||
| 802 | +} | ||
| 803 | + | ||
| 804 | +std::string | ||
| 772 | TfFinder::getFontName() | 805 | TfFinder::getFontName() |
| 773 | { | 806 | { |
| 774 | return this->font_name; | 807 | return this->font_name; |
| @@ -843,6 +876,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance( | @@ -843,6 +876,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance( | ||
| 843 | tok.write(QUtil::unsigned_char_pointer(DA.c_str()), DA.length()); | 876 | tok.write(QUtil::unsigned_char_pointer(DA.c_str()), DA.length()); |
| 844 | tok.finish(); | 877 | tok.finish(); |
| 845 | double tf = tff.getTf(); | 878 | double tf = tff.getTf(); |
| 879 | + DA = tff.getDA(); | ||
| 846 | 880 | ||
| 847 | std::string (*encoder)(std::string const&, char) = &QUtil::utf8_to_ascii; | 881 | std::string (*encoder)(std::string const&, char) = &QUtil::utf8_to_ascii; |
| 848 | std::string font_name = tff.getFontName(); | 882 | std::string font_name = tff.getFontName(); |
qpdf/qpdf.testcov
| @@ -425,3 +425,4 @@ QPDFPageDocumentHelper ignore annotation with no appearance 0 | @@ -425,3 +425,4 @@ QPDFPageDocumentHelper ignore annotation with no appearance 0 | ||
| 425 | QPDFFormFieldObjectHelper create AS from scratch 0 | 425 | QPDFFormFieldObjectHelper create AS from scratch 0 |
| 426 | QPDFFormFieldObjectHelper create AP from scratch 0 | 426 | QPDFFormFieldObjectHelper create AP from scratch 0 |
| 427 | QPDFFormFieldObjectHelper replaced BMC at EOF 0 | 427 | QPDFFormFieldObjectHelper replaced BMC at EOF 0 |
| 428 | +QPDFFormFieldObjectHelper fallback Tf 0 |
qpdf/qtest/qpdf/appearances-a-more2.pdf
No preview for this file type
qpdf/qtest/qpdf/need-appearances-more2.pdf
No preview for this file type