diff --git a/README.md b/README.md index 9d42da5..e7af061 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ pdf.fromData( '

Hello World

', options) -##### filename +##### fileName - You can specify the name of the PDF file. diff --git a/plugin.xml b/plugin.xml index dd7aa7c..921f07d 100644 --- a/plugin.xml +++ b/plugin.xml @@ -25,7 +25,6 @@ - diff --git a/src/android/PDFConfig.java b/src/android/PDFConfig.java deleted file mode 100644 index 7a0b984..0000000 --- a/src/android/PDFConfig.java +++ /dev/null @@ -1,29 +0,0 @@ -package android.print; - -import android.util.Log; -import org.apache.cordova.LOG; - -public class PDFConfig { - private static final String APPNAME ="PDFConfig"; - private PrintDocumentAdapter.LayoutResultCallback layout = null; - - public PDFConfig() { - layout = new PrintDocumentAdapter.LayoutResultCallback() { - public void onLayoutCancelled() { - Log.i(APPNAME, "onLayoutCancelled called: so this was cancelled ?"); - } - - public void onLayoutFailed(CharSequence error) { - Log.i(APPNAME, "onLayoutCancelledonLayoutFailed called ->" + error.toString()); - } - - public void onLayoutFinished(PrintDocumentInfo info, boolean changed) { - Log.i(APPNAME, "onLayoutFinished called ->" + info.toString()); - } - }; - } - - public PrintDocumentAdapter.LayoutResultCallback getLayout() { - return layout; - } -} diff --git a/src/android/PDFGenerator.java b/src/android/PDFGenerator.java index 332e3e0..128a15b 100644 --- a/src/android/PDFGenerator.java +++ b/src/android/PDFGenerator.java @@ -1,59 +1,34 @@ package com.pdf.generator; -import android.content.ActivityNotFoundException; import android.content.Context; -import android.content.Intent; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.pdf.PdfDocument; -import android.net.Uri; -import android.os.ParcelFileDescriptor; import android.print.PrintManager; import android.util.Log; -import android.view.View; import android.webkit.WebView; -import org.apache.cordova.CordovaInterface; -import org.apache.cordova.CordovaPlugin; import org.apache.cordova.CallbackContext; - +import org.apache.cordova.CordovaPlugin; import org.apache.cordova.LOG; import org.json.JSONArray; import org.json.JSONException; -import org.json.JSONObject; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; /** -* This class echoes a string called from JavaScript. -*/ + * This plugin creates a PDF from a given HTML website or string + */ public class PDFGenerator extends CordovaPlugin { - - private final static String APPNAME = "PDFGenerator"; - private WebView offscreenWebview = null; + private final static String LOG_TAG = "PDFGenerator"; public WebView getOffscreenWebkitInstance(Context ctx) { - LOG.i(APPNAME, "Mounting offscreen webview"); - if (this.offscreenWebview == null){ - WebView view = new WebView(ctx); - view.getSettings().setDatabaseEnabled(true); - view.getSettings().setJavaScriptEnabled(true); - - return this.offscreenWebview = view; - }else{ - return this.offscreenWebview; - } + LOG.d(LOG_TAG, "Mounting offscreen WebView"); + WebView view = new WebView(ctx); + view.getSettings().setDatabaseEnabled(true); + view.getSettings().setJavaScriptEnabled(true); + return view; } @Override - public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { - if (action.equals("htmlToPDF")) { + public boolean execute(String action, JSONArray args, CallbackContext callbackContext) { + if ("htmlToPDF".equals(action)) { this.pdfPrinter(args, callbackContext); - return true; } return false; @@ -64,52 +39,45 @@ public void onResume(boolean multitasking) { super.onResume(multitasking); } - private void pdfPrinter(final JSONArray args, final CallbackContext callbackContext) throws JSONException { + private void pdfPrinter(final JSONArray args, final CallbackContext callbackContext) { final Context ctx = this.cordova.getActivity().getApplicationContext(); - final CordovaInterface _cordova = this.cordova; - final CallbackContext cordovaCallback = callbackContext; - _cordova.getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - try { - WebView webview = getOffscreenWebkitInstance(ctx); + cordova.getActivity().runOnUiThread(() -> { + try { + WebView webview = getOffscreenWebkitInstance(ctx); - PrintManager printManager = (PrintManager) cordova.getActivity() - .getSystemService(Context.PRINT_SERVICE); + PrintManager printManager = (PrintManager) cordova.getActivity() + .getSystemService(Context.PRINT_SERVICE); - boolean outputBase64 = args.getString(4) != null && args.getString(4).equals("base64"); - PDFPrinterWebView printerWebView = new PDFPrinterWebView(printManager, ctx, outputBase64); + boolean outputBase64 = args.getString(4) != null && args.getString(4).equals("base64"); + PDFPrinterWebView printerWebView = new PDFPrinterWebView(printManager, ctx, outputBase64); - String fileNameArg = args.getString(5); - if (fileNameArg != null) { - printerWebView.setFileName(fileNameArg); - } + String fileNameArg = args.getString(5); + if (fileNameArg != null) { + printerWebView.setFileName(fileNameArg); + } - String pageType = args.getString(2); - printerWebView.setPageType(pageType); + String pageType = args.getString(2); + printerWebView.setPageType(pageType); - String orientation = args.getString(3); - if (orientation != null) { - printerWebView.setOrientation(orientation); - } + String orientation = args.getString(3); + if (orientation != null) { + printerWebView.setOrientation(orientation); + } - printerWebView.setCordovaCallback(cordovaCallback); - webview.setWebViewClient(printerWebView); + printerWebView.setCordovaCallback(callbackContext); + webview.setWebViewClient(printerWebView); - if (args.getString(0) != null && !args.getString(0).equals("null")) - webview.loadUrl(args.getString(0)); + if (args.getString(0) != null && !args.getString(0).equals("null")) + webview.loadUrl(args.getString(0)); - if (args.getString(1) != null && !args.getString(1).equals("null")) - webview.loadDataWithBaseURL(null,args.getString(1), "text/HTML","UTF-8", null); + if (args.getString(1) != null && !args.getString(1).equals("null")) + webview.loadDataWithBaseURL(null, args.getString(1), "text/HTML", "UTF-8", null); - } catch (JSONException e) { - e.printStackTrace(); - Log.e(APPNAME, e.getMessage()); - cordovaCallback.error("Native pasing arguments: " + e.getMessage()); - } + } catch (JSONException e) { + Log.e(LOG_TAG, "Unable to parse JSON", e); + callbackContext.error("Native parsing arguments: " + e.getMessage()); } }); } - } diff --git a/src/android/PDFPrinter.java b/src/android/PDFPrinter.java index 98ef80c..9b926a6 100644 --- a/src/android/PDFPrinter.java +++ b/src/android/PDFPrinter.java @@ -1,6 +1,5 @@ package com.pdf.generator; -import android.print.PDFConfig; import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; @@ -8,7 +7,6 @@ import android.print.PageRange; import android.print.PrintAttributes; import android.print.PrintDocumentAdapter; -import android.print.PrintDocumentInfo; import android.webkit.WebView; import org.apache.cordova.LOG; @@ -18,26 +16,19 @@ */ public class PDFPrinter extends PrintDocumentAdapter { - - static final String APPNAME = "PDFPrinter"; - - private PrintDocumentAdapter mWrappedInstance = null; - private WebView webView = null; - private PrintAttributes attributes = null; - private PDFConfig config = null; + private static final String LOG_TAG = "PDFPrinter"; + private final WebView webView; + private PrintDocumentAdapter mWrappedInstance; public PDFPrinter(WebView webView, String fileName) { - if (Build.VERSION.SDK_INT >= 21) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { this.mWrappedInstance = webView.createPrintDocumentAdapter(fileName); } else { this.mWrappedInstance = webView.createPrintDocumentAdapter(); } - config = new PDFConfig(); this.webView = webView; } - - @Override public void onStart() { mWrappedInstance.onStart(); @@ -45,26 +36,27 @@ public void onStart() { @Override public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, - CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) { - + CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) { + mWrappedInstance.onLayout( - oldAttributes, - newAttributes, - cancellationSignal, - callback, - extras + oldAttributes, + newAttributes, + cancellationSignal, + callback, + extras ); } @Override public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, - WriteResultCallback callback) { + WriteResultCallback callback) { mWrappedInstance.onWrite(pages, destination, cancellationSignal, callback); } @Override public void onFinish() { - LOG.i(APPNAME, "Cleaning pdfwriter & webView objects."); + LOG.d(LOG_TAG, "Cleaning pdfwriter & webView objects."); mWrappedInstance.onFinish(); + webView.destroy(); } } diff --git a/src/android/PDFPrinterWebView.java b/src/android/PDFPrinterWebView.java index 93b2d4f..433051f 100644 --- a/src/android/PDFPrinterWebView.java +++ b/src/android/PDFPrinterWebView.java @@ -3,49 +3,35 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; -import android.os.CancellationSignal; -import android.os.ParcelFileDescriptor; -import android.print.PageRange; +import android.print.PDFtoBase64; +import android.print.PrintAttributes; import android.print.PrintDocumentAdapter; import android.print.PrintManager; -import android.util.Printer; import android.webkit.WebView; import android.webkit.WebViewClient; import org.apache.cordova.CallbackContext; -import android.util.Log; +import org.apache.cordova.LOG; -import java.io.File; -import java.lang.System; import java.util.HashMap; -import android.print.PDFtoBase64; -import android.print.PrintAttributes; -import android.os.Environment; - /** * Created by cesar on 22/01/2017. */ public class PDFPrinterWebView extends WebViewClient { - - private PrintManager printManager = null; private static final String TAG = "PDFPrinterWebView"; - private static final String PRINT_JOB = "PDFCordovaPlugin"; - private static final String PRINT_SUCESS = "sucess"; + private static final String PRINT_JOB = "PDFCordovaPlugin"; + private static final String PRINT_SUCCESS = "success"; - //Cordova Specific, delete this safely if not using cordova. + private PrintManager printManager; private CallbackContext cordovaCallback; private Context ctx; private boolean outputBase64; - private String fileName; private String orientation; - PrintAttributes.MediaSize pageType; - - HashMap pageOptions = new HashMap(); - - + private PrintAttributes.MediaSize pageType; + private HashMap pageOptions = new HashMap<>(); public PDFPrinterWebView(PrintManager _printerManager, Context ctx, Boolean outputBase64) { printManager = _printerManager; @@ -60,7 +46,9 @@ public PDFPrinterWebView(PrintManager _printerManager, Context ctx, Boolean outp public void setPageType(String type) { pageType = pageOptions.get(type); - if(pageType == null) pageType = pageOptions.get("A4"); + if (pageType == null) { + pageType = pageOptions.get("A4"); + } } public void setCordovaCallback(CallbackContext cordovaCallback) { @@ -81,40 +69,34 @@ public void onPageFinished(WebView webView, String url) { super.onPageFinished(webView, url); PrintAttributes.MediaSize mediaSize = pageType.asLandscape(); - if(!this.orientation.equalsIgnoreCase("landscape")) { - mediaSize = pageType.asPortrait(); + if (!"landscape".equalsIgnoreCase(this.orientation)) { + mediaSize = pageType.asPortrait(); } PrintAttributes attributes = new PrintAttributes.Builder() - .setMediaSize(mediaSize) - .setResolution(new PrintAttributes.Resolution("pdf", "pdf", 600, 600)) - .setMinMargins(new PrintAttributes.Margins(10,10,10,5)).build(); - //.setMinMargins(PrintAttributes.Margins.NO_MARGINS).build(); - - - PrintDocumentAdapter printAdapter = null; - - Log.e(TAG, "creating a new WebView adapter."); - if (Build.VERSION.SDK_INT >= 21) { - printAdapter = webView.createPrintDocumentAdapter(fileName); - } else { - printAdapter = webView.createPrintDocumentAdapter(); - } + .setMediaSize(mediaSize) + .setResolution(new PrintAttributes.Resolution("pdf", "pdf", 600, 600)) + .setMinMargins(new PrintAttributes.Margins(10, 10, 10, 5)).build(); + PrintDocumentAdapter printAdapter; if (this.outputBase64) { - Log.e(TAG, "generating a base64 representation of the PDF"); - PDFtoBase64 pdfToBase64 = new PDFtoBase64(attributes, this.ctx, this.cordovaCallback); + LOG.d(TAG, "creating a new WebView print adapter."); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + printAdapter = webView.createPrintDocumentAdapter(fileName); + } else { + printAdapter = webView.createPrintDocumentAdapter(); + } + + LOG.d(TAG, "generating a base64 representation of the PDF"); + PDFtoBase64 pdfToBase64 = new PDFtoBase64(attributes, this.ctx, this.cordovaCallback, webView); pdfToBase64.process(printAdapter); } else { - + LOG.d(TAG, "creating a new print job."); PDFPrinter pdfPrinterAdapter = new PDFPrinter(webView, fileName); - Log.e(TAG, "creating a new print job."); - printManager.print(PRINT_JOB, pdfPrinterAdapter, attributes ); - - this.cordovaCallback.success(PRINT_SUCESS); + printManager.print(PRINT_JOB, pdfPrinterAdapter, attributes); + this.cordovaCallback.success(PRINT_SUCCESS); } } - } diff --git a/src/android/PDFtoBase64.java b/src/android/PDFtoBase64.java index 48485ed..2c2b211 100644 --- a/src/android/PDFtoBase64.java +++ b/src/android/PDFtoBase64.java @@ -2,23 +2,28 @@ import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; -import android.util.Log; import org.apache.cordova.CallbackContext; +import org.apache.cordova.LOG; + import android.content.Context; import android.util.Base64; +import android.webkit.WebView; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import static android.print.PrintDocumentAdapter.*; + // https://github.com/cesarvr/pdf-generator/issues/9 // http://www.annalytics.co.uk/android/pdf/2017/04/06/Save-PDF-From-An-Android-WebView/ public class PDFtoBase64 { - private static final String TAG = PDFtoBase64.class.getSimpleName(); + private static final String LOG_TAG = "PDFtoBase64"; private static final String FILE_PREFIX = "PDF_GENERATOR"; - private static final String FILE_EXTENSION = "pdf"; + private static final String FILE_EXTENSION = ".pdf"; private static final String FILE_EMPTY_ERROR = "Error: Empty PDF File"; private static final String FILE_NOT_FOUND = "Error: Temp File Not Found"; private static final String IO_EXCEPTION = "Error: I/O"; @@ -28,57 +33,46 @@ public class PDFtoBase64 { private CallbackContext cordovaCallback; private File file; private String encodedBase64; + private WebView webView; - public PDFtoBase64(PrintAttributes printAttributes, Context ctx, CallbackContext cordovaCallback) { + public PDFtoBase64(PrintAttributes printAttributes, Context ctx, CallbackContext cordovaCallback, WebView webView) { this.printAttributes = printAttributes; this.ctx = ctx; this.cordovaCallback = cordovaCallback; + this.webView = webView; } public void getAsBase64() { - try{ + try { FileInputStream fileInputStreamReader = new FileInputStream(file); - byte[] bytes = new byte[(int)file.length()]; + byte[] bytes = new byte[(int) file.length()]; fileInputStreamReader.read(bytes); fileInputStreamReader.close(); - encodedBase64 = Base64.encodeToString( bytes, Base64.DEFAULT ); + encodedBase64 = Base64.encodeToString(bytes, Base64.DEFAULT); file.delete(); - if(encodedBase64.isEmpty()){ + if (encodedBase64.isEmpty()) { cordovaCallback.error(FILE_EMPTY_ERROR); - }else{ + } else { cordovaCallback.success(encodedBase64); } - } catch(FileNotFoundException ex) { - Log.e(TAG, "getAsBase64 Error File Not Found: ", ex ); - cordovaCallback.error(FILE_NOT_FOUND); - } catch(IOException ex) { - Log.e(TAG, "getAsBase64 Error in I/O: ", ex ); - cordovaCallback.error(IO_EXCEPTION); + } catch (FileNotFoundException ex) { + LOG.e(LOG_TAG, "getAsBase64 Error File Not Found: ", ex); + cordovaCallback.error(FILE_NOT_FOUND); + } catch (IOException ex) { + LOG.e(LOG_TAG, "getAsBase64 Error in I/O: ", ex); + cordovaCallback.error(IO_EXCEPTION); + } finally { + this.webView.destroy(); } } public void process(final PrintDocumentAdapter printAdapter) { - final CancellationSignal cancellationSignal = new CancellationSignal(); - - final PageRange[] ALL_PAGES_ARRAY = new PageRange[]{PageRange.ALL_PAGES}; + cancellationSignal.setOnCancelListener(() -> LOG.d(LOG_TAG, "onCancel: The action was cancelled")); - - cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() { - @Override - public void onCancel() { - Log.e(TAG, "onCancel: The action was cancelled"); - } - - }); - - - final PrintDocumentAdapter.WriteResultCallback myWriteResultCallback = new PrintDocumentAdapter.WriteResultCallback() { - - - + final WriteResultCallback myWriteResultCallback = new WriteResultCallback() { @Override public void onWriteFinished(PageRange[] pages) { super.onWriteFinished(pages); @@ -88,40 +82,30 @@ public void onWriteFinished(PageRange[] pages) { @Override public void onWriteCancelled() { super.onWriteCancelled(); - - Log.d(TAG, "onWriteCancelled: Cancelled!!"); + LOG.d(LOG_TAG, "onWriteCancelled: Cancelled"); } @Override public void onWriteFailed(CharSequence error) { super.onWriteFailed(error); - - Log.d(TAG, "onWriteFailed: Failed!!! " + error.toString() ); + LOG.e(LOG_TAG, "onWriteFailed: Failed: " + error); } }; - final PrintDocumentAdapter.LayoutResultCallback myLayoutResultCallback = new PrintDocumentAdapter.LayoutResultCallback() { + final LayoutResultCallback myLayoutResultCallback = new LayoutResultCallback() { @Override public void onLayoutFinished(PrintDocumentInfo info, boolean changed) { - printAdapter.onWrite(ALL_PAGES_ARRAY, getOutputFile(), cancellationSignal, myWriteResultCallback); } @Override public void onLayoutFailed(CharSequence error) { super.onLayoutFailed(error); - - Log.e(TAG, "onLayoutFailed: " + error.toString() ); + LOG.e(LOG_TAG, "onLayoutFailed: " + error); } }; - printAdapter.onLayout(null, printAttributes, null, myLayoutResultCallback, null); - } - - - private void Test(){ - - + printAdapter.onLayout(null, printAttributes, cancellationSignal, myLayoutResultCallback, null); } private ParcelFileDescriptor getOutputFile() { @@ -129,7 +113,7 @@ private ParcelFileDescriptor getOutputFile() { file = File.createTempFile(FILE_PREFIX, FILE_EXTENSION, ctx.getCacheDir()); return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE); } catch (Exception e) { - Log.e(TAG, "Failed to open ParcelFileDescriptor", e); + LOG.e(LOG_TAG, "Failed to open ParcelFileDescriptor", e); } return null; } diff --git a/www/pdf.js b/www/pdf.js index 7e0670a..329bab6 100644 --- a/www/pdf.js +++ b/www/pdf.js @@ -1,79 +1,68 @@ -/*global cordova, module*/ - - -function opts(options){ - - options.documentSize = options.documentSize || "A4"; - options.landscape = options.landscape || "portrait"; - options.orientation = options.orientation || "portrait"; - options.type = options.type || "base64"; - options.fileName = options.fileName || "default.pdf"; - options.baseUrl = options.baseUrl || null; - - return options; +/* global cordova, module */ + +function opts(options) { + options.documentSize = options.documentSize || "A4"; + options.landscape = options.landscape || "portrait"; + options.orientation = options.orientation || "portrait"; + options.type = options.type || "base64"; + options.fileName = options.fileName || "default.pdf"; + options.baseUrl = options.baseUrl || null; + return options; } -function validate(param, message){ - if(param === '' || - param === undefined || - param === null || - typeof param !== 'string' - ) - throw message +function validate(param, message) { + if (param === "" || param === undefined || param === null || typeof param !== "string") { + throw message; + } } - module.exports = { - htmlToPDF: function (options, successCallback, errorCallback) { - - if(!options.url && !options.data) throw "No URL or HTML Data found."; - - var url = options.url; - var data = options.data; - var docSize = options.documentSize || "A4"; - var landscape = options.landscape || "portrait"; - var type = options.type || "base64"; - var fileName = options.fileName || "default.pdf"; - var baseUrl = options.baseUrl; - - cordova.exec(successCallback, errorCallback, "PDFService", "htmlToPDF", [ url, data, docSize, landscape, type, fileName, baseUrl ]); + htmlToPDF: function(options, successCallback, errorCallback) { + if (!options.url && !options.data) { + throw "No URL or HTML Data found."; + } + + var url = options.url; + var data = options.data; + var docSize = options.documentSize || "A4"; + var landscape = options.landscape || "portrait"; + var type = options.type || "base64"; + var fileName = options.fileName || "default.pdf"; + var baseUrl = options.baseUrl; + + cordova.exec(successCallback, errorCallback, "PDFService", "htmlToPDF", [url, data, docSize, landscape, type, fileName, baseUrl]); }, - fromURL: function(url, options){ - return new Promise(function(resolve, reject){ - validate(url, "URL is required") - options = opts(options) - - cordova.exec(resolve, - reject, - "PDFService", - "htmlToPDF", [ url, - null, - options.documentSize, - options.landscape, - options.type, - options.fileName ]); - - }) - + fromURL: function(url, options) { + return new Promise(function(resolve, reject) { + validate(url, "URL is required"); + options = opts(options); + + cordova.exec(resolve, reject, "PDFService", "htmlToPDF", [ + url, + null, + options.documentSize, + options.landscape, + options.type, + options.fileName + ]); + }); }, - fromData: function(data, options){ - return new Promise(function(resolve, reject){ - validate(data, "String with HTML format is required") - options = opts(options) - - cordova.exec(resolve, - reject, - "PDFService", - "htmlToPDF", [ null, - data, - options.documentSize, - options.landscape, - options.type, - options.fileName, - options.baseUrl ]); - }) - + fromData: function(data, options) { + return new Promise(function(resolve, reject) { + validate(data, "String with HTML format is required"); + options = opts(options); + + cordova.exec(resolve, reject, "PDFService", "htmlToPDF", [ + null, + data, + options.documentSize, + options.landscape, + options.type, + options.fileName, + options.baseUrl + ]); + }); } };