<!-- diataxis: reference -->

# URL format reference

This page documents the Thumbor URL structure generated by `plone.pgthumbor`
and consumed by `zodb-pgjsonb-thumborblobloader`.

## URL structure

Thumbor URLs follow one of two formats depending on whether access control
verification is required.

### 2-segment (anonymous)

Used for publicly accessible images (where `Anonymous` is in the
object's `allowedRolesAndUsers` index).

```
{server_url}/{signature}/{operations}/{zoid_hex}/{tid_hex}
```

Example:

```
http://thumbor:8888/Ab3xY.../300x200/fit-in/smart/2a/ff
```

### 3-Segment (Authenticated)

Used for access-controlled images.
Appends the content object's ZOID so
the Thumbor auth handler can verify Plone permissions before delivery.

```
{server_url}/{signature}/{operations}/{zoid_hex}/{tid_hex}/{content_zoid_hex}
```

Example:

```
http://thumbor:8888/Xk9pQ.../300x200/fit-in/2a/ff/1a
```

When `paranoid_mode` is enabled in the Plone registry, all images use the
3-segment format regardless of their access control settings.

### Unsafe URLs

When `unsafe` mode is enabled (development only), the HMAC signature is
replaced with the literal string `unsafe`:

```
{server_url}/unsafe/{operations}/{zoid_hex}/{tid_hex}
```

## Path Segments

| Segment | Format | Description |
|---|---|---|
| `signature` | HMAC-SHA1 hash or `unsafe` | Cryptographic signature computed by `libthumbor.CryptoURL` using the shared security key. |
| `operations` | Thumbor operations string | Dimensions, fit-in, smart cropping, and filters encoded by libthumbor. |
| `zoid_hex` | Hexadecimal integer | ZODB OID of the `Blob` object (not the content object). Extracted from `NamedBlobImage._blob._p_oid`. |
| `tid_hex` | Hexadecimal integer | ZODB transaction ID (serial) of the blob. Extracted from `NamedBlobImage._blob._p_serial` after activation. |
| `content_zoid_hex` | Hexadecimal integer | ZODB OID of the content object that owns the image. Present only in 3-segment authenticated URLs. |

## HMAC-SHA1 Signing

URLs are signed using `libthumbor.CryptoURL` with the shared
`security_key`.
The signing covers the entire path after the server URL
(operations, image path, and all parameters). Thumbor validates the
signature before processing the request.

The key must match between Plone (`PGTHUMBOR_SECURITY_KEY` or the
`security_key` registry setting) and Thumbor (`SECURITY_KEY` in
`thumbor.conf`).

## Scale Mode Mapping

Plone scale modes are mapped to Thumbor parameters by
`scale_mode_to_thumbor()`:

| Plone Mode | `fit_in` | `smart` | Behavior |
|---|---|---|---|
| `scale` (default) | `True` | per `smart_cropping` setting | Fits image within the requested dimensions without cropping. Aspect ratio is preserved. Smart cropping is applied if enabled. |
| `cover` | `False` | per `smart_cropping` setting | Resizes and crops to fill the exact requested dimensions. Smart cropping selects the crop region when enabled. |
| `contain` | `True` | `False` | Fits image within the requested dimensions. Smart cropping is always disabled. |

The `smart_cropping` column reflects the `smart_cropping` boolean from
the Plone registry (`IThumborSettings`).
When `smart_cropping` is
`False`, the `smart` parameter is `False` for all modes.

## SVG Handling

SVG images (`image/svg+xml`) bypass Thumbor entirely.
The
`ThumborImageScale` detects the content type and falls back to standard
Plone image scaling, which serves SVGs directly without transformation.

## Blob ID Extraction

The `get_blob_ids()` function in `blob.py` extracts `(zoid, tid)` from a
`NamedBlobImage` or `NamedBlobFile` object:

1.
Accesses `named_image._blob` to get the underlying ZODB `Blob`.
2.
Reads `_p_oid` for the blob's OID.
3.
Calls `_p_activate()` to ensure the blob's state is loaded (ghost
   objects have `_p_serial` set to `z64`).
4.
Reads `_p_serial` for the committed transaction ID.
5.
Converts both 8-byte values to integers via `ZODB.utils.u64`.

Returns `None` if the blob is missing, has no OID, or has never been
committed.
