diff --git a/plugin.xml b/plugin.xml
index 32bf1f0..9ae64d9 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -101,7 +101,10 @@
-
+
+
-
-
diff --git a/src/android/PrintPdfAdapter.java b/src/android/PrintAdapter.java
similarity index 64%
rename from src/android/PrintPdfAdapter.java
rename to src/android/PrintAdapter.java
index df099b9..35bbfd7 100644
--- a/src/android/PrintPdfAdapter.java
+++ b/src/android/PrintAdapter.java
@@ -19,7 +19,6 @@
package de.appplant.cordova.plugin.printer;
-import android.content.Context;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
@@ -28,6 +27,8 @@ import android.print.PrintAttributes;
import android.print.PrintDocumentAdapter;
import android.print.PrintDocumentInfo;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.print.PrintHelper;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -39,23 +40,30 @@ import static android.print.PrintDocumentInfo.CONTENT_TYPE_DOCUMENT;
/**
* Document adapter to render and print PDF files.
*/
-class PrintPdfAdapter extends PrintDocumentAdapter {
+class PrintAdapter extends PrintDocumentAdapter {
- // The application context
- private @NonNull Context context;
+ // The name of the print job
+ private final @NonNull String jobName;
- // The path to the PDF file
- private @NonNull String path;
+ // The input stream to render
+ private final @NonNull InputStream input;
+
+ // The callback to inform once the job is done
+ private final @Nullable PrintHelper.OnPrintFinishCallback callback;
/**
* Constructor
*
- * @param context The context where to look for.
+ * @param jobName The name of the print job.
+ * @param input The input stream to render.
+ * @param callback The callback to inform once the job is done.
*/
- PrintPdfAdapter (@NonNull String path, @NonNull Context context)
+ PrintAdapter (@NonNull String jobName, @NonNull InputStream input,
+ @Nullable PrintHelper.OnPrintFinishCallback callback)
{
- this.path = path;
- this.context = context;
+ this.jobName = jobName;
+ this.input = input;
+ this.callback = callback;
}
@Override
@@ -70,11 +78,13 @@ class PrintPdfAdapter extends PrintDocumentAdapter {
if (cancellationSignal.isCanceled())
return;
- pdi = new PrintDocumentInfo.Builder("test")
+ pdi = new PrintDocumentInfo.Builder(jobName)
.setContentType(CONTENT_TYPE_DOCUMENT)
.build();
- callback.onLayoutFinished(pdi, true);
+ boolean changed = !newAttributes.equals(oldAttributes);
+
+ callback.onLayoutFinished(pdi, changed);
}
@Override
@@ -86,18 +96,10 @@ class PrintPdfAdapter extends PrintDocumentAdapter {
if (cancellationSignal.isCanceled())
return;
- AssetUtil io = new AssetUtil(context);
- InputStream in = io.open(path);
-
- if (in == null) {
- callback.onWriteFailed("File not found: " + path);
- return;
- }
-
- OutputStream out = new FileOutputStream(dest.getFileDescriptor());
+ OutputStream output = new FileOutputStream(dest.getFileDescriptor());
try {
- AssetUtil.copy(in, out);
+ PrintContent.copy(input, output);
} catch (IOException e) {
callback.onWriteFailed(e.getMessage());
return;
@@ -105,4 +107,19 @@ class PrintPdfAdapter extends PrintDocumentAdapter {
callback.onWriteFinished(new PageRange[]{ PageRange.ALL_PAGES });
}
+
+ /**
+ * Close input stream once the printing is done.
+ */
+ @Override
+ public void onFinish ()
+ {
+ super.onFinish();
+
+ PrintContent.close(input);
+
+ if (callback != null) {
+ callback.onFinish();
+ }
+ }
}
diff --git a/src/android/AssetUtil.java b/src/android/PrintContent.java
similarity index 67%
rename from src/android/AssetUtil.java
rename to src/android/PrintContent.java
index d9e7bc4..8e5e140 100644
--- a/src/android/AssetUtil.java
+++ b/src/android/PrintContent.java
@@ -29,16 +29,18 @@ import android.support.annotation.Nullable;
import android.util.Base64;
import java.io.ByteArrayInputStream;
+import java.io.Closeable;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.URLConnection;
-class AssetUtil {
+class PrintContent {
// List of supported content types
- enum ContentType { PLAIN, HTML, IMAGE, PDF, SELF }
+ enum ContentType { PLAIN, HTML, IMAGE, PDF, UNSUPPORTED }
// Application context
private final @NonNull Context context;
@@ -48,8 +50,8 @@ class AssetUtil {
*
* @param ctx The application context.
*/
- AssetUtil (@NonNull Context ctx) {
- this.context = ctx;
+ private PrintContent (@NonNull Context ctx) {
+ context = ctx;
}
/**
@@ -59,21 +61,60 @@ class AssetUtil {
*
* @return The content type even the file does not exist.
*/
- static @NonNull ContentType getContentType (@Nullable String path)
+ @NonNull
+ static ContentType getContentType (@Nullable String path,
+ @NonNull Context context)
+ {
+ return new PrintContent(context).getContentType(path);
+ }
+
+ /**
+ * Returns the content type for the file referenced by its uri.
+ *
+ * @param path The path to check.
+ *
+ * @return The content type even the file does not exist.
+ */
+ @NonNull
+ private ContentType getContentType (@Nullable String path)
{
ContentType type = ContentType.PLAIN;
- if (path == null || path.isEmpty())
- {
- type = ContentType.SELF;
- }
- else if (path.charAt(0) == '<')
+ if (path == null || path.isEmpty() || path.charAt(0) == '<')
{
type = ContentType.HTML;
}
- else if (path.matches("^[a-z]+://.+"))
+ else if (path.matches("^[a-z0-9]+://.+"))
{
- return path.endsWith(".pdf") ? ContentType.PDF : ContentType.IMAGE;
+ String mime;
+
+ if (path.startsWith("base64:")) {
+ try {
+ mime = URLConnection.guessContentTypeFromStream(openBase64(path));
+ } catch (IOException e) {
+ return ContentType.UNSUPPORTED;
+ }
+ } else {
+ mime = URLConnection.guessContentTypeFromName(path);
+ }
+
+ switch (mime)
+ {
+ case "image/bmp":
+ case "image/png":
+ case "image/jpeg":
+ case "image/jpeg2000":
+ case "image/jp2":
+ case "image/gif":
+ case "image/x-icon":
+ case "image/vnd.microsoft.icon":
+ case "image/heif":
+ return ContentType.IMAGE;
+ case "application/pdf":
+ return ContentType.PDF;
+ default:
+ return ContentType.UNSUPPORTED;
+ }
}
return type;
@@ -83,10 +124,25 @@ class AssetUtil {
* Opens a file://, res:// or base64:// Uri as a stream.
*
* @param path The file path to decode.
+ * @param context The application context.
*
* @return An open IO stream or null if the file does not exist.
*/
- @Nullable InputStream open (@NonNull String path)
+ @Nullable
+ static InputStream open (@NonNull String path, @NonNull Context context)
+ {
+ return new PrintContent(context).open(path);
+ }
+
+ /**
+ * Opens a file://, res:// or base64:// Uri as a stream.
+ *
+ * @param path The file path to decode.
+ *
+ * @return An open IO stream or null if the file does not exist.
+ */
+ @Nullable
+ private InputStream open (@NonNull String path)
{
InputStream stream = null;
@@ -110,6 +166,20 @@ class AssetUtil {
return stream;
}
+ /**
+ * Decodes a file://, res:// or base64:// Uri to bitmap.
+ *
+ * @param path The file path to decode.
+ * @param context The application context.
+ *
+ * @return A bitmap or null if the path is not valid
+ */
+ @Nullable
+ static Bitmap decode (@NonNull String path, @NonNull Context context)
+ {
+ return new PrintContent(context).decode(path);
+ }
+
/**
* Decodes a file://, res:// or base64:// Uri to bitmap.
*
@@ -117,7 +187,8 @@ class AssetUtil {
*
* @return A bitmap or null if the path is not valid
*/
- @Nullable Bitmap decode (@NonNull String path)
+ @Nullable
+ private Bitmap decode (@NonNull String path)
{
Bitmap bitmap;
@@ -150,7 +221,8 @@ class AssetUtil {
* @param input The readable input stream.
* @param output The writable output stream.
*
- * @throws IOException
+ * @throws IOException If the input stream is not readable,
+ * or the output stream is not writable.
*/
static void copy (@NonNull InputStream input,
@NonNull OutputStream output) throws IOException
@@ -162,8 +234,22 @@ class AssetUtil {
output.write(buf, 0, bytesRead);
}
- output.close();
- input.close();
+ input.reset();
+ close(output);
+ }
+
+ /**
+ * Closes the stream.
+ *
+ * @param stream The stream to close.
+ */
+ static void close (@NonNull Closeable stream)
+ {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ // ignore
+ }
}
/**
@@ -173,7 +259,8 @@ class AssetUtil {
*
* @return An open IO stream or null if the file does not exist.
*/
- private @Nullable InputStream openFile (@NonNull String path)
+ @Nullable
+ private InputStream openFile (@NonNull String path)
{
String absPath = path.substring(7);
@@ -191,7 +278,8 @@ class AssetUtil {
*
* @return A bitmap or null if the path is not valid
*/
- private @Nullable Bitmap decodeFile (@NonNull String path)
+ @Nullable
+ private Bitmap decodeFile (@NonNull String path)
{
String absPath = path.substring(7);
@@ -205,7 +293,8 @@ class AssetUtil {
*
* @return An open IO stream or null if the file does not exist.
*/
- private @Nullable InputStream openAsset (@NonNull String path)
+ @Nullable
+ private InputStream openAsset (@NonNull String path)
{
String resPath = path.replaceFirst("file:/", "www");
@@ -223,7 +312,8 @@ class AssetUtil {
*
* @return A bitmap or null if the path is not valid
*/
- private @Nullable Bitmap decodeAsset (@NonNull String path)
+ @Nullable
+ private Bitmap decodeAsset (@NonNull String path)
{
InputStream stream = openAsset(path);
Bitmap bitmap;
@@ -233,11 +323,7 @@ class AssetUtil {
bitmap = BitmapFactory.decodeStream(stream);
- try {
- stream.close();
- } catch (IOException e) {
- // ignore
- }
+ close(stream);
return bitmap;
}
@@ -249,7 +335,8 @@ class AssetUtil {
*
* @return An open IO stream or null if the file does not exist.
*/
- private @NonNull InputStream openResource (@NonNull String path)
+ @NonNull
+ private InputStream openResource (@NonNull String path)
{
String resPath = path.substring(6);
int resId = getResId(resPath);
@@ -264,7 +351,8 @@ class AssetUtil {
*
* @return A bitmap or null if the path is not valid
*/
- private @Nullable Bitmap decodeResource (@NonNull String path)
+ @Nullable
+ private Bitmap decodeResource (@NonNull String path)
{
String data = path.substring(9);
byte[] bytes = Base64.decode(data, 0);
@@ -279,7 +367,8 @@ class AssetUtil {
*
* @return An open IO stream or null if the file does not exist.
*/
- private @NonNull InputStream openBase64 (@NonNull String path)
+ @NonNull
+ private InputStream openBase64 (@NonNull String path)
{
String data = path.substring(9);
byte[] bytes = Base64.decode(data, 0);
@@ -294,7 +383,8 @@ class AssetUtil {
*
* @return A bitmap or null if the path is not valid
*/
- private @Nullable Bitmap decodeBase64 (@NonNull String path)
+ @Nullable
+ private Bitmap decodeBase64 (@NonNull String path)
{
String data = path.substring(9);
byte[] bytes = Base64.decode(data, 0);
@@ -333,10 +423,16 @@ class AssetUtil {
return resId;
}
+ /**
+ * Returns the asset manager for the app.
+ */
private AssetManager getAssets() {
return context.getAssets();
}
+ /**
+ * Returns the resource bundle for the app.
+ */
private Resources getResources() {
return context.getResources();
}
diff --git a/src/android/PrintManager.java b/src/android/PrintManager.java
index 3b2c645..9f8f2e2 100644
--- a/src/android/PrintManager.java
+++ b/src/android/PrintManager.java
@@ -31,12 +31,15 @@ import android.support.v4.print.PrintHelper;
import org.json.JSONArray;
import org.json.JSONObject;
+import java.io.InputStream;
+
import static android.content.Context.PRINT_SERVICE;
+import static de.appplant.cordova.plugin.printer.PrintContent.ContentType.UNSUPPORTED;
class PrintManager {
// The application context
- private @NonNull Context context;
+ private final @NonNull Context context;
/**
* Constructor
@@ -61,15 +64,16 @@ class PrintManager {
if (item != null)
{
- supported = new AssetUtil(context).open(item) != null;
+ supported = PrintContent.getContentType(item, context) != UNSUPPORTED;
}
return supported;
}
/**
- * @return List of all printable document types (utis).
+ * List of all printable document types (utis).
*/
+ @NonNull
static JSONArray getPrintableUTIs()
{
JSONArray utis = new JSONArray();
@@ -82,8 +86,6 @@ class PrintManager {
utis.put("public.heif");
utis.put("com.compuserve.gif");
utis.put("com.microsoft.ico");
- utis.put("com.microsoft.bmp");
- utis.put("com.microsoft.bmp");
return utis;
}
@@ -96,19 +98,20 @@ class PrintManager {
* @param settings Additional settings how to render the content.
* @param callback The function to invoke once the job is done.
*/
- void print (@Nullable String content, JSONObject settings,
+ void print (@Nullable String content, @NonNull JSONObject settings,
@Nullable PrintHelper.OnPrintFinishCallback callback)
{
- switch (AssetUtil.getContentType(content))
+ switch (PrintContent.getContentType(content, context))
{
case IMAGE:
+ //noinspection ConstantConditions
printImage(content, settings, callback);
break;
case PDF:
+ //noinspection ConstantConditions
printPdf(content, settings, callback);
break;
case HTML:
- case SELF:
case PLAIN:
// TODO
}
@@ -121,15 +124,19 @@ class PrintManager {
* @param settings Additional settings how to render the content.
* @param callback The function to invoke once the job is done.
*/
- private void printPdf (String path, JSONObject settings,
+ private void printPdf (@NonNull String path, @NonNull JSONObject settings,
@Nullable PrintHelper.OnPrintFinishCallback callback)
{
- PrintOptions options = new PrintOptions(settings);
- String jobName = options.getJobName();
- PrintPdfAdapter adapter = new PrintPdfAdapter(path, context);
- PrintAttributes attributes = options.toPrintAttributes();
+ InputStream stream = PrintContent.open(path, context);
- getPrintService().print(jobName, adapter, attributes);
+ if (stream == null) return;
+
+ PrintOptions options = new PrintOptions(settings);
+ String jobName = options.getJobName();
+ PrintAdapter adapter = new PrintAdapter(jobName, stream, callback);
+ PrintAttributes attrs = options.toPrintAttributes();
+
+ getPrintService().print(jobName, adapter, attrs);
}
/**
@@ -139,11 +146,10 @@ class PrintManager {
* @param settings Additional settings how to render the content.
* @param callback The function to invoke once the job is done.
*/
- private void printImage (String path, JSONObject settings,
+ private void printImage (@NonNull String path, @NonNull JSONObject settings,
@Nullable PrintHelper.OnPrintFinishCallback callback)
{
- AssetUtil decoder = new AssetUtil(context);
- Bitmap bitmap = decoder.decode(path);
+ Bitmap bitmap = PrintContent.decode(path, context);
if (bitmap == null) return;
@@ -159,7 +165,8 @@ class PrintManager {
/**
* Returns the print service of the app.
*/
- private @NonNull android.print.PrintManager getPrintService()
+ @NonNull
+ private android.print.PrintManager getPrintService()
{
return (android.print.PrintManager) context.getSystemService(PRINT_SERVICE);
}
diff --git a/src/android/PrintOptions.java b/src/android/PrintOptions.java
index 5895cad..25165eb 100644
--- a/src/android/PrintOptions.java
+++ b/src/android/PrintOptions.java
@@ -43,7 +43,7 @@ import static android.support.v4.print.PrintHelper.SCALE_MODE_FIT;
class PrintOptions {
// The print job settings
- private @NonNull JSONObject spec;
+ private final @NonNull JSONObject spec;
/**
* Constructor
@@ -140,9 +140,9 @@ class PrintOptions {
break;
}
- if (spec.has("graystyle"))
+ if (spec.has("monochrome"))
{
- if (spec.optBoolean("graystyle"))
+ if (spec.optBoolean("monochrome"))
{
printer.setColorMode(PrintHelper.COLOR_MODE_MONOCHROME);
}
@@ -152,16 +152,13 @@ class PrintOptions {
}
}
- if (spec.has("autoFit"))
+ if (spec.optBoolean("autoFit", true))
{
- if (spec.optBoolean("autoFit"))
- {
- printer.setScaleMode(SCALE_MODE_FIT);
- }
- else
- {
- printer.setScaleMode(SCALE_MODE_FILL);
- }
+ printer.setScaleMode(SCALE_MODE_FIT);
+ }
+ else
+ {
+ printer.setScaleMode(SCALE_MODE_FILL);
}
}
}
diff --git a/src/ios/APPPrinterInfo.m b/src/ios/APPPrinterInfo.m
index 05eb3e0..1657038 100644
--- a/src/ios/APPPrinterInfo.m
+++ b/src/ios/APPPrinterInfo.m
@@ -38,7 +38,7 @@
info.orientation = UIPrintInfoOrientationLandscape;
}
- if ([spec[@"graystyle"] boolValue])
+ if ([spec[@"monochrome"] boolValue])
{
if ([spec[@"photo"] boolValue])
{
diff --git a/src/windows/PrinterProxy.js b/src/windows/PrinterProxy.js
index 725b1cd..62ad3a2 100644
--- a/src/windows/PrinterProxy.js
+++ b/src/windows/PrinterProxy.js
@@ -93,7 +93,7 @@ exports.onPrintTaskRequested = function (event) {
args.setSource(exports._page);
});
- if (config.graystyle) {
+ if (config.monochrome) {
task.options.colorMode = Printing.PrintColorMode.grayscale;
} else {
task.options.colorMode = Printing.PrintColorMode.color;
diff --git a/www/printer.js b/www/printer.js
index c0f71ab..fd7fb13 100755
--- a/www/printer.js
+++ b/www/printer.js
@@ -23,12 +23,12 @@ var exec = require('cordova/exec'),
// Defaults
exports._defaults = {
- // name: 'unknown',
- // duplex: 'none',
- // landscape: false,
- // graystyle: false,
- // border: true,
- // copies: 1,
+ // name: 'unknown',
+ // duplex: 'none',
+ // landscape: false,
+ // monochrome: false,
+ // border: true,
+ // copies: 1,
ui: {
hideNumberOfCopies: false,