From 24b3dac0c0422bae6ffde7b9d91e939e78e339a5 Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Tue, 12 Oct 2021 22:30:30 +0000 Subject: #64716 - wmf display error add anothger heuristic - cumulate the bounding box of the shape records and compare it to window, viewport and emfbounds git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1894176 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/poi/hemf/record/emf/HemfComment.java | 19 ++--- .../org/apache/poi/hemf/record/emf/HemfDraw.java | 78 +++++++++++++++++++++ .../org/apache/poi/hemf/record/emf/HemfRecord.java | 11 ++- .../apache/poi/hemf/record/emf/HemfWindowing.java | 28 ++++++-- .../poi/hemf/record/emfplus/HemfPlusHeader.java | 6 +- .../poi/hemf/record/emfplus/HemfPlusMisc.java | 5 +- .../poi/hemf/record/emfplus/HemfPlusRecord.java | 4 +- .../org/apache/poi/hemf/usermodel/HemfPicture.java | 81 +++++++++++++++++----- 8 files changed, 191 insertions(+), 41 deletions(-) (limited to 'poi-scratchpad') diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java index 443a7ee4de..69b489927d 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfComment.java @@ -17,6 +17,8 @@ package org.apache.poi.hemf.record.emf; +import static org.apache.logging.log4j.util.Unbox.box; + import java.awt.geom.Rectangle2D; import java.io.IOException; import java.nio.charset.Charset; @@ -34,6 +36,7 @@ import org.apache.logging.log4j.Logger; import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.hemf.draw.HemfGraphics; import org.apache.poi.hemf.draw.HemfGraphics.EmfRenderState; +import org.apache.poi.hemf.record.emf.HemfRecord.RenderBounds; import org.apache.poi.hemf.record.emfplus.HemfPlusRecord; import org.apache.poi.hemf.record.emfplus.HemfPlusRecordIterator; import org.apache.poi.hwmf.usermodel.HwmfCharsetAware; @@ -47,8 +50,6 @@ import org.apache.poi.util.LittleEndianInputStream; import org.apache.poi.util.LocaleUtil; import org.apache.poi.util.RecordFormatException; -import static org.apache.logging.log4j.util.Unbox.box; - /** * Contains arbitrary data */ @@ -103,7 +104,7 @@ public class HemfComment { */ default void draw(HemfGraphics ctx) {} - default void calcBounds(Rectangle2D bounds, Rectangle2D viewport, EmfRenderState[] renderState) { } + default void calcBounds(RenderBounds holder) { } @Override @@ -137,8 +138,8 @@ public class HemfComment { } @Override - public void calcBounds(Rectangle2D window, Rectangle2D viewport, EmfRenderState[] renderState) { - data.calcBounds(window, viewport, renderState); + public void calcBounds(RenderBounds holder) { + data.calcBounds(holder); } @Override @@ -343,11 +344,11 @@ public class HemfComment { } @Override - public void calcBounds(Rectangle2D window, Rectangle2D viewport, EmfRenderState[] renderState) { - renderState[0] = EmfRenderState.EMFPLUS_ONLY; + public void calcBounds(RenderBounds holder) { + holder.setState(EmfRenderState.EMFPLUS_ONLY); for (HemfPlusRecord r : records) { - r.calcBounds(window, viewport, renderState); - if (!window.isEmpty() && !viewport.isEmpty()) { + r.calcBounds(holder); + if (!holder.getWindow().isEmpty() && !holder.getViewport().isEmpty()) { break; } } diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfDraw.java b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfDraw.java index 02366a5b8d..5918158564 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfDraw.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfDraw.java @@ -222,6 +222,16 @@ public final class HemfDraw { public HemfRecordType getGenericRecordType() { return getEmfRecordType(); } + + @Override + public void calcBounds(RenderBounds holder) { + Rectangle2D b = holder.getBounds(); + if (b.isEmpty()) { + b.setRect(bounds); + } else { + b.add(bounds); + } + } } /** @@ -323,6 +333,16 @@ public final class HemfDraw { public HemfRecordType getGenericRecordType() { return getEmfRecordType(); } + + @Override + public void calcBounds(RenderBounds holder) { + Rectangle2D b = holder.getBounds(); + if (b.isEmpty()) { + b.setRect(bounds); + } else { + b.add(bounds); + } + } } /** @@ -775,6 +795,16 @@ public final class HemfDraw { public HemfRecordType getGenericRecordType() { return getEmfRecordType(); } + + @Override + public void calcBounds(RenderBounds holder) { + Rectangle2D b = holder.getBounds(); + if (b.isEmpty()) { + b.setRect(bounds); + } else { + b.add(bounds); + } + } } /** @@ -808,6 +838,16 @@ public final class HemfDraw { public HemfRecordType getGenericRecordType() { return getEmfRecordType(); } + + @Override + public void calcBounds(RenderBounds holder) { + Rectangle2D b = holder.getBounds(); + if (b.isEmpty()) { + b.setRect(bounds); + } else { + b.add(bounds); + } + } } /** @@ -834,6 +874,14 @@ public final class HemfDraw { public HemfRecordType getGenericRecordType() { return getEmfRecordType(); } + + @Override + public void calcBounds(RenderBounds holder) { + Rectangle2D b = holder.getBounds(); + if (!b.isEmpty()) { + b.add(point); + } + } } /** @@ -864,6 +912,16 @@ public final class HemfDraw { public HemfRecordType getGenericRecordType() { return getEmfRecordType(); } + + @Override + public void calcBounds(RenderBounds holder) { + Rectangle2D b = holder.getBounds(); + if (b.isEmpty()) { + b.setRect(bounds); + } else { + b.add(bounds); + } + } } /** The EMR_POLYDRAW record specifies a set of line segments and Bezier curves. */ @@ -979,6 +1037,16 @@ public final class HemfDraw { public HemfRecordType getGenericRecordType() { return getEmfRecordType(); } + + @Override + public void calcBounds(RenderBounds holder) { + Rectangle2D b = holder.getBounds(); + if (b.isEmpty()) { + b.setRect(bounds); + } else { + b.add(bounds); + } + } } public static class EmfPolyDraw16 extends EmfPolyDraw { @@ -1201,6 +1269,16 @@ public final class HemfDraw { public Map> getGenericProperties() { return GenericRecordUtil.getGenericProperties("bounds", this::getBounds); } + + @Override + public void calcBounds(RenderBounds holder) { + Rectangle2D b = holder.getBounds(); + if (b.isEmpty()) { + b.setRect(bounds); + } else { + b.add(bounds); + } + } } diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfRecord.java b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfRecord.java index fe6a6ccf68..613b1f028e 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfRecord.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfRecord.java @@ -57,7 +57,16 @@ public interface HemfRecord extends GenericRecord { } } - default void calcBounds(Rectangle2D window, Rectangle2D viewport, HemfGraphics.EmfRenderState[] renderState) { + interface RenderBounds { + HemfGraphics.EmfRenderState getState(); + void setState(HemfGraphics.EmfRenderState state); + + Rectangle2D getWindow(); + Rectangle2D getViewport(); + Rectangle2D getBounds(); + } + + default void calcBounds(RenderBounds holder) { } /** diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfWindowing.java b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfWindowing.java index 46e28209f8..156d1d2a0a 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfWindowing.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfWindowing.java @@ -59,7 +59,8 @@ public class HemfWindowing { } @Override - public void calcBounds(Rectangle2D window, Rectangle2D viewport, HemfGraphics.EmfRenderState[] renderState) { + public void calcBounds(RenderBounds holder) { + Rectangle2D window = holder.getWindow(); double x = window.getX(); double y = window.getY(); window.setRect(x,y,size.getWidth(),size.getHeight()); @@ -86,7 +87,8 @@ public class HemfWindowing { } @Override - public void calcBounds(Rectangle2D window, Rectangle2D viewport, HemfGraphics.EmfRenderState[] renderState) { + public void calcBounds(RenderBounds holder) { + Rectangle2D window = holder.getWindow(); double w = window.getWidth(); double h = window.getHeight(); window.setRect(origin.getX(),origin.getY(),w,h); @@ -113,7 +115,8 @@ public class HemfWindowing { } @Override - public void calcBounds(Rectangle2D window, Rectangle2D viewport, HemfGraphics.EmfRenderState[] renderState) { + public void calcBounds(RenderBounds holder) { + Rectangle2D viewport = holder.getViewport(); double x = viewport.getX(); double y = viewport.getY(); viewport.setRect(x,y,extents.getWidth(),extents.getHeight()); @@ -140,7 +143,8 @@ public class HemfWindowing { } @Override - public void calcBounds(Rectangle2D window, Rectangle2D viewport, HemfGraphics.EmfRenderState[] renderState) { + public void calcBounds(RenderBounds holder) { + Rectangle2D viewport = holder.getViewport(); double w = viewport.getWidth(); double h = viewport.getHeight(); viewport.setRect(origin.getX(), origin.getY(), w, h); @@ -208,6 +212,16 @@ public class HemfWindowing { public HemfRecordType getGenericRecordType() { return getEmfRecordType(); } + + @Override + public void calcBounds(RenderBounds holder) { + Rectangle2D b = holder.getBounds(); + if (b.isEmpty()) { + b.setRect(bounds); + } else { + b.add(bounds); + } + } } /** @@ -231,7 +245,8 @@ public class HemfWindowing { } @Override - public void calcBounds(Rectangle2D window, Rectangle2D viewport, HemfGraphics.EmfRenderState[] renderState) { + public void calcBounds(RenderBounds holder) { + Rectangle2D viewport = holder.getViewport(); double x = viewport.getX(); double y = viewport.getY(); double w = viewport.getWidth(); @@ -262,7 +277,8 @@ public class HemfWindowing { } @Override - public void calcBounds(Rectangle2D window, Rectangle2D viewport, HemfGraphics.EmfRenderState[] renderState) { + public void calcBounds(RenderBounds holder) { + Rectangle2D window = holder.getWindow(); double x = window.getX(); double y = window.getY(); double w = window.getWidth(); diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusHeader.java b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusHeader.java index a271e77de1..32215fd81e 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusHeader.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusHeader.java @@ -20,7 +20,6 @@ package org.apache.poi.hemf.record.emfplus; import static org.apache.poi.util.GenericRecordUtil.getEnumBitsAsString; -import java.awt.geom.Rectangle2D; import java.io.IOException; import java.util.Map; import java.util.function.Supplier; @@ -28,6 +27,7 @@ import java.util.function.Supplier; import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.hemf.draw.HemfGraphics; import org.apache.poi.hemf.draw.HemfGraphics.EmfRenderState; +import org.apache.poi.hemf.record.emf.HemfRecord.RenderBounds; import org.apache.poi.util.BitField; import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.GenericRecordJsonWriter; @@ -136,8 +136,8 @@ public class HemfPlusHeader implements HemfPlusRecord { } @Override - public void calcBounds(Rectangle2D window, Rectangle2D viewport, EmfRenderState[] renderState) { - renderState[0] = EmfRenderState.EMF_DCONTEXT; + public void calcBounds(RenderBounds holder) { + holder.setState(EmfRenderState.EMF_DCONTEXT); } @Override diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusMisc.java b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusMisc.java index eaaf0a88f1..eee3d40bb1 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusMisc.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusMisc.java @@ -31,6 +31,7 @@ import java.util.function.Supplier; import org.apache.poi.hemf.draw.HemfDrawProperties; import org.apache.poi.hemf.draw.HemfGraphics; import org.apache.poi.hemf.record.emf.HemfFill; +import org.apache.poi.hemf.record.emf.HemfRecord.RenderBounds; import org.apache.poi.hwmf.record.HwmfRegionMode; import org.apache.poi.util.BitField; import org.apache.poi.util.BitFieldFactory; @@ -165,8 +166,8 @@ public class HemfPlusMisc { } @Override - public void calcBounds(Rectangle2D window, Rectangle2D viewport, HemfGraphics.EmfRenderState[] renderState) { - renderState[0] = HemfGraphics.EmfRenderState.EMF_DCONTEXT; + public void calcBounds(RenderBounds holder) { + holder.setState(HemfGraphics.EmfRenderState.EMF_DCONTEXT); } } diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusRecord.java b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusRecord.java index 99210ad7ab..6b943a43d6 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusRecord.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusRecord.java @@ -18,11 +18,11 @@ package org.apache.poi.hemf.record.emfplus; -import java.awt.geom.Rectangle2D; import java.io.IOException; import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.hemf.draw.HemfGraphics; +import org.apache.poi.hemf.record.emf.HemfRecord.RenderBounds; import org.apache.poi.util.Internal; import org.apache.poi.util.LittleEndianInputStream; @@ -56,7 +56,7 @@ public interface HemfPlusRecord extends GenericRecord { default void draw(HemfGraphics ctx) { } - default void calcBounds(Rectangle2D window, Rectangle2D viewport, HemfGraphics.EmfRenderState[] renderState) { + default void calcBounds(RenderBounds holder) { } @Override diff --git a/poi-scratchpad/src/main/java/org/apache/poi/hemf/usermodel/HemfPicture.java b/poi-scratchpad/src/main/java/org/apache/poi/hemf/usermodel/HemfPicture.java index 6f52414e42..1e81d1be84 100644 --- a/poi-scratchpad/src/main/java/org/apache/poi/hemf/usermodel/HemfPicture.java +++ b/poi-scratchpad/src/main/java/org/apache/poi/hemf/usermodel/HemfPicture.java @@ -19,6 +19,7 @@ package org.apache.poi.hemf.usermodel; import static java.lang.Math.abs; +import static java.util.Comparator.comparingDouble; import static org.apache.poi.hemf.draw.HemfGraphics.EmfRenderState.EMFPLUS_ONLY; import static org.apache.poi.hemf.draw.HemfGraphics.EmfRenderState.EMF_ONLY; @@ -36,12 +37,14 @@ import java.util.Map; import java.util.Spliterator; import java.util.function.Consumer; import java.util.function.Supplier; +import java.util.stream.Stream; import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.hemf.draw.HemfGraphics; import org.apache.poi.hemf.record.emf.HemfComment; import org.apache.poi.hemf.record.emf.HemfHeader; import org.apache.poi.hemf.record.emf.HemfRecord; +import org.apache.poi.hemf.record.emf.HemfRecord.RenderBounds; import org.apache.poi.hemf.record.emf.HemfRecordIterator; import org.apache.poi.hwmf.usermodel.HwmfCharsetAware; import org.apache.poi.hwmf.usermodel.HwmfEmbedded; @@ -125,7 +128,7 @@ public class HemfPicture implements Iterable, GenericRecord { boolean isInvalid = ReluctantRectangle2D.isEmpty(dim); if (isInvalid) { Rectangle2D lastDim = new ReluctantRectangle2D(); - getInnerBounds(lastDim, new ReluctantRectangle2D()); + getInnerBounds(lastDim, new Rectangle2D.Double(), new Rectangle2D.Double()); if (!lastDim.isEmpty()) { return lastDim; } @@ -133,24 +136,52 @@ public class HemfPicture implements Iterable, GenericRecord { return dim; } - public void getInnerBounds(Rectangle2D window, Rectangle2D viewport) { - HemfGraphics.EmfRenderState[] renderState = { HemfGraphics.EmfRenderState.INITIAL }; + public void getInnerBounds(Rectangle2D window, Rectangle2D viewport, Rectangle2D bounds) { + RenderBounds holder = new RenderBounds() { + private HemfGraphics.EmfRenderState state = HemfGraphics.EmfRenderState.INITIAL; + + @Override + public HemfGraphics.EmfRenderState getState() { + return state; + } + + @Override + public void setState(HemfGraphics.EmfRenderState state) { + this.state = state; + } + + @Override + public Rectangle2D getWindow() { + return window; + } + + @Override + public Rectangle2D getViewport() { + return viewport; + } + + @Override + public Rectangle2D getBounds() { + return bounds; + } + }; + for (HemfRecord r : getRecords()) { if ( - (renderState[0] == EMF_ONLY && r instanceof HemfComment.EmfComment) || - (renderState[0] == EMFPLUS_ONLY && !(r instanceof HemfComment.EmfComment)) + (holder.getState() == EMF_ONLY && r instanceof HemfComment.EmfComment) || + (holder.getState() == EMFPLUS_ONLY && !(r instanceof HemfComment.EmfComment)) ) { continue; } try { - r.calcBounds(window, viewport, renderState); + r.calcBounds(holder); } catch (RuntimeException ignored) { } - if (!window.isEmpty() && !viewport.isEmpty()) { - break; - } +// if (!window.isEmpty() && !viewport.isEmpty()) { +// break; +// } } } @@ -179,20 +210,30 @@ public class HemfPicture implements Iterable, GenericRecord { Rectangle2D emfBounds = getHeader().getBoundsRectangle(); Rectangle2D winBounds = new ReluctantRectangle2D(); Rectangle2D viewBounds = new ReluctantRectangle2D(); - getInnerBounds(winBounds, viewBounds); + Rectangle2D recBounds = new Rectangle2D.Double(); + getInnerBounds(winBounds, viewBounds, recBounds); Boolean forceHeader = (Boolean)ctx.getRenderingHint(Drawable.EMF_FORCE_HEADER_BOUNDS); if (forceHeader == null) { forceHeader = false; } - // this is a compromise ... sometimes winBounds are totally off :( - // but mostly they fit better than the header bounds - Rectangle2D b = - !viewBounds.isEmpty() && !forceHeader - ? viewBounds - : !winBounds.isEmpty() && !forceHeader - ? winBounds - : emfBounds; + + Rectangle2D b; + if (forceHeader) { + b = emfBounds; + } else if (recBounds.isEmpty()) { + // this is a compromise ... sometimes winBounds are totally off :( + // but mostly they fit better than the header bounds + b = !viewBounds.isEmpty() + ? viewBounds + : !winBounds.isEmpty() + ? winBounds + : emfBounds; + } else { + double recHyp = dia(recBounds); + b = Stream.of(emfBounds, winBounds, viewBounds). + min(comparingDouble(r -> abs(dia(r) - recHyp))).get(); + } ctx.translate(graphicsBounds.getCenterX(), graphicsBounds.getCenterY()); ctx.scale( @@ -217,6 +258,10 @@ public class HemfPicture implements Iterable, GenericRecord { } } + private static double dia(Rectangle2D bounds) { + return Math.sqrt(bounds.getWidth()*bounds.getWidth() + bounds.getHeight()*bounds.getWidth()); + } + public Iterable getEmbeddings() { return () -> new HemfEmbeddedIterator(HemfPicture.this); } -- cgit v1.2.3