All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.itextpdf.kernel.pdf.PdfNumTree Maven / Gradle / Ivy

There is a newer version: 9.0.0
Show newest version
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2024 Apryse Group NV
    Authors: Apryse Software.

    This program is offered under a commercial and under the AGPL license.
    For commercial licensing, contact us at https://itextpdf.com/sales.  For AGPL licensing, see below.

    AGPL licensing:
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    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 .
 */
package com.itextpdf.kernel.pdf;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;


public class PdfNumTree {


    private static final int NODE_SIZE = 40;

    private PdfCatalog catalog;
    private Map items = new HashMap<>();
    private PdfName treeType;

    /**
     * Creates the NumberTree of current Document
     *
     * @param catalog  Document catalog
     * @param treeType the type of tree. ParentTree or PageLabels.
     *
     */
    public PdfNumTree(PdfCatalog catalog, PdfName treeType) {
        this.treeType = treeType;
        this.catalog = catalog;
    }


    public Map getNumbers() {
        if (items.size() > 0) {
            return items;
        }

        PdfDictionary numbers = null;
        if (treeType.equals(PdfName.PageLabels)) {
            numbers = catalog.getPdfObject().getAsDictionary(PdfName.PageLabels);
        } else if (treeType.equals(PdfName.ParentTree)) {
            PdfDictionary structTreeRoot = catalog.getPdfObject().getAsDictionary(PdfName.StructTreeRoot);
            if (structTreeRoot != null) {
                numbers = structTreeRoot.getAsDictionary(PdfName.ParentTree);
            }
        }

        if (numbers != null) {
            readTree(numbers);
        }

        return items;
    }

    public void addEntry(int key, PdfObject value) { items.put(new Integer(key), value); }

    public PdfDictionary buildTree() {
        Integer[] numbers = new Integer[items.size()];
        numbers = items.keySet().toArray(numbers);
        Arrays.sort(numbers);
        if (numbers.length <= NODE_SIZE) {
            PdfDictionary dic = new PdfDictionary();
            PdfArray ar = new PdfArray();
            for (int k = 0; k < numbers.length; ++k) {
                ar.add(new PdfNumber((int) numbers[k]));
                ar.add(items.get(numbers[k]));
            }
            dic.put(PdfName.Nums, ar);
            return dic;
        }
        int skip = NODE_SIZE;
        PdfDictionary[] kids = new PdfDictionary[(numbers.length + NODE_SIZE - 1) / NODE_SIZE];
        for (int i = 0; i < kids.length; ++i) {
            int offset = i * NODE_SIZE;
            int end = Math.min(offset + NODE_SIZE, numbers.length);
            PdfDictionary dic = new PdfDictionary();
            PdfArray arr = new PdfArray();
            arr.add(new PdfNumber((int) numbers[offset]));
            arr.add(new PdfNumber((int) numbers[end - 1]));
            dic.put(PdfName.Limits, arr);
            arr = new PdfArray();
            for (; offset < end; ++offset) {
                arr.add(new PdfNumber((int) numbers[offset]));
                arr.add(items.get(numbers[offset]));
            }
            dic.put(PdfName.Nums, arr);
            dic.makeIndirect(catalog.getDocument());
            kids[i] = dic;
        }
        int top = kids.length;
        while (true) {
            if (top <= NODE_SIZE) {
                PdfArray arr = new PdfArray();
                for (int k = 0; k < top; ++k)
                    arr.add(kids[k]);
                PdfDictionary dic = new PdfDictionary();
                dic.put(PdfName.Kids, arr);
                return dic;
            }
            skip *= NODE_SIZE;
            int tt = (numbers.length + skip - 1 )/ skip;
            for (int k = 0; k < tt; ++k) {
                int offset = k * NODE_SIZE;
                int end = Math.min(offset + NODE_SIZE, top);
                PdfDictionary dic = (PdfDictionary) new PdfDictionary().makeIndirect(catalog.getDocument());
                PdfArray arr = new PdfArray();
                arr.add(new PdfNumber((int) numbers[k * skip]));
                arr.add(new PdfNumber((int) numbers[Math.min((k + 1) * skip, numbers.length) - 1]));
                dic.put(PdfName.Limits, arr);
                arr = new PdfArray();
                for (; offset < end; ++offset) {
                    arr.add(kids[offset]);
                }
                dic.put(PdfName.Kids, arr);
                kids[k] = dic;
            }
            top = tt;
        }
    }

    private void readTree(PdfDictionary dictionary) {
        if (dictionary != null) {
            iterateItems(dictionary, null);
        }
    }

    private PdfNumber iterateItems(PdfDictionary dictionary, PdfNumber leftOver) {
        PdfArray nums = dictionary.getAsArray(PdfName.Nums);
        if (nums != null) {
            for (int k = 0; k < nums.size(); k++) {
                PdfNumber number;
                if (leftOver == null)
                    number = nums.getAsNumber(k++);
                else {
                    number = leftOver;
                    leftOver = null;
                }
                if (k < nums.size()) {
                    items.put(number.intValue(), nums.get(k));
                } else {
                    return number;
                }
            }
        } else if ((nums = dictionary.getAsArray(PdfName.Kids)) != null) {
            for (int k = 0; k < nums.size(); k++) {
                PdfDictionary kid = nums.getAsDictionary(k);
                leftOver = iterateItems(kid, leftOver);
            }
        }
        return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy