mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-30 04:58:34 -06:00
docs(redact): describe the overlay, text state, description and inline image rules
This commit is contained in:
@@ -13,7 +13,10 @@ The parser is tolerant (unreadable bytes are skipped and counted, never fatal) a
|
||||
panics. `redact` and (later) `edit` build their interpreters on it; the graphics-state tracker
|
||||
and the `Patch` API of architecture §6 grow here.
|
||||
|
||||
Unfiltered inline images with built-in or Indexed colour spaces, and image masks, use their
|
||||
sample layout (including per-row byte padding) to locate `EI`. This preserves pixel bytes
|
||||
that look like the terminator. Filtered images and resource-defined colour spaces retain
|
||||
the tolerant delimiter heuristic; damaged or truncated layouts fall back to it too.
|
||||
An inline image ends where the renderer's tokenizer (`hayro-syntax`) ends it, so the parser
|
||||
and the renderer read the same operators after the image, and redaction removes what the page
|
||||
actually draws. Only where that tokenizer reads no image (its parameters don't read, or no `EI`
|
||||
passes its checks) does the parser locate `EI` by its own rules: unfiltered images with built-in
|
||||
or Indexed colour spaces, and image masks, by their sample layout (including per-row byte
|
||||
padding), other images by the tolerant delimiter heuristic. Such an image is counted in
|
||||
`Parsed::ambiguous_images`, because the operators after it may not be the ones the page draws.
|
||||
|
||||
+16
-6
@@ -20,7 +20,8 @@ clear_marks(&mut doc, None)?; // remove marks without app
|
||||
- **images**: fully covered → removed; partly covered → a copy with the covered pixels cleared
|
||||
(8/16-bit and 1/2/4-bit images, image masks; Flate/LZW/RL/A85/AHx). Codecs PdfCraft can't
|
||||
re-encode (DCT, JPX, JBIG2, CCITT) are removed whole (fail-closed); inline images under an
|
||||
area are removed. Images with separate `/SMask` or `/Mask` data are removed whole;
|
||||
area are removed. Images with separate `/SMask` or `/Mask` data, and images whose data decodes
|
||||
to more than twice their declared raster (plus a byte per row and 4 KiB), are removed whole;
|
||||
cleared copies drop `/Alternates` so alternate pixels cannot survive;
|
||||
- **vectors**: covered paths are removed; partly covered paths and shadings are clipped so
|
||||
nothing paints inside the areas;
|
||||
@@ -31,8 +32,13 @@ clear_marks(&mut doc, None)?; // remove marks without app
|
||||
page as a `/PCMark /Redaction` stream.
|
||||
|
||||
A verification pass re-reads each redacted page and fails the operation if any glyph or inline
|
||||
image is still under an area. Content that can't be decoded makes the operation fail rather than
|
||||
leave it unredacted. A Redact annotation with neither a usable `/QuadPoints` array nor a usable
|
||||
image is still under an area. It checks every content stream the page had, whatever its
|
||||
dictionary calls it; only the overlay streams this `apply` added (`Report::overlays`) are skipped.
|
||||
Text is placed with the font and size set by `Tf` or by an ExtGState's `/Font` through `gs`, and a
|
||||
form XObject starts from the text state of the content that draws it. Content that can't be
|
||||
decoded makes the operation fail rather than leave it unredacted, and so does an inline image the
|
||||
renderer's tokenizer reads no image for (`RedactError::Unreadable`): where the page's operators
|
||||
resume after it would be a guess. A Redact annotation with neither a usable `/QuadPoints` array nor a usable
|
||||
`/Rect` makes it fail with `RedactError::UnreadableMark` before anything changes, instead of
|
||||
skipping that mark. The count covers the marks on the pages being applied.
|
||||
|
||||
@@ -50,15 +56,19 @@ as Sanitize drops them, so a full rewrite of a tagged PDF can't keep a removed c
|
||||
A tree where that can't be done (an element written in place, or one too large to walk) makes
|
||||
`apply` fail with `RedactError::Tags` rather than leave the annotation reachable.
|
||||
|
||||
Replacement descriptions are removed only from marked-content spans changed by cleanup.
|
||||
Unchanged spans retain their descriptions; unused property entries are retired during redaction
|
||||
Replacement descriptions (`/Alt`, `/ActualText`, `/E`) are removed from marked-content spans
|
||||
changed by cleanup, from every structure element above them (found through both `/P` and `/K`),
|
||||
and from elements that lose an annotation reference, which also lose `/T`. An element written in
|
||||
place above one whose descriptions go makes `apply` fail with `RedactError::Tags`. Unchanged
|
||||
spans retain their descriptions; unused property entries are retired during redaction
|
||||
and hidden-content cleanup, including aliases in shared/inherited resources. Descriptions still
|
||||
used by surviving pages or forms are kept.
|
||||
|
||||
A redacted page that inherits `/Resources` from the page tree gets them pinned (by reference;
|
||||
a direct inherited dictionary is made one shared object first) before it is rewritten. The parent's
|
||||
`/Resources` is then retired unless another page still inherits it, so it cannot keep a removed
|
||||
XObject reachable. Pages that aren't redacted are left untouched.
|
||||
XObject reachable. Surviving form XObjects lose the resource entries for removed XObjects their own
|
||||
content doesn't draw, for the same reason. Pages that aren't redacted are left untouched.
|
||||
|
||||
## Remove hidden information / Sanitize
|
||||
|
||||
|
||||
Reference in New Issue
Block a user