| /* ==================================================================== |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| ==================================================================== */ |
| |
| package org.apache.poi.hwmf.record; |
| |
| import static org.apache.poi.hwmf.record.HwmfDraw.normalizeBounds; |
| import static org.apache.poi.hwmf.record.HwmfDraw.readBounds; |
| import static org.apache.poi.hwmf.record.HwmfDraw.readPointS; |
| |
| import java.awt.Shape; |
| 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.io.IOException; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.LinkedHashMap; |
| import java.util.Map; |
| import java.util.function.Supplier; |
| |
| import org.apache.poi.common.usermodel.GenericRecord; |
| import org.apache.poi.hwmf.draw.HwmfDrawProperties; |
| import org.apache.poi.hwmf.draw.HwmfGraphics; |
| import org.apache.poi.util.Dimension2DDouble; |
| import org.apache.poi.util.GenericRecordJsonWriter; |
| import org.apache.poi.util.GenericRecordUtil; |
| import org.apache.poi.util.LittleEndianConsts; |
| import org.apache.poi.util.LittleEndianInputStream; |
| |
| public class HwmfWindowing { |
| |
| /** |
| * The META_SETVIEWPORTORG record defines the viewport origin in the playback device context. |
| */ |
| public static class WmfSetViewportOrg implements HwmfRecord { |
| |
| protected final Point2D origin = new Point2D.Double(); |
| |
| @Override |
| public HwmfRecordType getWmfRecordType() { |
| return HwmfRecordType.setViewportOrg; |
| } |
| |
| @Override |
| public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { |
| return readPointS(leis, origin); |
| } |
| |
| @Override |
| public void draw(HwmfGraphics ctx) { |
| final HwmfDrawProperties prop = ctx.getProperties(); |
| Rectangle2D old = prop.getViewport(); |
| double oldX = (old == null ? 0 : old.getX()); |
| double oldY = (old == null ? 0 : old.getY()); |
| if (oldX != origin.getX() || oldY != origin.getY()) { |
| prop.setViewportOrg(origin.getX(), origin.getY()); |
| ctx.updateWindowMapMode(); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return GenericRecordJsonWriter.marshal(this); |
| } |
| |
| public Point2D getOrigin() { |
| return origin; |
| } |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties("origin", this::getOrigin); |
| } |
| } |
| |
| /** |
| * The META_SETVIEWPORTEXT record sets the horizontal and vertical extents |
| * of the viewport in the playback device context. |
| */ |
| public static class WmfSetViewportExt implements HwmfRecord { |
| |
| protected final Dimension2D extents = new Dimension2DDouble(); |
| |
| @Override |
| public HwmfRecordType getWmfRecordType() { |
| return HwmfRecordType.setViewportExt; |
| } |
| |
| @Override |
| public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { |
| // A signed integer that defines the vertical extent of the viewport in device units. |
| int height = leis.readShort(); |
| // A signed integer that defines the horizontal extent of the viewport in device units. |
| int width = leis.readShort(); |
| extents.setSize(width, height); |
| return 2*LittleEndianConsts.SHORT_SIZE; |
| } |
| |
| @Override |
| public void draw(HwmfGraphics ctx) { |
| final HwmfDrawProperties prop = ctx.getProperties(); |
| Rectangle2D old = prop.getViewport(); |
| double oldW = (old == null ? 0 : old.getWidth()); |
| double oldH = (old == null ? 0 : old.getHeight()); |
| if (oldW != extents.getWidth() || oldH != extents.getHeight()) { |
| prop.setViewportExt(extents.getWidth(), extents.getHeight()); |
| ctx.updateWindowMapMode(); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return GenericRecordJsonWriter.marshal(this); |
| } |
| |
| public Dimension2D getExtents() { |
| return extents; |
| } |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties("extents", this::getExtents); |
| } |
| } |
| |
| /** |
| * The META_OFFSETVIEWPORTORG record moves the viewport origin in the playback device context |
| * by specified horizontal and vertical offsets. |
| */ |
| public static class WmfOffsetViewportOrg implements HwmfRecord { |
| |
| protected final Point2D offset = new Point2D.Double(); |
| |
| @Override |
| public HwmfRecordType getWmfRecordType() { |
| return HwmfRecordType.offsetViewportOrg; |
| } |
| |
| @Override |
| public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { |
| return readPointS(leis, offset); |
| } |
| |
| @Override |
| public void draw(HwmfGraphics ctx) { |
| final HwmfDrawProperties prop = ctx.getProperties(); |
| Rectangle2D viewport = prop.getViewport(); |
| if (offset.getX() != 0 || offset.getY() != 0) { |
| double x = (viewport == null) ? 0 : viewport.getX(); |
| double y = (viewport == null) ? 0 : viewport.getY(); |
| prop.setViewportOrg(x + offset.getX(), y + offset.getY()); |
| ctx.updateWindowMapMode(); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return GenericRecordJsonWriter.marshal(this); |
| } |
| |
| public Point2D getOffset() { |
| return offset; |
| } |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties("offset", this::getOffset); |
| } |
| } |
| |
| /** |
| * The META_SETWINDOWORG record defines the output window origin in the playback device context. |
| */ |
| public static class WmfSetWindowOrg implements HwmfRecord { |
| |
| protected final Point2D origin = new Point2D.Double(); |
| |
| @Override |
| public HwmfRecordType getWmfRecordType() { |
| return HwmfRecordType.setWindowOrg; |
| } |
| |
| @Override |
| public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { |
| return readPointS(leis, origin); |
| } |
| |
| @Override |
| public void draw(HwmfGraphics ctx) { |
| final HwmfDrawProperties prop = ctx.getProperties(); |
| final Rectangle2D old = prop.getWindow(); |
| if (old.getX() != getX() || old.getY() != getY()) { |
| prop.setWindowOrg(getX(), getY()); |
| ctx.updateWindowMapMode(); |
| } |
| } |
| |
| public double getY() { |
| return origin.getY(); |
| } |
| |
| public double getX() { |
| return origin.getX(); |
| } |
| |
| @Override |
| public String toString() { |
| return GenericRecordJsonWriter.marshal(this); |
| } |
| |
| public Point2D getOrigin() { |
| return origin; |
| } |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties("origin", this::getOrigin); |
| } |
| |
| } |
| |
| /** |
| * The META_SETWINDOWEXT record defines the horizontal and vertical extents |
| * of the output window in the playback device context. |
| */ |
| public static class WmfSetWindowExt implements HwmfRecord { |
| |
| protected final Dimension2D size = new Dimension2DDouble(); |
| |
| @Override |
| public HwmfRecordType getWmfRecordType() { |
| return HwmfRecordType.setWindowExt; |
| } |
| |
| @Override |
| public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { |
| // A signed integer that defines the vertical extent of the window in logical units. |
| int height = leis.readShort(); |
| // A signed integer that defines the horizontal extent of the window in logical units. |
| int width = leis.readShort(); |
| size.setSize(width, height); |
| return 2*LittleEndianConsts.SHORT_SIZE; |
| } |
| |
| @Override |
| public void draw(HwmfGraphics ctx) { |
| final HwmfDrawProperties prop = ctx.getProperties(); |
| Rectangle2D old = prop.getWindow(); |
| double oldW = 0, oldH = 0; |
| if (old != null) { |
| oldW = old.getWidth(); |
| oldH = old.getHeight(); |
| } |
| if (oldW != size.getWidth() || oldH != size.getHeight()) { |
| prop.setWindowExt(size.getWidth(), size.getHeight()); |
| ctx.updateWindowMapMode(); |
| } |
| } |
| |
| public Dimension2D getSize() { |
| return size; |
| } |
| |
| @Override |
| public String toString() { |
| return GenericRecordJsonWriter.marshal(this); |
| } |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties("size", this::getSize); |
| } |
| } |
| |
| /** |
| * The META_OFFSETWINDOWORG record moves the output window origin in the |
| * playback device context by specified horizontal and vertical offsets. |
| */ |
| public static class WmfOffsetWindowOrg implements HwmfRecord { |
| |
| protected final Point2D offset = new Point2D.Double(); |
| |
| @Override |
| public HwmfRecordType getWmfRecordType() { |
| return HwmfRecordType.offsetWindowOrg; |
| } |
| |
| @Override |
| public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { |
| return readPointS(leis, offset); |
| } |
| |
| @Override |
| public void draw(HwmfGraphics ctx) { |
| final HwmfDrawProperties prop = ctx.getProperties(); |
| Rectangle2D old = prop.getWindow(); |
| if (offset.getX() != 0 || offset.getY() != 0) { |
| prop.setWindowOrg(old.getX() + offset.getX(), old.getY() + offset.getY()); |
| ctx.updateWindowMapMode(); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return GenericRecordJsonWriter.marshal(this); |
| } |
| |
| public Point2D getOffset() { |
| return offset; |
| } |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties("offset", this::getOffset); |
| } |
| } |
| |
| /** |
| * The META_OFFSETWINDOWORG record moves the output window origin in the |
| * playback device context by specified horizontal and vertical offsets. |
| */ |
| public static class WmfScaleWindowExt implements HwmfRecord { |
| |
| protected final Dimension2D scale = new Dimension2DDouble(); |
| |
| @Override |
| public HwmfRecordType getWmfRecordType() { |
| return HwmfRecordType.scaleWindowExt; |
| } |
| |
| @Override |
| public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { |
| // A signed integer that defines the amount by which to divide the |
| // result of multiplying the current y-extent by the value of the yNum member. |
| double yDenom = leis.readShort(); |
| // A signed integer that defines the amount by which to multiply the |
| // current y-extent. |
| double yNum = leis.readShort(); |
| // A signed integer that defines the amount by which to divide the |
| // result of multiplying the current x-extent by the value of the xNum member. |
| double xDenom = leis.readShort(); |
| // A signed integer that defines the amount by which to multiply the |
| // current x-extent. |
| double xNum = leis.readShort(); |
| |
| scale.setSize(xNum / xDenom, yNum / yDenom); |
| |
| return 4*LittleEndianConsts.SHORT_SIZE; |
| } |
| |
| @Override |
| public void draw(HwmfGraphics ctx) { |
| final HwmfDrawProperties prop = ctx.getProperties(); |
| Rectangle2D old = prop.getWindow(); |
| if (scale.getWidth() != 1.0 || scale.getHeight() != 1.0) { |
| double width = old.getWidth() * scale.getWidth(); |
| double height = old.getHeight() * scale.getHeight(); |
| ctx.getProperties().setWindowExt(width, height); |
| ctx.updateWindowMapMode(); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return GenericRecordJsonWriter.marshal(this); |
| } |
| |
| public Dimension2D getScale() { |
| return scale; |
| } |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties("scale", this::getScale); |
| } |
| |
| } |
| |
| |
| /** |
| * The META_SCALEVIEWPORTEXT record scales the horizontal and vertical extents of the viewport |
| * that is defined in the playback device context by using the ratios formed by the specified |
| * multiplicands and divisors. |
| */ |
| public static class WmfScaleViewportExt implements HwmfRecord { |
| |
| protected final Dimension2D scale = new Dimension2DDouble(); |
| |
| @Override |
| public HwmfRecordType getWmfRecordType() { |
| return HwmfRecordType.scaleViewportExt; |
| } |
| |
| @Override |
| public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { |
| // A signed integer that defines the amount by which to divide the |
| // result of multiplying the current y-extent by the value of the yNum member. |
| double yDenom = leis.readShort(); |
| // A signed integer that defines the amount by which to multiply the |
| // current y-extent. |
| double yNum = leis.readShort(); |
| // A signed integer that defines the amount by which to divide the |
| // result of multiplying the current x-extent by the value of the xNum member. |
| double xDenom = leis.readShort(); |
| // A signed integer that defines the amount by which to multiply the |
| // current x-extent. |
| double xNum = leis.readShort(); |
| |
| scale.setSize(xNum / xDenom, yNum / yDenom); |
| |
| return 4*LittleEndianConsts.SHORT_SIZE; |
| } |
| |
| @Override |
| public void draw(HwmfGraphics ctx) { |
| final HwmfDrawProperties prop = ctx.getProperties(); |
| final Rectangle2D old = prop.getViewport() == null ? prop.getWindow() : prop.getViewport(); |
| |
| if (scale.getWidth() != 1.0 || scale.getHeight() != 1.0) { |
| double width = old.getWidth() * scale.getWidth(); |
| double height = old.getHeight() * scale.getHeight(); |
| prop.setViewportExt(width, height); |
| ctx.updateWindowMapMode(); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return GenericRecordJsonWriter.marshal(this); |
| } |
| |
| public Dimension2D getScale() { |
| return scale; |
| } |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties("scale", this::getScale); |
| } |
| } |
| |
| /** |
| * The META_OFFSETCLIPRGN record moves the clipping region in the playback device context by the |
| * specified offsets. |
| */ |
| public static class WmfOffsetClipRgn implements HwmfRecord { |
| |
| protected final Point2D offset = new Point2D.Double(); |
| |
| @Override |
| public HwmfRecordType getWmfRecordType() { |
| return HwmfRecordType.offsetClipRgn; |
| } |
| |
| @Override |
| public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { |
| return readPointS(leis, offset); |
| } |
| |
| @Override |
| public void draw(HwmfGraphics ctx) { |
| final Shape oldClip = ctx.getProperties().getClip(); |
| if (oldClip == null) { |
| return; |
| } |
| AffineTransform at = new AffineTransform(); |
| at.translate(offset.getX(),offset.getY()); |
| final Shape newClip = at.createTransformedShape(oldClip); |
| ctx.setClip(newClip, HwmfRegionMode.RGN_COPY, false); |
| } |
| |
| @Override |
| public String toString() { |
| return GenericRecordJsonWriter.marshal(this); |
| } |
| |
| public Point2D getOffset() { |
| return offset; |
| } |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties("offset", this::getOffset); |
| } |
| |
| } |
| |
| /** |
| * The META_EXCLUDECLIPRECT record sets the clipping region in the playback device context to the |
| * existing clipping region minus the specified rectangle. |
| */ |
| public static class WmfExcludeClipRect implements HwmfRecord { |
| |
| /** a rectangle in logical units */ |
| protected final Rectangle2D bounds = new Rectangle2D.Double(); |
| |
| @Override |
| public HwmfRecordType getWmfRecordType() { |
| return HwmfRecordType.excludeClipRect; |
| } |
| |
| @Override |
| public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { |
| return readBounds(leis, bounds); |
| } |
| |
| @Override |
| public void draw(HwmfGraphics ctx) { |
| ctx.setClip(normalizeBounds(bounds), HwmfRegionMode.RGN_DIFF, false); |
| } |
| |
| @Override |
| public String toString() { |
| return GenericRecordJsonWriter.marshal(this); |
| } |
| |
| public Rectangle2D getBounds() { |
| return bounds; |
| } |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties("bounds", this::getBounds); |
| } |
| } |
| |
| |
| /** |
| * The META_INTERSECTCLIPRECT record sets the clipping region in the playback device context to the |
| * intersection of the existing clipping region and the specified rectangle. |
| */ |
| public static class WmfIntersectClipRect implements HwmfRecord { |
| |
| /** a rectangle in logical units */ |
| protected final Rectangle2D bounds = new Rectangle2D.Double(); |
| |
| @Override |
| public HwmfRecordType getWmfRecordType() { |
| return HwmfRecordType.intersectClipRect; |
| } |
| |
| @Override |
| public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { |
| return readBounds(leis, bounds); |
| } |
| |
| @Override |
| public void draw(HwmfGraphics ctx) { |
| ctx.setClip(bounds, HwmfRegionMode.RGN_AND, false); |
| } |
| |
| @Override |
| public String toString() { |
| return GenericRecordJsonWriter.marshal(this); |
| } |
| |
| public Rectangle2D getBounds() { |
| return bounds; |
| } |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties("bounds", this::getBounds); |
| } |
| } |
| |
| /** |
| * The META_SELECTCLIPREGION record specifies a Region Object to be the current clipping region. |
| */ |
| public static class WmfSelectClipRegion implements HwmfRecord { |
| |
| /** |
| * A 16-bit unsigned integer used to index into the WMF Object Table to get |
| * the region to be clipped. |
| */ |
| private int region; |
| |
| @Override |
| public HwmfRecordType getWmfRecordType() { |
| return HwmfRecordType.selectClipRegion; |
| } |
| |
| @Override |
| public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { |
| region = leis.readShort(); |
| return LittleEndianConsts.SHORT_SIZE; |
| } |
| |
| @Override |
| public void draw(HwmfGraphics ctx) { |
| |
| } |
| |
| public int getRegion() { |
| return region; |
| } |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties("region", this::getRegion); |
| } |
| } |
| |
| public static class WmfScanObject implements GenericRecord { |
| /** |
| * A 16-bit unsigned integer that specifies the number of horizontal (x-axis) |
| * coordinates in the ScanLines array. This value MUST be a multiple of 2, since left and right |
| * endpoints are required to specify each scanline. |
| */ |
| private int count; |
| /** |
| * A 16-bit unsigned integer that defines the vertical (y-axis) coordinate, in logical units, of the top scanline. |
| */ |
| private int top; |
| /** |
| * A 16-bit unsigned integer that defines the vertical (y-axis) coordinate, in logical units, of the bottom scanline. |
| */ |
| private int bottom; |
| /** |
| * A 16-bit unsigned integer that defines the horizontal (x-axis) coordinate, |
| * in logical units, of the left endpoint of the scanline. |
| */ |
| private int[] left_scanline; |
| /** |
| * A 16-bit unsigned integer that defines the horizontal (x-axis) coordinate, |
| * in logical units, of the right endpoint of the scanline. |
| */ |
| private int[] right_scanline; |
| /** |
| * A 16-bit unsigned integer that MUST be the same as the value of the Count |
| * field; it is present to allow upward travel in the structure. |
| */ |
| private int count2; |
| |
| public int init(LittleEndianInputStream leis) { |
| count = leis.readUShort(); |
| top = leis.readUShort(); |
| bottom = leis.readUShort(); |
| int size = 3*LittleEndianConsts.SHORT_SIZE; |
| left_scanline = new int[count/2]; |
| right_scanline = new int[count/2]; |
| for (int i=0; i<count/2; i++) { |
| left_scanline[i] = leis.readUShort(); |
| right_scanline[i] = leis.readUShort(); |
| size += 2*LittleEndianConsts.SHORT_SIZE; |
| } |
| count2 = leis.readUShort(); |
| size += LittleEndianConsts.SHORT_SIZE; |
| return size; |
| } |
| |
| @SuppressWarnings("ArraysAsListWithZeroOrOneArgument") |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties( |
| "count", () -> count, |
| "top", () -> top, |
| "bottom", () -> bottom, |
| "left_scanline", () -> Arrays.asList(left_scanline), |
| "right_scanline", () -> Arrays.asList(right_scanline), |
| "count2", () -> count2 |
| ); |
| } |
| } |
| |
| public static class WmfCreateRegion implements HwmfRecord, HwmfObjectTableEntry { |
| /** |
| * A 16-bit signed integer. A value that MUST be ignored. |
| */ |
| private int nextInChain; |
| /** |
| * A 16-bit signed integer that specifies the region identifier. It MUST be 0x0006. |
| */ |
| private int objectType; |
| /** |
| * A 32-bit unsigned integer. A value that MUST be ignored. |
| */ |
| private int objectCount; |
| /** |
| * A 16-bit signed integer that defines the size of the region in bytes plus the size of aScans in bytes. |
| */ |
| private int regionSize; |
| /** |
| * A 16-bit signed integer that defines the number of scanlines composing the region. |
| */ |
| private int scanCount; |
| |
| /** |
| * A 16-bit signed integer that defines the maximum number of points in any one scan in this region. |
| */ |
| private int maxScan; |
| |
| private final Rectangle2D bounds = new Rectangle2D.Double(); |
| |
| /** |
| * An array of Scan objects that define the scanlines in the region. |
| */ |
| private WmfScanObject[] scanObjects; |
| |
| @Override |
| public HwmfRecordType getWmfRecordType() { |
| return HwmfRecordType.createRegion; |
| } |
| |
| @Override |
| public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { |
| nextInChain = leis.readShort(); |
| objectType = leis.readShort(); |
| objectCount = leis.readInt(); |
| regionSize = leis.readShort(); |
| scanCount = leis.readShort(); |
| maxScan = leis.readShort(); |
| // A 16-bit signed integer that defines the x-coordinate, in logical units, of the |
| // upper-left corner of the rectangle. |
| double left = leis.readShort(); |
| // A 16-bit signed integer that defines the y-coordinate, in logical units, of the |
| // upper-left corner of the rectangle. |
| double top = leis.readShort(); |
| // A 16-bit signed integer that defines the x-coordinate, in logical units, of the |
| // lower-right corner of the rectangle. |
| double right = leis.readShort(); |
| // A 16-bit signed integer that defines the y-coordinate, in logical units, of the |
| // lower-right corner of the rectangle. |
| double bottom = leis.readShort(); |
| bounds.setRect(left, top, right-left, bottom-top); |
| |
| int size = 9*LittleEndianConsts.SHORT_SIZE+LittleEndianConsts.INT_SIZE; |
| |
| scanObjects = new WmfScanObject[scanCount]; |
| for (int i=0; i<scanCount; i++) { |
| size += (scanObjects[i] = new WmfScanObject()).init(leis); |
| } |
| |
| return size; |
| } |
| |
| @Override |
| public void draw(HwmfGraphics ctx) { |
| ctx.addObjectTableEntry(this); |
| } |
| |
| @Override |
| public void applyObject(HwmfGraphics ctx) { |
| Rectangle2D lastRect = null; |
| Area scanLines = new Area(); |
| int count = 0; |
| for (WmfScanObject so : scanObjects) { |
| int y = Math.min(so.top, so.bottom); |
| int h = Math.abs(so.top - so.bottom - 1); |
| for (int i=0; i<so.count/2; i++) { |
| int x = Math.min(so.left_scanline[i], so.right_scanline[i]); |
| int w = Math.abs(so.right_scanline[i] - so.left_scanline[i] - 1); |
| lastRect = new Rectangle2D.Double(x,y,w,h); |
| scanLines.add(new Area(lastRect)); |
| count++; |
| } |
| } |
| |
| Shape region = null; |
| if (count > 0) { |
| region = (count == 1) ? lastRect : scanLines; |
| } |
| |
| ctx.getProperties().setRegion(region); |
| } |
| |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| final Map<String,Supplier<?>> m = new LinkedHashMap<>(); |
| m.put("nextInChain", () -> nextInChain); |
| m.put("objectType", () -> objectType); |
| m.put("objectCount", () -> objectCount); |
| m.put("regionSize", () -> regionSize); |
| m.put("scanCount", () -> scanCount); |
| m.put("maxScan", () -> maxScan); |
| m.put("bounds", () -> bounds); |
| m.put("scanObjects", () -> Arrays.asList(scanObjects)); |
| return Collections.unmodifiableMap(m); |
| } |
| } |
| } |