It is deterministic. Running against the same data reproduces the exact
error.
You are correct. When I pass null for the root outline node, and pass null
in the recursive calls to prevent bookmarking from occuring, the issue does
go away.
I am fairly new to iText, so I am a little confused by your question about
the bookmarks being off by a single page. To create the bookmark
PdfDestination I call getVerticalPosition(true), I thought that the result
is just the y coordinate of the current vertical position within the entire
document. What do you mean by off by a single page?
-- Jason
On Tue, Apr 12, 2011 at 8:24 PM, Mark Storer <[email protected]> wrote:
> You can call getPageReference(Integer.MAX_INT) any time you like, though
> I don't recommend it. Any time getPageReference is called for a page
> greater than the last page when you call close, you get this exception. You
> can create all your page references in advance via getPageReference(), but
> they'd better have pages to go with them when you call close().
>
> This looks an awful lot like an off-by-one error. Are your bookmarks off
> by a single page?
>
> Is it deterministic? Does running your app over the same data reproduce
> the issue time and again?
>
> I suspect that if you disable your outline code, this problem will Go Away,
> though I can't point my finger at anything in particular to back that up.
>
> One final trick you could try would be to change
> PdfWriter.getPageReference(int) such that it logged the desired page along
> with a stack trace:
> try {
> throw new RuntimeException("Requested page " + page);
> } catch (RuntimeException re) {
> re.printStackTrace(myPrintWriter);
> }
>
> You really only need to track the largest request. If the error /is/
> deterministic, you can just log calls to getPageReference() when page
> ==1356568. There could be more than one.
>
> --Mark Storer
> Senior Software Engineer
> Cardiff.com
>
> import legalese.Disclaimer;
> Disclaimer<Cardiff> DisCard = null;
>
>
>
> ------------------------------
> *From:* Jason DeLawder [mailto:[email protected]]
> *Sent:* Tuesday, April 12, 2011 1:43 PM
> *To:* [email protected]
> *Subject:* [iText-questions] RuntimeExcpetion - Size of pageReferences and
> currentPageNumber -1 Are Not Equal
>
> I have written an application that exports hundreds of PDF documents
> from a content repository and then merges those documents into a single PDF
> document. Any PDFs that are either encrypted or corrupted are supplied to
> the requester as attachements to the merged PDF (ideally these shouldn't
> exist but they do get into the system).
>
> The domain object graph corresponding to the folders and documents in the
> content repository is recursively processed and the Document domain object
> has a reference to the file path where the document was exported. Once all
> of the files have been merged and bookmarks created, the PdfDocument is
> closed, but I am receiving the following RuntimeException
>
> 11/04/12 15:28:31 Caused by: java.lang.RuntimeException: The page 135658
> was requested but the document has only 135657 pages.
> 11/04/12 15:28:31 at
> com.itextpdf.text.pdf.PdfWriter.close(PdfWriter.java:1165)
> 11/04/12 15:28:31 at com.itextpdf.text.pdf.PdfCopy.close(PdfCopy.java:488)
> 11/04/12 15:28:31 at
> com.itextpdf.text.pdf.PdfDocument.close(PdfDocument.java:780)
> 11/04/12 15:28:31 at com.itextpdf.text.Document.close(Document.java:409)
> 11/04/12 15:28:31 at
> ebackend.service.pdf.ITextPDFService.append(ITextPDFService.java:249)
> 11/04/12 15:28:31 at
> ebackend.ejb.EbackendMessageBean.processRedactRequest(EbackendMessageBean.java:432)
>
> This exception only seems to occur when there is a large number of
> documents being merged. I have debugged over and over, but have been unable
> to determine why this error occurrs. The code is below, the methods of
> interest are append() and mergePDFs() and the merging begins with
> append().
>
> I would appreciate it if someone could take a quick look at the code to see
> if I am doing something incorrectly. If the code looks correct, what
> conditions could yield this result? What conditions could cause PdfWriter's
> pageReferences list to be larger than the currentPageNumber - 1 ?
>
> Thanks.
>
> public class ITextPDFService {
>
> private static final Logger logger =
> Logger.getLogger(ITextPDFService.class);
>
> /**
> * Loads the CoverPage pdf file and completes the embedded
> AcroForm. After
> * completing the AcroForm the file is wrapped in a domain object
> * so that it can be merged. The page is not added to in any way.
> *
> * @param info The CoverLetterInfo contains the summary data
> needed to create
> * the title/cover page.
> *
> * @param exportFolder The folder where all of the exported
> documents are located.
> *
> * @return Document that wraps the physical Cover Page file, null
> if the
> * cover page could not be created.
> *
> * @throws IOException
> * @throws DocumentException
> */
> private Document getCoverPage(CoverLetterInfo info, String
> exportFolder) {
>
> if(!exportFolder.endsWith("\\")){
> exportFolder+= "\\";
> }
>
> PdfStamper stamper = null;
> Document d = null;
> String coverLetterPath = exportFolder + "coverletter.pdf";
>
> try {
> InputStream is =
> getClass().getClassLoader().getResourceAsStream("coverletter.pdf");
> PdfReader reader = new PdfReader(is);
> stamper = new PdfStamper(reader, new
> FileOutputStream(coverLetterPath));
>
> AcroFields form = stamper.getAcroFields();
> form.setField("title", info.getLabelTitle());
> form.setField("user", info.getLabelUser());
> form.setField("folder", info.getLabelFolder());
> form.setField("company", info.getLabelCompany());
> form.setField("product", info.getLabelProduct());
> form.setField("summary", info.getLabelSummary());
> form.setField("dateRequested", info.getLabelDateRequested());
> form.setField("datePrinted", info.getLabelDatePrinted());
> form.setField("note", info.getLabelNote());
> stamper.setFormFlattening(true);
> d = new Document();
> d.setDownloadedPath(coverLetterPath);
>
> } catch(Exception e) {
> logger.error("Error creating the cover page for " +
> FilenameUtils.getName(exportFolder) ,e);
> e.printStackTrace();
>
> } finally {
> try {stamper.close();}catch(Exception e){
> logger.error("Unable to close PdfStamper",e); }
> }
>
> return d;
> }
>
>
> /**
> *
> * @param Folder
> * @param exportFolder
> * @param destFilePath
> * @param info
> * @param doPageStamps
> * @return
> * @throws Exception
> */
> public List<String> append(Folder Folder, String exportFolder,
> String destFilePath, CoverLetterInfo info, boolean doPageStamps) {
>
> List<String> errorDescriptions = new
> ArrayList<String>();
> // get the total number of pages for all documents in the export
> folder
> int totalPageNum = countPages(exportFolder);
> info.setTotalPageNumber(String.valueOf(totalPageNum));
>
> logger.info("Total Page Count: " + (totalPageNum + 1)); //
> including the cover page
>
> Document document = null;
> PdfCopy copy = null;
> try {
>
> document = new Document();
> copy = new PdfCopy(document, new
> FileOutputStream(destFilePath));
> document.open();
>
> // create and add the cover page
> try {
> Document coverLetter = getCoverPage(info, exportFolder);
> if(coverLetter != null)
> {
> PdfReader reader = new
> PdfReader(coverLetter.getDownloadedPath());
> PdfImportedPage page = copy.getImportedPage(reader,1);
> copy.addPage(page);
> }
> }
> catch(Exception e)
> {
> logger.error(e);
> errorDescriptions.add(COVER_LETTER_ERROR);
> }
>
> // merge pdfs
> logger.info("Begin merge of " + Folder.getName() + " folder
> contents.");
> long startTime = new Date().getTime();
> errorDescriptions.addAll(
> mergePDFs(copy,
> copy.getRootOutline(),
> Folder,
> doPageStamps,
> totalPageNum)
> );
> long endTime = new Date().getTime();
> logger.info("Merge of " + Folder + " folder contents
> completed. Time: " + ((endTime - startTime) / 1000) + " seconds");
> } catch(Exception e){
> logger.error("Unrecoverable error occurred creating base
> Document for folder " + Folder, e);
> throw new EbackendServiceException(e);
>
> } finally {
> if(document != null)
> document.close();
> }
>
> return errorDescriptions;
> }
>
> /**
> *
> * @param copy
> * @param outline
> * @param Folder
> * @param doPageStamps
> * @param totalPages
> * @return
> */
> public List<String> mergePDFs(PdfCopy copy, PdfOutline outline,
> Folder Folder, boolean doPageStamps, int totalPages) {
> List<String> errorDescriptions = new ArrayList<String>();
>
> PdfImportedPage page = null;
> Font font = new Font(Font.FontFamily.HELVETICA,12.0f,Font.BOLD);
>
> List children = Folder.getChildren();
> for(Object o : children)
> {
> if(o instanceof Folder)
> {
> Folder f = (Folder) o;
> if(f.getChildren().size() > 0 && f.hasDocumentDescendents()){
> PdfOutline subOutline = new PdfOutline(outline,
> new
> PdfDestination(PdfDestination.FITH,copy.getVerticalPosition(true)),
> f.getName(),
> true);
> subOutline.setStyle(Font.BOLD);
> logger.debug("Merging contents of folder: " + f.getName());
> errorDescriptions.addAll(
> mergePDF(copy,subOutline,f,doPageStamps, totalPages) );
> }
> }
> else if(o instanceof Document)
> {
> float startVerticalPosition = copy.getVerticalPosition(true);
> int startPage = copy.getCurrentPageNumber();
>
> String filePath = ( (Document)o).getDownloadedPath();
> logger.debug("Merging document: " + filePath);
> PdfReader reader = null;
> PdfCopy.PageStamp stamp = null;
> try
> {
> reader = new PdfReader(new
> RandomAccessFileOrArray(filePath),null);
> int pageCount = reader.getNumberOfPages();
>
> for(int i = 1; i <= pageCount; i++){
> page = copy.getImportedPage(reader,i);
> if(doPageStamps){
> stamp = copy.createPageStamp(page);
> ColumnText.showTextAligned(
> stamp.getOverContent(),
> Element.ALIGN_LEFT,
> new Phrase(String.format("Page %d of %d",
> copy.getCurrentPageNumber() - 1, totalPages ),font),
> 30.0f, 20.0f, 0.0f);
> stamp.alterContents();
> }
> copy.addPage(page);
> }
>
> }
> catch(Exception e) // could be encrypted or corrupted, the
> latter results in NPE within iText
> {
> e.printStackTrace();
> String fileBaseName = FilenameUtils.getName(filePath);
> logger.error("Error encountered with document " +
> fileBaseName + " creating error page ",e);
>
> // create an error page
> InputStream is =
> getErrorPageInputStream(fileBaseName,e.getMessage());
> PdfReader reader2 = null;
> try
> {
> reader2 = new PdfReader(is);
> page = copy.getImportedPage(reader2,1);
> if(doPageStamps)
> {
> stamp = copy.createPageStamp(page);
> ColumnText.showTextAligned(
> stamp.getOverContent(),
> Element.ALIGN_LEFT,
> new Phrase(String.format("Page %d of %d",
> copy.getCurrentPageNumber() - 1, totalPages ),font),
> 30.0f, 20.0f, 0.0f);
> stamp.alterContents();
> }
> copy.addPage(page);
> copy.addFileAttachment(
> ((Document)o).getName(),null,filePath,fileBaseName );
>
> errorDescriptions.add(String.format(MERGING_ERROR,((Document)o).getId(),e.getMessage()));
> }
> catch(Exception e2)
> {
> e2.printStackTrace();
> logger.error("Issue creating error page for document " +
> fileBaseName,e2);
> }
> finally
> {
> try {is.close(); } catch(Exception
> e3){logger.error("Unable to close error page InputStream",e3);}
> }
>
> }
> finally
> {
> /* based on iText source, I think this should result in an
> IndexOutOfBoundsException if the page counts do not match,
> but it does not */
> int endingPage = copy.getCurrentPageNumber();
> try {
> copy.getPageReference(--endingPage);
> }catch(Exception re){
> logger.error("Page counts are off after adding " +
> ((Document)o).getName() + ": " + ((Document)o).getId());
> }
>
> // Create a bookmark for the imported document
> if(endingPage > startPage)
> {
> new PdfOutline(outline,
> new
> PdfDestination(PdfDestination.FITH,startVerticalPosition),
> ((Document)o).getName(),
> true);
> }
> }
>
> }
>
> }
>
> return errorDescriptions;
>
> }
> }
>
>
>
> ------------------------------------------------------------------------------
> Forrester Wave Report - Recovery time is now measured in hours and minutes
> not days. Key insights are discussed in the 2010 Forrester Wave Report as
> part of an in-depth evaluation of disaster recovery service providers.
> Forrester found the best-in-class provider in terms of services and vision.
> Read this report now! http://p.sf.net/sfu/ibm-webcastpromo
>
> _______________________________________________
> iText-questions mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/itext-questions
>
> iText(R) is a registered trademark of 1T3XT BVBA.
> Many questions posted to this list can (and will) be answered with a
> reference to the iText book: http://www.itextpdf.com/book/
> Please check the keywords list before you ask for examples:
> http://itextpdf.com/themes/keywords.php
>
>
------------------------------------------------------------------------------
Benefiting from Server Virtualization: Beyond Initial Workload
Consolidation -- Increasing the use of server virtualization is a top
priority.Virtualization can reduce costs, simplify management, and improve
application availability and disaster protection. Learn more about boosting
the value of server virtualization. http://p.sf.net/sfu/vmware-sfdev2dev
_______________________________________________
iText-questions mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/itext-questions
iText(R) is a registered trademark of 1T3XT BVBA.
Many questions posted to this list can (and will) be answered with a reference
to the iText book: http://www.itextpdf.com/book/
Please check the keywords list before you ask for examples:
http://itextpdf.com/themes/keywords.php