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