[
https://issues.apache.org/jira/browse/TIKA-4855?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18109771#comment-18109771
]
ASF GitHub Bot commented on TIKA-4855:
--------------------------------------
dschmidt commented on code in PR #3095:
URL: https://github.com/apache/tika/pull/3095#discussion_r3892318747
##########
tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/WMFParser.java:
##########
@@ -32,25 +32,56 @@
import org.xml.sax.SAXException;
import org.apache.tika.annotation.TikaComponent;
+import org.apache.tika.config.ConfigDeserializer;
+import org.apache.tika.config.JsonConfig;
+import org.apache.tika.config.ParseContextConfig;
import org.apache.tika.exception.TikaException;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.TikaCoreProperties;
import org.apache.tika.mime.MediaType;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
+import org.apache.tika.parser.RenderingParser;
+import org.apache.tika.renderer.Renderer;
import org.apache.tika.sax.XHTMLContentHandler;
/**
* This parser offers a very rough capability to extract text if there
* is text stored in the WMF files.
*/
Review Comment:
Merged into one.
##########
tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/MetafileRendering.java:
##########
@@ -0,0 +1,135 @@
+/*
+ * 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.parser.microsoft;
+
+import java.io.IOException;
+
+import org.xml.sax.SAXException;
+
+import org.apache.tika.exception.TikaException;
+import org.apache.tika.extractor.EmbeddedDocumentExtractor;
+import org.apache.tika.extractor.EmbeddedDocumentUtil;
+import org.apache.tika.io.TikaInputStream;
+import org.apache.tika.metadata.HttpHeaders;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.TikaCoreProperties;
+import org.apache.tika.mime.MediaType;
+import org.apache.tika.parser.ParseContext;
+import org.apache.tika.renderer.RenderResult;
+import org.apache.tika.renderer.RenderResults;
+import org.apache.tika.renderer.Renderer;
+import org.apache.tika.renderer.microsoft.POIMetafileRenderer;
+import org.apache.tika.sax.EmbeddedContentHandler;
+import org.apache.tika.sax.XHTMLContentHandler;
+
+/**
+ * Shared by {@link EMFParser} and {@link WMFParser}: renders a parsed
+ * metafile through a {@link Renderer} and emits the result as an embedded
+ * document, the way the PDF parser emits page renderings. The rendering of
+ * a {@link TikaCoreProperties.EmbeddedResourceType#THUMBNAIL} is itself a
+ * THUMBNAIL (it is the same picture in a form a client can display); any
+ * other rendering is a {@link
TikaCoreProperties.EmbeddedResourceType#RENDERING}.
+ */
+final class MetafileRendering {
+
+ private MetafileRendering() {
+ }
+
+ /**
+ * @param injected the renderer set on the parser, or null
+ * @param picture the parsed {@code HemfPicture} or {@code HwmfPicture}
+ */
+ static void render(Renderer injected, MetafileParserConfig config,
MediaType type,
+ Object picture, XHTMLContentHandler xhtml, Metadata
metadata,
+ ParseContext context) throws IOException, SAXException {
+ //like the PDF parser: the injected renderer if it handles the type,
+ //the default one otherwise
+ Renderer renderer = injected != null &&
injected.getSupportedTypes(context).contains(type)
+ ? injected : defaultRenderer(config);
+ Metadata renderMetadata = Metadata.newInstance(context);
+ renderMetadata.set(TikaCoreProperties.TYPE, type.toString());
+ EmbeddedDocumentExtractor extractor =
+ EmbeddedDocumentUtil.getEmbeddedDocumentExtractor(context);
+ try (TikaInputStream pictureStream = TikaInputStream.get(new byte[0]);
+ RenderResults results = render(renderer, pictureStream, picture,
renderMetadata,
+ context)) {
+ if (results == null) {
+ return;
+ }
Review Comment:
It is recorded on the metafile's metadata now.
##########
tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/renderer/microsoft/POIMetafileRenderer.java:
##########
@@ -0,0 +1,259 @@
+/*
+ * 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.renderer.microsoft;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.Dimension2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import javax.imageio.ImageIO;
+
+import org.apache.poi.hemf.usermodel.HemfPicture;
+import org.apache.poi.hwmf.record.HwmfFill;
+import org.apache.poi.hwmf.record.HwmfRecord;
+import org.apache.poi.hwmf.usermodel.HwmfPicture;
+
+import org.apache.tika.annotation.TikaComponent;
+import org.apache.tika.exception.TikaException;
+import org.apache.tika.io.TemporaryResources;
+import org.apache.tika.io.TikaInputStream;
+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;
+import org.apache.tika.renderer.RenderRequest;
+import org.apache.tika.renderer.RenderResult;
+import org.apache.tika.renderer.RenderResults;
+import org.apache.tika.renderer.Renderer;
+import org.apache.tika.renderer.RenderingTracker;
+
+/**
+ * Renders EMF and WMF images to a raster image through POI's HEMF and HWMF,
+ * the way {@code PDFBoxRenderer} renders PDF pages. The rendering has the
+ * configured width, its height follows the image's aspect ratio, and it is
+ * drawn on a white canvas. Metafiles have no pages, so the render requests
+ * are ignored and a single result is returned.
+ * <p>
+ * The WMF thumbnails that Word stores in the SummaryInformation of a .doc
+ * consist of a window extent and a single {@code dibStretchBlt} record, for
+ * which POI cannot compute bounds; those are rendered from the record's
+ * bitmap directly.
+ */
+@TikaComponent(name = "poi-metafile-renderer")
+public class POIMetafileRenderer implements Renderer {
+
+ public static final String RENDERED_BY = "poi-metafile-renderer";
+
+ public static final MediaType EMF = MediaType.image("emf");
+ public static final MediaType WMF = MediaType.image("wmf");
+
+ private static final Set<MediaType> SUPPORTED_TYPES =
+ Collections.unmodifiableSet(new HashSet<>(Arrays.asList(EMF,
WMF)));
+
+ private static final int MAX_WIDTH = 10000;
+
+ private int width = 800;
+ private String imageFormatName = "png";
+
+ @Override
+ public Set<MediaType> getSupportedTypes(ParseContext context) {
+ return SUPPORTED_TYPES;
+ }
+
+ /**
+ * Renders the metafile in the stream, or the {@link HemfPicture} or
+ * {@link HwmfPicture} set as the stream's open container. The metadata's
+ * {@link TikaCoreProperties#TYPE} tells EMF from WMF when a stream is
+ * parsed; it defaults to EMF.
+ */
+ @Override
+ public RenderResults render(TikaInputStream tis, Metadata metadata,
ParseContext parseContext,
+ RenderRequest... requests) throws IOException,
TikaException {
+ Object picture = tis.getOpenContainer();
+ if (!(picture instanceof HemfPicture) && !(picture instanceof
HwmfPicture)) {
+ picture =
WMF.toString().equals(metadata.get(TikaCoreProperties.TYPE))
+ ? new HwmfPicture(tis) : new HemfPicture(tis);
+ }
+ RenderingTracker tracker = parseContext.get(RenderingTracker.class);
+ if (tracker == null) {
+ tracker = new RenderingTracker();
+ parseContext.set(RenderingTracker.class, tracker);
+ }
+ int id = tracker.getNextId();
+ Metadata renderingMetadata = Metadata.newInstance(parseContext);
+ renderingMetadata.set(TikaCoreProperties.EMBEDDED_RESOURCE_TYPE,
+ TikaCoreProperties.EmbeddedResourceType.RENDERING.name());
+ RenderResults results = new RenderResults(new TemporaryResources());
+ try {
+ long start = System.currentTimeMillis();
+ BufferedImage image = picture instanceof HemfPicture
+ ? draw((HemfPicture) picture) : draw((HwmfPicture)
picture);
+ Path tmpFile = write(image, id);
+ renderingMetadata.set(Rendering.RENDERED_MS,
System.currentTimeMillis() - start);
+ renderingMetadata.add(Rendering.RENDERED_BY, RENDERED_BY);
+ renderingMetadata.set(HttpHeaders.CONTENT_TYPE, "image/" +
imageFormatName);
+ results.add(new RenderResult(RenderResult.STATUS.SUCCESS, id,
tmpFile,
+ renderingMetadata));
+ } catch (SecurityException e) {
+ throw e;
+ } catch (Exception e) {
+ results.add(new RenderResult(RenderResult.STATUS.EXCEPTION, id,
null,
+ renderingMetadata));
+ }
Review Comment:
Recorded, like PDFBoxRenderer does.
##########
CHANGES.txt:
##########
@@ -1,5 +1,16 @@
Release 4.1.0 - unreleased
+ * Raster previews for the vector thumbnails of Office documents: the new
+ poi-metafile-renderer draws EMF and WMF images through POI (a PNG of
+ a configurable width; Word's bitmap-in-WMF thumbnails from the bitmap
+ directly), EMFParser and WMFParser are RenderingParsers that emit the
+ rendering as a RENDERING embedded document with "emf-parser" /
+ "wmf-parser": {"renderImage": true, "renderWidth": 800}, off by
+ default and restrictable to e.g. THUMBNAIL embedded documents with
+ "renderOnlyEmbeddedResourceTypes", and OfficeParser emits the
SummaryInformation thumbnail of the
+ OLE2 formats (a WMF) as a THUMBNAIL embedded document, as the OOXML
+ parsers do with the docProps thumbnail (TIKA-4855).
Review Comment:
Wrapped.
##########
tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/EMFParser.java:
##########
@@ -62,12 +68,39 @@
* We'd have to do something like what PDFBox or XPS do to sort the
* runs and then put the cow back together from the hamburger...lol...
*/
+/**
+ * Extracts the text of an EMF image and its embedded WMF and multi-format
Review Comment:
Merged into one.
> Render EMF/WMF images to raster previews and emit the OLE2 SummaryInformation
> thumbnail
> ---------------------------------------------------------------------------------------
>
> Key: TIKA-4855
> URL: https://issues.apache.org/jira/browse/TIKA-4855
> Project: Tika
> Issue Type: Improvement
> Reporter: Dominik Schmidt
> Priority: Major
>
> Office documents carry their preview image as a vector metafile: the OOXML
> docProps/thumbnail.emf of Word (an EMF wrapping a WMF) and thumbnail.wmf of
> Excel, and the SummaryInformation thumbnail (PIDSI_THUMBNAIL,
> CF_METAFILEPICT, a WMF) of the OLE2 formats, which PowerPoint writes almost
> always and Word/Excel on request. Neither is usable as a preview outside
> Windows, and outside the JVM there is no maintained EMF/WMF rasterizer. POI's
> HEMF/HWMF can draw both and Tika already bundles them.
> Proposal, following the PDF parser's rendering design:
> 1. A Renderer for image/emf and image/wmf (POI HemfPicture/HwmfPicture drawn
> onto a white canvas, a PNG of a configurable width, the height following the
> aspect ratio). The WMF thumbnails Word writes consist of a setWindowExt and a
> dibStretchBlt record only, for which POI cannot compute bounds; for those the
> renderer emits the record's bitmap.
> 2. EMFParser and WMFParser implement RenderingParser and, with "emf-parser" /
> "wmf-parser": {"renderImage": true, "renderWidth": 800} (off by default),
> emit the rendering as a RENDERING embedded document named after the image,
> the way the PDF parser emits page renderings. An injected renderer is used
> when it supports the type, the POI one otherwise.
> 3. OfficeParser emits the SummaryInformation thumbnail of the OLE2 formats as
> a THUMBNAIL embedded document (image/wmf, named thumbnail.wmf), consistent
> with the docProps thumbnail of the OOXML parsers. Existing tests that count
> the embedded documents of .ppt fixtures gain one.
> With that, a client that asks for THUMBNAIL and RENDERING embedded documents
> gets a raster preview for docx, xlsx, doc, xls and ppt files that carry a
> thumbnail, with the same request it uses for every other format. Verified
> against tika-server with /unpack: each of these yields the thumbnail at depth
> 1 and its PNG rendering at depth 2.
> Note for clients: with rendering enabled every embedded metafile is rendered,
> e.g. the picture of an OLE object, so the preview is the RENDERING under the
> THUMBNAIL, not the first RENDERING.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)