iText 5 itextpdf.jar Source Code

itextpdf.jar is a component in iText 5 Java library to provide core functionalities. iText Java library allows you to generate and manage PDF documents.

The Source Code files are provided at iText GitHub site.

You can compile it to generate your JAR file, using pom.xml as the build configuration file.

The source code of itextpdf-5.5.14.jar is provided below:

✍: FYIcenter.com

com/itextpdf/text/pdf/parser/clipper/ClipperBase.java

/*
 *
 * This file is part of the iText (R) project.
 * Copyright (c) 2014-2015 iText Group NV
 * Authors: Bruno Lowagie, Paulo Soares, et al.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License version 3
 * as published by the Free Software Foundation with the addition of the
 * following permission added to Section 15 as permitted in Section 7(a):
 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
 * ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
 * OF THIRD PARTY RIGHTS
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
 * http://itextpdf.com/terms-of-use/
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License,
 * a covered work must retain the producer line in every PDF that is created
 * or manipulated using iText.
 *
 * You can be released from the requirements of the license by purchasing
 * a commercial license. Buying such a license is mandatory as soon as you
 * develop commercial activities involving the iText software without
 * disclosing the source code of your own applications.
 * These activities include: offering paid services to customers as an ASP,
 * serving PDFs on the fly in a web application, shipping iText with a closed
 * source product.
 *
 * For more information, please contact iText Software Corp. at this
 * address: sales@itextpdf.com
 *
 *
 * This class is based on the C# open source freeware library Clipper:
 * http://www.angusj.com/delphi/clipper.php
 * The original classes were distributed under the Boost Software License:
 *
 * Freeware for both open source and commercial applications
 * Copyright 2010-2014 Angus Johnson
 * Boost Software License - Version 1.0 - August 17th, 2003
 *
 * Permission is hereby granted, free of charge, to any person or organization
 * obtaining a copy of the software and accompanying documentation covered by
 * this license (the "Software") to use, reproduce, display, distribute,
 * execute, and transmit the Software, and to prepare derivative works of the
 * Software, and to permit third-parties to whom the Software is furnished to
 * do so, all subject to the following:
 *
 * The copyright notices in the Software and this entire statement, including
 * the above license grant, this restriction and the following disclaimer,
 * must be included in all copies of the Software, in whole or in part, and
 * all derivative works of the Software, unless such copies or derivative
 * works are solely in the form of machine-executable object code generated by
 * a source language processor.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */
package com.itextpdf.text.pdf.parser.clipper;

import com.itextpdf.text.pdf.parser.clipper.Point.LongPoint;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

public abstract class ClipperBase implements Clipper {
    protected class LocalMinima {
        long y;
        Edge leftBound;
        Edge rightBound;
        LocalMinima next;
    };

    protected class Scanbeam {
        long y;
        Scanbeam next;
    };

    private static void initEdge( Edge e, Edge eNext, Edge ePrev, LongPoint pt ) {
        e.next = eNext;
        e.prev = ePrev;
        e.setCurrent( new LongPoint( pt ) );
        e.outIdx = Edge.UNASSIGNED;
    }

    private static void initEdge2( Edge e, PolyType polyType ) {
        if (e.getCurrent().getY() >= e.next.getCurrent().getY()) {
            e.setBot( new LongPoint( e.getCurrent() ) );
            e.setTop( new LongPoint( e.next.getCurrent() ) );
        }
        else {
            e.setTop( new LongPoint( e.getCurrent() ) );
            e.setBot( new LongPoint( e.next.getCurrent() ) );
        }
        e.updateDeltaX();
        e.polyTyp = polyType;
    }

