pdf « Intelligrape Groovy & Grails Blogs

Posts Tagged ‘ pdf ’

Using Data URLs for embedding images in Flying Saucer generated PDFs

Posted by on August 24th, 2012

We extensively use Flying Saucer to generate PDFs from GSPs in our grails applications. However, there is always the issue of embedding images from within the application because the URLs are usually relative to the environment and as such, embedding them in PDFs with a URL in the src attribute is cumbersome.

To get around this, we decided to write our own implementation of the ReplacedElementFactory taking some help from this excellent snippets of code. However, we didn’t find a need to go with our custom implementation of Base64 encoding and as such, we ended up using the sun.misc.BASE64Decoder. The resulting class looked like this :


import com.lowagie.text.BadElementException
import com.lowagie.text.Image
import org.w3c.dom.Element
import org.xhtmlrenderer.extend.FSImage
import org.xhtmlrenderer.extend.ReplacedElement
import org.xhtmlrenderer.extend.ReplacedElementFactory
import org.xhtmlrenderer.extend.UserAgentCallback
import org.xhtmlrenderer.layout.LayoutContext
import org.xhtmlrenderer.pdf.ITextFSImage
import org.xhtmlrenderer.pdf.ITextImageElement
import org.xhtmlrenderer.render.BlockBox
import org.xhtmlrenderer.simple.extend.FormSubmissionListener

public class B64ImgReplacedElementFactory implements ReplacedElementFactory {

 public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box, UserAgentCallback uac, int cssWidth, int cssHeight) {
     Element e = box.getElement();
     if (e == null) {
         return null;
     }
     String nodeName = e.getNodeName();
     if (nodeName.equals("img")) {
         String attribute = e.getAttribute("src");
         FSImage fsImage;
         try {
             fsImage = buildImage(attribute, uac);
         } catch (BadElementException e1) {
             fsImage = null;
         } catch (IOException e1) {
             fsImage = null;
         }
         if (fsImage != null) {
             if (cssWidth != -1 || cssHeight != -1) {
                 fsImage.scale(cssWidth, cssHeight);
             }
             return new ITextImageElement(fsImage);
         }
     }
     return null;
 }

 protected FSImage buildImage(String srcAttr, UserAgentCallback uac) throws IOException, BadElementException {
      FSImage fsImage;
      if (srcAttr.startsWith("data:image/")) {
         String b64encoded = srcAttr.substring(srcAttr.indexOf("base64,") + "base64,".length(), srcAttr.length());
         byte[] decodedBytes = new sun.misc.BASE64Decoder().decodeBuffer(b64encoded);
         fsImage = new ITextFSImage(Image.getInstance(decodedBytes));
      } else {
         fsImage = uac.getImageResource(srcAttr).getImage();
      }
      return fsImage;
 }

 public void remove(Element e) {
 }

 public void reset() {
 }

 @Override
 public void setFormSubmissionListener(FormSubmissionListener listener) {
 }
}

Now, in the code where we call the Renderer, we used :

 byte[] generatePdf(String content) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] bytes = null
        ITextRenderer renderer = new ITextRenderer();
        SharedContext sharedContext = renderer.getSharedContext();
        sharedContext.setPrint(true);
        sharedContext.setInteractive(false);
        sharedContext.setReplacedElementFactory(new B64ImgReplacedElementFactory());
        sharedContext.getTextRenderer().setSmoothingThreshold(0);
        try {
            renderer.setDocumentFromString(content);
            renderer.layout();
            renderer.createPDF(byteArrayOutputStream);
            bytes = byteArrayOutputStream.toByteArray()
        }
        catch (Throwable e) {
            log.error("Error while generating pdf ${e.message}", e)
        }
        return bytes
    }

Now, we can embed images in the form of data URLs in our GSPs using base64 encoded version of the image bytes.

Posted in Grails, HTML-UI-CSS

Request Mocking to use groovyPagesTemplateEngine in backend threads

Posted by on December 27th, 2010

We have a setup where a backend thread, fired by the Spring Events, does some processing, generates a PDF and emails the result to the user.
The code we were using to generate the HTML from a GSP to be converted to a PDF using iText was as follows :

        def webRequest = RequestContextHolder.getRequestAttributes()
        def originalOut = webRequest.out
        try {
            def sw = new StringWriter()
            def pw = new PrintWriter(sw)
            webRequest.out = pw
            groovyPagesTemplateEngine.createTemplate("path_to_gsp").make([model:model]).writeTo(pw)
            return sw.toString()
        } finally {
          webRequest.out = originalOut
        }

There was the obvious fallibility of this code that there was no Current Request associated with the backend thread!

After doing some googling around it, I came across a few threads and posts which talked about Request Mocking, which has been used in Grails Template Engine Plugin.  We overcame this by using the code snippet given below to mock the web request

def webRequest = RequestContextHolder.getRequestAttributes()
if(!webRequest) {
          def servletContext  = ServletContextHolder.getServletContext()
          def applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext)
          webRequest = grails.util.GrailsWebUtil.bindMockWebRequest(applicationContext)
}

However, things didn’t end there. This code broke while working on a WAR environment. The problem was that the MockWebRequest class was part of the “org.springframework:org.springframework.test:3.0.3.RELEASE” jar and had to be included in the BuildConfig.groovy as


