• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Adding text to PDF using iText instead of CFPDF

New Here ,
Oct 15, 2009 Oct 15, 2009

Copy link to clipboard

Copied

Hi,

I know this may seem a bit off topic being posted here but i'm asking this board since i'm a complete JAVA noob and i figure some of you CF folk might have had to do this before.

Anyway, about my question...i'm already adding a watermark image to a pdf using iText (CF8) thanks to the help of fellow poster (=cfSearching=).  What i'm looking for is the best way to go about adding some text to this same pdf.  I need to add 4 lines of text (with specific font and size) and center it underneath the added image.   Does anyone have a site they could point me to as to how to add formatted text and how to get the width of that text so as to align it correctly?  I've search Google and looked at a lot of JAVA code but being a JAVA noob it's tough to figure out exactly which libs and methods can be used to do this. 

Any help would be greatly appreciated!

-Michael

TOPICS
Advanced techniques

Views

12.3K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Valorous Hero , Oct 17, 2009 Oct 17, 2009

The classes you need are PdfTable and PdfCell

http://cfsearching.blogspot.com/2008/09/getting-started-with-itext-tables.html

I was curious, so I threw together a rough example. It adds the table to a pdfTemplate, then adds the watermark template to each page. The positioning and table dimensions are based on my sample data, so you will need to tweak them.  Just make sure the template dimensions are large enough to accomodate your image and text. If the dimensions are not large enough, the watermar

...

Votes

Translate

Translate
Valorous Hero ,
Oct 15, 2009 Oct 15, 2009

Copy link to clipboard

Copied

It all depends, but from what you have described you could create a merged image (ie current image plus the text beneath it).  Then apply the merged image as the watermark.  But are the four lines of text static or dynamic and do you need to figure out how to wrap the text? Maybe you can 'rig up' an example in your favorite image program to show the desired results.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 15, 2009 Oct 15, 2009

Copy link to clipboard

Copied

Hi again!

Well, the merged image is an idea but i'd rather have it be actual text so that it is at least copy/paste-able if viewed on a computer.

The four lines of text are dynamic (company name, broker name, phone number, email address) and limited to 40 characters.  Right now they are being added via CFPDF and DDX and use the following code in the DDX file to add it to the PDF.

<PDF result="DestinationFile">
     <PDF source="SourceFile">
          <Watermark
          rotation="0"
          opacity="100%"
          horizontalAnchor="#horzAnchor#"
          horizontalOffset="#horzOffset#"
          verticalAnchor="#vertAnchor#"
          verticalOffset="#vertOffset#"
          alternation="OddPages"
          >
               <StyledText text-align="center">
                    <p font="#font#" color="#color#" >#left(dCompany,maxlinechars)#</p>
                    <p font="#font#" color="#color#" >#left(dName,maxlinechars)#</p>
                    <p font="#font#" color="#color#" >#left(dPhone,maxlinechars)#</p>
                    <p font="#font#" color="#color#" >#left(dEmail,maxlinechars)#</p>
               </StyledText>
          </Watermark>
     </PDF>
</PDF>

Then using the created pdf from above, i use a slightly modified version of the cfscript code ( that uses iText) you provided me previously to add a logo image just above this text.  The only changes i made to it were resizing of the image and adding where to place it.  Here is that code:

