Sunday, December 1, 2013

Liferay Document Viewer Plugin Portlet


Objective: 

Create Plug-in portlet  to view documents

Liferay already have documents preview in documents and media portlet by using that we can view documents

Document preview concept is uses Apache PDF Box by default from this we can see the PDF document.

For this we need not to do any configuration so that it will automatically view the PDF documents.

For better quality views life ray have provide future to configure Image Magick tool so that we can view documents with very good quality.

If we not configure Image Magick tool for life ray then it will show following message in the console  when we try to preview documents in liferay.


Liferay is not configured to use ImageMagick for generating Document Library previews and will default to PDFBox. For better quality previews, install ImageMagick and enable


If we use Image Magic tool then document is converted into images. Means each page is converted into one image.

This can be handle by liferay libraries the main class is PDFProcessorImpl.java it will take care the all the things

Download LiferayDocViewr  portlet from following location

You can find source and war file


Note: 

Portlet developed in Liferay 6.1GA2 EE version

If you want deploy in CE version you just do changes in liferay-plugin-package.properties
Liferay 6.1 EE version

name=LiferayDocViewr
module-group-id=liferay-ee
module-incremental-version=1
tags=
short-description=
change-log=
page-url=http://www.liferay.com
author=Liferay, Inc.
licenses=EE
liferay-versions=6.1.20


Liferay 6.1 CE version

name = LiferayDocViewr
module-group-id=liferay
module-incremental-version=1
tags=
short-description=
change-log=
page-url=http://www.liferay.com
author=Liferay, Inc.
licenses=LGPL
liferay-versions=6.1.1

Procedure for deploy portlet:

You can use war file and directly place in your portal deploy folder and test or you can also use source to deploy portlet.

Once portlet is deployed successfully you can see the portlet in sample category name as
Liferay Doc Viewer.

Login as Admin and add some sample documents using Document Media Portlet in liferay

Note:

Before use this portlet read entire article and then test the portlet

Now our target id create plug-in portlet for to view documents

  1. Configure Image Magic tool
  2. Configure Open Office and Start Open Office Service.
  3. Develop portlet to view documents


Configure Image Magic tool

Download Image Magick Tool from Following Location


Install image magic in your system, follow the installation steps and choose your image magick installation directory

Generally it is in program Files, this path we will use in liferay Image magick configuration


Now login as Admin in liferay and go control panel

Go to portal server section and click on Server Administration menu form the tab choose External Service from that enable image magick tool and configure Image Magick installation path


The following is screen for Image Magick configuration in liferay.




Now Document Viewer uses Images Magick service to generate images from document then we can see view good quality

If any quality problem then go through following URL from liferay wiki

Configure Open Office and Start Open Office Service

From document viewer can support by default PDF view. If we want see MS office documents and open office documents we need to configure open office and we need to start open office service.

The concept something like first documents will be converted into PDF and then PDF documents will be converted into images based on pages the document contains.each page converted into one image.

Go through following link configure open office and start open office service


Develop portlet to view documents

Liferay have already provides document preview in Document Library Portlet.

They have created AUI JavaScript to make view template.

This AUI script will take preview URL and Number of pages count as options.
The page preview URL something like Follows


The following is Example URL




Each time when the request have  /document URL pattern the request will be handled by WebServerServlet.java  servlet this will start PDFProcessor and do further actions like convert PDF to images or documents to PDF and then images.

The following is important java classes

PDFProcessorUtil.java and PDFProcessorImpl.java

Internally it uses many implementation classes from portal

Note:

If document is more then it will take time to generate images

If document is ms office or open office first it should convert into PDF and then images so It will take time to complete this process.

