Commit 293a2e52b3fbd6dac2c89dfb35a546cdc027eb1b
1 parent
3cfd6546
Disregard appearance state when irrelevant (fixes #949)
If /AP is a dictionary of streams rather than a dictionary of dictionaries, disregard /AS, which is supposed to point to a subkey of one of the dictionaries. This fix prevents qpdf's annotation flattening from discarding some annotations when /AS is erroneously set.
Showing
8 changed files
with
35 additions
and
11 deletions
ChangeLog
| ... | ... | @@ -5,6 +5,15 @@ |
| 5 | 5 | reserved object fits better in the QPDF API. The old call just |
| 6 | 6 | delegates to the new one. |
| 7 | 7 | |
| 8 | +2023-05-13 Jay Berkenbilt <ejb@ql.org> | |
| 9 | + | |
| 10 | + * When an annotation dictionary's appearance dictionary (`/AP`) | |
| 11 | + has a key that is a stream, disregard `/AS` (which is supposed to | |
| 12 | + point to a subkey). This enables qpdf to not ignore annotations | |
| 13 | + that have incorrect values for `/AS` when the appearance stream is | |
| 14 | + directly in the `/AP` dictionary instead of in a subkey. Fixes | |
| 15 | + #949. | |
| 16 | + | |
| 8 | 17 | 2023-04-02 Jay Berkenbilt <ejb@ql.org> |
| 9 | 18 | * Allow QPDFJob's workflow to be split into a reading phase and a |
| 10 | 19 | writing phase to allow the caller to operate on the QPDF object | ... | ... |
libqpdf/QPDFAnnotationObjectHelper.cc
| ... | ... | @@ -54,7 +54,14 @@ QPDFAnnotationObjectHelper::getAppearanceStream( |
| 54 | 54 | std::string desired_state = state.empty() ? getAppearanceState() : state; |
| 55 | 55 | if (ap.isDictionary()) { |
| 56 | 56 | QPDFObjectHandle ap_sub = ap.getKey(which); |
| 57 | - if (ap_sub.isStream() && desired_state.empty()) { | |
| 57 | + if (ap_sub.isStream()) { | |
| 58 | + // According to the spec, Appearance State is supposed to | |
| 59 | + // refer to a subkey of the appearance stream when /AP is | |
| 60 | + // a dictionary, but files have been seen in the wild | |
| 61 | + // where Appearance State is `/N` and `/AP` is a stream. | |
| 62 | + // Therefore, if `which` points to a stream, disregard | |
| 63 | + // state and just use the stream. See qpdf issue #949 for | |
| 64 | + // details. | |
| 58 | 65 | QTC::TC("qpdf", "QPDFAnnotationObjectHelper AP stream"); |
| 59 | 66 | return ap_sub; |
| 60 | 67 | } | ... | ... |
manual/release-notes.rst
| ... | ... | @@ -26,6 +26,14 @@ For a detailed list of changes, please see the file |
| 26 | 26 | - Add ``QPDF::newReserved`` as a better alternative to |
| 27 | 27 | ``QPDFObjectHandle::newReserved``. |
| 28 | 28 | |
| 29 | + - Bug fixes | |
| 30 | + | |
| 31 | + - Ignore an annotation's appearance state when the annotation only | |
| 32 | + has one appearance. This prevents qpdf's annotation flattening | |
| 33 | + logic from throwing away appearances of annotations whose | |
| 34 | + annotation state is set incorrectly, as has been seen in some | |
| 35 | + PDF files. | |
| 36 | + | |
| 29 | 37 | 11.3.0: February 25, 2023 |
| 30 | 38 | - CLI Enhancements |
| 31 | 39 | ... | ... |
qpdf/qtest/qpdf/form-form-bad-fields-array.out
| ... | ... | @@ -178,7 +178,7 @@ Page: 11 0 R |
| 178 | 178 | Subtype: /Widget |
| 179 | 179 | Rect: [123.4, 692.1, 260.9, 706.7] |
| 180 | 180 | Appearance stream (/N): 14 0 R |
| 181 | - Appearance stream (/N, /3): null | |
| 181 | + Appearance stream (/N, /3): 14 0 R | |
| 182 | 182 | Annotation: 16 0 R |
| 183 | 183 | Field: 16 0 R |
| 184 | 184 | Subtype: /Widget |
| ... | ... | @@ -249,5 +249,5 @@ Page: 35 0 R |
| 249 | 249 | Subtype: /Widget |
| 250 | 250 | Rect: [113.6, 378.5, 351.3, 396.3] |
| 251 | 251 | Appearance stream (/N): 36 0 R |
| 252 | - Appearance stream (/N, /3): null | |
| 252 | + Appearance stream (/N, /3): 36 0 R | |
| 253 | 253 | test 43 done | ... | ... |
qpdf/qtest/qpdf/form-form-document-defaults.out
| ... | ... | @@ -166,7 +166,7 @@ Page: 11 0 R |
| 166 | 166 | Subtype: /Widget |
| 167 | 167 | Rect: [123.4, 692.1, 260.9, 706.7] |
| 168 | 168 | Appearance stream (/N): 14 0 R |
| 169 | - Appearance stream (/N, /3): null | |
| 169 | + Appearance stream (/N, /3): 14 0 R | |
| 170 | 170 | Annotation: 16 0 R |
| 171 | 171 | Field: 16 0 R |
| 172 | 172 | Subtype: /Widget |
| ... | ... | @@ -237,5 +237,5 @@ Page: 35 0 R |
| 237 | 237 | Subtype: /Widget |
| 238 | 238 | Rect: [113.6, 378.5, 351.3, 396.3] |
| 239 | 239 | Appearance stream (/N): 36 0 R |
| 240 | - Appearance stream (/N, /3): null | |
| 240 | + Appearance stream (/N, /3): 36 0 R | |
| 241 | 241 | test 43 done | ... | ... |
qpdf/qtest/qpdf/form-form-empty-from-odt.out
| ... | ... | @@ -166,7 +166,7 @@ Page: 11 0 R |
| 166 | 166 | Subtype: /Widget |
| 167 | 167 | Rect: [123.4, 692.1, 260.9, 706.7] |
| 168 | 168 | Appearance stream (/N): 14 0 R |
| 169 | - Appearance stream (/N, /3): null | |
| 169 | + Appearance stream (/N, /3): 14 0 R | |
| 170 | 170 | Annotation: 16 0 R |
| 171 | 171 | Field: 16 0 R |
| 172 | 172 | Subtype: /Widget |
| ... | ... | @@ -237,5 +237,5 @@ Page: 35 0 R |
| 237 | 237 | Subtype: /Widget |
| 238 | 238 | Rect: [113.6, 378.5, 351.3, 396.3] |
| 239 | 239 | Appearance stream (/N): 36 0 R |
| 240 | - Appearance stream (/N, /3): null | |
| 240 | + Appearance stream (/N, /3): 36 0 R | |
| 241 | 241 | test 43 done | ... | ... |
qpdf/qtest/qpdf/form-form-errors.out
| ... | ... | @@ -171,7 +171,7 @@ Page: 11 0 R |
| 171 | 171 | Subtype: /Widget |
| 172 | 172 | Rect: [123.4, 692.1, 260.9, 706.7] |
| 173 | 173 | Appearance stream (/N): 14 0 R |
| 174 | - Appearance stream (/N, /3): null | |
| 174 | + Appearance stream (/N, /3): 14 0 R | |
| 175 | 175 | Annotation: 16 0 R |
| 176 | 176 | Field: 16 0 R |
| 177 | 177 | Subtype: /Widget |
| ... | ... | @@ -242,5 +242,5 @@ Page: 35 0 R |
| 242 | 242 | Subtype: /Widget |
| 243 | 243 | Rect: [113.6, 378.5, 351.3, 396.3] |
| 244 | 244 | Appearance stream (/N): 36 0 R |
| 245 | - Appearance stream (/N, /3): null | |
| 245 | + Appearance stream (/N, /3): 36 0 R | |
| 246 | 246 | test 43 done | ... | ... |
qpdf/qtest/qpdf/form-form-mod1.out
| ... | ... | @@ -166,7 +166,7 @@ Page: 11 0 R |
| 166 | 166 | Subtype: /Widget |
| 167 | 167 | Rect: [123.4, 692.1, 260.9, 706.7] |
| 168 | 168 | Appearance stream (/N): 14 0 R |
| 169 | - Appearance stream (/N, /3): null | |
| 169 | + Appearance stream (/N, /3): 14 0 R | |
| 170 | 170 | Annotation: 16 0 R |
| 171 | 171 | Field: 16 0 R |
| 172 | 172 | Subtype: /Widget |
| ... | ... | @@ -237,5 +237,5 @@ Page: 35 0 R |
| 237 | 237 | Subtype: /Widget |
| 238 | 238 | Rect: [113.6, 378.5, 351.3, 396.3] |
| 239 | 239 | Appearance stream (/N): 36 0 R |
| 240 | - Appearance stream (/N, /3): null | |
| 240 | + Appearance stream (/N, /3): 36 0 R | |
| 241 | 241 | test 43 done | ... | ... |