Browse Source

#60656 - Support export file that contains emf and render it correctly

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1841134 13f79535-47bb-0310-9956-ffa450edef68
tags/REL_4_1_0
Andreas Beeker 5 years ago
parent
commit
e6e1f622d8

+ 16
- 0
src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java View File

@@ -20,10 +20,26 @@ package org.apache.poi.hemf.draw;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;

import org.apache.poi.hwmf.draw.HwmfDrawProperties;
import org.apache.poi.hwmf.draw.HwmfGraphics;

public class HemfGraphics extends HwmfGraphics {
public HemfGraphics(Graphics2D graphicsCtx, Rectangle2D bbox) {
super(graphicsCtx,bbox);
}

@Override
public HemfDrawProperties getProperties() {
if (prop == null) {
prop = new HemfDrawProperties();
}
return (HemfDrawProperties)prop;
}

@Override
public void saveProperties() {
assert(prop != null);
propStack.add(prop);
prop = new HemfDrawProperties((HemfDrawProperties)prop);
}
}

+ 222
- 1
src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java View File

@@ -17,7 +17,10 @@

package org.apache.poi.hemf.record.emf;

import java.awt.geom.AffineTransform;
import static org.apache.poi.hwmf.record.HwmfBrushStyle.BS_NULL;
import static org.apache.poi.hwmf.record.HwmfBrushStyle.BS_SOLID;

import java.awt.Color;
import java.awt.geom.Dimension2D;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
@@ -25,10 +28,13 @@ import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;

import org.apache.poi.hemf.draw.HemfDrawProperties;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hwmf.draw.HwmfGraphics;
import org.apache.poi.hwmf.record.HwmfColorRef;
import org.apache.poi.hwmf.record.HwmfDraw;
import org.apache.poi.hwmf.record.HwmfDraw.WmfSelectObject;
import org.apache.poi.hwmf.record.HwmfPenStyle;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;

@@ -40,6 +46,12 @@ public class HemfDraw {
*/
public static class EmfSelectObject extends WmfSelectObject implements HemfRecord {

private static final HwmfColorRef WHITE = new HwmfColorRef(Color.WHITE);
private static final HwmfColorRef LTGRAY = new HwmfColorRef(new Color(0x00C0C0C0));
private static final HwmfColorRef GRAY = new HwmfColorRef(new Color(0x00808080));
private static final HwmfColorRef DKGRAY = new HwmfColorRef(new Color(0x00404040));
private static final HwmfColorRef BLACK = new HwmfColorRef(Color.BLACK);

@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.selectObject;
@@ -52,6 +64,125 @@ public class HemfDraw {
objectIndex = leis.readInt();
return LittleEndianConsts.INT_SIZE;
}

@Override
public void draw(HemfGraphics ctx) {
if ((objectIndex & 0x80000000) != 0) {
selectStockObject(ctx);
} else {
super.draw(ctx);
}
}

private void selectStockObject(HemfGraphics ctx) {
final HemfDrawProperties prop = ctx.getProperties();
switch (objectIndex) {
case 0x80000000:
// WHITE_BRUSH - A white, solid-color brush
// BrushStyle: BS_SOLID
// Color: 0x00FFFFFF
prop.setBrushColor(WHITE);
prop.setBrushStyle(BS_SOLID);
break;
case 0x80000001:
// LTGRAY_BRUSH - A light gray, solid-color brush
// BrushStyle: BS_SOLID
// Color: 0x00C0C0C0
prop.setBrushColor(LTGRAY);
prop.setBrushStyle(BS_SOLID);
break;
case 0x80000002:
// GRAY_BRUSH - A gray, solid-color brush
// BrushStyle: BS_SOLID
// Color: 0x00808080
prop.setBrushColor(GRAY);
prop.setBrushStyle(BS_SOLID);
break;
case 0x80000003:
// DKGRAY_BRUSH - A dark gray, solid color brush
// BrushStyle: BS_SOLID
// Color: 0x00404040
prop.setBrushColor(DKGRAY);
prop.setBrushStyle(BS_SOLID);
break;
case 0x80000004:
// BLACK_BRUSH - A black, solid color brush
// BrushStyle: BS_SOLID
// Color: 0x00000000
prop.setBrushColor(BLACK);
prop.setBrushStyle(BS_SOLID);
break;
case 0x80000005:
// NULL_BRUSH - A null brush
// BrushStyle: BS_NULL
prop.setBrushStyle(BS_NULL);
break;
case 0x80000006:
// WHITE_PEN - A white, solid-color pen
// PenStyle: PS_COSMETIC + PS_SOLID
// ColorRef: 0x00FFFFFF
prop.setPenStyle(HwmfPenStyle.valueOf(0));
prop.setPenWidth(1);
prop.setPenColor(WHITE);
break;
case 0x80000007:
// BLACK_PEN - A black, solid-color pen
// PenStyle: PS_COSMETIC + PS_SOLID
// ColorRef: 0x00000000
prop.setPenStyle(HwmfPenStyle.valueOf(0));
prop.setPenWidth(1);
prop.setPenColor(BLACK);
break;
case 0x80000008:
// NULL_PEN - A null pen
// PenStyle: PS_NULL
prop.setPenStyle(HwmfPenStyle.valueOf(HwmfPenStyle.HwmfLineDash.NULL.wmfFlag));
break;
case 0x8000000A:
// OEM_FIXED_FONT - A fixed-width, OEM character set
// Charset: OEM_CHARSET
// PitchAndFamily: FF_DONTCARE + FIXED_PITCH
break;
case 0x8000000B:
// ANSI_FIXED_FONT - A fixed-width font
// Charset: ANSI_CHARSET
// PitchAndFamily: FF_DONTCARE + FIXED_PITCH
break;
case 0x8000000C:
// ANSI_VAR_FONT - A variable-width font
// Charset: ANSI_CHARSET
// PitchAndFamily: FF_DONTCARE + VARIABLE_PITCH
break;
case 0x8000000D:
// SYSTEM_FONT - A font that is guaranteed to be available in the operating system
break;
case 0x8000000E:
// DEVICE_DEFAULT_FONT
// The default font that is provided by the graphics device driver for the current output device
break;
case 0x8000000F:
// DEFAULT_PALETTE
// The default palette that is defined for the current output device.
break;
case 0x80000010:
// SYSTEM_FIXED_FONT
// A fixed-width font that is guaranteed to be available in the operating system.
break;
case 0x80000011:
// DEFAULT_GUI_FONT
// The default font that is used for user interface objects such as menus and dialog boxes.
break;
case 0x80000012:
// DC_BRUSH
// The solid-color brush that is currently selected in the playback device context.
break;
case 0x80000013:
// DC_PEN
// The solid-color pen that is currently selected in the playback device context.
break;
}
}

}


@@ -717,8 +848,98 @@ public class HemfDraw {
protected long readPoint(LittleEndianInputStream leis, Point2D point) {
return readPointS(leis, point);
}
}

public static class EmfBeginPath implements HemfRecord {
@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.beginPath;
}

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return 0;
}
}

public static class EmfEndPath implements HemfRecord {
@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.endPath;
}

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return 0;
}
}

public static class EmfAbortPath implements HemfRecord {
@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.abortPath;
}

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return 0;
}
}

public static class EmfCloseFigure implements HemfRecord {
@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.closeFigure;
}

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return 0;
}
}

public static class EmfFlattenPath implements HemfRecord {
@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.flattenPath;
}

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return 0;
}
}

public static class EmfWidenPath implements HemfRecord {
@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.widenPath;
}

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return 0;
}
}

/**
* The EMR_STROKEPATH record renders the specified path by using the current pen.
*/
public static class EmfStrokePath implements HemfRecord {
protected final Rectangle2D bounds = new Rectangle2D.Double();

@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.strokePath;
}

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
// A 128-bit WMF RectL object, which specifies bounding rectangle, in device units
return readRectL(leis, bounds);
}
}

static long readRectL(LittleEndianInputStream leis, Rectangle2D bounds) {
/* A 32-bit signed integer that defines the x coordinate, in logical coordinates,
* of the ... corner of the rectangle.

+ 19
- 0
src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFill.java View File

@@ -617,4 +617,23 @@ public class HemfFill {

return 6 * LittleEndian.INT_SIZE;
}

/**
* The EMR_FILLPATH record closes any open figures in the current path and fills the path's interior by
* using the current brush and polygon-filling mode.
*/
public static class EmfFillPath implements HemfRecord {
protected final Rectangle2D bounds = new Rectangle2D.Double();

@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.fillPath;
}

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
// A 128-bit WMF RectL object, which specifies bounding rectangle, in device units
return readRectL(leis, bounds);
}
}
}

+ 56
- 37
src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java View File

@@ -17,10 +17,11 @@

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.hemf.record.emf.HemfFill.readBitmap;
import static org.apache.poi.hemf.record.emf.HemfRecordIterator.HEADER_SIZE;

import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -37,7 +38,6 @@ import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode;
import org.apache.poi.hwmf.record.HwmfPalette.PaletteEntry;
import org.apache.poi.hwmf.record.HwmfPenStyle;
import org.apache.poi.hwmf.record.HwmfPenStyle.HwmfLineDash;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;

@@ -56,22 +56,22 @@ public class HemfMisc {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {

// A 32-bit unsigned integer that specifies the number of palette entries.
int nPalEntries = (int)leis.readUInt();
int nPalEntries = (int) leis.readUInt();
// A 32-bit unsigned integer that specifies the offset to the palette entries from the start of this record.
int offPalEntries = (int)leis.readUInt();
int offPalEntries = (int) leis.readUInt();

int size = 2*LittleEndianConsts.INT_SIZE;
int undefinedSpace1 = (int)(offPalEntries - size - HEADER_SIZE);
int size = 2 * LittleEndianConsts.INT_SIZE;
int undefinedSpace1 = (int) (offPalEntries - size - HEADER_SIZE);
assert (undefinedSpace1 >= 0);
leis.skipFully(undefinedSpace1);
size += undefinedSpace1;

for (int i=0; i<nPalEntries; i++) {
for (int i = 0; i < nPalEntries; i++) {
PaletteEntry pe = new PaletteEntry();
size += pe.init(leis);
}

int undefinedSpace2 = (int)(recordSize - size - LittleEndianConsts.INT_SIZE);
int undefinedSpace2 = (int) (recordSize - size - LittleEndianConsts.INT_SIZE);
assert (undefinedSpace2 >= 0);
leis.skipFully(undefinedSpace2);
size += undefinedSpace2;
@@ -81,7 +81,7 @@ public class HemfMisc {
// LogPaletteEntry objects, if they exist, MUST precede this field.
long sizeLast = leis.readUInt();
size += LittleEndianConsts.INT_SIZE;
assert ((sizeLast-HEADER_SIZE) == recordSize && recordSize == size);
assert ((sizeLast - HEADER_SIZE) == recordSize && recordSize == size);

return size;
}
@@ -179,7 +179,7 @@ public class HemfMisc {
* A 32-bit unsigned integer that specifies the background mode
* and MUST be in the BackgroundMode (section 2.1.4) enumeration
*/
bkMode = HwmfBkMode.valueOf((int)leis.readUInt());
bkMode = HwmfBkMode.valueOf((int) leis.readUInt());
return LittleEndianConsts.INT_SIZE;
}
}
@@ -195,7 +195,7 @@ public class HemfMisc {

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return super.init(leis, recordSize, (int)recordId);
return super.init(leis, recordSize, (int) recordId);
}
}

@@ -212,7 +212,7 @@ public class HemfMisc {
@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
// A 32-bit unsigned integer whose definition MUST be in the MapMode enumeration
mapMode = HwmfMapMode.valueOf((int)leis.readUInt());
mapMode = HwmfMapMode.valueOf((int) leis.readUInt());
return LittleEndianConsts.INT_SIZE;
}
}
@@ -230,7 +230,7 @@ public class HemfMisc {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
// A 32-bit unsigned integer that specifies the raster operation mode and
// MUST be in the WMF Binary Raster Op enumeration
drawMode = HwmfBinaryRasterOp.valueOf((int)leis.readUInt());
drawMode = HwmfBinaryRasterOp.valueOf((int) leis.readUInt());
return LittleEndianConsts.INT_SIZE;
}
}
@@ -250,12 +250,14 @@ public class HemfMisc {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
// A 32-bit unsigned integer that specifies the stretch mode and MAY be
// in the StretchMode enumeration.
stretchBltMode = StretchBltMode.valueOf((int)leis.readUInt());
stretchBltMode = StretchBltMode.valueOf((int) leis.readUInt());
return LittleEndianConsts.INT_SIZE;
}
}

/** The EMR_CREATEBRUSHINDIRECT record defines a logical brush for graphics operations. */
/**
* The EMR_CREATEBRUSHINDIRECT record defines a logical brush for graphics operations.
*/
public static class EmfCreateBrushIndirect extends HwmfMisc.WmfCreateBrushIndirect implements HemfRecord {
/**
* A 32-bit unsigned integer that specifies the index of the logical brush object in the
@@ -270,13 +272,13 @@ public class HemfMisc {

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
brushIdx = (int)leis.readUInt();
brushIdx = (int) leis.readUInt();

brushStyle = HwmfBrushStyle.valueOf((int)leis.readUInt());
brushStyle = HwmfBrushStyle.valueOf((int) leis.readUInt());
colorRef = new HwmfColorRef();
int size = colorRef.init(leis);
brushHatch = HwmfHatchStyle.valueOf((int)leis.readUInt());
return size+3*LittleEndianConsts.INT_SIZE;
brushHatch = HwmfHatchStyle.valueOf((int) leis.readUInt());
return size + 3 * LittleEndianConsts.INT_SIZE;

}
}
@@ -294,12 +296,14 @@ public class HemfMisc {

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
objectIndex = (int)leis.readUInt();
objectIndex = (int) leis.readUInt();
return LittleEndianConsts.INT_SIZE;
}
}

/** The EMR_CREATEPEN record defines a logical pen for graphics operations. */
/**
* The EMR_CREATEPEN record defines a logical pen for graphics operations.
*/
public static class EmfCreatePen extends HwmfMisc.WmfCreatePenIndirect implements HemfRecord {
/**
* A 32-bit unsigned integer that specifies the index of the logical palette object
@@ -315,11 +319,11 @@ public class HemfMisc {

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
penIndex = (int)leis.readUInt();
penIndex = (int) leis.readUInt();

// A 32-bit unsigned integer that specifies the PenStyle.
// The value MUST be defined from the PenStyle enumeration table
penStyle = HwmfPenStyle.valueOf((int)leis.readUInt());
penStyle = HwmfPenStyle.valueOf((int) leis.readUInt());

int widthX = leis.readInt();
int widthY = leis.readInt();
@@ -327,7 +331,7 @@ public class HemfMisc {

int size = colorRef.init(leis);

return size + 4*LittleEndianConsts.INT_SIZE;
return size + 4 * LittleEndianConsts.INT_SIZE;
}
}

@@ -349,27 +353,27 @@ public class HemfMisc {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
final int startIdx = leis.getReadIndex();

penIndex = (int)leis.readUInt();
penIndex = (int) leis.readUInt();

// A 32-bit unsigned integer that specifies the offset from the start of this
// record to the DIB header, if the record contains a DIB.
int offBmi = (int)leis.readUInt();
int offBmi = (int) leis.readUInt();

// A 32-bit unsigned integer that specifies the size of the DIB header, if the
// record contains a DIB.
int cbBmi = (int)leis.readUInt();
int cbBmi = (int) leis.readUInt();

// A 32-bit unsigned integer that specifies the offset from the start of this
// record to the DIB bits, if the record contains a DIB.
int offBits = (int)leis.readUInt();
int offBits = (int) leis.readUInt();

// A 32-bit unsigned integer that specifies the size of the DIB bits, if the record
// contains a DIB.
int cbBits = (int)leis.readUInt();
int cbBits = (int) leis.readUInt();

// A 32-bit unsigned integer that specifies the PenStyle.
// The value MUST be defined from the PenStyle enumeration table
penStyle = HwmfPenStyle.valueOf((int)leis.readUInt());
penStyle = HwmfPenStyle.valueOf((int) leis.readUInt());

// A 32-bit unsigned integer that specifies the width of the line drawn by the pen.
// If the pen type in the PenStyle field is PS_GEOMETRIC, this value is the width in logical
@@ -383,7 +387,7 @@ public class HemfMisc {
// If the pen type in the PenStyle field is PS_GEOMETRIC, this value MUST be either BS_SOLID or BS_HATCHED.
// The value of this field can be BS_NULL, but only if the line style specified in PenStyle is PS_NULL.
// The BS_NULL style SHOULD be used to specify a brush that has no effect
brushStyle = HwmfBrushStyle.valueOf((int)leis.readUInt());
brushStyle = HwmfBrushStyle.valueOf((int) leis.readUInt());

int size = 8 * LittleEndianConsts.INT_SIZE;

@@ -393,10 +397,10 @@ public class HemfMisc {

// The number of elements in the array specified in the StyleEntry
// field. This value SHOULD be zero if PenStyle does not specify PS_USERSTYLE.
final int numStyleEntries = (int)leis.readUInt();
size += 2*LittleEndianConsts.INT_SIZE;
final int numStyleEntries = (int) leis.readUInt();
size += 2 * LittleEndianConsts.INT_SIZE;

assert(numStyleEntries == 0 || penStyle.getLineDash() == HwmfLineDash.USERSTYLE);
assert (numStyleEntries == 0 || penStyle.getLineDash() == HwmfLineDash.USERSTYLE);

// An optional array of 32-bit unsigned integers that defines the lengths of
// dashes and gaps in the line drawn by this pen, when the value of PenStyle is
@@ -409,8 +413,8 @@ public class HemfMisc {

styleEntry = new int[numStyleEntries];

for (int i=0; i<numStyleEntries; i++) {
styleEntry[i] = (int)leis.readUInt();
for (int i = 0; i < numStyleEntries; i++) {
styleEntry[i] = (int) leis.readUInt();
}

size += numStyleEntries * LittleEndianConsts.INT_SIZE;
@@ -435,7 +439,7 @@ public class HemfMisc {

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
miterLimit = (int)leis.readUInt();
miterLimit = (int) leis.readUInt();
return LittleEndianConsts.INT_SIZE;
}

@@ -444,4 +448,19 @@ public class HemfMisc {
ctx.getProperties().setPenMiterLimit(miterLimit);
}
}


public static class EmfSetBrushOrgEx implements HemfRecord {
protected final Point2D origin = new Point2D.Double();

@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.setBrushOrgEx;
}

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return readPointL(leis, origin);
}
}
}

+ 10
- 10
src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordType.java View File

@@ -36,7 +36,7 @@ public enum HemfRecordType {
setWindowOrgEx(0x0000000A, HemfWindowing.EmfSetWindowOrgEx::new),
setViewportExtEx(0x0000000B, HemfWindowing.EmfSetViewportExtEx::new),
setViewportOrgEx(0x0000000C, HemfWindowing.EmfSetViewportOrgEx::new),
setbrushorgex(0x0000000D, UnimplementedHemfRecord::new),
setBrushOrgEx(0x0000000D, HemfMisc.EmfSetBrushOrgEx::new),
eof(0x0000000E, HemfMisc.EmfEof::new),
setPixelV(0x0000000F, HemfDraw.EmfSetPixelV::new),
setMapperFlags(0x00000010, HemfMisc.EmfSetMapperFlags::new),
@@ -82,16 +82,16 @@ public enum HemfRecordType {
polyDraw(0x00000038, HemfDraw.EmfPolyDraw::new),
setarcdirection(0x00000039, UnimplementedHemfRecord::new),
setMiterLimit(0x0000003A, HemfMisc.EmfSetMiterLimit::new),
beginpath(0x0000003B, UnimplementedHemfRecord::new),
endpath(0x0000003C, UnimplementedHemfRecord::new),
closefigure(0x0000003D, UnimplementedHemfRecord::new),
fillpath(0x0000003E, UnimplementedHemfRecord::new),
beginPath(0x0000003B, HemfDraw.EmfBeginPath::new),
endPath(0x0000003C, HemfDraw.EmfEndPath::new),
closeFigure(0x0000003D, HemfDraw.EmfCloseFigure::new),
fillPath(0x0000003E, HemfFill.EmfFillPath::new),
strokeandfillpath(0x0000003F, UnimplementedHemfRecord::new),
strokepath(0x00000040, UnimplementedHemfRecord::new),
flattenpath(0x00000041, UnimplementedHemfRecord::new),
widenpath(0x00000042, UnimplementedHemfRecord::new),
selectclippath(0x00000043, UnimplementedHemfRecord::new),
abortpath(0x00000044, UnimplementedHemfRecord::new),
strokePath(0x00000040, HemfDraw.EmfStrokePath::new),
flattenPath(0x00000041, HemfDraw.EmfFlattenPath::new),
widenPath(0x00000042, HemfDraw.EmfWidenPath::new),
selectClipPath(0x00000043, HemfWindowing.EmfSelectClipPath::new),
abortPath(0x00000044, HemfDraw.EmfAbortPath::new),
// no 45 ?!
comment(0x00000046, HemfComment.EmfComment::new),
fillRgn(0x00000047, HemfFill.EmfFillRgn::new),

+ 25
- 1
src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfWindowing.java View File

@@ -19,6 +19,7 @@ package org.apache.poi.hemf.record.emf;

import java.io.IOException;

import org.apache.poi.hemf.record.emf.HemfFill.HemfRegionMode;
import org.apache.poi.hwmf.record.HwmfWindowing;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@@ -197,4 +198,27 @@ public class HemfWindowing {
return 4*LittleEndianConsts.INT_SIZE;
}
}
}

/**
* The EMR_SELECTCLIPPATH record specifies the current path as a clipping region for a playback
* device context, combining the new region with any existing clipping region using the specified mode.
*/
public static class EmfSelectClipPath implements HemfRecord {
protected HemfRegionMode regionMode;

@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.selectClipPath;
}

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
// A 32-bit unsigned integer that specifies the way to use the path.
// The value MUST be in the RegionMode enumeration
regionMode = HemfRegionMode.valueOf(leis.readInt());

return LittleEndianConsts.INT_SIZE;
}
}

}

+ 3
- 6
src/scratchpad/src/org/apache/poi/hemf/record/emf/UnimplementedHemfRecord.java View File

@@ -27,19 +27,16 @@ import org.apache.poi.util.LittleEndianInputStream;
@Internal
public class UnimplementedHemfRecord implements HemfRecord {

private long recordId;
public UnimplementedHemfRecord() {

}
private HemfRecordType recordType;

@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.getById(recordId);
return recordType;
}

@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
this.recordId = recordId;
recordType = HemfRecordType.getById(recordId);
long skipped = IOUtils.skipFully(leis, recordSize);
if (skipped < recordSize) {
throw new IOException("End of stream reached before record read");

+ 1
- 1
src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusHeader.java View File

@@ -34,7 +34,7 @@ public class HemfPlusHeader implements HemfPlusRecord {
private long logicalDpiY;

@Override
public HemfPlusRecordType getRecordType() {
public HemfPlusRecordType getEmfPlusRecordType() {
return HemfPlusRecordType.header;
}


+ 1
- 1
src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRecord.java View File

@@ -27,7 +27,7 @@ import org.apache.poi.util.LittleEndianInputStream;
@Internal
public interface HemfPlusRecord {

HemfPlusRecordType getRecordType();
HemfPlusRecordType getEmfPlusRecordType();

int getFlags();


+ 1
- 1
src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRecordIterator.java View File

@@ -57,7 +57,7 @@ public class HemfPlusRecordIterator implements Iterator<HemfPlusRecord> {
}

private HemfPlusRecord _next() {
if (currentRecord != null && HemfPlusRecordType.eof == currentRecord.getRecordType()) {
if (currentRecord != null && HemfPlusRecordType.eof == currentRecord.getEmfPlusRecordType()) {
return null;
}
// A 16-bit unsigned integer that identifies this record type

+ 4
- 4
src/scratchpad/src/org/apache/poi/hemf/record/emfplus/UnimplementedHemfPlusRecord.java View File

@@ -29,13 +29,13 @@ public class UnimplementedHemfPlusRecord implements HemfPlusRecord {

private static final int MAX_RECORD_LENGTH = 1_000_000;

private long recordId;
private HemfPlusRecordType recordType;
private int flags;
private byte[] recordBytes;

@Override
public HemfPlusRecordType getRecordType() {
return HemfPlusRecordType.getById(recordId);
public HemfPlusRecordType getEmfPlusRecordType() {
return recordType;
}

@Override
@@ -45,7 +45,7 @@ public class UnimplementedHemfPlusRecord implements HemfPlusRecord {

@Override
public long init(LittleEndianInputStream leis, long dataSize, long recordId, int flags) throws IOException {
this.recordId = recordId;
recordType = HemfPlusRecordType.getById(recordId);
this.flags = flags;
recordBytes = IOUtils.safelyAllocate(dataSize, MAX_RECORD_LENGTH);
leis.readFully(recordBytes);

+ 32
- 27
src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java View File

@@ -52,11 +52,12 @@ import org.apache.poi.util.LocaleUtil;

public class HwmfGraphics {

protected final List<HwmfDrawProperties> propStack = new LinkedList<>();
protected HwmfDrawProperties prop;

private static final Charset DEFAULT_CHARSET = LocaleUtil.CHARSET_1252;
private final Graphics2D graphicsCtx;
private final List<HwmfDrawProperties> propStack = new LinkedList<>();
private HwmfDrawProperties prop = new HwmfDrawProperties();
private List<HwmfObjectTableEntry> objectTable = new ArrayList<>();
private final List<HwmfObjectTableEntry> objectTable = new ArrayList<>();
/** Bounding box from the placeable header */
private final Rectangle2D bbox;
private final AffineTransform initialAT;
@@ -75,11 +76,14 @@ public class HwmfGraphics {
}

public HwmfDrawProperties getProperties() {
if (prop == null) {
prop = new HwmfDrawProperties();
}
return prop;
}

public void draw(Shape shape) {
HwmfLineDash lineDash = prop.getPenStyle().getLineDash();
HwmfLineDash lineDash = getProperties().getPenStyle().getLineDash();
if (lineDash == HwmfLineDash.NULL) {
// line is not drawn
return;
@@ -89,22 +93,22 @@ public class HwmfGraphics {

// first draw a solid background line (depending on bkmode)
// only makes sense if the line is not solid
if (prop.getBkMode() == HwmfBkMode.OPAQUE && (lineDash != HwmfLineDash.SOLID && lineDash != HwmfLineDash.INSIDEFRAME)) {
if (getProperties().getBkMode() == HwmfBkMode.OPAQUE && (lineDash != HwmfLineDash.SOLID && lineDash != HwmfLineDash.INSIDEFRAME)) {
graphicsCtx.setStroke(new BasicStroke(stroke.getLineWidth()));
graphicsCtx.setColor(prop.getBackgroundColor().getColor());
graphicsCtx.setColor(getProperties().getBackgroundColor().getColor());
graphicsCtx.draw(shape);
}

// then draw the (dashed) line
graphicsCtx.setStroke(stroke);
graphicsCtx.setColor(prop.getPenColor().getColor());
graphicsCtx.setColor(getProperties().getPenColor().getColor());
graphicsCtx.draw(shape);
}

public void fill(Shape shape) {
if (prop.getBrushStyle() != HwmfBrushStyle.BS_NULL) {
if (getProperties().getBrushStyle() != HwmfBrushStyle.BS_NULL) {
// GeneralPath gp = new GeneralPath(shape);
// gp.setWindingRule(prop.getPolyfillMode().awtFlag);
// gp.setWindingRule(getProperties().getPolyfillMode().awtFlag);
graphicsCtx.setPaint(getFill());
graphicsCtx.fill(shape);
}
@@ -114,14 +118,14 @@ public class HwmfGraphics {

protected BasicStroke getStroke() {
// TODO: fix line width calculation
float width = (float)prop.getPenWidth();
float width = (float)getProperties().getPenWidth();
if (width == 0) {
width = 1;
}
HwmfPenStyle ps = prop.getPenStyle();
HwmfPenStyle ps = getProperties().getPenStyle();
int cap = ps.getLineCap().awtFlag;
int join = ps.getLineJoin().awtFlag;
float miterLimit = (float)prop.getPenMiterLimit();
float miterLimit = (float)getProperties().getPenMiterLimit();
float dashes[] = ps.getLineDash().dashes;
boolean dashAlt = ps.isAlternateDash();
// This value is not an integer index into the dash pattern array.
@@ -132,7 +136,7 @@ public class HwmfGraphics {
}

protected Paint getFill() {
switch (prop.getBrushStyle()) {
switch (getProperties().getBrushStyle()) {
default:
case BS_INDEXED:
case BS_PATTERN8X8:
@@ -148,20 +152,20 @@ public class HwmfGraphics {
}

protected Paint getSolidFill() {
return prop.getBrushColor().getColor();
return getProperties().getBrushColor().getColor();
}

protected Paint getHatchedFill() {
int dim = 7, mid = 3;
BufferedImage bi = new BufferedImage(dim, dim, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g = bi.createGraphics();
Color c = (prop.getBkMode() == HwmfBkMode.TRANSPARENT)
Color c = (getProperties().getBkMode() == HwmfBkMode.TRANSPARENT)
? new Color(0, true)
: prop.getBackgroundColor().getColor();
: getProperties().getBackgroundColor().getColor();
g.setColor(c);
g.fillRect(0, 0, dim, dim);
g.setColor(prop.getBrushColor().getColor());
HwmfHatchStyle h = prop.getBrushHatch();
g.setColor(getProperties().getBrushColor().getColor());
HwmfHatchStyle h = getProperties().getBrushHatch();
if (h == HwmfHatchStyle.HS_HORIZONTAL || h == HwmfHatchStyle.HS_CROSS) {
g.drawLine(0, mid, dim, mid);
}
@@ -179,7 +183,7 @@ public class HwmfGraphics {
}

protected Paint getPatternPaint() {
BufferedImage bi = prop.getBrushBitmap();
BufferedImage bi = getProperties().getBrushBitmap();
return (bi == null) ? null
: new TexturePaint(bi, new Rectangle(0,0,bi.getWidth(),bi.getHeight()));
}
@@ -244,8 +248,9 @@ public class HwmfGraphics {
* Saves the current properties to the stack
*/
public void saveProperties() {
assert(prop != null);
propStack.add(prop);
prop = new HwmfDrawProperties(prop);
prop = new HwmfDrawProperties(prop);
}
/**
@@ -260,7 +265,7 @@ public class HwmfGraphics {
}
int stackIndex = index;
if (stackIndex < 0) {
int curIdx = propStack.indexOf(prop);
int curIdx = propStack.indexOf(getProperties());
if (curIdx == -1) {
// the current element is not pushed to the stacked, i.e. it's the last
curIdx = propStack.size();
@@ -280,8 +285,8 @@ public class HwmfGraphics {
* This methods gathers and sets the corresponding graphics transformations.
*/
public void updateWindowMapMode() {
Rectangle2D win = prop.getWindow();
HwmfMapMode mapMode = prop.getMapMode();
Rectangle2D win = getProperties().getWindow();
HwmfMapMode mapMode = getProperties().getMapMode();
graphicsCtx.setTransform(initialAT);

switch (mapMode) {
@@ -320,7 +325,7 @@ public class HwmfGraphics {
}

public void drawString(byte[] text, Rectangle2D bounds, int dx[]) {
HwmfFont font = prop.getFont();
HwmfFont font = getProperties().getFont();
if (font == null || text == null || text.length == 0) {
return;
}
@@ -386,12 +391,12 @@ public class HwmfGraphics {
try {
graphicsCtx.translate(bounds.getX(), bounds.getY()+fontH);
graphicsCtx.rotate(angle);
if (prop.getBkMode() == HwmfBkMode.OPAQUE) {
if (getProperties().getBkMode() == HwmfBkMode.OPAQUE) {
// TODO: validate bounds
graphicsCtx.setBackground(prop.getBackgroundColor().getColor());
graphicsCtx.setBackground(getProperties().getBackgroundColor().getColor());
graphicsCtx.fill(new Rectangle2D.Double(0, 0, bounds.getWidth(), bounds.getHeight()));
}
graphicsCtx.setColor(prop.getTextColor().getColor());
graphicsCtx.setColor(getProperties().getTextColor().getColor());
graphicsCtx.drawString(as.getIterator(), 0, 0); // (float)bounds.getX(), (float)bounds.getY());
} finally {
graphicsCtx.setTransform(at);

+ 2
- 2
src/scratchpad/testcases/org/apache/poi/hemf/hemfplus/extractor/HemfPlusExtractorTest.java View File

@@ -42,7 +42,7 @@ public class HemfPlusExtractorTest {
EmfCommentDataPlus emfPlus = getCommentRecord("SimpleEMF_windows.emf", 0);
List<HemfPlusRecord> records = emfPlus.getRecords();
assertEquals(1, records.size());
assertEquals(HemfPlusRecordType.header, records.get(0).getRecordType());
assertEquals(HemfPlusRecordType.header, records.get(0).getEmfPlusRecordType());

HemfPlusHeader header = (HemfPlusHeader)records.get(0);
assertEquals(240, header.getLogicalDpiX());
@@ -67,7 +67,7 @@ public class HemfPlusExtractorTest {
assertEquals(expected.size(), records.size());

for (int i = 0; i < expected.size(); i++) {
assertEquals(expected.get(i), records.get(i).getRecordType());
assertEquals(expected.get(i), records.get(i).getEmfPlusRecordType());
}
}


Loading…
Cancel
Save