com.propelics.pdfcreator.PdfcreatorModule.java Source code

Java tutorial

Introduction

Here is the source code for com.propelics.pdfcreator.PdfcreatorModule.java

Source

/**
 * This file was auto-generated by the Titanium Module SDK helper for Android
 * Appcelerator Titanium Mobile
 * Copyright (c) 2009-2013 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 *
 */
package com.propelics.pdfcreator;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Set;
import java.io.StringReader;
import java.io.StringWriter;

import org.apache.commons.io.IOUtils;
import org.appcelerator.kroll.KrollDict;
import org.appcelerator.kroll.KrollModule;
import org.appcelerator.kroll.annotations.Kroll;
import org.appcelerator.kroll.common.Log;
import org.appcelerator.titanium.TiApplication;
import org.appcelerator.titanium.io.TiBaseFile;
import org.appcelerator.titanium.io.TiFileFactory;
import org.appcelerator.titanium.proxy.TiViewProxy;
import org.appcelerator.titanium.util.TiConvert;
import org.appcelerator.titanium.view.TiUIView;
import org.w3c.tidy.Tidy;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.webkit.WebView;

import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Font;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.FontFactoryImp;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.tool.xml.XMLWorker;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.Pipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
import com.itextpdf.tool.xml.pipeline.css.CSSResolver;
import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipeline;
import com.itextpdf.tool.xml.pipeline.end.PdfWriterPipeline;
import com.itextpdf.tool.xml.parser.XMLParser;
import com.itextpdf.tool.xml.html.CssAppliersImpl;
import com.itextpdf.tool.xml.pipeline.html.AbstractImageProvider;
import com.itextpdf.tool.xml.html.Tags;

@Kroll.module(name = "PDFCreator", id = "com.propelics.pdfcreator")
public class PdfcreatorModule extends KrollModule {

    // Standard Debugging variables
    private static final String MODULE_NAME = "PdfcreatorModule";
    private static final String PROXY_NAME = "PDF_PROXY";

    // Private members
    private static TiApplication app;

    // You can define constants with @Kroll.constant, for example:
    // @Kroll.constant public static final String EXTERNAL_NAME = value;
    public PdfcreatorModule() {
        super();
    }

    @Kroll.onAppCreate
    public static void onAppCreate(TiApplication myApp) {
        Log.d(MODULE_NAME, "inside onAppCreate");
        app = myApp;
        // put module init code that needs to run when the application is created
    }

    // Methods

    /**
     * @method generatePDFWithHTML
     * Generates a PDF with the given file name, based on a HTML file
     * @param {String} filename Name of the PDF file
     * @param {String} html String with the HTML
     * @param {String} [author] Author for metadata
     * Fires a "complete" event when the PDF is generated
     * Fires a "error" event when a error is presented
     */
    @Kroll.method(runOnUiThread = true)
    public void generatePDFWithHTML(final HashMap args) {
        Log.d(PROXY_NAME, "generatePDFWithHTML()");

        String html = "";
        String author = "";
        String filename = "";
        final float marginPt = 28.35f;//1cm == 28.35pt

        try {
            if (args.containsKey("filename")) {
                filename = (String) args.get("filename");
                Log.d(PROXY_NAME, "filename: " + filename);
            } else
                return;

            if (args.containsKey("html")) {
                html = (String) args.get("html");
                Log.d(PROXY_NAME, "html: " + html);
            } else
                return;

            if (args.containsKey("author")) {
                author = (String) args.get("author");
                Log.d(PROXY_NAME, "author: " + author);
            }

            //create a new document
            Document document = new Document(PageSize.LETTER, marginPt, marginPt, marginPt, 0);
            TiBaseFile file = TiFileFactory.createTitaniumFile(filename, true);

            // Parse to XHTML
            StringWriter xhtmlWriter = new StringWriter();
            Tidy tidy = new Tidy();

            // tidy.setXHTML(true);
            tidy.setXmlOut(true);
            tidy.parse(new StringReader(html), xhtmlWriter);
            String xhtml = xhtmlWriter.toString();

            //get Instance of the PDFWriter
            PdfWriter pdfWriter = PdfWriter.getInstance(document, file.getOutputStream());

            //document header attributes
            document.addAuthor(author);
            document.addCreationDate();
            document.setPageSize(PageSize.LETTER);

            //open document
            document.open();

            // From Stack Overflow lol

            MyFontFactory fontFactory = new MyFontFactory();
            FontFactory.setFontImp(fontFactory);

            // HtmlPipelineContext htmlContext = new HtmlPipelineContext(new CssAppliersImpl(fontFactory));
            HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
            htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
            CSSResolver cssResolver = XMLWorkerHelper.getInstance().getDefaultCssResolver(true);
            Pipeline<?> pipeline = new CssResolverPipeline(cssResolver,
                    new HtmlPipeline(htmlContext, new PdfWriterPipeline(document, pdfWriter)));
            XMLWorker worker = new XMLWorker(pipeline, true);
            XMLParser p = new XMLParser(worker);
            p.parse(new StringReader(xhtml));

            // Finish SO c&P

            // Older code
            /*
            // Font Provider creation
            MyFontFactory fontProvider = new MyFontFactory();
            // fontProvider.register("/DroidSans.ttf");
                
            //get the XMLWorkerHelper Instance
            XMLWorkerHelper worker = XMLWorkerHelper.getInstance();
            //convert to PDF
            worker.parseXHtml(pdfWriter, document, new ByteArrayInputStream(xhtml.getBytes("UTF-8")), null, fontProvider); //Load xhtml
            */

            //close the document
            document.close();
            //close the writer
            pdfWriter.close();

            sendCompleteEvent(filename);

        } catch (Exception e) {
            sendErrorEvent(e);
        }
    }