The following is code for document viewer template
<%@page import="com.liferay.portlet.documentlibrary.util.DLUtil"%>
<%@page import="com.liferay.portlet.documentlibrary.util.PDFProcessorUtil"%>
<%@page import="com.liferay.portal.kernel.repository.model.FileVersion"%>
<%@page import="com.liferay.portal.kernel.repository.model.FileEntry"%>
<%@page import="com.liferay.portlet.documentlibrary.service.DLAppLocalServiceUtil"%>
<%@page import="com.liferay.portlet.documentlibrary.service.DLAppHelperLocalServiceUtil"%>
<%@ include file="init.jsp"%>
<%
long fileEntryId=ParamUtil.getLong(renderRequest,"fileEntryId");
FileEntry fileEntry=DLAppLocalServiceUtil.getFileEntry(fileEntryId);
FileVersion fileVersion=fileEntry.getFileVersion();
boolean hasPDFImages = PDFProcessorUtil.hasImages(fileVersion);
int previewFileCount = 0;
String previewFileURL = null;
String[] previewFileURLs = null;
String videoThumbnailURL = null;
String previewQueryString = null;
if (hasPDFImages) {
            previewFileCount = PDFProcessorUtil.getPreviewFileCount(fileVersion);
            previewQueryString = "&previewFileIndex=";
            previewFileURL = DLUtil.getPreviewURL(fileEntry, fileVersion, themeDisplay, previewQueryString);
            %>
            <div class="lfr-preview-file" id="<portlet:namespace />previewFile">
            <div class="lfr-preview-file-content"
                        id="<portlet:namespace />previewFileContent">
                        <div class="lfr-preview-file-image-current-column">
                                    <div class="lfr-preview-file-image-container">
                                                <img class="lfr-preview-file-image-current"
                                                            id="<portlet:namespace />previewFileImage"
                                                            src="<%= previewFileURL + "1" %>" />
                                    </div>
                                    <span class="lfr-preview-file-actions aui-helper-hidden"
                                                id="<portlet:namespace />previewFileActions"> <span
                                                class="lfr-preview-file-toolbar"
                                                id="<portlet:namespace />previewToolbar"></span> <span
                                                class="lfr-preview-file-info"> <span
                                                            class="lfr-preview-file-index"
                                                            id="<portlet:namespace />previewFileIndex">1</span> of <span
                                                            class="lfr-preview-file-count"><%= previewFileCount %></span>
                                    </span>
                                    </span>
                        </div>

                        <div class="lfr-preview-file-images"
                                    id="<portlet:namespace />previewImagesContent">
                                    <div class="lfr-preview-file-images-content"></div>
                        </div>
            </div>
</div>
<aui:script use="aui-base,liferay-preview">
new Liferay.Preview(
                                    {
            actionContent: '#<portlet:namespace />previewFileActions',
            baseImageURL: '<%= previewFileURL %>',
            boundingBox: '#<portlet:namespace />previewFile',
    contentBox: '#<portlet:namespace />previewFileContent',
            currentPreviewImage: '#<portlet:namespace />previewFileImage',
            imageListContent: '#<portlet:namespace />previewImagesContent',
            maxIndex: <%= previewFileCount %>,
    previewFileIndexNode: '#<portlet:namespace />previewFileIndex',
            toolbar: '#<portlet:namespace />previewToolbar'
            }).render();
</aui:script>
<%}else{%>
<h2>Unable to view document</h2>
<%}%>

Liferay.Preview needs options baseImageURL and maxIndex means total page count.

Note:

We can also use Jquery Page Flip to make better view


Tip to generate images

<%
for(int i=1;i<= previewFileCount;i++){%>

<img   id="<portlet:namespace />previewFileImage"
src="<%= previewFileURL + "1" %>"
/>

<%}%>

Important Points

  • Liferay have provide document view by default by using PDF box
  • To get better quality view we need to configure Image Magick tool to liferay .
  • To view only PDF documents then we need not to configure open office.
  • To View documents we need to configure open office and we need to start open office service
  • In document view each page converted into one image by PDF processor.
  • If documents are Open office or MS office then first it will be converted into PDF and then it will be converted into images based on number of pages document contains
  • Liferay provide AUI java script template to view documents we can also use JQuery Page Flip to make better view.
  • The following are portlet screen shots

Screen 1:



Screen 2:



Reference Links


https://www.liferay.com/web/alexander.chow/blog/-/blogs/7341017


Author
Meera Prince

Friday, November 22, 2013

Export Journal Content as PDF in Liferay

 

Objective:

Export Journal Content/Web Content  as PDF.

Liferay have feature to export journal content as PDF.

Liferay already have support to export journal content as PDF document but we need to do open office configuration.

Here we are doing without help of open office configuration.

With help of JTidy and Flying Saucer we will export general content as PDF with zero configurations.

Download Export Jorinal Content  portlet from following location

You can find source and war file


Note: 

Portlet developed in Liferay 6.1GA2 EE version
If you want deploy in CE version you just do changes in liferay-plugin-package.properties

Liferay 6.1 EE version

name= ExportJournalContentAsPDF
module-group-id=liferay-ee
module-incremental-version=1
tags=
short-description=
change-log=
page-url=http://www.liferay.com
author=Liferay, Inc.
licenses=EE
portal-dependency-jars=\
    jstl-api.jar,\
    jstl-impl.jar
portal-dependency-tlds=c.tld
liferay-versions=6.1.20


Liferay 6.1 CE version

name = ExportJournalContentAsPDF
module-group-id=liferay
module-incremental-version=1
tags=
short-description=
change-log=
page-url=http://www.liferay.com
author=Liferay, Inc.
licenses=LGPL
portal-dependency-jars=\
    jstl-api.jar,\
    jstl-impl.jar
portal-dependency-tlds=c.tld
liferay-versions=6.1.1

Procedure for deploy portlet:

You can use war file and directly place in your portal deploy folder and test or you can also use source to deploy portlet.

Once portlet is deployed successfully you can see the portlet in sample category name as
Export Jorinal Content.

JTidy:

JTidy  is java based library for cleaning up malformed and faulty HTML and JTidy provides a DOM interface to the document that is being processed, which effectively makes you able to use JTidy as a DOM parser for real-world HTML.

Go through following link to get more information about JTidy.


Flying Saucer:

Flying Saucer is java library to generate PDF from HTML and XML. This is pretty interesting library to generate PDF very easy way even complex PDF too. Generally we can design content in HTML the same thing we can generate as PDF.

Go through following link to get more information about flying saucer


