2

Is there a way i can split up a large jgraph graphics 2d document into multiple pages in a pdf using itext. I have a large flowchart created using jgraph. I need to write this flowchart into a pdf wit multiple pages. I need to make sure that each pdf page height is limited to 5000.SO if the graphics object height is more than 5000 it spans across multiple pages in the pdf. Is there a way i can read the graphics object in chunk (upto a height of 5000 in each iteration), keep writing it to a new pdf page and iterate till i completely read the object. Any inputs/directions will be helpful.

Below is what i have till now -

float imageIdealHeight = 5000;
float imageIdealWidth = 5000;
float imageActualWidth=0;
float imageActualHeight=0;
mxRectangle imageBounds = ((mxGraph) graph).getGraphBounds();
imageActualWidth= (float) imageBounds.getWidth();
imageActualHeight = (float) imageBounds.getHeight();

System.out.println("Actual Width = "+imageActualWidth);
System.out.println("Actual Height = "+imageActualHeight);

numPages = (int) Math.ceil(imageActualHeight/imageIdealHeight);

Rectangle actualRectangle = new Rectangle(imageActualWidth, imageActualHeight);

//Custom Rectangle
Rectangle idealRectangle = new Rectangle(imageIdealWidth, imageIdealHeight);
Document document = new Document(idealRectangle );

//Create Pdf Writer
PdfWriter writer = PdfWriter.getInstance(document, fos);

//Open Document
document.open();

//Create huge template with actual image dimensions 
PdfContentByte canvas = writer.getDirectContent();
PdfTemplate template = canvas.createTemplate(imageActualWidth, imageActualHeight);
PdfCanvasFactory pdfCanvasFactory = new PdfCanvasFactory(canvas);

//Draw graphics to this template 
Graphics2D g2=template.createGraphics(imageActualWidth, imageActualHeight);
mxGraphics2DCanvas mxcanvas = new mxGraphics2DCanvas( g2);

mxcanvas = (mxGraphics2DCanvas) mxCellRenderer.drawCells((mxGraph) graph, null, 1, null, pdfCanvasFactory);
mxcanvas.getGraphics().dispose();

g2.dispose();

//Add template now...      
canvas.addTemplate(template,0, -15000);
document.newPage();
canvas.addTemplate(template, 0, -10000);
document.newPage();
canvas.addTemplate(template,0 , -5000);
document.newPage();
canvas.addTemplate(template, 0, 0);
document.newPage();

document.close();

2 Answers2

1

You want a PDF with pages that measure 5000 by 5000 user units. This means that you're going to create a document with a custom rectangle like this:

Rectangle rect = new Rectangle(5000, 5000);
Document document = new Document(rect);

Obviously, you're also going to create a writer like this:

PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("my_file.pdf"));

And you're going to open the document:

document.open();

Let's assume that your Graphics2D "image" is 10000 by 10000 point. This means that you'd need to distribute that image over 4 pages.

The trick is to create a PdfTemplate object that measures 10000 by 10000.

PdfContentByte canvas = writer.getDirectContent();
PdfTemplate template = canvas.createTemplate(10000, 10000);

Now we'll draw the graphics to this template:

Graphics2D gd2d = new PdfGraphics2D(template, 10000, 10000);
// draw stuff to gd2d
gd2d.dispose();

You've now created a large Form XObject with content that doesn't fit a page. This content will be present in the PDF file only once as an external object (hence the term XObject). All you have to do, is to add the document as many times as needed.

For example:

canvas.addTemplate(template, 0, 0);
document.newPage();

I hope you have a notion of the coordinate system: (0, -5000), (-5000, -5000), (0, 0) and (-5000, 0) are the x, y offsets needed to divide a 10000 by 10000 object over 4 pages that are only 5000 by 5000 in size.

The only line of code that remains, is:

document.close();

And you're done.

For a full example, see LargeTemplate:

public void createPdf(String dest) throws IOException, DocumentException {
    float width = 602;
    float height = 15872;
    float maxHeight = 5000;
    Document document = new Document(new Rectangle(width, maxHeight));
    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(DEST));
    document.open();
    PdfContentByte canvas = writer.getDirectContent();
    PdfTemplate template = canvas.createTemplate(width, height);
    Graphics2D g2d = new PdfGraphics2D(template, width, height);
    for (int x = 10; x < width; x += 100) {
        for (int y = 10; y < height; y += 100) {
            g2d.drawString(String.format("(%s,%s)", x, y), x, y);
        }
    }
    g2d.dispose();
    int pages = ((int)height / (int)maxHeight) + 1;
    for (int p = 0; p < pages; ) {
        p++;
        canvas.addTemplate(template, 0, (p * maxHeight) - height);
        document.newPage();
    }
    document.close();
}