    private static boolean rangeTest( LongPoint Pt, boolean useFullRange ) {
        if (useFullRange) {
            if (Pt.getX() > HI_RANGE || Pt.getY() > HI_RANGE || -Pt.getX() > HI_RANGE || -Pt.getY() > HI_RANGE)
                throw new IllegalStateException("Coordinate outside allowed range");
        } else if (Pt.getX() > LOW_RANGE || Pt.getY() > LOW_RANGE || -Pt.getX() > LOW_RANGE || -Pt.getY() > LOW_RANGE) {
            return rangeTest(Pt, true);
        }

        return useFullRange;
    }

    private static Edge removeEdge( Edge e ) {
        //removes e from double_linked_list (but without removing from memory)
        e.prev.next = e.next;
        e.next.prev = e.prev;
        final Edge result = e.next;
        e.prev = null; //flag as removed (see ClipperBase.Clear)
        return result;
    }

    private final static long LOW_RANGE = 0x3FFFFFFF;

    private final static long HI_RANGE = 0x3FFFFFFFFFFFFFFFL;

    protected LocalMinima minimaList;

    protected LocalMinima currentLM;

    private final List<List<Edge>> edges;

    protected boolean useFullRange;

    protected boolean hasOpenPaths;

    protected final boolean preserveCollinear;

    private final static Logger LOGGER = Logger.getLogger( Clipper.class.getName() );

    protected ClipperBase( boolean preserveCollinear ) //constructor (nb: no external instantiation)
    {
        this.preserveCollinear = preserveCollinear;
        minimaList = null;
        currentLM = null;
        hasOpenPaths = false;
        edges = new ArrayList<List<Edge>>();
    }