<cfscript>                    
    fullPathToInputFile = "#tempdestfilepath#";
     writeoutput("<br>fullPathToInputFile=#fullPathToInputFile#");
    fullPathToWatermark = osFile("#request.logofilepath##qord.userlogo_file#",request.os);
     writeoutput("<br>fullPathToWatermark=#fullPathToWatermark#");
    fullPathToOutputFile =  "#destfilepath#";
     writeoutput("<br>fullPathToOutputFile=#fullPathToOutputFile#");
     ppi = 72; // points per inch
     
     watermark_x =  ceiling(#qord.pdftemplate_logo_x# * ppi);      // from bottom left corder of pdf
     watermark_y =  ceiling(#qord.pdftemplate_logo_y# * ppi);     // from bottom left corder of pdf
     
     fh = ceiling(0.75 * ppi);
     fw = ceiling(1.75 * ppi);
     
   if( not fileexists(fullPathToInputFile) )
   {
              savedErrorMessage = savedErrorMessage & "<li>Input file pdf for logo add does not exist<br>#fullPathToInputFile#</li>";
   }
   else
   {
             try {
             // create PdfReader instance to read in source pdf
             pdfReader = createObject("java", "com.lowagie.text.pdf.PdfReader").init(fullPathToInputFile);
             totalPages = pdfReader.getNumberOfPages();
     
             // create PdfStamper instance to create new watermarked file
             outStream = createObject("java", "java.io.FileOutputStream").init(fullPathToOutputFile);
             pdfStamper = createObject("java", "com.lowagie.text.pdf.PdfStamper").init(pdfReader, outStream);
     
             // Read in the watermark image
             img = createObject("java", "com.lowagie.text.Image").getInstance(fullPathToWatermark);
                w = img.scaledWidth();
               h = img.scaledHeight();
               
               //$is[0] = w
               //$is[1] = h
               
               if( w >= h )
              {
                  orientation = 0;
              }
              else
              {
                  orientation = 1;
                  fw = max_h;
                  fh = max_w;
              }
              if ( w > fw || h > fh )
              {
                  if( ( w - fw ) >= ( h - fh ) )
                  {
                      iw = fw;
                      ih = ( fw / w ) * h;
                  }
                  else
                  {
                      ih = fh;
                      iw = ( ih / h ) * w;
                  }
                  t = 1;
              }
              else
              {
                  iw = w;
                  ih = h;
                  t = 2;
              }
               
             // adding content to each page
             i = 0;
             //while (i LT totalPages) {
                 i = i + 1;
                 content = pdfStamper.getOverContent( javacast("int", i) );
                 img.setAbsolutePosition(javacast("float", watermark_x), javacast("float", watermark_y));
                    if(t==1)
                    {
                         img.scaleAbsoluteWidth( javacast("float", iw) );
                         img.scaleAbsoluteHeight( javacast("float", ih) );
                    }
                    
                 content.addImage(img);
                 WriteOutput("Watermarked page "& i &"<br>");
             //}
     
             //WriteOutput("Finished!");
             }       
             catch (java.lang.Exception e) {
             savedErrorMessage = savedErrorMessage & "<li>#e#</li>";
             }
         // closing PdfStamper will generate the new PDF file
         if (IsDefined("pdfStamper")) {
             pdfStamper.close();
         }
         if (IsDefined("outStream")) {
             outStream.close();
         }
   }
       
</cfscript>

The above code resized the image to a certain width/height if needed and adds it to the pdf. 

I just figured they might be a way to tap into one of the java objects that would allow adding the text.  Ideally, adding the text and image to some sort of 'bounding box' that would allow centering of the image and text in relation to that bounding box.  Or if there is no way to add to a bounding box, a way to get the horizontal length of the longest line of text so i could calculate a common centerline for the image and text.

I've attached the following pdf to show how the image and text would look together.  This example is not to scale but a similar image and text would be added to a separate pdf.

Thanks for you help.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Valorous Hero ,
Oct 15, 2009 Oct 15, 2009

Copy link to clipboard

Copied

Well, the merged image is an idea but i'd rather have it be

actual text so that it is at least copy/paste-able if viewed

on a computer.

Ah, I see. I suggested a merged image because that would be the simplest to implement. But if you want to preserve the text "as text", obviously that would not do the trick. You could probably achieve something similar using tables. Put the image in one row/cell and the centered text in another.

Bear in mind it has been a long day, and my brain is fried But I think that should work.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 16, 2009 Oct 16, 2009

Copy link to clipboard

Copied

Thanks for the reply!

So, taking my cfscript into account above, which JAVA object has the methods that i need to:

     1) add a table to a pdf  (1 col 2 row with each cell set to center)

     2) insert an image into the top cell

     3) insert text into the bottom cell

Here are the java objects defined in my code:

     pdfReader = createObject("java", "com.lowagie.text.pdf.PdfReader").init(fullPathToInputFile);

     outStream = createObject("java", "java.io.FileOutputStream").init(fullPathToOutputFile);

     pdfStamper = createObject("java", "com.lowagie.text.pdf.PdfStamper").init(pdfReader, outStream);

     img = createObject("java", "com.lowagie.text.Image").getInstance(fullPathToWatermark);

Can i use one of the objects above or do i need to instantiate a different object?  This is where i'm confused...if i knew which lib to research i'm sure i could figure it out...

Thanks...

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Valorous Hero ,
Oct 17, 2009 Oct 17, 2009

Copy link to clipboard

Copied

The classes you need are PdfTable and PdfCell

http://cfsearching.blogspot.com/2008/09/getting-started-with-itext-tables.html

I was curious, so I threw together a rough example. It adds the table to a pdfTemplate, then adds the watermark template to each page. The positioning and table dimensions are based on my sample data, so you will need to tweak them.  Just make sure the template dimensions are large enough to accomodate your image and text. If the dimensions are not large enough, the watermark may not be visible.


<!---
    NOTES:
    1. This code uses deprecated methods for compatibility with the iText version in CF8
    2. The table dimensions and watermark positions used are for demo purposes only and should be adjusted.

    Test Files:
    PDF:   http://itextdocs.lowagie.com/examples/com/lowagie/examples/general/copystamp/ChapterSection.pdf
    IMAGE: http://code.google.com/apis/themes/images/beveled_purpleblue.png
--->

