# How BBOX_SCALE Controls Layout Detection and Chunk Parsing in Chandra

> Discover how the BBOX_SCALE setting in Chandra controls layout detection and chunk parsing by defining the OCR model's virtual coordinate grid and impacting pixel coordinate conversion.

- Repository: [Datalab/chandra](https://github.com/datalab-to/chandra)
- Tags: internals
- Published: 2026-03-27

---

**The `BBOX_SCALE` setting defines the resolution of the virtual coordinate grid used by Chandra's OCR model, directly determining how bounding box values in HTML attributes are converted to absolute pixel coordinates during layout analysis.**

Chandra, an open-source document intelligence pipeline maintained by datalab-to, extracts visual structure by prompting language models to generate HTML markup with `data-bbox` attributes. The `BBOX_SCALE` constant defined in [`chandra/settings.py`](https://github.com/datalab-to/chandra/blob/main/chandra/settings.py) establishes the fixed canvas size that bridges the model's normalized output with the actual dimensions of source images.

## The BBOX_SCALE Virtual Coordinate System

In [`chandra/settings.py`](https://github.com/datalab-to/chandra/blob/main/chandra/settings.py) at line 16, `BBOX_SCALE` is set to `1000` by default. This value represents the width and height of the abstract square canvas on which the model draws bounding boxes.

When the model annotates a document, it outputs HTML elements containing `data-bbox` attributes with four integers (x0, y0, x1, y1) representing coordinates within this 1000×1000 grid. Because the model operates on this fixed virtual canvas regardless of the input image size, changing `BBOX_SCALE` directly impacts the granularity of spatial detail the model must predict.

## Converting Scaled Coordinates to Pixel Values

The transformation from model coordinates to image pixels occurs in the `parse_layout` function within [`chandra/output.py`](https://github.com/datalab-to/chandra/blob/main/chandra/output.py) (lines 199-227). This function performs a three-step normalization process using the `BBOX_SCALE` value:

First, it computes per-pixel scalers by dividing the actual image dimensions by the scale factor:

```python
width_scaler = width / bbox_scale
height_scaler = height / bbox_scale

```

Next, it multiplies the four scaled values from `data-bbox` by these scalers to recover absolute pixel positions (lines 221-227):

```python
bbox = [
    max(0, int(bbox[0] * width_scaler)),   # left (x0)

    max(0, int(bbox[1] * height_scaler)), # top (y0)

    min(int(bbox[2] * width_scaler), width),   # right (x1)

    min(int(bbox[3] * height_scaler), height)  # bottom (y1)

]

```

Finally, the function clamps these values to the image bounds to prevent overflow.

## Impact on Layout Detection Granularity

The choice of `BBOX_SCALE` creates a direct trade-off between coordinate precision and model complexity:

- **Larger values** (e.g., 2000) produce smaller per-pixel scalers, allowing the model to specify finer spatial details with higher precision
- **Smaller values** (e.g., 500) create coarser granularity that may be easier for the model to predict but result in less precise bounding boxes

According to the source code in [`chandra/output.py`](https://github.com/datalab-to/chandra/blob/main/chandra/output.py), the `width / bbox_scale` and `height / bbox_scale` calculations ensure that regardless of the scale setting, the final pixel coordinates remain accurate relative to the original image dimensions.

## Propagation Through Chunk Parsing

The `parse_chunks` function in [`chandra/output.py`](https://github.com/datalab-to/chandra/blob/main/chandra/output.py) (lines 42-45) acts as a thin wrapper around `parse_layout`, ensuring the same `BBOX_SCALE` value propagates through the entire pipeline:

```python
def parse_chunks(html: str, image: Image.Image, bbox_scale=settings.BBOX_SCALE):
    layout = parse_layout(html, image, bbox_scale=bbox_scale)
    chunks = [asdict(block) for block in layout]
    return chunks

```

This guarantees that bounding boxes embedded in the final JSON chunks correspond exactly to the pixel coordinates of the source image, maintaining consistency between layout detection and downstream chunk consumption. The setting is also passed to the model backends in [`chandra/model/vllm.py`](https://github.com/datalab-to/chandra/blob/main/chandra/model/vllm.py) and [`chandra/model/hf.py`](https://github.com/datalab-to/chandra/blob/main/chandra/model/hf.py) to ensure the language model generates coordinates in the correct scale.

## Implementation Examples

### Inspecting the Current Scale

To verify the active configuration:

```python
from chandra import settings

print("Current BBOX_SCALE:", settings.BBOX_SCALE)  # Output: 1000

```

### Manual Parsing with Custom Scale

Override the default scale when processing specific images:

```python
from chandra.output import parse_chunks
from PIL import Image

img = Image.open("document.png")
html = "<div data-label='Header' data-bbox='0 0 1000 200'>Content</div>"

# Use a finer 2000-grid for higher precision

chunks = parse_chunks(html, img, bbox_scale=2000)
print(chunks[0]["bbox"])  # Pixel coordinates scaled appropriately

```

### API Integration

When using the high-level API, the system respects `settings.BBOX_SCALE` automatically:

```python
from chandra.scripts.run_app import run_ocr_on_image

result = run_ocr_on_image("invoice.pdf")
print(result["chunks"][0]["bbox"])  # Accurate pixel coordinates

```

## Summary

- **BBOX_SCALE** in [`chandra/settings.py`](https://github.com/datalab-to/chandra/blob/main/chandra/settings.py) defines the virtual 1000×1000 coordinate grid used by the OCR model
- **parse_layout** in [`chandra/output.py`](https://github.com/datalab-to/chandra/blob/main/chandra/output.py) converts scaled `data-bbox` values to pixels using `width / BBOX_SCALE` and `height / BBOX_SCALE` calculations at lines 199-227
- **parse_chunks** propagates the same scale setting through to JSON output to ensure coordinate accuracy
- The model backends in [`chandra/model/vllm.py`](https://github.com/datalab-to/chandra/blob/main/chandra/model/vllm.py) and [`chandra/model/hf.py`](https://github.com/datalab-to/chandra/blob/main/chandra/model/hf.py) receive this setting to maintain consistent output formatting
- Changing the scale requires coordinated updates to the model prompt or fine-tuning, as the conversion logic automatically adapts to the configured value

## Frequently Asked Questions

### What is the default BBOX_SCALE value in Chandra?

The default value is `1000`, defined in [`chandra/settings.py`](https://github.com/datalab-to/chandra/blob/main/chandra/settings.py) at line 16. This creates a 1000×1000 virtual canvas for the model to specify bounding box coordinates.

### How does increasing BBOX_SCALE improve layout detection?

Larger values reduce the per-pixel scaler (width/scale), meaning each integer increment in the model's output represents a smaller physical distance in the source image. This allows the model to define tighter, more precise bounding boxes around document elements.

### Where does the coordinate conversion happen in the codebase?

The conversion from scaled to pixel coordinates occurs in the `parse_layout` function within [`chandra/output.py`](https://github.com/datalab-to/chandra/blob/main/chandra/output.py) (lines 199-227), which computes scalers and transforms the four `data-bbox` integers into absolute pixel positions.

### Can I use different BBOX_SCALE values for different documents?

Yes. While `settings.BBOX_SCALE` provides the global default, you can pass a custom `bbox_scale` parameter directly to `parse_layout` or `parse_chunks` for individual processing calls, as shown in the implementation examples above.