dependencies{

runtime 'org.springframework:org.springframework.test:3.0.3.RELEASE'

}

Ensure that the line


mavenCentral()

is not commented in BuildConfig.groovy

We were working on Grails 1.3.4

 

Hope this helps.
Vivek

http://in.linkedin.com/in/svivekkrishna

Posted in Grails

Using iText PdfStamper to insert Images in PDFs while preserving Acroforms

Posted by on November 29th, 2010

We had a requirement that a template PDF which had Acroform fields had to be pre-populated (like name, email id etc) and sent to the end user so that he/she only needed to fill in the details which were expected to be filled by him/her.

After going through the iText library, we found that the PdfStamper class was the best way to go about it. However, we also discovered that we needed to embed a data matrix image in the document so that it can be identified by scanning the printed version of the document which is received back from the end user. After pondering on how to do it, we stumbled across this page. This was the perfect solution we were looking for.

Our service method looked something like

def populateFieldsAndSetImage(byte[] pdf){
        PdfReader reader = new PdfReader(pdf)
        ByteArrayOutputStream output = new ByteArrayOutputStream()
        def stamper = new PdfStamper(reader, output)
        AcroFields form= stamper.getAcroFields()
        form.setField('Address', 'Noida, India - 201301') //Set the form field
        PdfContentByte content = stamper.getOverContent(reader.getNumberOfPages())
        Image image = Image.getInstance(new URL("Absolute URL to the image to be embedded"))

        image.setAbsolutePosition(450,650)
        image.scaleAbsolute(200,200)
        content.addImage(image)
        reader.close()
        stamper.close()
        return output.toByteArray() //returns the Byte Array of the PDF contents
    }

And the calling method had code which looked like this :

        File file = new File('/home/vivek/filledForm.pdf') //File to which the filled pdf will be written
        file.bytes = populateFieldsAndSetImage(new File('/home/vivek/form.pdf').bytes) // set the bytes of filledForm.pdf with the byte array returned by populateFieldsAndSetImage()

The PDF had pre filled forms and the identification image also got inserted.

Hope this helps.
Vivek

http://in.linkedin.com/in/svivekkrishna

Posted in Java tools

Handling Password Protected Pdf with PdfReader

Posted by on August 19th, 2010

In one of our grails project , we had to attach cover to Pdf file . But since some of pdf’s uploaded were password protected.

To handle this scenario we added bouncyCastle.jar , so our version of iText was able to handle password protected pdf .
And Then to check whether pdf is password protected or not , we used “Boolean isOpenedWithFullPermission()” method.

PdfReader pdf = PdfReader("filePath")
Boolean editable = pdf.isOpenedWithFullPermissions()
 
if(editable){
//attach Cover
}else {
//skip  cover
}

As “isOpenedWithFullPermissions()” returns a Boolean variable ,
it was easy for us to recognize whether we would be able to edit (i.e attach cover in our case) depending on its output. (i,e true or false)
 

_________________________________
Hitesh Bhatia
Mail
LinkedIn,Facebook,Twitter
_________________________________

Posted in Grails, Groovy

Open Pdf in Google Docs using Time Based Cache in Grails

Posted by on June 23rd, 2010

Recently, we had a requirement where secure URLs were to be made accessible to Google.

Our implementation was to send a url with token valid for 10 seconds. The token expired automatically after 10 seconds. We used time based cache for this as described here: http://snippets.dzone.com/posts/show/2360

T set max time to 10 seconds , I set default MaxAge to 10 millis in above file only which could have also been done easily using its constructor.

Here’s how we did it ,

class AbcController {
    static TimedMap timedMap = new TimedMap()
 
   //  while calling "addDocumentUrl" path of document was passed as params attachmentPath
    def addDocumentUrl = {
 	        String attachmentPath = params.attachmentPath
 	        String token = UUID.randomUUID().toString()
 	        timedMap.put(uniqueIdentification,attachmentPath)
 	        redirect(url: getGoogleUrl(token))          // this will  make google hit specified url
 	    }
 
     String getGoogleUrl(String token) {
 	        String absoluteUrl = ConfigurationHolder.config.builder.absoluteURL
                String GOOGLE_URL="http://docs.google.com/viewer?embedded=true&url="
 	        String googlePath = GOOGLE_URL + absoluteUrl + "/abc/someAction/" + token
 	        return googlePath
 	    }
}

Action someAction was made public so that Google was able to access it. And when Google hits this action it gives token as id.

   def someAction = {
        String key = params.id.toString()
        try {
            String attachmentPath = timedMap.get(key)
            File file = new File(attachmentPath)
            response.setHeader("Content-disposition", "attachment; filename=pdf")
            response.setContentType("application/pdf")
            response.setContentLength(file.size().toInteger());
            OutputStream out = response.getOutputStream();
            out.write(file.readBytes());
            out.flush()
            out.close();
        } catch (Exception e) {
            e.printStackTrace()
        }
    }

_______________________________
Hitesh Bhatia
hitesh@intelligrape.com

http://in.linkedin.com/in/bhatiahitesh

_______________________________

Posted in Grails, Groovy, Java tools