Skip to content

Commit 363378f

Browse files
authored
TIKA-4749 - improve inline handling of metadata only (#2866)
1 parent 681f9e8 commit 363378f

4 files changed

Lines changed: 78 additions & 9 deletions

File tree

tika-core/src/main/java/org/apache/tika/parser/AutoDetectParser.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ public void parse(TikaInputStream tis, ContentHandler handler, Metadata metadata
160160
// don't leak into CONTENT_TYPE
161161
metadata.set(Metadata.CONTENT_TYPE,
162162
EmbeddedDocumentUtil.normalizeMediaType(type.toString()));
163+
// Metadata-only pseudo-parse: register the entry, skip the content parse.
164+
if (context.get(MetadataOnlyParse.class) != null) {
165+
return;
166+
}
163167
//check for zero-byte inputstream
164168
if (tis.getOpenContainer() == null) {
165169
if (autoDetectParserConfig.getThrowOnZeroBytes()) {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.tika.parser;
18+
19+
/**
20+
* ParseContext marker telling {@link AutoDetectParser} to register the embedded
21+
* entry but skip the content parse. Set by metadata-only passes that pseudo-parse
22+
* a placeholder stream only to register an entry. Independent of throwOnZeroBytes.
23+
*/
24+
public final class MetadataOnlyParse {
25+
26+
/**
27+
* Singleton instance indicating the current parse should not dispatch to a
28+
* content parser.
29+
*/
30+
public static final MetadataOnlyParse INSTANCE = new MetadataOnlyParse();
31+
32+
private MetadataOnlyParse() {
33+
// Private constructor for singleton
34+
}
35+
}

tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/parser/pdf/image/ImageGraphicsEngine.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@
5757

5858
import org.apache.tika.exception.TikaException;
5959
import org.apache.tika.exception.TikaMemoryLimitException;
60-
import org.apache.tika.exception.ZeroByteFileException;
6160
import org.apache.tika.extractor.EmbeddedDocumentExtractor;
6261
import org.apache.tika.extractor.EmbeddedDocumentUtil;
6362
import org.apache.tika.io.BoundedInputStream;
6463
import org.apache.tika.io.TikaInputStream;
6564
import org.apache.tika.metadata.Metadata;
6665
import org.apache.tika.metadata.TikaCoreProperties;
6766
import org.apache.tika.metadata.TikaPagedText;
67+
import org.apache.tika.parser.MetadataOnlyParse;
6868
import org.apache.tika.parser.ParseContext;
6969
import org.apache.tika.parser.pdf.PDFParserConfig;
7070
import org.apache.tika.parser.pdf.PDMetadataExtractor;
@@ -448,16 +448,14 @@ protected void extractInlineImageMetadataOnly(PDImage pdImage, Metadata metadata
448448
metadata.set(Metadata.IMAGE_WIDTH, pdImage.getWidth());
449449
metadata.set(Metadata.IMAGE_LENGTH, pdImage.getHeight());
450450
//TODO: what else can we extract from the PDImage without rendering?
451-
ZeroByteFileException.IgnoreZeroByteFileException before =
452-
parseContext.get(ZeroByteFileException.IgnoreZeroByteFileException.class);
451+
//Register the image's metadata entry without decoding it (marker skips the parse).
453452
try (TikaInputStream tis = TikaInputStream.get(new byte[0])) {
454-
parseContext.set(ZeroByteFileException.IgnoreZeroByteFileException.class,
455-
ZeroByteFileException.IGNORE_ZERO_BYTE_FILE_EXCEPTION);
453+
parseContext.set(MetadataOnlyParse.class, MetadataOnlyParse.INSTANCE);
456454
embeddedDocumentExtractor.parseEmbedded(tis,
457455
new EmbeddedContentHandler(xhtml), metadata, parseContext, false);
458456
} finally {
459-
//replace whatever was there before
460-
parseContext.set(ZeroByteFileException.IgnoreZeroByteFileException.class, before);
457+
//clear so it can't leak to the next image
458+
parseContext.set(MetadataOnlyParse.class, null);
461459
}
462460
}
463461

tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/test/java/org/apache/tika/parser/pdf/PDFParserTest.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
import org.apache.tika.config.loader.TikaLoader;
4848
import org.apache.tika.exception.AccessPermissionException;
4949
import org.apache.tika.exception.EncryptedDocumentException;
50-
import org.apache.tika.exception.ZeroByteFileException;
5150
import org.apache.tika.extractor.DocumentSelector;
5251
import org.apache.tika.io.TikaInputStream;
5352
import org.apache.tika.metadata.Font;
@@ -62,7 +61,9 @@
6261
import org.apache.tika.metadata.XMPPDF;
6362
import org.apache.tika.mime.MediaType;
6463
import org.apache.tika.parser.AutoDetectParser;
64+
import org.apache.tika.parser.AutoDetectParserConfig;
6565
import org.apache.tika.parser.CompositeParser;
66+
import org.apache.tika.parser.MetadataOnlyParse;
6667
import org.apache.tika.parser.ParseContext;
6768
import org.apache.tika.parser.Parser;
6869
import org.apache.tika.parser.PasswordProvider;
@@ -1358,7 +1359,7 @@ public void testExtractInlineImageMetadata() throws Exception {
13581359
config.setExtractInlineImageMetadataOnly(true);
13591360
context.set(PDFParserConfig.class, config);
13601361
List<Metadata> metadataList = getRecursiveMetadata("testOCR.pdf", context);
1361-
assertNull(context.get(ZeroByteFileException.IgnoreZeroByteFileException.class));
1362+
assertNull(context.get(MetadataOnlyParse.class));
13621363
assertEquals(2, metadataList.size());
13631364
assertEquals("image/png", metadataList.get(1).get(Metadata.CONTENT_TYPE));
13641365
assertEquals("/image-0.png",
@@ -1368,6 +1369,37 @@ public void testExtractInlineImageMetadata() throws Exception {
13681369
assertEquals("image-0.png", metadataList.get(1).get(TikaCoreProperties.RESOURCE_NAME_KEY));
13691370
}
13701371

1372+
@Test
1373+
public void testExtractInlineImageMetadataThrowOnZeroBytesFalse() throws Exception {
1374+
//TIKA-4749: in metadata-only mode the inline image is registered via a
1375+
//placeholder pseudo-parse. With throwOnZeroBytes=false that placeholder used
1376+
//to be handed to a real parser (image/OCR), recording a spurious embedded
1377+
//exception. The MetadataOnlyParse marker must make it skip the parse instead.
1378+
ParseContext context = new ParseContext();
1379+
PDFParserConfig config = new PDFParserConfig();
1380+
config.setExtractInlineImageMetadataOnly(true);
1381+
context.set(PDFParserConfig.class, config);
1382+
1383+
AutoDetectParser p = new AutoDetectParser();
1384+
AutoDetectParserConfig adpc = new AutoDetectParserConfig();
1385+
adpc.setThrowOnZeroBytes(false);
1386+
p.setAutoDetectParserConfig(adpc);
1387+
1388+
List<Metadata> metadataList =
1389+
getRecursiveMetadata("testOCR.pdf", p, new Metadata(), context, false);
1390+
assertNull(context.get(MetadataOnlyParse.class));
1391+
assertEquals(2, metadataList.size());
1392+
Metadata image = metadataList.get(1);
1393+
assertEquals("image/png", image.get(Metadata.CONTENT_TYPE));
1394+
assertEquals(261, (int) image.getInt(Metadata.IMAGE_LENGTH));
1395+
assertEquals(934, (int) image.getInt(Metadata.IMAGE_WIDTH));
1396+
//the placeholder must not be dispatched to any content parser. Without the
1397+
//fix it is (EmptyParser here; ImageParser+TesseractOCRParser when tesseract
1398+
//is installed, which is what records the spurious embedded exception).
1399+
assertEquals(0, image.getValues(TikaCoreProperties.TIKA_PARSED_BY).length);
1400+
assertNull(image.get(TikaCoreProperties.EMBEDDED_EXCEPTION));
1401+
}
1402+
13711403
/**
13721404
* Simple class to count end of document events. If functionality is useful,
13731405
* move to org.apache.tika in src/test

0 commit comments

Comments
 (0)