<cfscript>
    err = "";
    // TEST VALUES
    maxlinechars = 40;
    dCompany = "Google Inc";
    dName = "1600 Amphitheatre Parkway";
    dPhone = "+1 650-253-0000";
    dEmail = "someone@google.com";
   
    // simplify code by putting the watermark text values into an array
    textElements    = [ dCompany, dName, dPhone, dEmail ];
    inputFile        = ExpandPath("ChapterSection.pdf");
    outputFile        = ExpandPath("ChapterSection_Watermark_ImageWithText.pdf"); 
    imgPath        = ExpandPath("/dev/beveled_purpleblue.png");

    try {
        // initalize objects for reading and writing the pdf       
        pdfReader = createObject("java", "com.lowagie.text.pdf.PdfReader").init(inputFile);
        outStream = createObject("java", "java.io.FileOutputStream").init(outputFile);
        pdfStamper = createObject("java", "com.lowagie.text.pdf.PdfStamper").init( pdfReader, outStream );

        // get the dimension of the watermark image       
        // note: the table width and height are sample values for demo only ..
        // must ensure your dimensions are large enough to accomdate your text and image
        // otherwise the watermark may not be fully visible
        img = createObject("java", "com.lowagie.text.Image").getInstance(imgPath);
        tableWidth = img.width() + 100;
        tableHeight = img.height() + 75;
       
        // create a template for storing the table
        cb = pdfStamper.getOverContent(1);
        template = cb.createTemplate(tableWidth, tableHeight);

        // create a single column table       
        table = createObject("java", "com.lowagie.text.pdf.PdfPTable").init( 1 );
        table.setTotalWidth( tableWidth );

        // reusable objects for adding table rows
        PdfCell = createObject("java", "com.lowagie.text.pdf.PdfPCell");
        Phrase = createObject("java", "com.lowagie.text.Phrase");

        // add the watermark image to the first row       
        imageCell = PdfCell.init( img, false );
        imageCell.setBorder( PdfCell.NO_BORDER);
        imageCell.setHorizontalAlignment( PdfCell.ALIGN_CENTER );
        table.addCell( imageCell );

        // add each text element in the array to a new row
        for (x = 1; x <= arrayLen(textElements); x++) {
            textCell = PdfCell.init( Phrase.init( textElements ) );
            textCell.setBorder( PdfCell.NO_BORDER );
            textCell.setHorizontalAlignment( PdfCell.ALIGN_CENTER );
            table.addCell( textCell );
        }
       
        // get the calculated table height
        table.calculateHeightsFast();
        tableHeight = table.getTotalHeight();
        table.writeSelectedRows(0, -1, 0, tableHeight, template);
        WriteOutput("Calculated tableWidth="& tableWidth &", tableHeight="& tableHeight &"<br>");

        // add the template watermark to each page
        // note: the x/yPos values are for demo only (top right) ...
        i = 0;
        totalPages = pdfReader.getNumberOfPages();
        while (i LT totalPages) {
            i = i + 1;
            content = pdfStamper.getOverContent( javacast("int", i) );
            // arbitrary positioning code
            pageSize = pdfReader.getPageSize(i);
            yPos = pageSize.height() - tableHeight - 15;
            xPos = (pageSize.width() - tableWidth) - 25;
            content.addTemplate( template, xPos, yPos );
            WriteOutput("Watermarked page "& i &" at xPos="& xPos &",yPos="& yPos &"<br>");
        }
    }
    catch (Exception e) {
        err = e;
    }
    if (IsDefined("pdfStamper")) {
             pdfStamper.close();
    }

    if (IsDefined("outStream"))
    {
        outStream.close();
    }
</cfscript>

<cfdump var="#err#" label="ERROR">

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 18, 2009 Oct 18, 2009

Copy link to clipboard

Copied

With some slight modification to your code i was able to get it to work.  Many thanks again for all your help with iText.  I can really see the benfits of using the underlying java objects to maniputlate PDF's instead of using the CFPDF items (if needing finer control of modification).

BTW, the i had to change the following lines:

FROM:   imageCell.setHorizontalAlignment( PdfCell.ALIGN_CENTER );

TO   imageCell.setHorizontalAlignment( img.ALIGN_CENTER );

and

FROM:    textCell.setHorizontalAlignment( PdfCell.ALIGN_CENTER );

TO:    textCell.setHorizontalAlignment( Phrase.ALIGN_CENTER );

From what my google search found, you need to set the alignment value on the object within the table cell.  Which seems odd to me (from an HTML point of view)

Again,  many thanks...  I'll have to look into your blog ( http://cfsearching.blogspot.com ) more for the info on using iText in CF.

-Michael

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Valorous Hero ,
Oct 18, 2009 Oct 18, 2009

Copy link to clipboard

Copied

LATEST

FROM: imageCell.setHorizontalAlignment(

PdfCell.ALIGN_CENTER );

Hi again,

Yes, I just realized that I was originally testing the code with a later version. So the last minute change to use PdfCell.ALIGN_CENTER did not work with CF8. It was basically a lazy short-cut, to avoid creating another object just to get the alignment constants. But I see it does not work with CF8's version of iText.

The alignment constants are defined higher up in the chain: ie Elements class. In later versions of iText you can access the constants through PdfCell because it extends => Rectangle => which implements Element (where the constants are). But that does not seem to be the case with CF8's version. So PdfCell.ALIGN_CENTER results in an error, because no such constant exists.

What does work is to create an "Element" object and then use Element.ALIGN_CENTER:

Element = createObject("java", "com.lowagie.text.Element");

imageCell.setHorizontalAlignment( Element.ALIGN_CENTER );

....

textCell.setHorizontalAlignment( Element.ALIGN_CENTER );

-Leigh

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Resources
Documentation