Skip to content

[Feature]: Option to force grayscale output (contrast-preserving decolorization) #1699

Open

Description

@jbarlow83

Split from #1651.

Allow forcing color input to grayscale on output (drop color).

Archival-safety caveat: a naive luminance conversion (e.g. PIL convert('L')) can collapse distinct colors that share similar luminance, harming contrast and legibility — coloured text, highlights, stamps. Doing this properly needs a contrast-preserving decolorization algorithm (cf. cv2.decolor / Lu et al., "Real-time contrast preserving decolorization") so colours that map to similar gray stay distinguishable.

Constraint: implement this without a heavy dependency — we do not want to pull in something as large as OpenCV just for decolorization. We essentially want cv2.decolor's behaviour from a lightweight implementation (or make it an optional/plugin feature).

Current state: the rasterizer auto-selects the minimum colour depth a page needs but never forces colour→gray.

Activity

  1. ikeago commented on Oct 12, 2026

    @ikeago

    Hi! I’m working on this and have a focused implementation in progress.

    The approach is the discrete linear method from Lu, Xu, and Jia’s “Real-time Contrast Preserving Decolorization”: evaluate the 66 convex RGB weightings (0.1 increments) against a fixed sample of color pairs using the bimodal contrast objective, then apply the selected mapping with Pillow. This adds no dependency.

    I’m exposing it as --force-grayscale / force_grayscale=True. The conversion runs only on the visible rasterized page, after OCR input preparation, so the image sent to the OCR engine and the Tesseract cache remain unchanged. Existing grayscale pixels pass through unchanged, transparency is composited onto white paper, and DPI is preserved.

    I’ll include focused algorithm, option-plumbing, and pipeline-order tests, along with documentation and runtime evidence. Happy to adjust the option name or integration point if you prefer a different public shape.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions