- Support export file that contains emf and render it correctly

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1843025 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2018-10-06 18:23:59 +00:00
parent 93b7cb0bc7
commit 2b12e29c92
3 changed files with 112 additions and 41 deletions
src/scratchpad/src/org/apache/poi

View File

@ -19,7 +19,6 @@ package org.apache.poi.hemf.record.emf;
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 java.awt.geom.AffineTransform;
import java.awt.geom.Area;
@ -114,7 +113,7 @@ public class HemfFill {
* optionally in combination with a brush pattern, according to a specified raster operation, stretching or
* compressing the output to fit the dimensions of the destination, if necessary.
*/
public static class EmfStretchBlt extends HwmfFill.WmfBitBlt implements HemfRecord {
public static class EmfStretchBlt extends HwmfFill.WmfBitBlt implements HemfRecord, HemfBounded {
protected final Rectangle2D bounds = new Rectangle2D.Double();
/** An XForm object that specifies a world-space to page-space transform to apply to the source bitmap. */
@ -129,11 +128,7 @@ public class HemfFill {
*/
protected int usageSrc;
/** The source bitmap header. */
protected byte[] bmiSrc;
/** The source bitmap bits. */
protected byte[] bitsSrc;
protected final HwmfBitmapDib bitmap = new HwmfBitmapDib();
@Override
public HemfRecordType getEmfRecordType() {
@ -142,6 +137,8 @@ public class HemfFill {
@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
int startIdx = leis.getReadIndex();
long size = readRectL(leis, bounds);
size += readBounds2(leis, this.dstBounds);
@ -190,33 +187,103 @@ public class HemfFill {
srcBounds.setRect(srcPnt.getX(), srcPnt.getY(), srcWidth, srcHeight);
}
// size + type and size field
final int undefinedSpace1 = (int)(offBmiSrc - size - HEADER_SIZE);
assert(undefinedSpace1 >= 0);
leis.skipFully(undefinedSpace1);
size += undefinedSpace1;
bmiSrc = IOUtils.safelyAllocate(cbBmiSrc, MAX_RECORD_LENGTH);
leis.readFully(bmiSrc);
size += cbBmiSrc;
final int undefinedSpace2 = (int)(offBitsSrc - size - HEADER_SIZE);
assert(undefinedSpace2 >= 0);
leis.skipFully(undefinedSpace2);
size += undefinedSpace2;
bitsSrc = IOUtils.safelyAllocate(cbBitsSrc, MAX_RECORD_LENGTH);
leis.readFully(bitsSrc);
size += cbBitsSrc;
size += readBitmap(leis, bitmap, startIdx, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc);
return size;
}
@Override
public Rectangle2D getRecordBounds() {
return bounds;
}
@Override
public Rectangle2D getShapeBounds(HemfGraphics ctx) {
return dstBounds;
}
protected boolean srcEqualsDstDimension() {
return false;
}
}
/**
* The EMR_STRETCHDIBITS record specifies a block transfer of pixels from a source bitmap to a
* destination rectangle, optionally in combination with a brush pattern, according to a specified raster
* operation, stretching or compressing the output to fit the dimensions of the destination, if necessary.
*/
public static class EmfStretchDiBits extends HwmfFill.WmfStretchDib implements HemfRecord, HemfBounded {
protected final Rectangle2D bounds = new Rectangle2D.Double();
@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.stretchDiBits;
}
@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
final int startIdx = leis.getReadIndex();
long size = readRectL(leis, bounds);
// A 32-bit signed integer that specifies the logical x-coordinate of the upper-left
// corner of the destination rectangle.
int xDest = leis.readInt();
int yDest = leis.readInt();
size += 2*LittleEndianConsts.INT_SIZE;
size += readBounds2(leis, srcBounds);
// A 32-bit unsigned integer that specifies the offset, in bytes from the start
// of this record to the source bitmap header.
int offBmiSrc = (int)leis.readUInt();
// A 32-bit unsigned integer that specifies the size, in bytes, of the source bitmap header.
int cbBmiSrc = (int)leis.readUInt();
// A 32-bit unsigned integer that specifies the offset, in bytes, from the
// start of this record to the source bitmap bits.
int offBitsSrc = (int)leis.readUInt();
// A 32-bit unsigned integer that specifies the size, in bytes, of the source bitmap bits.
int cbBitsSrc = (int)leis.readUInt();
// A 32-bit unsigned integer that specifies how to interpret values in the color table
// in the source bitmap header. This value MUST be in the DIBColors enumeration
colorUsage = ColorUsage.valueOf(leis.readInt());
// A 32-bit unsigned integer that specifies a raster operation code.
// These codes define how the color data of the source rectangle is to be combined with the color data
// of the destination rectangle and optionally a brush pattern, to achieve the final color.
// The value MUST be in the WMF Ternary Raster Operation enumeration
rasterOperation = HwmfTernaryRasterOp.valueOf(leis.readInt());
// A 32-bit signed integer that specifies the logical width of the destination rectangle.
int cxDest = leis.readInt();
// A 32-bit signed integer that specifies the logical height of the destination rectangle.
int cyDest = leis.readInt();
dstBounds.setRect(xDest, yDest, cxDest, cyDest);
size += 8*LittleEndianConsts.INT_SIZE;
size += readBitmap(leis, dib, startIdx, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc);
return size;
}
@Override
public Rectangle2D getRecordBounds() {
return bounds;
}
@Override
public Rectangle2D getShapeBounds(HemfGraphics ctx) {
return dstBounds;
}
}
/**
* The EMR_BITBLT record specifies a block transfer of pixels from a source bitmap to a destination rectangle,
* optionally in combination with a brush pattern, according to a specified raster operation.
@ -235,7 +302,7 @@ public class HemfFill {
/** The EMR_FRAMERGN record draws a border around the specified region using the specified brush. */
public static class EmfFrameRgn extends HwmfDraw.WmfFrameRegion implements HemfRecord {
public static class EmfFrameRgn extends HwmfDraw.WmfFrameRegion implements HemfRecord, HemfBounded {
private final Rectangle2D bounds = new Rectangle2D.Double();
private final List<Rectangle2D> rgnRects = new ArrayList<>();
@ -263,18 +330,23 @@ public class HemfFill {
@Override
public void draw(HwmfGraphics ctx) {
ctx.applyObjectTableEntry(brushIndex);
ctx.fill(getShape());
}
Area frame = new Area();
for (Rectangle2D rct : rgnRects) {
frame.add(new Area(rct));
}
Rectangle2D frameBounds = frame.getBounds2D();
AffineTransform at = new AffineTransform();
at.translate(bounds.getX()-frameBounds.getX(), bounds.getY()-frameBounds.getY());
at.scale(bounds.getWidth()/frameBounds.getWidth(), bounds.getHeight()/frameBounds.getHeight());
frame.transform(at);
@Override
public Rectangle2D getRecordBounds() {
return bounds;
}
ctx.fill(frame);
@Override
public Rectangle2D getShapeBounds(HemfGraphics ctx) {
return getShape().getBounds2D();
}
protected Area getShape() {
final Area frame = new Area();
rgnRects.forEach((rct) -> frame.add(new Area(rct)));
return frame;
}
}

View File

@ -104,7 +104,7 @@ public enum HemfRecordType {
maskblt(0x0000004E, UnimplementedHemfRecord::new),
plgblt(0x0000004F, UnimplementedHemfRecord::new),
setDiBitsToDevice(0x00000050, HemfFill.EmfSetDiBitsToDevice::new),
stretchdibits(0x00000051, UnimplementedHemfRecord::new),
stretchDiBits(0x00000051, HemfFill.EmfStretchDiBits::new),
extCreateFontIndirectW(0x00000052, HemfText.ExtCreateFontIndirectW::new),
exttextouta(0x00000053, HemfText.EmfExtTextOutA::new),
exttextoutw(0x00000054, HemfText.EmfExtTextOutW::new),

View File

@ -430,13 +430,13 @@ public class HwmfFill {
* the playback device context, and the destination pixels are to be combined to
* form the new image.
*/
private HwmfTernaryRasterOp rasterOperation;
protected HwmfTernaryRasterOp rasterOperation;
/**
* A 16-bit unsigned integer that defines whether the Colors field of the
* DIB contains explicit RGB values or indexes into a palette.
*/
private ColorUsage colorUsage;
protected ColorUsage colorUsage;
/** the source rectangle. */
protected final Rectangle2D srcBounds = new Rectangle2D.Double();
@ -448,7 +448,7 @@ public class HwmfFill {
* A variable-sized DeviceIndependentBitmap Object (section 2.2.2.9) that is the
* source of the color data.
*/
private HwmfBitmapDib dib;
protected final HwmfBitmapDib dib = new HwmfBitmapDib();
@Override
public HwmfRecordType getWmfRecordType() {
@ -471,7 +471,6 @@ public class HwmfFill {
size += readBounds2(leis, srcBounds);
size += readBounds2(leis, dstBounds);
dib = new HwmfBitmapDib();
size += dib.init(leis, (int)(recordSize-6-size));
return size;