JoffJoff
JoffJoff

Reputation: 145

COSStream has been closed and cannot be read. Perhaps its enclosing PDDocument has been closed?

Essentially, I am attempting to create a small tool in Java where I take the text from some kind of user input, think of an ordinary text box, and create a PDF file with it.

So far, I managed to scrape something really quickly with my barebones knowledge of PDFBox.

In my application, I am instantiating this class(the one shown below) in another one with GUI elements and if I input text, in let's say a text box, and running this PDFLetter script once - it works like a charm but running it a second time, it crashes and gives me this annoying error:

COSStream has been closed and cannot be read. Perhaps it's enclosing PDDocument has been closed?

I do not really see any way that I could trigger this error in my code. I thought it had something to do with my rudimentary 'jump to next page' solution but it works in its current state, so I do not know what to believe anymore.

The way I am instantiating the class, in case you need to know, is like this:

PDFLetter.PDFLetterGenerate(textInput.getValue().toString());   

Additionally, I thought it had to be some kind of a problem with garbage collection that triggered the problem but I no longer think that this is the case.

public class PDFLetter {
    private static final int PAGE_MARGIN = 80;

    static float TABLE_HEIGHT;  

    static Boolean newPage = false;

public static String text = // null;
        "Ding Dong ding dong Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et "
        + "Imperdiet dui accumsan sit amet. Risus in hendrerit gravida rutrum quisque non tellus orci ac.";

static List<String> textList = new ArrayList<String>();

PDDocument document = new PDDocument();
static PDPage main_page = new PDPage();
static PDPage new_page = new PDPage(); 

static File file = new File("C:/PDFTests/temp.pdf"); 

public void PDFLetterGenerate (String args) throws Exception {
    text = args;
    text = text.replace("\n", "").replace("\r", "");

    if(file.exists()) file.delete();
    file.createNewFile();
    //Creating PDF document object 
    PDDocument document = new PDDocument();       
    document.addPage(main_page);  
    mainBody(document, main_page);      
    document.addPage(new_page);                          
    if(!newPage) document.removePage(new_page);

    document.save(file);
    document.close(); 
}

public static void mainBody(PDDocument doc, PDPage page) throws Exception { 
        final float width = page.getMediaBox().getWidth()-(2*PAGE_MARGIN);
        int fontSize = 11;
        float leading = 1.5f * fontSize;
        final float max = 256;
        PDFont pdfFont = PDType1Font.HELVETICA;

        @SuppressWarnings("deprecation")
        PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true);

        int lastSpace = -1;
        while (text.length() > 0){
            int spaceIndex = text.indexOf(' ', lastSpace + 1);
            if (spaceIndex < 0) spaceIndex = text.length();
            String subString = text.substring(0, spaceIndex);
            float size = fontSize * pdfFont.getStringWidth(subString) / 1000;

            if (size > width){
                if (lastSpace < 0) lastSpace = spaceIndex;
                subString = text.substring(0, lastSpace);
                textList.add(subString);
                text = text.substring(lastSpace).trim();
                lastSpace = -1;
            }

            else if (spaceIndex == text.length()){
                textList.add(text);
                text = "";
            }

            else{
                lastSpace = spaceIndex;
            }
        }

        contentStream.beginText();
        contentStream.setFont(pdfFont, fontSize);
        contentStream.newLineAtOffset(PAGE_MARGIN, TABLE_HEIGHT);


        @SuppressWarnings("deprecation")
        PDPageContentStream newStream = new PDPageContentStream(doc, new_page, true, true);

        int nextPage_i = 0;

        for (int i=0; i<textList.size(); i++)//String line: textList){
            System.out.println("HEIGHT: "+ TABLE_HEIGHT);
            nextPage_i = i;
            String line = textList.get(i);
            float charSpacing = 0;

            if (line.length() > 1){         
                float size = fontSize * pdfFont.getStringWidth(line) / 1000;
                float free = width - size;
                if (free > 0){
                    charSpacing = free / (line.length() - 1);
                }
                TABLE_HEIGHT = TABLE_HEIGHT - 10;
            }

            contentStream.setCharacterSpacing(charSpacing); 
            contentStream.showText(line);
            contentStream.newLineAtOffset(0, -leading);

