123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843 |
- /* ====================================================================
- 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 java.awt.Shape;
- import java.awt.geom.Arc2D;
- import java.awt.geom.Area;
- import java.awt.geom.Dimension2D;
- import java.awt.geom.Ellipse2D;
- import java.awt.geom.Line2D;
- import java.awt.geom.Path2D;
- import java.awt.geom.Point2D;
- import java.awt.geom.Rectangle2D;
- import java.awt.geom.RoundRectangle2D;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Map;
- import java.util.function.Supplier;
-
- import org.apache.poi.hwmf.draw.HwmfGraphics;
- import org.apache.poi.hwmf.draw.HwmfGraphics.FillDrawStyle;
- import org.apache.poi.util.Dimension2DDouble;
- import org.apache.poi.util.GenericRecordJsonWriter;
- import org.apache.poi.util.GenericRecordUtil;
- import org.apache.poi.util.Internal;
- import org.apache.poi.util.LittleEndianConsts;
- import org.apache.poi.util.LittleEndianInputStream;
-
- @SuppressWarnings("WeakerAccess")
- public final class HwmfDraw {
-
- private HwmfDraw() {}
-
- /**
- * The META_MOVETO record sets the output position in the playback device context to a specified
- * point.
- */
- public static class WmfMoveTo implements HwmfRecord {
-
- protected final Point2D point = new Point2D.Double();
-
- @Override
- public HwmfRecordType getWmfRecordType() {
- return HwmfRecordType.moveTo;
- }
-
- @Override
- public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- return readPointS(leis, point);
- }
-
- @Override
- public void draw(HwmfGraphics ctx) {
- ctx.getProperties().setLocation(point);
- }
-
- @Override
- public String toString() {
- return GenericRecordJsonWriter.marshal(this);
- }
-
- public Point2D getPoint() {
- return point;
- }
-
- @Override
- public Map<String, Supplier<?>> getGenericProperties() {
- return GenericRecordUtil.getGenericProperties("point", this::getPoint);
- }
- }
-
- /**
- * The META_LINETO record draws a line from the drawing position that is defined in the playback
- * device context up to, but not including, the specified point.
- */
- public static class WmfLineTo implements HwmfRecord {
-
- protected final Point2D point = new Point2D.Double();
-
- @Override
- public HwmfRecordType getWmfRecordType() {
- return HwmfRecordType.lineTo;
- }
-
- @Override
- public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- return readPointS(leis, point);
- }
-
- @Override
- public void draw(HwmfGraphics ctx) {
- Point2D start = ctx.getProperties().getLocation();
- Line2D line = new Line2D.Double(start, point);
- ctx.draw(line);
- ctx.getProperties().setLocation(point);
- }
-
- @Override
- public String toString() {
- return GenericRecordJsonWriter.marshal(this);
- }
-
- public Point2D getPoint() {
- return point;
- }
-
- @Override
- public Map<String, Supplier<?>> getGenericProperties() {
- return GenericRecordUtil.getGenericProperties("point", this::getPoint);
- }
- }
-
- /**
- * The META_POLYGON record paints a polygon consisting of two or more vertices connected by
- * straight lines. The polygon is outlined by using the pen and filled by using the brush and polygon fill
- * mode that are defined in the playback device context.
- */
- public static class WmfPolygon implements HwmfRecord {
-
- protected Path2D poly;
-
- @Override
- public HwmfRecordType getWmfRecordType() {
- return HwmfRecordType.polygon;
- }
-
- @Override
- public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- //A 16-bit signed integer that defines the number of points in the array.
- int numberOfPoints = leis.readShort();
-
- poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, numberOfPoints);
- for (int i=0; i<numberOfPoints; i++) {
- // A 16-bit signed integer that defines the horizontal (x) coordinate of the point.
- int x = leis.readShort();
- // A 16-bit signed integer that defines the vertical (y) coordinate of the point.
- int y = leis.readShort();
- if (i==0) {
- poly.moveTo(x, y);
- } else {
- poly.lineTo(x, y);
- }
- }
-
- if (numberOfPoints > 0 && addClose()) {
- // polygons are closed / polylines not
- poly.closePath();
- }
-
- return LittleEndianConsts.SHORT_SIZE+numberOfPoints*LittleEndianConsts.INT_SIZE;
- }
-
- @Override
- public void draw(HwmfGraphics ctx) {
- Path2D p = (Path2D)poly.clone();
- // don't close the path
- p.setWindingRule(ctx.getProperties().getWindingRule());
- getFillDrawStyle().handler.accept(ctx, p);
- }
-
- @Override
- public String toString() {
- return GenericRecordJsonWriter.marshal(this);
- }
-
- /**
- * @return true, if the shape should be filled
- */
- protected FillDrawStyle getFillDrawStyle() {
- return FillDrawStyle.FILL;
- }
-
- public Path2D getPoly() {
- return poly;
- }
-
- /**
- * @return {@code true} if the path needs to be closed
- */
- protected boolean addClose() {
- return true;
- }
-
- @Override
- public Map<String, Supplier<?>> getGenericProperties() {
- return GenericRecordUtil.getGenericProperties("poly", this::getPoly);
- }
- }
-
- /**
- * The META_POLYLINE record draws a series of line segments by connecting the points in the
- * specified array.
- */
- public static class WmfPolyline extends WmfPolygon {
-
- @Override
- public HwmfRecordType getWmfRecordType() {
- return HwmfRecordType.polyline;
- }
-
- @Override
- protected FillDrawStyle getFillDrawStyle() {
- return FillDrawStyle.DRAW;
- }
-
- @Override
- protected boolean addClose() {
- return false;
- }
- }
-
- /**
- * The META_ELLIPSE record draws an ellipse. The center of the ellipse is the center of the specified
- * bounding rectangle. The ellipse is outlined by using the pen and is filled by using the brush; these
- * are defined in the playback device context.
- */
- public static class WmfEllipse implements HwmfRecord {
- protected final Rectangle2D bounds = new Rectangle2D.Double();
-
- @Override
- public HwmfRecordType getWmfRecordType() {
- return HwmfRecordType.ellipse;
- }
-
- @Override
- public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- return readBounds(leis, bounds);
- }
-
- @Override
- public void draw(HwmfGraphics ctx) {
- ctx.fill(getShape());
- }
-
- protected Ellipse2D getShape() {
- return new Ellipse2D.Double(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight());
- }
-
- @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_FRAMEREGION record draws a border around a specified region using a specified brush.
- */
- public static class WmfFrameRegion implements HwmfRecord {
- /**
- * A 16-bit unsigned integer used to index into the WMF Object Table to get
- * the region to be framed.
- */
- protected int regionIndex;
- /**
- * A 16-bit unsigned integer used to index into the WMF Object Table to get the
- * Brush to use for filling the region.
- */
- protected int brushIndex;
-
- /**
- * The region frame, in logical units
- */
- protected final Dimension2D frame = new Dimension2DDouble();
-
- @Override
- public HwmfRecordType getWmfRecordType() {
- return HwmfRecordType.frameRegion;
- }
-
- @Override
- public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- regionIndex = leis.readUShort();
- brushIndex = leis.readUShort();
- // A 16-bit signed integer that defines the height/width, in logical units, of the region frame.
- int height = leis.readShort();
- int width = leis.readShort();
- frame.setSize(width, height);
- return 4*LittleEndianConsts.SHORT_SIZE;
- }
-
- @Override
- public void draw(HwmfGraphics ctx) {
- ctx.applyObjectTableEntry(brushIndex);
- ctx.applyObjectTableEntry(regionIndex);
- Rectangle2D inner = ctx.getProperties().getRegion().getBounds();
- double x = inner.getX()-frame.getWidth();
- double y = inner.getY()-frame.getHeight();
- double w = inner.getWidth()+2.0*frame.getWidth();
- double h = inner.getHeight()+2.0*frame.getHeight();
- Rectangle2D outer = new Rectangle2D.Double(x,y,w,h);
- Area frame = new Area(outer);
- frame.subtract(new Area(inner));
- ctx.fill(frame);
- }
-
- public int getRegionIndex() {
- return regionIndex;
- }
-
- public int getBrushIndex() {
- return brushIndex;
- }
-
- public Dimension2D getFrame() {
- return frame;
- }
-
- @Override
- public Map<String, Supplier<?>> getGenericProperties() {
- return GenericRecordUtil.getGenericProperties(
- "regionIndex", this::getRegionIndex,
- "brushIndex", this::getBrushIndex,
- "frame", this::getFrame);
- }
- }
-
- /**
- * The META_POLYPOLYGON record paints a series of closed polygons. Each polygon is outlined by
- * using the pen and filled by using the brush and polygon fill mode; these are defined in the playback
- * device context. The polygons drawn by this function can overlap.
- */
- public static class WmfPolyPolygon implements HwmfRecord {
-
- protected final List<Path2D> polyList = new ArrayList<>();
-
- @Override
- public HwmfRecordType getWmfRecordType() {
- return HwmfRecordType.polyPolygon;
- }
-
- @Override
- public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- // see also CVE-2008-3014 - https://dl.packetstormsecurity.net/papers/attack/CVE-2008-3014.pdf ;)
- // A 16-bit unsigned integer that defines the number of polygons in the object.
- int numberOfPolygons = leis.readUShort();
- // A NumberOfPolygons array of 16-bit unsigned integers that define the number of points for
- // each polygon in the object.
- int[] pointsPerPolygon = new int[numberOfPolygons];
-
- int size = LittleEndianConsts.SHORT_SIZE;
-
- for (int i=0; i<numberOfPolygons; i++) {
- pointsPerPolygon[i] = leis.readUShort();
- size += LittleEndianConsts.SHORT_SIZE;
- }
-
- for (int nPoints : pointsPerPolygon) {
- // An array of 16-bit signed integers that define the coordinates of the polygons.
- // (Note: MS-WMF wrongly says unsigned integers ...)
- Path2D poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, nPoints);
- for (int i=0; i<nPoints; i++) {
- int x = leis.readShort();
- int y = leis.readShort();
- size += 2*LittleEndianConsts.SHORT_SIZE;
- if (i == 0) {
- poly.moveTo(x, y);
- } else {
- poly.lineTo(x, y);
- }
- }
- poly.closePath();
- polyList.add(poly);
- }
-
- return size;
- }
-
- @Override
- public void draw(HwmfGraphics ctx) {
- Shape shape = getShape(ctx);
- if (shape == null) {
- return;
- }
-
- switch (getFillDrawStyle()) {
- case DRAW:
- ctx.draw(shape);
- break;
- case FILL:
- ctx.fill(shape);
- break;
- case FILL_DRAW:
- ctx.fill(shape);
- ctx.draw(shape);
- break;
- }
- }
-
- protected FillDrawStyle getFillDrawStyle() {
- // Each polygon SHOULD be outlined using the current pen, and filled using the current brush and
- // polygon fill mode that are defined in the playback device context. The polygons defined by this
- // record can overlap.
- return FillDrawStyle.FILL_DRAW;
- }
-
- /**
- * @return true, if a polyline should be closed, i.e. is a polygon
- */
- protected boolean isClosed() {
- return true;
- }
-
- protected Shape getShape(HwmfGraphics ctx) {
- int windingRule = ctx.getProperties().getWindingRule();
-
- if (isClosed()) {
- Area area = null;
- for (Path2D poly : polyList) {
- Path2D p = (Path2D)poly.clone();
- p.setWindingRule(windingRule);
- Area newArea = new Area(p);
- if (area == null) {
- area = newArea;
- } else {
- area.exclusiveOr(newArea);
- }
- }
- return area;
- } else {
- Path2D path = new Path2D.Double();
- path.setWindingRule(windingRule);
- for (Path2D poly : polyList) {
- path.append(poly, false);
- }
- return path;
- }
- }
-
- @Override
- public String toString() {
- return GenericRecordJsonWriter.marshal(this);
- }
-
- public List<Path2D> getPolyList() {
- return polyList;
- }
-
- @Override
- public Map<String, Supplier<?>> getGenericProperties() {
- return GenericRecordUtil.getGenericProperties("polyList", this::getPolyList);
- }
- }
-
- /**
- * The META_RECTANGLE record paints a rectangle. The rectangle is outlined by using the pen and
- * filled by using the brush that are defined in the playback device context.
- */
- public static class WmfRectangle implements HwmfRecord {
- protected final Rectangle2D bounds = new Rectangle2D.Double();
-
- @Override
- public HwmfRecordType getWmfRecordType() {
- return HwmfRecordType.rectangle;
- }
-
- @Override
- public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- return readBounds(leis, bounds);
- }
-
- @Override
- public void draw(HwmfGraphics ctx) {
- ctx.fill(bounds);
- }
-
- @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_SETPIXEL record sets the pixel at the specified coordinates to the specified color.
- */
- public static class WmfSetPixel implements HwmfRecord {
- /**
- * A ColorRef Object that defines the color value.
- */
- protected final HwmfColorRef colorRef = new HwmfColorRef();
-
- protected final Point2D point = new Point2D.Double();
-
-
- @Override
- public HwmfRecordType getWmfRecordType() {
- return HwmfRecordType.setPixel;
- }
-
- @Override
- public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- int size = colorRef.init(leis);
- return size+ readPointS(leis, point);
- }
-
- @Override
- public void draw(HwmfGraphics ctx) {
- Shape s = new Rectangle2D.Double(point.getX(), point.getY(), 1, 1);
- ctx.fill(s);
- }
-
- public HwmfColorRef getColorRef() {
- return colorRef;
- }
-
- public Point2D getPoint() {
- return point;
- }
-
- @Override
- public Map<String, Supplier<?>> getGenericProperties() {
- return GenericRecordUtil.getGenericProperties(
- "colorRef", this::getColorRef,
- "point", this::getPoint
- );
- }
- }
-
- /**
- * The META_ROUNDRECT record paints a rectangle with rounded corners. The rectangle is outlined
- * using the pen and filled using the brush, as defined in the playback device context.
- */
- public static class WmfRoundRect implements HwmfRecord {
- protected final Dimension2D corners = new Dimension2DDouble();
-
- protected final Rectangle2D bounds = new Rectangle2D.Double();
-
-
- @Override
- public HwmfRecordType getWmfRecordType() {
- return HwmfRecordType.roundRect;
- }
-
- @Override
- public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- // A 16-bit signed integer that defines the height/width, in logical coordinates,
- // of the ellipse used to draw the rounded corners.
- int height = leis.readShort();
- int width = leis.readShort();
- corners.setSize(width, height);
- return 2*LittleEndianConsts.SHORT_SIZE+readBounds(leis, bounds);
- }
-
- @Override
- public void draw(HwmfGraphics ctx) {
- ctx.fill(getShape());
- }
-
- protected RoundRectangle2D getShape() {
- return new RoundRectangle2D.Double(
- bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(),
- corners.getWidth(), corners.getHeight()
- );
- }
-
- public Dimension2D getCorners() {
- return corners;
- }
-
- public Rectangle2D getBounds() {
- return bounds;
- }
-
- @Override
- public Map<String, Supplier<?>> getGenericProperties() {
- return GenericRecordUtil.getGenericProperties(
- "bounds", this::getBounds,
- "corners", this::getCorners
- );
- }
-
- }
-
-
- /**
- * The META_ARC record draws an elliptical arc.
- */
- public static class WmfArc implements HwmfRecord {
- public enum WmfArcClosure {
- ARC(HwmfRecordType.arc, Arc2D.OPEN, FillDrawStyle.DRAW),
- CHORD(HwmfRecordType.chord, Arc2D.CHORD, FillDrawStyle.FILL_DRAW),
- PIE(HwmfRecordType.pie, Arc2D.PIE, FillDrawStyle.FILL_DRAW);
-
- public final HwmfRecordType recordType;
- public final int awtType;
- public final FillDrawStyle drawStyle;
-
- WmfArcClosure(HwmfRecordType recordType, int awtType, FillDrawStyle drawStyle) {
- this.recordType = recordType;
- this.awtType = awtType;
- this.drawStyle = drawStyle;
- }
- }
-
- /** starting point of the arc */
- protected final Point2D startPoint = new Point2D.Double();
-
- /** ending point of the arc */
- protected final Point2D endPoint = new Point2D.Double();
-
- /** the bounding rectangle */
- protected final Rectangle2D bounds = new Rectangle2D.Double();
-
-
- @Override
- public HwmfRecordType getWmfRecordType() {
- return HwmfRecordType.arc;
- }
-
- @Override
- public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- readPointS(leis, endPoint);
- readPointS(leis, startPoint);
- readBounds(leis, bounds);
-
- return 8*LittleEndianConsts.SHORT_SIZE;
- }
-
- @Override
- public void draw(HwmfGraphics ctx) {
- getFillDrawStyle().handler.accept(ctx, getShape());
- }
-
- public WmfArcClosure getArcClosure() {
- switch (getWmfRecordType()) {
- default:
- case arc:
- return WmfArcClosure.ARC;
- case chord:
- return WmfArcClosure.CHORD;
- case pie:
- return WmfArcClosure.PIE;
- }
- }
-
- protected FillDrawStyle getFillDrawStyle() {
- return getArcClosure().drawStyle;
- }
-
- protected Arc2D getShape() {
- double startAngle = Math.toDegrees(Math.atan2(-(startPoint.getY() - bounds.getCenterY()), startPoint.getX() - bounds.getCenterX()));
- double endAngle = Math.toDegrees(Math.atan2(-(endPoint.getY() - bounds.getCenterY()), endPoint.getX() - bounds.getCenterX()));
- double arcAngle = (endAngle - startAngle) + (endAngle - startAngle > 0 ? 0 : 360);
- if (startAngle < 0) {
- startAngle += 360;
- }
-
- return new Arc2D.Double(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(),
- startAngle, arcAngle, getArcClosure().awtType);
- }
-
- @Override
- public String toString() {
- return GenericRecordJsonWriter.marshal(this);
- }
-
- public Point2D getStartPoint() {
- return startPoint;
- }
-
- public Point2D getEndPoint() {
- return endPoint;
- }
-
- public Rectangle2D getBounds() {
- return bounds;
- }
-
- @Override
- public Map<String, Supplier<?>> getGenericProperties() {
- final Arc2D arc = getShape();
- return GenericRecordUtil.getGenericProperties(
- "startPoint", this::getStartPoint,
- "endPoint", this::getEndPoint,
- "startAngle", arc::getAngleStart,
- "extentAngle", arc::getAngleExtent,
- "bounds", this::getBounds
- );
- }
- }
-
- /**
- * The META_PIE record draws a pie-shaped wedge bounded by the intersection of an ellipse and two
- * radials. The pie is outlined by using the pen and filled by using the brush that are defined in the
- * playback device context.
- */
- public static class WmfPie extends WmfArc {
-
- @Override
- public HwmfRecordType getWmfRecordType() {
- return HwmfRecordType.pie;
- }
- }
-
- /**
- * The META_CHORD record draws a chord, which is defined by a region bounded by the intersection of
- * an ellipse with a line segment. The chord is outlined using the pen and filled using the brush
- * that are defined in the playback device context.
- */
- public static class WmfChord extends WmfArc {
-
- @Override
- public HwmfRecordType getWmfRecordType() {
- return HwmfRecordType.chord;
- }
- }
-
-
- /**
- * The META_SELECTOBJECT record specifies a graphics object for the playback device context. The
- * new object replaces the previous object of the same type, unless if the previous object is a palette
- * object. If the previous object is a palette object, then the META_SELECTPALETTE record must be
- * used instead of the META_SELECTOBJECT record, as the META_SELECTOBJECT record does not
- * support replacing the palette object type.
- */
- public static class WmfSelectObject implements HwmfRecord {
-
- /**
- * A 16-bit unsigned integer used to index into the WMF Object Table to
- * get the object to be selected.
- */
- protected int objectIndex;
-
- @Override
- public HwmfRecordType getWmfRecordType() {
- return HwmfRecordType.selectObject;
- }
-
- @Override
- public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- objectIndex = leis.readUShort();
- return LittleEndianConsts.SHORT_SIZE;
- }
-
- @Override
- public void draw(HwmfGraphics ctx) {
- ctx.applyObjectTableEntry(objectIndex);
- }
-
- @Override
- public String toString() {
- return GenericRecordJsonWriter.marshal(this);
- }
-
- public int getObjectIndex() {
- return objectIndex;
- }
-
- @Override
- public Map<String, Supplier<?>> getGenericProperties() {
- return GenericRecordUtil.getGenericProperties("objectIndex", this::getObjectIndex);
- }
- }
-
- @SuppressWarnings("DuplicatedCode")
- static int readBounds(LittleEndianInputStream leis, Rectangle2D bounds) {
- // The 16-bit signed integers that defines the corners of the bounding rectangle.
- int bottom = leis.readShort();
- int right = leis.readShort();
- int top = leis.readShort();
- int left = leis.readShort();
-
- int x = Math.min(left, right);
- int y = Math.min(top, bottom);
- int w = Math.abs(left - right - 1);
- int h = Math.abs(top - bottom - 1);
-
- bounds.setRect(x, y, w, h);
-
- return 4 * LittleEndianConsts.SHORT_SIZE;
- }
-
- @SuppressWarnings("DuplicatedCode")
- static int readRectS(LittleEndianInputStream leis, Rectangle2D bounds) {
- // The 16-bit signed integers that defines the corners of the bounding rectangle.
- int left = leis.readShort();
- int top = leis.readShort();
- int right = leis.readShort();
- int bottom = leis.readShort();
-
- int x = Math.min(left, right);
- int y = Math.min(top, bottom);
- int w = Math.abs(left - right - 1);
- int h = Math.abs(top - bottom - 1);
-
- bounds.setRect(x, y, w, h);
-
- return 4 * LittleEndianConsts.SHORT_SIZE;
- }
-
- static int readPointS(LittleEndianInputStream leis, Point2D point) {
- // a signed integer that defines the x/y-coordinate, in logical units.
- int y = leis.readShort();
- int x = leis.readShort();
- point.setLocation(x, y);
- return 2*LittleEndianConsts.SHORT_SIZE;
- }
-
- @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())
- );
- }
- }
|