Published 2026 | Version v1
Other Open

DocQT

  • 1. ROR icon Laboratoire Informatique, Image et Interaction (L3i)

Description

DocQT - Improving Document Forgery Localization Robustness via Diverse JPEG Quantization-Tables

 
Repository containing JPEG quantization tables used for the Real-QT protocol.
Dataset name: DocQT.
Only header-extracted quantization matrices are provided.
 

Paper

 
- arXiv: https://arxiv.org/abs/2605.19688
 

Hugging Face Dataset

 
- Dataset on Hugging Face Hub: https://huggingface.co/datasets/Kyliroco/DocQT
 

Citation

 
If you use DocQT, this quantization-table repository, or build upon our article, please cite our paper:
 
@misc{ronfleuxcorail2026docqt,
title={DocQT: Improving Document Forgery Localization Robustness via Diverse JPEG Quantization Tables},
author={Kylian Ronfleux-Corail and Guillaume Bernard and Mickael Coustaty and Nicolas Sidere},
year={2026},
eprint={2605.19688},
archivePrefix={arXiv},
primaryClass={cs.CV},
doi={10.48550/arXiv.2605.19688},
url={https://arxiv.org/abs/2605.19688}
}

Available quantization tables

 
- Luminance tables: `quantification_luminance.json`
  - Number of tables: 859
- Chrominance tables: `quantification_chrominance.json`
  - Number of tables: 294
 

## File format

 
Both files are stored in JSON for better portability and long-term compatibility.
 
- Root object: a list of quantization tables
- One table: a flat list of 64 integers
- Table values: integers
 
In other words, each file follows this structure:
 
- list[table]
- table = list[64 integer values]
 

## Example: load DocQT from Hugging Face Hub

 
from datasets import load_dataset

def load_docqt_from_hub() -> tuple[list[list[int]], list[list[int]]]:
  dataset = load_dataset("Kyliroco/DocQT")

  luminance_split = dataset["luminance"]
  chrominance_split = dataset["chrominance"]

  # The 64-value quantization tables are stored in the "text" column.
  luminance_tables = luminance_split["text"]
  chrominance_tables = chrominance_split["text"]

  return luminance_tables, chrominance_tables

luminance_tables, chrominance_tables = load_docqt_from_hub()
 
 
Each selected table must be a flat list of 64 integer values before passing
it to Pillow through `qtables`.
 

Example: use quantization tables with Pillow JPEG compression

 
 
import json
from pathlib import Path
from PIL import Image

def load_quantization_tables(base_dir: str = ".") -> tuple[list, list]:
  base_path = Path(base_dir)

  luminance_tables = json.loads(
  (base_path / "quantification_luminance.json").read_text(encoding="utf-8")
  )
  chrominance_tables = json.loads(
  (base_path / "quantification_chrominance.json").read_text(encoding="utf-8")
  )

  return luminance_tables, chrominance_tables

luminance_tables, chrominance_tables = load_quantization_tables(".")
 
Choose the table indices you want to use for compression.
luma_idx = 0
chroma_idx = 0


luma_qtable = luminance_tables[luma_idx]
chroma_qtable = chrominance_tables[chroma_idx]


with Image.open("input.png") as image:
  image = image.convert("RGB")
  image.save(
  "output_custom_qtables.jpg",
  format="JPEG",
  qtables=[luma_qtable, chroma_qtable],
  subsampling="4:2:0",
  optimize=True,
  )
Note: avoid passing a quality value if you want to keep your custom qtables as-is.
 

 

Files

quantification_chrominance.json

Files (235.6 kB)

Name Size Download all
md5:c8451b30f62d74e2110f164c1787c3a9
52.9 kB Preview Download
md5:c1db3dbe4b3f1fc1e24439ad44842675
182.6 kB Preview Download

Additional details