As you can see, I used the dimensions you mention in your comment:

float width = 602;
float height = 15872;

I also introduce a maximum height:

float maxHeight = 5000;

I create a page with dimensions width x maxHeight and a Graphics2D template with dimensions width x height. For testing purposes, I use drawString() to draw coordinate information every 100 points.

I calulate how many pages I'll need:

int pages = ((int)height / (int)maxHeight) + 1;

Now I add the template as many times as there are pages, using some elementary math to calculate the offset:

for (int p = 0; p < pages; ) {
    p++;
    canvas.addTemplate(template, 0, (p * maxHeight) - height);
    document.newPage();
}

I don't know which Math you are using, but the resulting PDF looks exactly the way I expect it: large_template.pdf

Bruno Lowagie
  • 75,994
  • 9
  • 109
  • 165
  • Thanks Bruno. I tried the above but i only see the last chunk of my image (5000 user units) in the first page of my pdf and all other pages are blank. Below is my code snippet- – shoukatghouse Jul 18 '14 at 06:44
  • Do not use comments to add code. Update your question. Also: do some more experiments before you ask a question. The Form XObject is added to the page all right if you use `addTemplate()`. Now try some different values for `x` and `y`. – Bruno Lowagie Jul 18 '14 at 06:51
  • Thanks Bruno. I tried various xy cordinates. I printed the actual size of my image and that is 602 X 15872 in dimension. I tried below x,y coordinates.All of them give me only the last chunk of my image in the first page of pdf and rest all pages blank. – shoukatghouse Jul 18 '14 at 07:29
  • Sorry i missed to add the coordinates i tried in my earlier comment..I tried (0,-15000),(0,-10000),(0,-5000),(0,0).. Am i missing something? – shoukatghouse Jul 18 '14 at 08:03
  • Maybe you should do the math. I'm updating my example, based on your specific case. – Bruno Lowagie Jul 18 '14 at 11:01
  • I asked you do do some Math. You copy/pasted my values. People who copy/paste code without understanding the meaning of what they copy will never be true developers. – Bruno Lowagie Jul 18 '14 at 11:10
  • Sorry i did that part of my code before you updated your code snippet .. It was bad timing from my part to update my code here :).. i am going to dig furthur into it.. i feel somehow the initial huge template i am creating is only having the last chunk of the image.. i will update furthur after doing more work and reading.. Thanks so much for your help.. – shoukatghouse Jul 18 '14 at 11:59
  • Of course: if the template doesn't contain the data you won't see the data. That's why I created a template with test data that covers the complete template. – Bruno Lowagie Jul 18 '14 at 12:04
  • Hi Bruno, After a bit of reading and analyzing , I got this working.. There were two issues- Firstly the template was not having the entire data and second i was not using proper maths as you already mentioned.. I am mentioning the final solution in the answer. Again thanks much for your help and directions.. – shoukatghouse Jul 18 '14 at 14:27
0
    int numPages; 
    float imageIdealHeight = 5000;
    float imageIdealWidth = 5000;
    float imageActualWidth=0;
    float imageActualHeight=0;
    mxRectangle imageBounds = ((mxGraph) graph).getGraphBounds();
    imageActualWidth= (float) imageBounds.getWidth();
    imageActualHeight = (float) imageBounds.getHeight();

    System.out.println("Actual Width = "+imageActualWidth);
    System.out.println("Actual Height = "+imageActualHeight);

    numPages = (int) Math.ceil(imageActualHeight/imageIdealHeight);

    Rectangle actualRectangle = new Rectangle(imageActualWidth, imageActualHeight);

    //Custom Rectangle
    Rectangle idealRectangle = new Rectangle(imageActualWidth, imageIdealHeight);
    Document document = new Document(idealRectangle);

    //Create Pdf Writer
    PdfWriter writer = PdfWriter.getInstance(document, fos);

    //Open Document
    document.open();

    //Create huge template with actual image dimensions 
    PdfContentByte canvas = writer.getDirectContent();
    PdfTemplate template = canvas.createTemplate(imageActualWidth, imageActualHeight);


    //Draw graphics to this template 
   Graphics2D g2=template.createGraphics(imageActualWidth, imageActualHeight);
   g2.drawImage(img, null, 0, 0);
   g2.dispose();  
   for (int p = numPages; p > 0; ) {
   p--;
        canvas.addTemplate(template, 0, -  ((p-1) *imageIdealHeight  + (imageActualHeight  % imageIdealHeight))  );            
        document.newPage();
    }


    document.close();