Search in sources :

Example 1 with PolyTree

use of com.itextpdf.kernel.pdf.canvas.parser.clipper.PolyTree in project i7j-pdfsweep by itext.

the class PdfCleanUpFilter method checkIfRectanglesIntersect.

/**
 * Return true if two given rectangles (specified by an array of points) intersect.
 *
 * @param rect1 the first rectangle, considered as a subject of intersection. Even if it's width is zero,
 *              it still can be intersected by second rectangle.
 * @param rect2 the second rectangle, considered as intersecting rectangle. If it has zero width rectangles
 *              are never considered as intersecting.
 * @return true if the rectangles intersect, false otherwise
 */
static boolean checkIfRectanglesIntersect(Point[] rect1, Point[] rect2) {
    IClipper clipper = new DefaultClipper();
    // If the redaction area is degenerate, the result will be false
    if (!ClipperBridge.addPolygonToClipper(clipper, rect2, PolyType.CLIP)) {
        // If the content area is degenerate, let's process this case specifically
        if (!ClipperBridge.addPolygonToClipper(clipper, rect1, PolyType.SUBJECT)) {
            // because the redaction line corresponds to the descent line of the content.
            if (!ClipperBridge.addPolylineSubjectToClipper(clipper, rect2)) {
                return false;
            }
            if (rect1.length != rect2.length) {
                return false;
            }
            Point startPoint = rect2[0];
            Point endPoint = rect2[0];
            for (int i = 1; i < rect2.length; i++) {
                if (rect2[i].distance(startPoint) > EPS) {
                    endPoint = rect2[i];
                    break;
                }
            }
            for (int i = 0; i < rect1.length; i++) {
                if (isPointOnALineSegment(rect1[i], startPoint, endPoint, true)) {
                    return true;
                }
            }
        }
        return false;
    }
    // According to clipper documentation:
    // The function will return false if the path is invalid for clipping. A path is invalid for clipping when:
    // - it has less than 2 vertices;
    // - it has 2 vertices but is not an open path;
    // - the vertices are all co-linear and it is not an open path.
    // Reference: http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/ClipperBase/Methods/AddPath.htm
    // If addition returns false, this means that there are less than 3 distinct points, because of rectangle zero width.
    // Let's in this case specify the path as polyline, because we still want to know if redaction area
    // intersects even with zero-width rectangles.
    boolean intersectionSubjectAdded = ClipperBridge.addPolygonToClipper(clipper, rect1, PolyType.SUBJECT);
    if (intersectionSubjectAdded) {
        // working with paths is considered to be a bit faster in terms of performance.
        Paths paths = new Paths();
        clipper.execute(ClipType.INTERSECTION, paths, PolyFillType.NON_ZERO, PolyFillType.NON_ZERO);
        return !checkIfIntersectionRectangleDegenerate(paths.getBounds(), false) && !paths.isEmpty();
    } else {
        int rect1Size = rect1.length;
        intersectionSubjectAdded = ClipperBridge.addPolylineSubjectToClipper(clipper, rect1);
        if (!intersectionSubjectAdded) {
            // According to the comment above,
            // this could have happened only if all four passed points are actually the same point.
            // Adding here a point really close to the original point, to make sure it's not covered by the
            // intersecting rectangle.
            double smallDiff = 0.01;
            List<Point> rect1List = new ArrayList<Point>(Arrays.asList(rect1));
            rect1List.add(new Point(rect1[0].getX() + smallDiff, rect1[0].getY()));
            rect1 = rect1List.toArray(new Point[rect1Size]);
            intersectionSubjectAdded = ClipperBridge.addPolylineSubjectToClipper(clipper, rect1);
            assert intersectionSubjectAdded;
        }
        PolyTree polyTree = new PolyTree();
        clipper.execute(ClipType.INTERSECTION, polyTree, PolyFillType.NON_ZERO, PolyFillType.NON_ZERO);
        Paths paths = Paths.makePolyTreeToPaths(polyTree);
        return !checkIfIntersectionRectangleDegenerate(paths.getBounds(), true) && !paths.isEmpty();
    }
}
Also used : PolyTree(com.itextpdf.kernel.pdf.canvas.parser.clipper.PolyTree) DefaultClipper(com.itextpdf.kernel.pdf.canvas.parser.clipper.DefaultClipper) ArrayList(java.util.ArrayList) IClipper(com.itextpdf.kernel.pdf.canvas.parser.clipper.IClipper) Point(com.itextpdf.kernel.geom.Point) Paths(com.itextpdf.kernel.pdf.canvas.parser.clipper.Paths) Point(com.itextpdf.kernel.geom.Point)

Example 2 with PolyTree

use of com.itextpdf.kernel.pdf.canvas.parser.clipper.PolyTree in project i7j-pdfsweep by itext.

the class PdfCleanUpFilter method filterFillPath.

/**
 * Note: this method will close all unclosed subpaths of the passed path.
 *
 * @param path        the PathRenderInfo object to be filtered.
 * @param ctm         a {@link com.itextpdf.kernel.geom.Path} transformation matrix.
 * @param fillingRule If the subpath is contour, pass any value.
 * @return a filtered {@link com.itextpdf.kernel.geom.Path} object.
 */
private com.itextpdf.kernel.geom.Path filterFillPath(com.itextpdf.kernel.geom.Path path, Matrix ctm, int fillingRule) {
    path.closeAllSubpaths();
    IClipper clipper = new DefaultClipper();
    ClipperBridge.addPath(clipper, path, PolyType.SUBJECT);
    for (Rectangle rectangle : regions) {
        try {
            Point[] transfRectVertices = transformPoints(ctm, true, getRectangleVertices(rectangle));
            ClipperBridge.addPolygonToClipper(clipper, transfRectVertices, PolyType.CLIP);
        } catch (PdfException e) {
            if (!(e.getCause() instanceof NoninvertibleTransformException)) {
                throw e;
            } else {
                logger.error(MessageFormatUtil.format(CleanUpLogMessageConstant.FAILED_TO_PROCESS_A_TRANSFORMATION_MATRIX));
            }
        }
    }
    PolyFillType fillType = PolyFillType.NON_ZERO;
    if (fillingRule == PdfCanvasConstants.FillingRule.EVEN_ODD) {
        fillType = PolyFillType.EVEN_ODD;
    }
    PolyTree resultTree = new PolyTree();
    clipper.execute(ClipType.DIFFERENCE, resultTree, fillType, PolyFillType.NON_ZERO);
    return ClipperBridge.convertToPath(resultTree);
}
Also used : NoninvertibleTransformException(com.itextpdf.kernel.geom.NoninvertibleTransformException) PdfException(com.itextpdf.kernel.exceptions.PdfException) PolyTree(com.itextpdf.kernel.pdf.canvas.parser.clipper.PolyTree) DefaultClipper(com.itextpdf.kernel.pdf.canvas.parser.clipper.DefaultClipper) Rectangle(com.itextpdf.kernel.geom.Rectangle) IClipper(com.itextpdf.kernel.pdf.canvas.parser.clipper.IClipper) Point(com.itextpdf.kernel.geom.Point) PolyFillType(com.itextpdf.kernel.pdf.canvas.parser.clipper.IClipper.PolyFillType)

Example 3 with PolyTree

use of com.itextpdf.kernel.pdf.canvas.parser.clipper.PolyTree in project i7j-pdfsweep by itext.

the class PdfCleanUpFilter method filterStrokePath.

private com.itextpdf.kernel.geom.Path filterStrokePath(com.itextpdf.kernel.geom.Path sourcePath, Matrix ctm, float lineWidth, int lineCapStyle, int lineJoinStyle, float miterLimit, LineDashPattern lineDashPattern) {
    com.itextpdf.kernel.geom.Path path = sourcePath;
    JoinType joinType = ClipperBridge.getJoinType(lineJoinStyle);
    EndType endType = ClipperBridge.getEndType(lineCapStyle);
    if (lineDashPattern != null && !lineDashPattern.isSolid()) {
        path = LineDashPattern.applyDashPattern(path, lineDashPattern);
    }
    ClipperOffset offset = new ClipperOffset(miterLimit, PdfCleanUpTool.arcTolerance * PdfCleanUpTool.floatMultiplier);
    List<Subpath> degenerateSubpaths = ClipperBridge.addPath(offset, path, joinType, endType);
    PolyTree resultTree = new PolyTree();
    offset.execute(resultTree, lineWidth * PdfCleanUpTool.floatMultiplier / 2);
    com.itextpdf.kernel.geom.Path offsetedPath = ClipperBridge.convertToPath(resultTree);
    if (degenerateSubpaths.size() > 0) {
        if (endType == EndType.OPEN_ROUND) {
            List<Subpath> circles = convertToCircles(degenerateSubpaths, lineWidth / 2);
            offsetedPath.addSubpaths(circles);
        } else if (endType == EndType.OPEN_SQUARE && lineDashPattern != null) {
            List<Subpath> squares = convertToSquares(degenerateSubpaths, lineWidth, sourcePath);
            offsetedPath.addSubpaths(squares);
        }
    }
    return filterFillPath(offsetedPath, ctm, PdfCanvasConstants.FillingRule.NONZERO_WINDING);
}
Also used : Subpath(com.itextpdf.kernel.geom.Subpath) PolyTree(com.itextpdf.kernel.pdf.canvas.parser.clipper.PolyTree) ClipperOffset(com.itextpdf.kernel.pdf.canvas.parser.clipper.ClipperOffset) JoinType(com.itextpdf.kernel.pdf.canvas.parser.clipper.IClipper.JoinType) EndType(com.itextpdf.kernel.pdf.canvas.parser.clipper.IClipper.EndType) List(java.util.List) ArrayList(java.util.ArrayList)

Aggregations

PolyTree (com.itextpdf.kernel.pdf.canvas.parser.clipper.PolyTree)3 Point (com.itextpdf.kernel.geom.Point)2 DefaultClipper (com.itextpdf.kernel.pdf.canvas.parser.clipper.DefaultClipper)2 IClipper (com.itextpdf.kernel.pdf.canvas.parser.clipper.IClipper)2 ArrayList (java.util.ArrayList)2 PdfException (com.itextpdf.kernel.exceptions.PdfException)1 NoninvertibleTransformException (com.itextpdf.kernel.geom.NoninvertibleTransformException)1 Rectangle (com.itextpdf.kernel.geom.Rectangle)1 Subpath (com.itextpdf.kernel.geom.Subpath)1 ClipperOffset (com.itextpdf.kernel.pdf.canvas.parser.clipper.ClipperOffset)1 EndType (com.itextpdf.kernel.pdf.canvas.parser.clipper.IClipper.EndType)1 JoinType (com.itextpdf.kernel.pdf.canvas.parser.clipper.IClipper.JoinType)1 PolyFillType (com.itextpdf.kernel.pdf.canvas.parser.clipper.IClipper.PolyFillType)1 Paths (com.itextpdf.kernel.pdf.canvas.parser.clipper.Paths)1 List (java.util.List)1