JPEG DCT Scrubbing¶
The dicom_dre.jpeg_dct_scrubber module blanks rectangular regions in JPEG
Baseline images by zeroing DCT coefficients directly in the compressed
bitstream. The module performs no full decompression or recompression, so
non-blanked regions stay bit-for-bit identical with no quality loss.
Note
This module implements the JPEG Baseline path of the pixel-scrub stage. For how it fits into the end-to-end de-identification pipeline, see Architecture.
Background¶
The DCT-domain redaction approach comes from the PixelMed DICOM Toolkit. PixelMed demonstrated removing burned-in text from JPEG-compressed DICOM images by operating on the Huffman-coded DCT coefficients, without decoding and re-encoding pixel data. This module is a Python port of the PixelMed JPEG Selective Block Redaction Codec by David A. Clunie, with an optional C accelerator. The module source reproduces the PixelMed BSD license at the top.
Supported format¶
Only JPEG Baseline (SOF0) is supported:
8-bit sample precision
Huffman-coded entropy coding
Sequential DCT
The module rejects progressive JPEG, arithmetic coding, and extended JPEG
processes with a ValueError.
How it works¶
The module parses the JPEG bytestream marker by marker (SOI, SOF0, DHT, DQT, DRI, SOS, EOI).
It builds decode and encode lookup structures from the Huffman tables in the DHT segments.
It decodes the entropy-coded segment after each SOS marker MCU by MCU. For each 8x8 DCT block, it checks whether the block overlaps any of the specified blanking regions.
For a block that overlaps a blanking region, the module sets the DC coefficient to zero and replaces all 63 AC coefficients with an EOB (end-of-block) marker. This produces a uniform mid-gray patch in the output.
The module passes blocks outside blanking regions through with their original coefficients. Two separate DC prediction chains (one for the input stream, one for the output stream) ensure that modifying one block does not corrupt the DC values of later blocks.
The module handles restart markers (DRI/RST) by resetting both prediction chains at each restart interval boundary.
C accelerator¶
The pure-Python entropy codec processes one bit at a time through Python method
calls (BitReader, BitWriter, HuffmanTable). This is correct but slow. A
single DICOM study can contain hundreds of JPEG frames that each need
DCT-domain blanking.
The C extension _jpeg_dct_accel reimplements _process_entropy_segment in C
via CFFI, yielding approximately 300x speedup over the Python fallback.
When the C extension is not available, the module emits a warning and falls back to the Python implementation.
To compile the extension locally:
just build-ext
This runs uv run python -m dicom_dre._jpeg_dct_accel_build and writes the
compiled _jpeg_dct_accel*.so next to the module.
API¶
scrub_jpeg(input_path, output_path, regions)¶
Read a JPEG file from input_path, blank the specified regions, and write the
result to output_path.
Name |
Type |
Description |
|---|---|---|
|
|
Path to the input JPEG file |
|
|
Path to write the scrubbed JPEG file |
|
|
Rectangles to blank as |
scrub_jpeg_bytes(data, regions)¶
Scrub JPEG data in memory and return the modified bytes.
Name |
Type |
Description |
|---|---|---|
|
|
Raw JPEG data |
|
|
Rectangles to blank as |
Returns: bytes, the modified JPEG data.
Command-line usage¶
Run the module directly for testing:
python -m dicom_dre.jpeg_dct_scrubber input.jpg output.jpg 10,5,200,50 300,400,100,30
Each region argument is a comma-separated x,y,width,height rectangle.