Copilot commented on code in PR #3179: URL: https://github.com/apache/tika/pull/3179#discussion_r4019739715
########## tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/extractor/ThumbnailUnpackSelector.java: ########## @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tika.pipes.core.extractor; + +import java.util.Locale; +import java.util.Set; + +import org.apache.tika.annotation.TikaComponent; +import org.apache.tika.config.TransientParseState; +import org.apache.tika.extractor.UnpackSelector; +import org.apache.tika.metadata.HttpHeaders; +import org.apache.tika.metadata.Metadata; +import org.apache.tika.metadata.Rendering; +import org.apache.tika.metadata.TikaCoreProperties; +import org.apache.tika.mime.MediaType; +import org.apache.tika.parser.ParseContext; + +/** + * Unpacks the one embedded document a client would show as the document's thumbnail and + * nothing else. A candidate is a raster image that is a {@code THUMBNAIL} at depth 1 (stored + * thumbnail), a rendered {@code THUMBNAIL} at depth 2 (the rasterized vector thumbnail of an + * Office document; {@code tk:rendering:rendered-by} marks it), or a {@code RENDERING} at + * depth 1 (the first page of a PDF); the first candidate of a parse wins. The thumbnail of a + * document inside an archive is that document's, not the archive's, and is not a candidate. + * Pair it with parser config that renders only those, as the catalog preset {@code thumbnails} + * does; clients reading {@code /rmeta} apply the same rule. + * + * @since Apache Tika 4.1.0 + */ +@TikaComponent +public class ThumbnailUnpackSelector implements UnpackSelector { + + private static final Set<String> VECTOR_TYPES = Set.of("image/emf", "image/x-emf", + "image/wmf", "image/x-wmf", "image/svg+xml"); + + /** Marks a parse whose thumbnail is taken; the selector itself may be shared. */ + private static final class Taken implements TransientParseState { + } + + @Override + public boolean select(Metadata metadata) { + return isCandidate(metadata); + } + + /** The stateless rule; {@code /rmeta} clients pick the first embedded document it accepts. */ + public static boolean isCandidate(Metadata metadata) { + String type = metadata.get(TikaCoreProperties.EMBEDDED_RESOURCE_TYPE); + Integer depth = metadata.getInt(TikaCoreProperties.EMBEDDED_DEPTH); + if (type == null || depth == null || !isRaster(metadata)) { + return false; + } + if (TikaCoreProperties.EmbeddedResourceType.THUMBNAIL.name().equals(type)) { + return depth == 1 + || (depth == 2 && metadata.get(Rendering.RENDERED_BY) != null); + } + return TikaCoreProperties.EmbeddedResourceType.RENDERING.name().equals(type) + && depth == 1; + } + + @Override + public boolean select(Metadata metadata, ParseContext context) { + if (context.get(Taken.class) != null || !isCandidate(metadata)) { + return false; + } + context.set(Taken.class, new Taken()); Review Comment: Because `Taken` is stored in the `ParseContext` and is never cleared, reusing one context for a second top-level parse permanently rejects every later candidate. `ParseContext` is allowed to survive later parses (for example, `CompositeParser` explicitly caches state on reused contexts), so this per-parse overload does not actually reset at a parse boundary; bind the marker to the current parse lifecycle or clear it when the top-level parse starts, and add a reuse test. ########## tika-pipes/tika-pipes-core/src/main/resources/org/apache/tika/pipes/core/presets/thumbnails.json: ########## @@ -0,0 +1,17 @@ +{ + // one raster thumbnail per document, nothing else; the rule is in ThumbnailUnpackSelector + "thumbnail-unpack-selector": {}, Review Comment: This selector only filters bytes when `UnpackExtractor` stores an already-parsed child; it does not stop the embedded parser from traversing later siblings or descendants. Because this preset leaves `EmbeddedLimits` at its unlimited defaults, a large/deep archive can still parse and render its entire tree (including every PDF's first page) before discarding all but one image, which conflicts with the documented bounded/cheap preset behavior. Add explicit embedded depth/count limits that still allow the direct depth-2 vector-thumbnail render, or add an equivalent traversal short-circuit. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
