Azure / Azure/azure-sdk-for-python
[contentunderstanding] Figure crops are unavailable when `contentRange` is used
- 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
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