    /**
     * @method generatePDFwithWebView
     * Generates a PDF with the given webview, obtaining all of its content as an image
     * @param {String} filename Name of the PDF file
     * @param {TiUIView} webview Web View to obtain the html from
     * @param {Integer} [quality] Quality of the image to generate, from 0 to 100
     * Fires a "complete" event when the PDF is generated
     * Fires a "error" event when a error is presented
     */
    @Kroll.method(runOnUiThread = true)
    public void generatePDFwithWebView(final HashMap args) {
        Log.d(PROXY_NAME, "generatePDF()");

        if (TiApplication.isUIThread()) {
            generateiTextPDFfunction(args);
        } else {
            app.getCurrentActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    generateiTextPDFfunction(args);
                }
            });
        }
    }

    //Private functions

    private void generateiTextPDFfunction(HashMap args) {
        Log.d(PROXY_NAME, "generateiTextPDFfunction()");

        String filename = "";
        TiUIView webview = null;
        int quality = 100;

        try {
            if (args.containsKey("filename")) {
                filename = (String) args.get("filename");
                Log.d(PROXY_NAME, "filename: " + filename);
            } else
                return;

            if (args.containsKey("webview")) {
                TiViewProxy viewProxy = (TiViewProxy) args.get("webview");
                webview = viewProxy.getOrCreateView();
                Log.d(PROXY_NAME, "webview: " + webview.toString());
            } else
                return;

            if (args.containsKey("quality")) {
                quality = TiConvert.toInt(args.get("quality"));
            }

            TiBaseFile file = TiFileFactory.createTitaniumFile(filename, true);
            Log.d(PROXY_NAME, "file full path: " + file.nativePath());

            OutputStream outputStream = file.getOutputStream();
            final int MARGIN = 0;
            final float PDF_WIDTH = PageSize.LETTER.getWidth() - MARGIN * 2; // A4: 595 //Letter: 612
            final float PDF_HEIGHT = PageSize.LETTER.getHeight() - MARGIN * 2; // A4: 842 //Letter: 792
            final int DEFAULT_VIEW_WIDTH = 980;
            final int DEFAULT_VIEW_HEIGHT = 1384;
            int viewWidth = DEFAULT_VIEW_WIDTH;
            int viewHeight = DEFAULT_VIEW_HEIGHT;

            Document pdfDocument = new Document(PageSize.LETTER, MARGIN, MARGIN, MARGIN, MARGIN);
            PdfWriter docWriter = PdfWriter.getInstance(pdfDocument, outputStream);

            Log.d(PROXY_NAME, "PDF_WIDTH: " + PDF_WIDTH);
            Log.d(PROXY_NAME, "PDF_HEIGHT: " + PDF_HEIGHT);

            WebView view = (WebView) webview.getNativeView();

            if (TiApplication.isUIThread()) {

                viewWidth = view.capturePicture().getWidth();
                viewHeight = view.capturePicture().getHeight();

                if (viewWidth <= 0) {
                    viewWidth = DEFAULT_VIEW_WIDTH;
                }

                if (viewHeight <= 0) {
                    viewHeight = DEFAULT_VIEW_HEIGHT;
                }

            } else {
                Log.e(PROXY_NAME, "NO UI THREAD");
                viewWidth = DEFAULT_VIEW_WIDTH;
                viewHeight = DEFAULT_VIEW_HEIGHT;
            }

            view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
            Log.d(PROXY_NAME, "viewWidth: " + viewWidth);
            Log.d(PROXY_NAME, "viewHeight: " + viewHeight);

            float scaleFactorWidth = 1 / (viewWidth / PDF_WIDTH);
            float scaleFactorHeight = 1 / (viewHeight / PDF_HEIGHT);

            Log.d(PROXY_NAME, "scaleFactorWidth: " + scaleFactorWidth);
            Log.d(PROXY_NAME, "scaleFactorHeight: " + scaleFactorHeight);

            Bitmap viewBitmap = Bitmap.createBitmap(viewWidth, viewHeight, Bitmap.Config.ARGB_8888);
            Canvas viewCanvas = new Canvas(viewBitmap);

            // Paint paintAntialias = new Paint();
            // paintAntialias.setAntiAlias(true);
            // paintAntialias.setFilterBitmap(true);

            Drawable bgDrawable = view.getBackground();
            if (bgDrawable != null) {
                bgDrawable.draw(viewCanvas);
            } else {
                viewCanvas.drawColor(Color.WHITE);
            }
            view.draw(viewCanvas);

            TiBaseFile pdfImg = createTempFile(filename);

            viewBitmap.compress(Bitmap.CompressFormat.PNG, quality, pdfImg.getOutputStream());

            FileInputStream pdfImgInputStream = new FileInputStream(pdfImg.getNativeFile());
            byte[] pdfImgBytes = IOUtils.toByteArray(pdfImgInputStream);
            pdfImgInputStream.close();

            pdfDocument.open();
            float yFactor = viewHeight * scaleFactorWidth;
            int pageNumber = 1;

            do {
                if (pageNumber > 1) {
                    pdfDocument.newPage();
                }
                pageNumber++;
                yFactor -= PDF_HEIGHT;

                Image pageImage = Image.getInstance(pdfImgBytes, true);
                // Image pageImage = Image.getInstance(buffer.array());
                pageImage.scalePercent(scaleFactorWidth * 100);
                pageImage.setAbsolutePosition(0f, -yFactor);
                pdfDocument.add(pageImage);

                Log.d(PROXY_NAME, "yFactor: " + yFactor);
            } while (yFactor > 0);

            pdfDocument.close();

            sendCompleteEvent(filename);

        } catch (Exception exception) {
            sendErrorEvent(exception);
        }
    }

    // method to invoke success callback
    private void sendCompleteEvent(String filename) {
        if (this.hasListeners("complete")) {
            KrollDict props = new KrollDict();
            props.put("filename", filename);
            this.fireEvent("complete", props);
        }
    }

    // method to invoke error callback
    private void sendErrorEvent(Exception error) {
        Log.e(PROXY_NAME, "Error", error);

        if (this.hasListeners("error")) {
            KrollDict props = new KrollDict();
            props.put("message", error.toString());
            this.fireEvent("error", props);
        }
    }

    private TiBaseFile createTempFile(String filename) {
        TiBaseFile file = TiFileFactory.createTitaniumFile(filename, true);
        file.getNativeFile().deleteOnExit();

        return file;
    }

    private class MyFontFactory extends FontFactoryImp {
        @Override
        public Font getFont(String fontname, String encoding, boolean embedded, float size, int style,
                BaseColor color, boolean cached) {
            Log.i(PROXY_NAME, "=fontname: " + fontname + " =encoding: " + encoding + " =embedded : " + embedded
                    + " =size: " + size + " =style: " + style + " =BaseColor: " + color);
            return super.getFont("/system/fonts/Roboto.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED, size, style,
                    color, cached);
        }
    }
}