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@1845612 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
acfed6fb29
commit
8b3974f945
|
@ -18,6 +18,7 @@
|
|||
package org.apache.poi.hemf.record.emf;
|
||||
|
||||
import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
|
||||
import static org.apache.poi.hwmf.record.HwmfDraw.normalizeBounds;
|
||||
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.Arc2D;
|
||||
|
@ -660,7 +661,7 @@ public class HemfDraw {
|
|||
|
||||
@Override
|
||||
public void draw(HemfGraphics ctx) {
|
||||
ctx.draw(path -> path.append(bounds, false), FillDrawStyle.FILL_DRAW);
|
||||
ctx.draw(path -> path.append(normalizeBounds(bounds), false), FillDrawStyle.FILL_DRAW);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1127,8 +1128,9 @@ public class HemfDraw {
|
|||
}
|
||||
|
||||
static long readDimensionInt(LittleEndianInputStream leis, Dimension2D dimension) {
|
||||
final double width = leis.readUInt();
|
||||
final double height = leis.readUInt();
|
||||
// although the spec says "use unsigned ints", there are examples out there using signed ints
|
||||
final double width = leis.readInt();
|
||||
final double height = leis.readInt();
|
||||
dimension.setSize(width, height);
|
||||
return 2*LittleEndianConsts.INT_SIZE;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import static org.apache.poi.hemf.record.emf.HemfDraw.readPointL;
|
|||
import static org.apache.poi.hemf.record.emf.HemfDraw.readRectL;
|
||||
import static org.apache.poi.hemf.record.emf.HemfRecordIterator.HEADER_SIZE;
|
||||
import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
|
||||
import static org.apache.poi.hwmf.record.HwmfDraw.pointToString;
|
||||
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
|
@ -588,6 +589,17 @@ public class HemfFill {
|
|||
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return
|
||||
"{ bounds: " + boundsToString(bounds) +
|
||||
", dest: " + pointToString(dest) +
|
||||
", src: " + boundsToString(src) +
|
||||
", usageSrc: '" + usageSrc + "'" +
|
||||
", bitmap: " + bitmap +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
|
||||
static long readBitmap(final LittleEndianInputStream leis, final HwmfBitmapDib bitmap,
|
||||
|
|
|
@ -36,6 +36,11 @@ public class HemfFont extends HwmfFont {
|
|||
|
||||
protected static class LogFontExDv implements LogFontDetails {
|
||||
protected int[] designVector;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{ designVectorLen: " + (designVector == null ? 0 : designVector.length) + " }";
|
||||
}
|
||||
}
|
||||
|
||||
protected static class LogFontPanose implements LogFontDetails {
|
||||
|
@ -195,6 +200,25 @@ public class HemfFont extends HwmfFont {
|
|||
protected Letterform letterform;
|
||||
protected MidLine midLine;
|
||||
protected XHeight xHeight;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return
|
||||
"{ styleSize: " + styleSize +
|
||||
", vendorId: " + vendorId +
|
||||
", culture: " + culture +
|
||||
", familyType: '" + familyType + "'" +
|
||||
", serifStyle: '" + serifStyle + "'" +
|
||||
", weight: '" + weight + "'" +
|
||||
", proportion: '" + proportion + "'" +
|
||||
", contrast: '" + contrast + "'" +
|
||||
", strokeVariation: '" + strokeVariation + "'" +
|
||||
", armStyle: '" + armStyle + "'" +
|
||||
", letterform: '" + letterform + "'" +
|
||||
", midLine: '" + midLine + "'" +
|
||||
", xHeight: '" + xHeight + "'" +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
|
||||
protected String fullname;
|
||||
|
@ -435,12 +459,19 @@ public class HemfFont extends HwmfFont {
|
|||
size += (2+numAxes)*LittleEndianConsts.INT_SIZE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return
|
||||
"{ fullname: '" + (fullname == null ? "" : fullname) + "'" +
|
||||
", style: '" + (style == null ? "" : style) + "'" +
|
||||
", script: '" + (script == null ? "" : script) + "'" +
|
||||
", details: " + details +
|
||||
"," + super.toString().substring(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int readString(LittleEndianInputStream leis, StringBuilder sb, int limit) throws IOException {
|
||||
sb.setLength(0);
|
||||
|
|
|
@ -126,7 +126,7 @@ public class HemfHeader implements HemfRecord {
|
|||
", bytes: " + bytes +
|
||||
", records: " + records +
|
||||
", handles: " + handles +
|
||||
", description: '" + description + "'" +
|
||||
", description: '" + (description == null ? "" : description) + "'" +
|
||||
", nPalEntries: " + nPalEntries +
|
||||
", hasExtension1: " + hasExtension1 +
|
||||
", cbPixelFormat: " + cbPixelFormat +
|
||||
|
|
|
@ -745,10 +745,22 @@ public class HemfMisc {
|
|||
|
||||
@Override
|
||||
public void applyObject(HwmfGraphics ctx) {
|
||||
if (!bitmap.isValid()) {
|
||||
return;
|
||||
}
|
||||
HwmfDrawProperties props = ctx.getProperties();
|
||||
props.setBrushStyle(HwmfBrushStyle.BS_PATTERN);
|
||||
BufferedImage bmp = bitmap.getImage();
|
||||
props.setBrushBitmap(bmp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return
|
||||
"{ penIndex: " + penIndex +
|
||||
", colorUsage: " + colorUsage +
|
||||
", bitmap: " + bitmap +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -199,7 +199,11 @@ public class HemfText {
|
|||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.drawString(rawTextBytes, stringLength, reference, bounds, options, dx, isUnicode());
|
||||
// A 32-bit floating-point value that specifies the scale factor to apply along
|
||||
// the axis to convert from page space units to .01mm units.
|
||||
// This SHOULD be used only if the graphics mode specified by iGraphicsMode is GM_COMPATIBLE.
|
||||
Dimension2D scl = graphicsMode == EmfGraphicsMode.GM_COMPATIBLE ? scale : null;
|
||||
ctx.drawString(rawTextBytes, stringLength, reference, scl, bounds, options, dx, isUnicode());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.poi.hemf.record.emf;
|
|||
|
||||
import static org.apache.poi.hemf.record.emf.HemfDraw.readDimensionInt;
|
||||
import static org.apache.poi.hemf.record.emf.HemfDraw.readPointL;
|
||||
import static org.apache.poi.hwmf.record.HwmfDraw.normalizeBounds;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -135,7 +136,7 @@ public class HemfWindowing {
|
|||
|
||||
@Override
|
||||
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
|
||||
return HemfDraw.readRectL(leis, bounds);
|
||||
return HemfDraw.readRectL(leis, normalizeBounds(bounds));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -93,6 +93,8 @@ public class HwmfDrawProperties {
|
|||
textVAlignAsian = HwmfTextVerticalAlignment.TOP;
|
||||
rasterOp = HwmfTernaryRasterOp.PATCOPY;
|
||||
clip = null;
|
||||
font = new HwmfFont();
|
||||
font.initDefaults();
|
||||
}
|
||||
|
||||
public HwmfDrawProperties(HwmfDrawProperties other) {
|
||||
|
|
|
@ -30,6 +30,7 @@ import java.awt.font.TextAttribute;
|
|||
import java.awt.font.TextLayout;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Dimension2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
@ -333,8 +334,9 @@ public class HwmfGraphics {
|
|||
case MM_ANISOTROPIC:
|
||||
// scale window bounds to output bounds
|
||||
if (view != null) {
|
||||
graphicsCtx.translate(view.getX() - win.getX(), view.getY() - win.getY());
|
||||
graphicsCtx.translate(view.getCenterX(), view.getCenterY());
|
||||
graphicsCtx.scale(view.getWidth() / win.getWidth(), view.getHeight() / win.getHeight());
|
||||
graphicsCtx.translate(-win.getCenterX(), -win.getCenterY());
|
||||
}
|
||||
break;
|
||||
case MM_ISOTROPIC:
|
||||
|
@ -362,10 +364,10 @@ public class HwmfGraphics {
|
|||
}
|
||||
|
||||
public void drawString(byte[] text, int length, Point2D reference) {
|
||||
drawString(text, length, reference, null, null, null, false);
|
||||
drawString(text, length, reference, null, null, null, null, false);
|
||||
}
|
||||
|
||||
public void drawString(byte[] text, int length, Point2D reference, Rectangle2D clip, WmfExtTextOutOptions opts, List<Integer> dx, boolean isUnicode) {
|
||||
public void drawString(byte[] text, int length, Point2D reference, Dimension2D scale, Rectangle2D clip, WmfExtTextOutOptions opts, List<Integer> dx, boolean isUnicode) {
|
||||
final HwmfDrawProperties prop = getProperties();
|
||||
|
||||
HwmfFont font = prop.getFont();
|
||||
|
@ -489,6 +491,9 @@ public class HwmfGraphics {
|
|||
|
||||
graphicsCtx.translate(reference.getX(), reference.getY());
|
||||
graphicsCtx.rotate(angle);
|
||||
if (scale != null) {
|
||||
graphicsCtx.scale(scale.getWidth() < 0 ? -1 : 1, scale.getHeight() < 0 ? -1 : 1);
|
||||
}
|
||||
graphicsCtx.translate(dst.getX(), dst.getY());
|
||||
graphicsCtx.setColor(prop.getTextColor().getColor());
|
||||
graphicsCtx.drawString(as.getIterator(), 0, 0);
|
||||
|
|
|
@ -45,9 +45,11 @@ import org.apache.poi.util.RecordFormatException;
|
|||
*/
|
||||
public class HwmfBitmapDib {
|
||||
|
||||
private static final POILogger logger = POILogFactory.getLogger(HwmfBitmapDib.class);
|
||||
private static final int BMP_HEADER_SIZE = 14;
|
||||
private static final int MAX_RECORD_LENGTH = HwmfPicture.MAX_RECORD_LENGTH;
|
||||
|
||||
public static enum BitCount {
|
||||
public enum BitCount {
|
||||
/**
|
||||
* The image SHOULD be in either JPEG or PNG format. <6> Neither of these formats includes
|
||||
* a color table, so this value specifies that no color table is present. See [JFIF] and [RFC2083]
|
||||
|
@ -129,7 +131,7 @@ public class HwmfBitmapDib {
|
|||
}
|
||||
}
|
||||
|
||||
public static enum Compression {
|
||||
public enum Compression {
|
||||
/**
|
||||
* The bitmap is in uncompressed red green blue (RGB) format that is not compressed
|
||||
* and does not use color masks.
|
||||
|
@ -198,9 +200,7 @@ public class HwmfBitmapDib {
|
|||
}
|
||||
}
|
||||
|
||||
private final static POILogger logger = POILogFactory.getLogger(HwmfBitmapDib.class);
|
||||
private static final int BMP_HEADER_SIZE = 14;
|
||||
|
||||
|
||||
private int headerSize;
|
||||
private int headerWidth;
|
||||
private int headerHeight;
|
||||
|
@ -406,7 +406,27 @@ public class HwmfBitmapDib {
|
|||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return (imageData != null);
|
||||
// the recordsize ended before the image data
|
||||
if (imageData == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ignore all black mono-brushes
|
||||
if (this.headerBitCount == BitCount.BI_BITCOUNT_1) {
|
||||
if (colorTable == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Color c : colorTable) {
|
||||
if (!Color.BLACK.equals(c)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public InputStream getBMPStream() {
|
||||
|
@ -448,6 +468,24 @@ public class HwmfBitmapDib {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return
|
||||
"{ headerSize: " + headerSize +
|
||||
", width: " + headerWidth +
|
||||
", height: " + headerHeight +
|
||||
", planes: " + headerPlanes +
|
||||
", bitCount: '" + headerBitCount + "'" +
|
||||
", compression: '" + headerCompression + "'" +
|
||||
", imageSize: " + headerImageSize +
|
||||
", xPelsPerMeter: " + headerXPelsPerMeter +
|
||||
", yPelsPerMeter: " + headerYPelsPerMeter +
|
||||
", colorUsed: " + headerColorUsed +
|
||||
", colorImportant: " + headerColorImportant +
|
||||
", imageSize: " + (imageData == null ? 0 : imageData.length) +
|
||||
"}";
|
||||
}
|
||||
|
||||
protected BufferedImage getPlaceholder() {
|
||||
BufferedImage bi = new BufferedImage(headerWidth, headerHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = bi.createGraphics();
|
||||
|
|
|
@ -763,5 +763,15 @@ public class HwmfDraw {
|
|||
return "{ w: "+dim.getWidth()+", h: "+dim.getHeight()+" }";
|
||||
}
|
||||
|
||||
@Internal
|
||||
public static Rectangle2D normalizeBounds(Rectangle2D bounds) {
|
||||
return (bounds.getWidth() >= 0 && bounds.getHeight() >= 0) ? bounds
|
||||
: new Rectangle2D.Double(
|
||||
bounds.getWidth() >= 0 ? bounds.getMinX() : bounds.getMaxX(),
|
||||
bounds.getHeight() >= 0 ? bounds.getMinY() : bounds.getMaxY(),
|
||||
Math.abs(bounds.getWidth()),
|
||||
Math.abs(bounds.getHeight())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -498,7 +498,7 @@ public class HwmfFill {
|
|||
prop.setRasterOp(rasterOperation);
|
||||
if (bitmap.isValid()) {
|
||||
ctx.drawImage(getImage(), srcBounds, dstBounds);
|
||||
} else {
|
||||
} else if (!dstBounds.isEmpty()) {
|
||||
BufferedImage bi = new BufferedImage((int)dstBounds.getWidth(), (int)dstBounds.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
ctx.drawImage(bi, dstBounds, dstBounds);
|
||||
}
|
||||
|
|
|
@ -369,6 +369,21 @@ public class HwmfFont implements FontInfo {
|
|||
return 5*LittleEndianConsts.SHORT_SIZE+8*LittleEndianConsts.BYTE_SIZE+readBytes;
|
||||
}
|
||||
|
||||
public void initDefaults() {
|
||||
height = -12;
|
||||
width = 0;
|
||||
escapement = 0;
|
||||
weight = 400;
|
||||
italic = false;
|
||||
underline = false;
|
||||
strikeOut = false;
|
||||
charSet = FontCharset.ANSI;
|
||||
outPrecision = WmfOutPrecision.OUT_DEFAULT_PRECIS;
|
||||
quality = WmfFontQuality.ANTIALIASED_QUALITY;
|
||||
pitchAndFamily = FontFamily.FF_DONTCARE.getFlag() | (FontPitch.DEFAULT.getNativeId() << 6);
|
||||
facename = "SansSerif";
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
@ -479,7 +494,7 @@ public class HwmfFont implements FontInfo {
|
|||
", charset: '"+charSet+"'"+
|
||||
", outPrecision: '"+outPrecision+"'"+
|
||||
", clipPrecision: '"+clipPrecision+"'"+
|
||||
", qualtiy: '"+quality+"'"+
|
||||
", quality: '"+quality+"'"+
|
||||
", pitch: '"+getPitch()+"'"+
|
||||
", family: '"+getFamily()+"'"+
|
||||
", facename: '"+facename+"'"+
|
||||
|
|
|
@ -454,6 +454,9 @@ public class HwmfMisc {
|
|||
|
||||
@Override
|
||||
public void applyObject(HwmfGraphics ctx) {
|
||||
if (patternDib != null && !patternDib.isValid()) {
|
||||
return;
|
||||
}
|
||||
HwmfDrawProperties prop = ctx.getProperties();
|
||||
prop.setBrushStyle(style);
|
||||
prop.setBrushBitmap(getImage());
|
||||
|
|
|
@ -391,7 +391,7 @@ public class HwmfText {
|
|||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.drawString(rawTextBytes, stringLength, reference, bounds, options, dx, false);
|
||||
ctx.drawString(rawTextBytes, stringLength, reference, null, bounds, options, dx, false);
|
||||
}
|
||||
|
||||
public String getText(Charset charset) throws IOException {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.apache.poi.hwmf.record;
|
||||
|
||||
import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
|
||||
import static org.apache.poi.hwmf.record.HwmfDraw.normalizeBounds;
|
||||
import static org.apache.poi.hwmf.record.HwmfDraw.pointToString;
|
||||
import static org.apache.poi.hwmf.record.HwmfDraw.readBounds;
|
||||
import static org.apache.poi.hwmf.record.HwmfDraw.readPointS;
|
||||
|
@ -398,6 +399,7 @@ public class HwmfWindowing {
|
|||
|
||||
@Override
|
||||
public void applyObject(HwmfGraphics ctx) {
|
||||
ctx.setClip(normalizeBounds(bounds), HwmfRegionMode.RGN_DIFF, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue