Table of Contents

Smart Redaction (PII Detection + PDF Redaction)

Smart redaction combines two LM-Kit.NET capabilities into one compliance-ready workflow: PiiExtraction finds sensitive values in a document, and PdfRedactor permanently removes them. A human reviews the suggestions before anything is deleted, so the final decision, and the accountability, stays with a person. Everything runs 100% on-device: no cloud, no data leaves the machine.

The workflow has four stages:

IDENTIFY  ->  REVIEW (human-in-the-loop)  ->  REMOVE  ->  VERIFY

Why Not Just Draw a Black Box

A black rectangle over a name is not redaction: the text underneath is still there and is recoverable by copy-paste, text extraction, or raw stream inspection. Smart redaction detects the sensitive values and then applies true redaction, deleting the underlying content (text glyphs, image pixels, vector graphics, and intersecting annotations). The output carries no recoverable trace of the removed values.


1. Identify

PiiExtraction analyzes every page and returns each detected value with its type, a confidence score, and its occurrences: the exact bounding boxes where the value appears on the page. Use InferenceModality.Text so those glyph positions are preserved for redaction.

using LMKit.Data;
using LMKit.Inference;
using LMKit.Model;
using LMKit.TextAnalysis;

LM model = LM.LoadFromModelID("qwen3.5:4b");

var extractor = new PiiExtraction(model)
{
    PreferredInferenceModality = InferenceModality.Text, // keep glyph positions for redaction
};

using var document = new Attachment("account_application.pdf");
var entities = extractor.Extract(document);

foreach (var entity in entities)
{
    Console.WriteLine($"{entity.EntityDefinition.Label}: \"{entity.Value}\" " +
                      $"(confidence {entity.Confidence:0.00}, {entity.Occurrences.Count} occurrence(s))");
}

Extract accepts a PDF or an image attachment. Each PiiExtractedEntity.Occurrences item is a TextRegion that carries the value's bounding box on the page, which is exactly what the redactor places its marks on.

The built-in types cover person, email, phone, postal address, URL, IP address, date of birth, Social Security number, credit card, and bank account. Add your own with a custom definition:

extractor.PiiEntityDefinitions.Add(new PiiExtraction.PiiEntityDefinition("SWIFT code"));

For scanned PDFs without a text layer, attach an OCR engine so the text can be recovered first:

extractor.OcrEngine = new LMKit.Extraction.Ocr.LMKitOcr();

2. Review (Human-in-the-Loop)

Never redact automatically in a compliance workflow. Present the suggestions to a person who keeps or drops each one. A confidence score makes triage fast: auto-approve the obvious ones and only prompt for the uncertain.

// Example policy: auto-approve high-confidence items, queue the rest for a human.
var approved = new List<PiiExtraction.PiiExtractedEntity>();
var needsReview = new List<PiiExtraction.PiiExtractedEntity>();

foreach (var entity in entities)
{
    if (entity.Confidence >= 0.85f)
        approved.Add(entity);
    else
        needsReview.Add(entity); // show these to a reviewer before deciding
}

3. Remove

Turn each approved entity into redaction marks. Detected occurrences are TextRegions, which feed straight into PdfRedactionArea.FromRegion, so each mark hugs the matched glyphs. Adding the value to SearchTerms as well is a safety net that catches any occurrence not resolved to a region.

using LMKit.Document.Pdf;

var request = new PdfRedactionRequest();
foreach (var entity in approved)
{
    foreach (var occurrence in entity.Occurrences)
        request.Areas.AddRange(PdfRedactionArea.FromRegion(occurrence));

    request.SearchTerms.Add(entity.Value);
}

byte[] source = File.ReadAllBytes("account_application.pdf");
PdfRedactionResult result = PdfRedactor.RedactToBytes(source, request);
File.WriteAllBytes("account_application_redacted.pdf", result.Data);

Console.WriteLine($"Removed {result.Report.RemovedGlyphs} glyphs across {result.Report.PagesProcessed} page(s).");

4. Verify

Prove the removal. Re-open the redacted bytes and search for each value: a compliant pipeline records this evidence.

using LMKit.Document.Pdf;

using var redacted = new Attachment(result.Data, "redacted.pdf");
foreach (string value in approved.Select(e => e.Value).Distinct())
{
    int hits = PdfSearch.FindText(redacted, value).TotalMatches;
    Console.WriteLine(hits == 0
        ? $"OK: \"{value}\" is unrecoverable."
        : $"LEAK: \"{value}\" still found {hits} time(s).");
}

Security and Compliance Notes

  • On-device: detection and redaction run locally. Documents never leave your infrastructure, which supports GDPR, HIPAA, and data-residency requirements.
  • True removal: content is deleted from the content streams, image data, and annotations, then the pages are regenerated. Nothing is left in a hidden layer.
  • Human accountability: the review stage keeps the final decision with a person, reducing the risk from a false negative or a model error.
  • Auditable: the PdfRedactionReport records exactly what was removed (glyphs, images, paths, annotations, pages), and the verification step provides evidence that the values are gone.
  • Encrypted sources: pass a password via PdfRedactionOptions.Password; the redacted output is always written unencrypted.

See Also

Share