Why we are using JTidy with Flying Saucer?

Generally when we use HTML in flying saucer that should be well formed, if any syntax errors or any other malformed data then it won’t be exported as PDF.

Generally when we generate PDF with help of flying saucer we mostly getting html content as dynamic, so we need to use JTidy to clean HTML, means to correct syntax errors and clean malformed data.

Steps to generate PDF

  1. Get html contents from any sources
  2. Convert html data as Input Stream
  3. Apply JTidy to cleans html data make it as well formed w3c document.
  4. Pass w3c document to flying saucer to generate PDF.


Get html contents from any sources:

First we need to get HTML data from any sources we can use any URL to get html data mean its string of html tags.

Example:

We can manually prepare html data as string or we get html data from any URL.






String html = ""<!DOCTYPE HTML><<html><head><title>First parse</title></head>"
  + "<body><p>This is test HTML.</p></body></html>";


Convert html data as Input Stream:

Now once get html content as String now we need convert string to input stream


String html = ""<!DOCTYPE HTML><<html><head><title>First parse</title></head>"

  + "<body><p>This is test HTML.</p></body></html>";
InputStream is = new ByteArrayInputStream(html.getBytes());



Apply JTidy to cleans html data make it as well formed w3c document


String html = ""<!DOCTYPE HTML><<html><head><title>First parse</title></head>"
  + "<body><p>This is test HTML.</p></body></html>";
InputStream is = new ByteArrayInputStream(articleHtml.getBytes());
Tidy tidy = new Tidy();
org.w3c.dom.Document doc = tidy.parseDOM(is, null);



Pass w3c document to flying saucer to generate PDF



OutputStream outputStream = resourceResponse.getPortletOutputStream();
ITextRenderer renderer = new ITextRenderer();
renderer.setDocument(doc, null);
renderer.layout();
renderer.createPDF(outputStream);



Note:

This process can apply anywhere to generate PDF from HTML using flying saucer.

The following is complete example to export journal content as PDF


import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.portlet.PortletException;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import com.liferay.portal.kernel.language.LanguageUtil;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.theme.ThemeDisplay;
import com.liferay.portlet.journal.model.JournalArticleDisplay;
import com.liferay.portlet.journalcontent.util.JournalContentUtil;
import com.liferay.util.bridges.mvc.MVCPortlet;
import com.lowagie.text.DocumentException;
import org.w3c.dom.Document;
import org.w3c.tidy.Tidy;
import org.xhtmlrenderer.pdf.ITextRenderer;
public class ExportJorinalContentAction extends MVCPortlet {
            @Override
            public void serveResource(
                                    ResourceRequest resourceRequest, ResourceResponse resourceResponse)
                        throws IOException, PortletException {
                        String articleId=ParamUtil.getString(resourceRequest,"webContentSelectBox");
                        ThemeDisplay themeDisplay = (ThemeDisplay)resourceRequest.getAttribute(WebKeys.THEME_DISPLAY);
                        long groupId =ParamUtil.getLong(resourceRequest,"sitesSelectBox");
                        try {
                        //get journal article
                        JournalArticleDisplay articleDisplay = JournalContentUtil.getDisplay(groupId, articleId, "", LanguageUtil.getLanguageId(resourceRequest),themeDisplay);
                        //set up response to handle PDF
                        resourceResponse.reset();
                        resourceResponse.setContentType("application/pdf");
                        resourceResponse.setProperty("Content-disposition", "attachment; filename=\"" + articleDisplay.getTitle().concat(StringPool.PERIOD).concat("pdf") + "\"");
                        OutputStream outputStream = resourceResponse.getPortletOutputStream();
                        String articleHtml = "<!DOCTYPE HTML><html><body>"+articleDisplay.getContent()+"</body></html>";
                        //prepend portal URL to local document library relative URLs
                        articleHtml = articleHtml.replaceAll("src=\"/documents", "src=\""+themeDisplay.getPortalURL()+"/documents");
                        Tidy tidy = new Tidy();
                        // Create inputStream to parse with tidy.
                        InputStream is = new ByteArrayInputStream(articleHtml.getBytes());
                        // Create XML Document from tidy
                        Document doc = tidy.parseDOM(is, null);
                        //render PDF
                        ITextRenderer renderer = new ITextRenderer();
                        renderer.setDocument(doc, null);
                        renderer.layout();
                        renderer.createPDF(outputStream);
                                   
                        } catch (DocumentException e) {
                                    // TODO Auto-generated catch block
                                    e.printStackTrace();
                        }
                       
            }
}


Important points

  • With the help of JTidy and Flying saucer we can generate PDF from  HTML
  • We can also apply CSS to html in flying saucer.
  • Without configuration of open office in Liferay we can export Journal Content as PDF with the help of Flying saucer.


 I have written Article about flying saucer.


Note:

In above example I did not use JTidy to clean HTML but better use JTidy to clean HTML and pass to flying saucer so that we can get PDF without any problems.

Screens:

Journal Content Export Portlet




Example Journal Content for Export




Example PDF after Export




Reference Links:



Recent Posts

Recent Posts Widget

Popular Posts