            if(TABLE_HEIGHT <= 280){  
                contentStream.endText();  
                contentStream.close(); 
                newPage = true;
                break; 
            } 
        } 

        if(!newPage){
            contentStream.endText();  
            contentStream.close(); 
        }

        else if (newPage){          
            float NEW_HEIGHT = 600;             
            newStream.beginText();
            newStream.setFont(pdfFont, fontSize);
            newStream.newLineAtOffset(PAGE_MARGIN, NEW_HEIGHT);

            for (int j=nextPage_i; j<textList.size(); j++)//String line: textList){
                System.out.println("HEIGHT: "+ NEW_HEIGHT);
                nextPage_i = j;
                String line = textList.get(j);
                float charSpacing = 0;

                if (line.length() > 1){         
                    float size = fontSize * pdfFont.getStringWidth(line) / 1000;
                    float free = width - size;
                    if (free > 0)
                    {
                        charSpacing = free / (line.length() - 1);
                    }
                    NEW_HEIGHT = NEW_HEIGHT - 10; 
                }
                newStream.setCharacterSpacing(charSpacing); 
                newStream.showText(line);
                newStream.newLineAtOffset(0, -leading);
            }
            newStream.endText();  
            newStream.close();
        }
        lastSpace = -1;
    }

Upvotes: 1

Views: 3960

Answers (2)

Gayan Chinthaka
Gayan Chinthaka

Reputation: 569

In my case, The error happens because the input PDDocument is closed prematurely, but its resources (e.g., fonts, images) are still referenced in the output document. When trying to save the output document, there are no referenced resources and getting this error.

previous code

try (PDDocument outputDocument = new PDDocument()) {
    File[] listOfFiles = Files to be merged
    PDPageTree pageTree = outputDocument.getDocumentCatalog().getPages();

    for (File file : listOfFiles) {
        if (file.isFile()) {
            try {
                try(PDDocument inputDoc = PDDocument.load(file, memSetting)){
                    for (PDPage page : document.getPages()) {
                        pageTree.add(page);
                    }
                }
            } catch (Exception e) {
            }
        }
    }
    outputDocument.save(output);
} catch (Exception e) {
} 

fixed code

List<PDDocument> inputFiles = new ArrayList<>();

try (PDDocument outputDocument = new PDDocument()) {
    File[] listOfFiles = Files to be merged

    PDPageTree pageTree = outputDocument.getDocumentCatalog().getPages();

    for (File file : listOfFiles) {
        if (file.isFile()) {
            try {
                PDDocument inputDoc = PDDocument.load(file, memSetting);
                inputFiles.add(inputDoc);
                
                addPagesFromDocument(pageTree, inputDoc);
                
            } catch (Exception e) {
            }
        }
    }

    outputDocument.save(output);
} catch (Exception e) {
} finally {
    inputFiles.forEach(doc -> {
        try { doc.close(); } catch (IOException e) { /* handle */ }
    });
}
private static void addPagesFromDocument(PDPageTree pageTree, PDDocument document) {
        for (PDPage page : document.getPages()) {
            pageTree.add(page);
      }
}

Upvotes: 0

mkl
mkl

Reputation: 96039

Pull the PDPage instantiations into PDFLetterGenerate:

public void PDFLetterGenerate (String args) throws Exception {
    PDPage main_page = new PDPage();
    PDPage new_page = new PDPage(); 

    text = args;
    text = text.replace("\n", "").replace("\r", "");

    if(file.exists()) file.delete();
    file.createNewFile();
    //Creating PDF document object 
    PDDocument document = new PDDocument();       
    document.addPage(main_page);  
    mainBody(document, main_page);      
    document.addPage(new_page);                          
    if(!newPage) document.removePage(new_page);

    document.save(file);
    document.close(); 
}

In your code the pages are instantiated once and the underlying streams are closed after the first run of PDFLetterGenerate when the local PDDocument document is closed after having the pages added to it.

Furthermore, also make new_page an argument of mainBody instead of counting on a static variable to hold it.

There are a number of other issues in your code, but the changes above should get you started.

Upvotes: 3

Related Questions