    public boolean addPath( Path pg, PolyType polyType, boolean Closed ) {

        if (!Closed && polyType == PolyType.CLIP) {
            throw new IllegalStateException( "AddPath: Open paths must be subject." );
        }

        int highI = pg.size() - 1;
        if (Closed) {
            while (highI > 0 && pg.get( highI ).equals( pg.get( 0 ) )) {
                --highI;
            }
        }
        while (highI > 0 && pg.get( highI ).equals( pg.get( highI - 1 ) )) {
            --highI;
        }
        if (Closed && highI < 2 || !Closed && highI < 1) {
            return false;
        }

        //create a new edge array ...
        final List<Edge> edges = new ArrayList<Edge>( highI + 1 );
        for (int i = 0; i <= highI; i++) {
            edges.add( new Edge() );
        }

        boolean IsFlat = true;

        //1. Basic (first) edge initialization ...
        edges.get( 1 ).setCurrent( new LongPoint( pg.get( 1 ) ) );
        useFullRange = rangeTest( pg.get( 0 ), useFullRange );
        useFullRange = rangeTest( pg.get( highI ), useFullRange );
        initEdge( edges.get( 0 ), edges.get( 1 ), edges.get( highI ), pg.get( 0 ) );
        initEdge( edges.get( highI ), edges.get( 0 ), edges.get( highI - 1 ), pg.get( highI ) );
        for (int i = highI - 1; i >= 1; --i) {
            useFullRange = rangeTest( pg.get( i ), useFullRange );
            initEdge( edges.get( i ), edges.get( i + 1 ), edges.get( i - 1 ), pg.get( i ) );
        }
        Edge eStart = edges.get( 0 );

        //2. Remove duplicate vertices, and (when closed) collinear edges ...
        Edge e = eStart, eLoopStop = eStart;
        for (;;) {
            //nb: allows matching start and end points when not Closed ...
            if (e.getCurrent().equals( e.next.getCurrent() ) && (Closed || !e.next.equals( eStart ))) {
                if (e == e.next) {
                    break;
                }
                if (e == eStart) {
                    eStart = e.next;
                }
                e = removeEdge( e );
                eLoopStop = e;
                continue;
            }
            if (e.prev == e.next) {
                break; //only two vertices
            }
            else if (Closed && Point.slopesEqual( e.prev.getCurrent(), e.getCurrent(), e.next.getCurrent(), useFullRange )
                            && (!isPreserveCollinear() || !Point.isPt2BetweenPt1AndPt3( e.prev.getCurrent(), e.getCurrent(), e.next.getCurrent() ))) {
                //Collinear edges are allowed for open paths but in closed paths
                //the default is to merge adjacent collinear edges into a single edge.
                //However, if the PreserveCollinear property is enabled, only overlapping
                //collinear edges (ie spikes) will be removed from closed paths.
                if (e == eStart) {
                    eStart = e.next;
                }
                e = removeEdge( e );
                e = e.prev;
                eLoopStop = e;
                continue;
            }
            e = e.next;
            if (e == eLoopStop || !Closed && e.next == eStart) {
                break;
            }
        }

        if (!Closed && e == e.next || Closed && e.prev == e.next) {
            return false;
        }

        if (!Closed) {
            hasOpenPaths = true;
            eStart.prev.outIdx = Edge.SKIP;
        }

        //3. Do second stage of edge initialization ...
        e = eStart;
        do {
            initEdge2( e, polyType );
            e = e.next;
            if (IsFlat && e.getCurrent().getY() != eStart.getCurrent().getY()) {
                IsFlat = false;
            }
        }
        while (e != eStart);

        //4. Finally, add edge bounds to LocalMinima list ...

        //Totally flat paths must be handled differently when adding them
        //to LocalMinima list to avoid endless loops etc ...
        if (IsFlat) {
            if (Closed) {
                return false;
            }
            e.prev.outIdx = Edge.SKIP;
            final LocalMinima locMin = new LocalMinima();
            locMin.next = null;
            locMin.y = e.getBot().getY();
            locMin.leftBound = null;
            locMin.rightBound = e;
            locMin.rightBound.side = Edge.Side.RIGHT;
            locMin.rightBound.windDelta = 0;
            for ( ; ; )
            {
                if (e.getBot().getX() != e.prev.getTop().getX()) e.reverseHorizontal();
                if (e.next.outIdx == Edge.SKIP) break;
                e.nextInLML = e.next;
                e = e.next;
            }
            insertLocalMinima( locMin );
            this.edges.add( edges );
            return true;
        }

        this.edges.add( edges );
        boolean leftBoundIsForward;
        Edge EMin = null;

        //workaround to avoid an endless loop in the while loop below when
        //open paths have matching start and end points ...
        if (e.prev.getBot().equals( e.prev.getTop() )) {
            e = e.next;
        }

        for (;;) {
            e = e.findNextLocMin();
            if (e == EMin) {
                break;
            }
            else if (EMin == null) {
                EMin = e;
            }

            //E and E.Prev now share a local minima (left aligned if horizontal).
            //Compare their slopes to find which starts which bound ...
            final LocalMinima locMin = new LocalMinima();
            locMin.next = null;
            locMin.y = e.getBot().getY();
            if (e.deltaX < e.prev.deltaX) {
                locMin.leftBound = e.prev;
                locMin.rightBound = e;
                leftBoundIsForward = false; //Q.nextInLML = Q.prev
            }
            else {
                locMin.leftBound = e;
                locMin.rightBound = e.prev;
                leftBoundIsForward = true; //Q.nextInLML = Q.next
            }
            locMin.leftBound.side = Edge.Side.LEFT;
            locMin.rightBound.side = Edge.Side.RIGHT;

            if (!Closed) {
                locMin.leftBound.windDelta = 0;
            }
            else if (locMin.leftBound.next == locMin.rightBound) {
                locMin.leftBound.windDelta = -1;
            }
            else {
                locMin.leftBound.windDelta = 1;
            }
            locMin.rightBound.windDelta = -locMin.leftBound.windDelta;

            e = processBound( locMin.leftBound, leftBoundIsForward );
            if (e.outIdx == Edge.SKIP) {
                e = processBound( e, leftBoundIsForward );
            }

            Edge E2 = processBound( locMin.rightBound, !leftBoundIsForward );
            if (E2.outIdx == Edge.SKIP) {
                E2 = processBound( E2, !leftBoundIsForward );
            }

            if (locMin.leftBound.outIdx == Edge.SKIP) {
                locMin.leftBound = null;
            }
            else if (locMin.rightBound.outIdx == Edge.SKIP) {
                locMin.rightBound = null;
            }
            insertLocalMinima( locMin );
            if (!leftBoundIsForward) {
                e = E2;
            }
        }
        return true;

    }

    public boolean addPaths( Paths ppg, PolyType polyType, boolean closed ) {
        boolean result = false;
        for (int i = 0; i < ppg.size(); ++i) {
            if (addPath( ppg.get( i ), polyType, closed )) {
                result = true;
            }
        }
        return result;
    }

    public void clear() {
        disposeLocalMinimaList();
        edges.clear();
        useFullRange = false;
        hasOpenPaths = false;
    }

    private void disposeLocalMinimaList() {
        while (minimaList != null) {
            final LocalMinima tmpLm = minimaList.next;
            minimaList = null;
            minimaList = tmpLm;
        }
        currentLM = null;
    }

    private void insertLocalMinima( LocalMinima newLm ) {
        if (minimaList == null) {
            minimaList = newLm;
        }
        else if (newLm.y >= minimaList.y) {
            newLm.next = minimaList;
            minimaList = newLm;
        }
        else {
            LocalMinima tmpLm = minimaList;
            while (tmpLm.next != null && newLm.y < tmpLm.next.y) {
                tmpLm = tmpLm.next;
            }
            newLm.next = tmpLm.next;
            tmpLm.next = newLm;
        }
    }

    public boolean isPreserveCollinear() {
        return preserveCollinear;
    }

    protected void popLocalMinima() {
        LOGGER.entering( ClipperBase.class.getName(), "popLocalMinima" );
        if (currentLM == null) {
            return;
        }
        currentLM = currentLM.next;
    }

    private Edge processBound( Edge e, boolean LeftBoundIsForward ) {
        Edge EStart, result = e;
        Edge Horz;

        if (result.outIdx == Edge.SKIP) {
            //check if there are edges beyond the skip edge in the bound and if so
            //create another LocMin and calling ProcessBound once more ...
            e = result;
            if (LeftBoundIsForward) {
                while (e.getTop().getY() == e.next.getBot().getY()) {
                    e = e.next;
                }
                while (e != result && e.deltaX == Edge.HORIZONTAL) {
                    e = e.prev;
                }
            }
            else {
                while (e.getTop().getY() == e.prev.getBot().getY()) {
                    e = e.prev;
                }
                while (e != result && e.deltaX == Edge.HORIZONTAL) {
                    e = e.next;
                }
            }
            if (e == result) {
                if (LeftBoundIsForward) {
                    result = e.next;
                }
                else {
                    result = e.prev;
                }
            }
            else {
                //there are more edges in the bound beyond result starting with E
                if (LeftBoundIsForward) {
                    e = result.next;
                }
                else {
                    e = result.prev;
                }
                final LocalMinima locMin = new LocalMinima();
                locMin.next = null;
                locMin.y = e.getBot().getY();
                locMin.leftBound = null;
                locMin.rightBound = e;
                e.windDelta = 0;
                result = processBound( e, LeftBoundIsForward );
                insertLocalMinima( locMin );
            }
            return result;
        }

        if (e.deltaX == Edge.HORIZONTAL) {
            //We need to be careful with open paths because this may not be a
            //true local minima (ie E may be following a skip edge).
            //Also, consecutive horz. edges may start heading left before going right.
            if (LeftBoundIsForward) {
                EStart = e.prev;
            }
            else {
                EStart = e.next;
            }
            if (EStart.deltaX == Edge.HORIZONTAL) //ie an adjoining horizontal skip edge
            {
                if (EStart.getBot().getX() != e.getBot().getX() && EStart.getTop().getX() != e.getBot().getX())
                    e.reverseHorizontal();
            }
            else if (EStart.getBot().getX() != e.getBot().getX())
                e.reverseHorizontal();
        }

        EStart = e;
        if (LeftBoundIsForward) {
            while (result.getTop().getY() == result.next.getBot().getY() && result.next.outIdx != Edge.SKIP) {
                result = result.next;
            }
            if (result.deltaX == Edge.HORIZONTAL && result.next.outIdx != Edge.SKIP) {
                //nb: at the top of a bound, horizontals are added to the bound
                //only when the preceding edge attaches to the horizontal's left vertex
                //unless a Skip edge is encountered when that becomes the top divide
                Horz = result;
                while (Horz.prev.deltaX == Edge.HORIZONTAL) {
                    Horz = Horz.prev;
                }
                if (Horz.prev.getTop().getX() > result.next.getTop().getX()) result = Horz.prev;
            }
            while (e != result) {
                e.nextInLML = e.next;
                if (e.deltaX == Edge.HORIZONTAL && e != EStart && e.getBot().getX() != e.prev.getTop().getX()) {
                    e.reverseHorizontal();
                }
                e = e.next;
            }
            if (e.deltaX == Edge.HORIZONTAL && e != EStart && e.getBot().getX() != e.prev.getTop().getX()) {
                e.reverseHorizontal();
            }
            result = result.next; //move to the edge just beyond current bound
        }
        else {
            while (result.getTop().getY() == result.prev.getBot().getY() && result.prev.outIdx != Edge.SKIP) {
                result = result.prev;
            }
            if (result.deltaX == Edge.HORIZONTAL && result.prev.outIdx != Edge.SKIP) {
                Horz = result;
                while (Horz.next.deltaX == Edge.HORIZONTAL) {
                    Horz = Horz.next;
                }
                if (Horz.next.getTop().getX() == result.prev.getTop().getX() ||
                        Horz.next.getTop().getX() > result.prev.getTop().getX()) result = Horz.next;
            }

            while (e != result) {
                e.nextInLML = e.prev;
                if (e.deltaX == Edge.HORIZONTAL && e != EStart && e.getBot().getX() != e.next.getTop().getX()) {
                    e.reverseHorizontal();
                }
                e = e.prev;
            }
            if (e.deltaX == Edge.HORIZONTAL && e != EStart && e.getBot().getX() != e.next.getTop().getX()) {
                e.reverseHorizontal();
            }
            result = result.prev; //move to the edge just beyond current bound
        }
        return result;
    }

    protected static Path.OutRec parseFirstLeft(Path.OutRec FirstLeft) {
        while (FirstLeft != null && FirstLeft.getPoints() == null)
            FirstLeft = FirstLeft.firstLeft;
        return FirstLeft;
    }

    protected void reset() {
        currentLM = minimaList;
        if (currentLM == null) {
            return; //ie nothing to process
        }

        //reset all edges ...
        LocalMinima lm = minimaList;
        while (lm != null) {
            Edge e = lm.leftBound;
            if (e != null) {
                e.setCurrent( new LongPoint( e.getBot() ) );
                e.side = Edge.Side.LEFT;
                e.outIdx = Edge.UNASSIGNED;
            }
            e = lm.rightBound;
            if (e != null) {
                e.setCurrent( new LongPoint( e.getBot() ) );
                e.side = Edge.Side.RIGHT;
                e.outIdx = Edge.UNASSIGNED;
            }
            lm = lm.next;
        }
    }

}

com/itextpdf/text/pdf/parser/clipper/ClipperBase.java

 

Or download all of them as a single archive file:

File name: itextpdf-5.5.14-fyi.zip
File size: 2163839 bytes
Release date: 2009-10-09
Download 

 

iText-2.1.6.jar - iText, a JAVA-PDF library

iText layout.jar Source Code

Download and Install iText Java Library

⇑⇑ iText for PDF Generation

2021-07-03, 111154👍, 0💬