Azure / Azure/azure-sdk-for-python

[contentunderstanding] Figure crops are unavailable when `contentRange` is used

Open
#48,730 1 comment 2 reactions 0 assignees View on GitHub
Client Cognitive - Content Understanding customer-reported needs-team-triage question
Dominant language
Python
Stars
5.6k
Forks
3.4k
Avg merge
1d 21h
Merged PRs (30d)
193

Description

**Package Name**: azure-ai-contentunderstanding
**Package Version**: 1.1.0 (azure-core 1.41.0)
**Operating System**: Ubuntu 26.04 LTS (Linux 7.0.0-30-generic, x86_64)
**Python Version**: 3.14.4

**Service:** Azure AI Content Understanding (document analysis)
**API versions affected:** `2025-11-01` (GA) and `2026-06-01-preview` — both reproduced
**Client:** reproduced over REST; also via `azure-ai-contentunderstanding` 1.1.0 (Python)
**Region:** Sweden Central
**Analyzer:** custom, `baseAnalyzerId: prebuilt-document`, `returnDetails: true`,
`enableFigureDescription: false`, `enableFigureAnalysis: false`

## Summary

When a document is analyzed with `contentRange`, the analysis result reports figures
with **absolute** page numbers, but the figure-crop endpoint resolves page dimensions
by the page's **position within the analyzed range**. The two disagree, and the crop
cannot be fetched.

Concretely, the crop succeeds only when

```
absolute page number of the figure ≤ number of pages the request analyzed
```

which is always true when the range starts at page 1, and frequently false otherwise.

## What happens

Analyze a 7-page PDF with `contentRange=4-7`. The result is correct and internally
consistent — it uses the document's own page numbers throughout:

* `contents[].pages[].pageNumber` = 4, 5, 6, 7
* the figure on page 5 has `id` = `"5.1"`
* its `source` reads `D(5,…)`

Fetching that figure then fails:

```
GET /contentunderstanding/analyzerResults/{operationId}/files/figures/5.1?api-version=2025-11-01

404 Not Found
{"error":{"code":"NotFound","message":"Resource not found.","innererror":{
"code":"OperationNotFound",
"message":"Page 5 is missing required dimension information.
Unable to crop image 'figureImage-5.1'."}}}
```

The page dimensions are present in the analysis result: `pages[]` for page 5 reports
`width: 8.26`, `height: 11.0`, `unit: inch`.

## Evidence that the id is right and the page exists

**The absolute id is the one the service expects.** Asking for the same figure by its
position within the range returns a different error, so `5.1` is not a wrong id:

```
GET …/files/figures/2.1 → "Figure with ID '2.1' was not found.
Please verify the ID exists in the analysis result."
```

**The service can produce the page image for the same page.** On a request that
analyzed pages 98-197 of a 374-page document, the figure on page 108 cannot be
cropped, yet:

```
GET …/files/pages/108 → 200 OK, 311 744 bytes (PNG)
GET …/files/pages/11 → "Page image for page 11 was not found."
```

So `files/pages/{n}` indexes by absolute page number and works, while
`files/figures/{page}.{n}` fails for the same page in the same result.

## Measured rule

Five requests, two documents, one analyzer. `N` is the number of pages the request
analyzed:

| `contentRange` | `N` | figure pages | crop |
|---|---|---|---|
| `1-4` | 4 | 1 | **works** |
| `1-100` | 100 | 1, 8, 9 | **works** |
| `7-20` | 14 | 8, 9 | **works** |
| `4-7` | 4 | 5 | fails |
| `98-197` | 100 | 108 … 196 (38 figures) | fails, all 38 |

The rule `figure page ≤ N` predicts all five. Note the third row: the range does **not**
start at page 1 and the crops still work, because 8 and 9 are within 14. So the trigger
is the page number exceeding the analyzed page count, not the range offset itself.

## Impact

A document longer than the 300-page per-analysis limit has to be read in ranges. Any
figure whose page number exceeds the length of the range that read it can therefore
never be cropped — and since a range is at most 300 pages, **no figure beyond page 300
of any document can be retrieved at all**.

Measured on a real 374-page publication: of the figures in pages 108-196, none of the
38 could be fetched. The text, the figure elements and the OCR text inside the figures
are all returned correctly; only the cropped images are unreachable.

## Minimal reproduction

1. Any PDF of 7 pages with an embedded raster image on page 5.
2. `POST …/analyzers/{id}:analyzeBinary?api-version=2025-11-01&stringEncoding=codePoint&range=4-7`
with the PDF as `application/pdf`.
3. Poll `…/analyzerResults/{operationId}` to `Succeeded`.
4. Read the figure id from `result.contents[0].figures[0].id` — it is `5.1`.
5. `GET …/analyzerResults/{operationId}/files/figures/5.1` → 404, as above.

Repeating steps 2-5 with `range=1-4` and a figure on page 1 succeeds, on the same
document and the same analyzer.

## Expected behaviour

Every figure returned in an analysis result should be retrievable from
`files/figures/{id}` using the id the result itself reports, whatever `contentRange`
was used.

## Workaround in use

Split the PDF locally and submit each part as its own document, without
`contentRange`. Within a part, no page number can exceed the part's page count, so the
crops are always available — at the cost of translating page numbers, `source`
expressions and figure ids back to the original document.

[example-freight-brief.pdf](https://github.com/user-attachments/files/31427426/example-freight-brief.pdf)

Contributor guide

Open the contributing guide

Research direction

Start with the minimal REST reproduction using contentRange=4-7, then compare the reported figure ID and page number with the files/figures and files/pages endpoints. Done means every figure ID returned in an analysis result can be retrieved regardless of the analyzed range; the payload does not identify a repository file or test to modify.

Written by the indexing model from the issue text.

Assessment

Tech stack
azure, python
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.