Skip to content

TIKA-4856: /unpack/thumbnail returns the document thumbnail with its metadata - #3096

Open
dschmidt wants to merge 14 commits into
apache:mainfrom
dschmidt:unpack-thumbnail
Open

TIKA-4856: /unpack/thumbnail returns the document thumbnail with its metadata#3096
dschmidt wants to merge 14 commits into
apache:mainfrom
dschmidt:unpack-thumbnail

Conversation

@dschmidt

@dschmidt dschmidt commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Proof of concept for TIKA-4856, restructured after the discussion in the ticket. The core is the thumbnail defaults and the switch that applies them to the existing endpoints; that is what a client needs to get a document's thumbnail without knowing parser component names. The /unpack/thumbnail endpoint is a convenience on top and can be dropped or reshaped without losing the rest. The shape of the switch (query parameter) and of the config block (top-level key) are open to change.

Why

The thumbnail of a document is one of its embedded documents, typed THUMBNAIL, and /rmeta lists it already. Where a raster image only exists after rendering (the first page of a PDF, the EMF/WMF thumbnail of an Office document), a request needs a parse context that knows the component names, and that context should be the same for every caller.

Thumbnail defaults

ThumbnailDefaults (tika-server-core) holds that context in one place: first PDF page rendered at 96 dpi (maxRenderedPages: 1, so the text is still extracted from the whole document), EMF/WMF thumbnail rendered (that one only, renderOnlyEmbeddedResourceTypes: ["THUMBNAIL"] from #3095).

Three layers, each overriding the one before: built-in defaults, a thumbnail-defaults block in the server config (same shape as a request config), the request's own config part. The defaults are plain JSON parser configurations set with ParseContext.setJsonConfig, so a parser that is not installed never reads them.

?renderThumbnails=true

On /rmeta, /unpack, /unpack/all and /unpack/thumbnail: lays the defaults under the request. Without it a parse is the cheap extraction of stored thumbnails; rendering is opt-in, with the same switch everywhere. The index request of a search service becomes /rmeta/text?renderThumbnails=true: metadata, text, and the thumbnail with its dimensions in one parse.

/unpack/thumbnail (optional)

What only makes sense when the thumbnail is all the caller wants (no text extraction, no OCR, only THUMBNAIL and RENDERING extracted, image capped at 32 MiB), plus the defaults when renderThumbnails=true; a PDF without the switch answers 204. ThumbnailSelector picks the raster THUMBNAIL below the document, the rendering below a vector THUMBNAIL, or the first page RENDERING, and answers as JSON:

{
  "metadata": { "Content-Type": "image/png", "tiff:ImageWidth": "800", "tk:embedded-resource-type": "RENDERING", ... },
  "image": "iVBORw0KGgo..."
}

PDFParserConfig.maxRenderedPages

Bounds the page rendering of both rendering strategies independently of maxPages; without it /rmeta could only render the first page by also cutting the text after it.

Verified

Against a server built from main plus the open thumbnail PRs: docx, xlsx, doc, xls, ppt, pptx, odt, epub, GeoGebra, Pages, Numbers, Keynote, mp3, m4a, flac, ogg, pdf, nef and pef answer with the right image; a zip, a plain jpeg and a doc without a thumbnail answer 204. Raw camera files no longer need their file name since #3099.

Open points

https://issues.apache.org/jira/browse/TIKA-4856

… metadata

Parses in unpack mode with a fixed configuration (the first PDF page and
EMF/WMF images rendered, THUMBNAIL and RENDERING embedded documents
extracted with their metadata), then picks the raster THUMBNAIL directly
below the document, the rendering of a vector THUMBNAIL, or the RENDERING
of the first page, and answers with JSON: the embedded document's metadata
and the image as base64. 204 when the document has no thumbnail.
@dschmidt
dschmidt marked this pull request as ready for review August 29, 2026 16:45
@dschmidt
dschmidt marked this pull request as draft August 29, 2026 18:51
@dschmidt
dschmidt marked this pull request as ready for review August 29, 2026 18:53
@dschmidt
dschmidt marked this pull request as draft August 29, 2026 19:14
@dschmidt

Copy link
Copy Markdown
Contributor Author

Remarked it as draft as I'm wondering if we need a better concept

…unpack, thumbnail-defaults in the server config, PDF maxRenderedPages
# Conflicts:
#	CHANGES.txt
@dschmidt
dschmidt marked this pull request as ready for review August 29, 2026 20:19
@THausherr
THausherr requested a lite review from Copilot August 29, 2026 20:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class thumbnail support to Tika Server by centralizing “thumbnail defaults” (PDF first-page rendering + EMF/WMF thumbnail rendering) and exposing them via query flags and a new convenience endpoint, while also introducing a PDF parser limit to bound rendering without limiting text extraction.

Changes:

  • Introduces ThumbnailDefaults and ThumbnailSelector, enabling consistent server-side thumbnail rendering/selection behavior.
  • Adds ?renderThumbnails=true to /rmeta, /unpack, and /unpack/all, plus a new /unpack/thumbnail endpoint returning {metadata, image(base64)}.
  • Adds PDFParserConfig.maxRenderedPages and enforces it in both PDF rendering paths, with new tests.

Reviewed changes

Copilot reviewed 15 out of 17 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tika-server/tika-server-standard/src/test/java/org/apache/tika/server/standard/UnpackerThumbnailTest.java End-to-end tests for /unpack/thumbnail and /rmeta?renderThumbnails=true.
tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/resource/ThumbnailSelectorTest.java Unit tests for thumbnail selection precedence rules.
tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/resource/ThumbnailDefaultsTest.java Unit tests for built-in defaults, config overrides, and merge behavior.
tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/UnpackerResource.java Adds /unpack/thumbnail and renderThumbnails query param support for unpack endpoints.
tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaResource.java Wires ThumbnailDefaults from server config and exposes them to resources.
tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/ThumbnailSelector.java Implements thumbnail selection logic among embedded docs (thumbnail vs rendering fallback).
tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/ThumbnailDefaults.java Defines built-in thumbnail parser JSON defaults + config override/merge/application logic.
tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/RecursiveMetadataResource.java Adds renderThumbnails query param to /rmeta endpoints and applies defaults.
tika-serialization/src/main/java/org/apache/tika/config/loader/TikaJsonConfig.java Adds thumbnail-defaults as a known top-level JSON config key.
tika-parsers/.../src/test/java/org/apache/tika/parser/pdf/PDFMaxRenderedPagesTest.java Tests for maxRenderedPages behavior and JSON config support.
tika-parsers/.../src/main/java/org/apache/tika/parser/pdf/PDFParserConfig.java Adds maxRenderedPages with validation and accessor methods.
tika-parsers/.../src/main/java/org/apache/tika/parser/pdf/PDFParser.java Uses maxRenderedPages to bound rendered page range for PDF rendering.
tika-parsers/.../src/main/java/org/apache/tika/parser/pdf/PDF2XHTML.java Skips per-page rendering after maxRenderedPages for page-end rendering strategy.
docs/modules/ROOT/pages/using-tika/server/index.adoc Documents thumbnail behavior, query flag, endpoint, and config override block.
CHANGES.txt Adds release notes for the new thumbnail capabilities and maxRenderedPages.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +357 to +360
byte[] image;
try (InputStream is = zip.getInputStream(imageEntry)) {
image = is.readAllBytes();
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bounded now: the image is capped at 32 MiB (entry size checked, then read one byte past the limit so a wrong size claim cannot slip through), 413 beyond that. Camera previews and page renderings are a few MB at most, so the constant is generous.

@dschmidt

Copy link
Copy Markdown
Contributor Author

Mh, maybe the /thumbnail endpoint should have the renderThumbnails param as well. So we can still opt in to rendering while using the selection logic anyhow. So it's a simple consistent switch for pure extraction or more expensive rendering

@dschmidt

Copy link
Copy Markdown
Contributor Author

Done: /unpack/thumbnail takes renderThumbnails as well. Without it a request is the cheap extraction of stored thumbnails, rendering is opt-in with the same switch everywhere.

# Conflicts:
#	CHANGES.txt

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 17 changed files in this pull request and generated 2 comments.

Comment on lines +184 to +187
/**
* Sends the file name along, as a client would: raw camera formats are
* detected by their extension.
*/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, the comment predates TIKA-4861.

Comment on lines +389 to +405

/**
* What only makes sense when the thumbnail is all the caller wants: no
* text, no OCR, only THUMBNAIL and RENDERING embedded documents extracted,
* together with their metadata, down to the rendering of a thumbnail
* (depth 2). With {@code renderThumbnails} the {@link ThumbnailDefaults}
* are laid under that, the same switch as on the other endpoints; without
* it only stored thumbnails are found. The request's own parser
* configuration wins where present.
*/
private void configureThumbnailParse(ParseContext pc, boolean renderThumbnails) {
//the text is not part of the answer: do not extract it
tikaResource.setupContentHandlerFactory(pc, "ignore");
ThumbnailDefaults noOcr = ThumbnailDefaults.none()
.with("{\"pdf-parser\": {\"ocr\": {\"strategy\": \"NO_OCR\"}}, "
+ "\"tesseract-ocr-parser\": {\"skipOcr\": true}}");
(renderThumbnails ? tikaResource.getThumbnailDefaults().with(noOcr) : noOcr).applyTo(pc);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made it a constant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants