mirror of https://github.com/apache/poi.git
#60656 - Support export file that contains emf and render it correctly
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1847209 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
30d4934edc
commit
11cbe34ee5
|
@ -23,7 +23,9 @@ import static org.apache.poi.hemf.record.emf.HemfFill.readXForm;
|
|||
import static org.apache.poi.hemf.record.emf.HemfRecordIterator.HEADER_SIZE;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.NoninvertibleTransformException;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -31,6 +33,7 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.apache.poi.hemf.draw.HemfDrawProperties;
|
||||
import org.apache.poi.hemf.draw.HemfGraphics;
|
||||
import org.apache.poi.hwmf.draw.HwmfDrawProperties;
|
||||
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
||||
|
@ -632,6 +635,7 @@ public class HemfMisc {
|
|||
public static class EmfModifyWorldTransform implements HemfRecord {
|
||||
protected final AffineTransform xForm = new AffineTransform();
|
||||
protected HemfModifyWorldTransformMode modifyWorldTransformMode;
|
||||
protected HemfHeader header;
|
||||
|
||||
@Override
|
||||
public HemfRecordType getEmfRecordType() {
|
||||
|
@ -652,17 +656,50 @@ public class HemfMisc {
|
|||
return size + LittleEndianConsts.INT_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeader(HemfHeader header) {
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(HemfGraphics ctx) {
|
||||
if (modifyWorldTransformMode == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final HemfDrawProperties prop = ctx.getProperties();
|
||||
|
||||
final AffineTransform tx;
|
||||
switch (modifyWorldTransformMode) {
|
||||
case MWT_LEFTMULTIPLY:
|
||||
|
||||
AffineTransform wsTrans;
|
||||
final Rectangle2D win = prop.getWindow();
|
||||
boolean noSetWindowExYet = win.getWidth() == 1 && win.getHeight() == 1;
|
||||
if (noSetWindowExYet) {
|
||||
// TODO: understand world-space transformation [MSDN-WRLDPGSPC]
|
||||
// experimental and horrible solved, because the world-space transformation behind it
|
||||
// is not understood :(
|
||||
// only found one example which had landscape bounds and transform of 90 degress
|
||||
|
||||
try {
|
||||
wsTrans = xForm.createInverse();
|
||||
} catch (NoninvertibleTransformException e) {
|
||||
wsTrans = new AffineTransform();
|
||||
}
|
||||
|
||||
Rectangle2D emfBounds = header.getBoundsRectangle();
|
||||
|
||||
if (xForm.getShearX() == -1.0 && xForm.getShearY() == 1.0) {
|
||||
// rotate 90 deg
|
||||
wsTrans.translate(-emfBounds.getHeight(), emfBounds.getHeight());
|
||||
}
|
||||
} else {
|
||||
wsTrans = adaptXForm(ctx.getTransform());
|
||||
}
|
||||
|
||||
tx = ctx.getTransform();
|
||||
tx.concatenate(adaptXForm(tx));
|
||||
tx.concatenate(wsTrans);
|
||||
break;
|
||||
case MWT_RIGHTMULTIPLY:
|
||||
tx = ctx.getTransform();
|
||||
|
@ -690,7 +727,7 @@ public class HemfMisc {
|
|||
Function<Double,Double> nn = (d) -> (d == 0. ? 0. : d);
|
||||
double yDiff = Math.signum(nn.apply(xForm.getTranslateY())) == Math.signum(nn.apply(other.getTranslateY())) ? 1. : -1.;
|
||||
double xDiff = Math.signum(nn.apply(xForm.getTranslateX())) == Math.signum(nn.apply(other.getTranslateX())) ? 1. : -1.;
|
||||
return new AffineTransform(
|
||||
return new AffineTransform(
|
||||
xForm.getScaleX() == 0 ? 1. : xForm.getScaleX(),
|
||||
yDiff * xForm.getShearY(),
|
||||
xDiff * xForm.getShearX(),
|
||||
|
|
|
@ -52,4 +52,10 @@ public interface HemfRecord {
|
|||
((HwmfRecord) this).draw(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the header reference, in case the record needs to refer to it
|
||||
* @param header the emf header
|
||||
*/
|
||||
default void setHeader(HemfHeader header) {}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,14 @@ public class HemfPicture implements Iterable<HemfRecord> {
|
|||
// in case the (first) parsing throws an exception, we can provide the
|
||||
// records up to that point
|
||||
isParsed = true;
|
||||
new HemfRecordIterator(stream).forEachRemaining(records::add);
|
||||
HemfHeader[] header = new HemfHeader[1];
|
||||
new HemfRecordIterator(stream).forEachRemaining(r -> {
|
||||
if (r instanceof HemfHeader) {
|
||||
header[0] = (HemfHeader) r;
|
||||
}
|
||||
r.setHeader(header[0]);
|
||||
records.add(r);
|
||||
});
|
||||
}
|
||||
return records;
|
||||
}
|
||||
|
@ -116,23 +123,34 @@ public class HemfPicture implements Iterable<HemfRecord> {
|
|||
return new Dimension2DDouble(Math.abs(width*coeff), Math.abs(height*coeff));
|
||||
}
|
||||
|
||||
private static double minX(Rectangle2D bounds) {
|
||||
return Math.min(bounds.getMinX(), bounds.getMaxX());
|
||||
}
|
||||
|
||||
private static double minY(Rectangle2D bounds) {
|
||||
return Math.min(bounds.getMinY(), bounds.getMaxY());
|
||||
}
|
||||
|
||||
public void draw(Graphics2D ctx, Rectangle2D graphicsBounds) {
|
||||
HemfHeader header = (HemfHeader)getRecords().get(0);
|
||||
|
||||
AffineTransform at = ctx.getTransform();
|
||||
try {
|
||||
Rectangle2D emfBounds = header.getBoundsRectangle();
|
||||
ctx.translate(graphicsBounds.getCenterX()-emfBounds.getCenterX(), graphicsBounds.getCenterY()-emfBounds.getCenterY());
|
||||
|
||||
// scale output bounds to image bounds
|
||||
ctx.translate(emfBounds.getCenterX(), emfBounds.getCenterY());
|
||||
ctx.translate(minX(graphicsBounds), minY(graphicsBounds));
|
||||
ctx.scale(graphicsBounds.getWidth()/emfBounds.getWidth(), graphicsBounds.getHeight()/emfBounds.getHeight());
|
||||
ctx.translate(-emfBounds.getCenterX(), -emfBounds.getCenterY());
|
||||
ctx.translate(-minX(emfBounds), -minY(emfBounds));
|
||||
|
||||
int idx = 0;
|
||||
HemfGraphics g = new HemfGraphics(ctx, emfBounds);
|
||||
for (HemfRecord r : getRecords()) {
|
||||
g.draw(r);
|
||||
try {
|
||||
g.draw(r);
|
||||
} catch (RuntimeException ignored) {
|
||||
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
} finally {
|
||||
|
|
|
@ -374,9 +374,6 @@ public class HwmfGraphics {
|
|||
final HwmfDrawProperties prop = getProperties();
|
||||
|
||||
final AffineTransform at = graphicsCtx.getTransform();
|
||||
if (at.getScaleX() == 0. || at.getScaleY() == 0.) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
at.createInverse();
|
||||
|
@ -687,11 +684,4 @@ public class HwmfGraphics {
|
|||
graphicsCtx.setTransform(at);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bounding box
|
||||
*/
|
||||
public Rectangle2D getBbox() {
|
||||
return (Rectangle2D)bbox.clone();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue