iText Table of Contents Page Reordering

While dynamically generating a PDF using the iText PDF library, I ran into a bit of a snag with the table of contents. In order for iText to properly generate a table of contents, the PDF has to be finished; otherwise the code has no way of knowing what page the referenced content is on. There are several good tutorials on generating the table of contents, and then reordering the pages so the table of contents is the first page. Unfortunately, there was not much help out there on how to make the table of contents the second page. I had a title page, so I could not switch it with the first.

What I ended up doing was building on the reorder algorithm. The following allows for multiple page table of contents, and starts the table of contents on the second page.

//When you add your table of contents, get its page number for the reordering:
int toc = writer.getPageNumber();

// always add to a new page before reordering pages.
document.newPage();

// get the total number of pages that needs to be reordered
int total = writer.reorderPages(null);

// change the order
int[] order = new int[total];

for (int i = 0; i < total; i++) {
  if (i == 0){
    order[i] = 1;
  } else  if (i == 1){
    order [i] = toc;
  } else {
    order[i] = (i - 1) + toc;
    if (order[i] > total){
      order[i] -=  total;
      order[i] += 1;
    }
  }
}

// apply the new order
writer.reorderPages(order);

document.close();

Now, some explanation:

As stated in the comment, in order to reorder the pages, you will need to know on what page number your table of contents starts. In order to do that, you need to store the page number as a variable when you add the table of contents:

int toc = writer.getPageNumber();

Once you have finished adding all your content to the PDF, call:

document.newPage();

If you are reordering pages, it is a requirement to add a new page. The page will not actually be inserted into your document.

To grab the total number of pages in the document run:

int total = writer.reorderPages(null);

Then we are going to create an array of integers:

int[] order = new int[total];

These integers are going to be our page numbers.

We are going to loop through each page. To keep the title page as page one, we will set the first integer in the array to 1 (page 1).

for (int i = 0; i < total; i++) {
  if (i == 0){
    order[i] = 1;
  }

Next, we will make the second integer in the array the first page of the table of contents.

else if (i == 1){
    order [i] = toc;
}

Essentially, we are saying, if we are at page 2, set it to page x (x being the first page of the table of contents).

For each subsequent page, we have to check if it is an additional page in the table of contents section, or if it is the rest of the actual document.

else {
    order[i] = (i - 1) + toc;
    if (order[i] > total){
      order[i] -=  total;
      order[i] += 1;
    }
}

What we are doing here is looking at the index of the array, subtracting one so the pages of the table of contents will remain sequential. Imagine we have ten pages, and the last three pages are the generated table of contents. Index 0 is page 1. Index 1 is page 8. Now, the next index is 2 (what will be the third page), so we are going to add the index to the table of contents page number to increment through the table of contents. 2 +8 is 10, not 9. So until we have finished going through the table of contents, we have to subtract 1 from the index. Otherwise we skip a page, and we will end up missing a page in the end. Actually, the code will just fail.

We check to see if the table of contents is finished by asking if the page number at index “i” is greater than the total number of possible pages. The last page of the document is the last page of the table of contents. So if the page number exceeds the total, then we are going to subtract the total from the current page number. Again, in our ten page PDF example: Index 4 - 1 is 3. Then we add the toc page number (8) to get 11. That is now the current page number of index 4. When we check to see if that page is outside the total possible pages, we find that it is. So we subtract the total possible pages (10). Then we are left with index 4 equalling page number 1. But we are already referencing page 1 in index 0. Remember we subtracted one from the index in the previous operation? Well, we are just going to add that back now that we are finished iterating through the table of contents. So index 4 is now correctly referencing page 2.

Once we have iterated through the entire array, we set this new order (using our 10 page example, the new order would be: 1, 8, 9, 10, 2, 3, 4, 5, 6, 7) as the order of the document using this method:

writer.reorderPages(order);

document.close();

Then we close the document and go about our merry way.

← Return Home