From f10e625fd4249bdd0e41ff2156c5b09562e083e7 Mon Sep 17 00:00:00 2001 From: Eddie Date: Thu, 15 Feb 2018 09:49:44 -0600 Subject: [PATCH 01/26] Add page options to example --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index cbc5e5b..dae7251 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,10 @@ class Example extends Component { html: '

PDF TEST

', fileName: 'test', directory: 'docs', + page: { + size: page.size.UsLetter, + orientation: page.orientation.Landscape, + }, }; let file = await RNHTMLtoPDF.convert(options) From a542d1b5ac5fbaedc91839fca407fe6d414cd9f8 Mon Sep 17 00:00:00 2001 From: Edward Sutton Date: Thu, 15 Feb 2018 10:23:17 -0600 Subject: [PATCH 02/26] Add page size and orientation options --- .../main/java/android/print/PdfConverter.java | 286 ++++++++++++------ .../htmltopdf/RNHTMLtoPDFModule.java | 6 +- index.js | 33 +- 3 files changed, 221 insertions(+), 104 deletions(-) diff --git a/android/src/main/java/android/print/PdfConverter.java b/android/src/main/java/android/print/PdfConverter.java index 44d9a2f..9764512 100644 --- a/android/src/main/java/android/print/PdfConverter.java +++ b/android/src/main/java/android/print/PdfConverter.java @@ -5,6 +5,8 @@ package android.print; +import com.facebook.react.bridge.ReadableMap; + import android.content.Context; import android.os.Build; import android.os.Handler; @@ -18,113 +20,197 @@ /** * Converts HTML to PDF. *

- * Can convert only one task at a time, any requests to do more conversions before - * ending the current task are ignored. + * Can convert only one task at a time, any requests to do more conversions + * before ending the current task are ignored. */ public class PdfConverter implements Runnable { - private static final String TAG = "PdfConverter"; - private static PdfConverter sInstance; - - private Context mContext; - private String mHtmlString; - private File mPdfFile; - private PrintAttributes mPdfPrintAttrs; - private boolean mIsCurrentlyConverting; - private WebView mWebView; - - private PdfConverter() { - } - - public static synchronized PdfConverter getInstance() { - if (sInstance == null) - sInstance = new PdfConverter(); - - return sInstance; - } - - @Override - public void run() { - mWebView = new WebView(mContext); - mWebView.setWebViewClient(new WebViewClient() { - @Override - public void onPageFinished(WebView view, String url) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) - throw new RuntimeException("call requires API level 19"); - else { - PrintDocumentAdapter documentAdapter = mWebView.createPrintDocumentAdapter(); - documentAdapter.onLayout(null, getPdfPrintAttrs(), null, new PrintDocumentAdapter.LayoutResultCallback() { - }, null); - documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFileDescriptor(), null, new PrintDocumentAdapter.WriteResultCallback() { - @Override - public void onWriteFinished(PageRange[] pages) { - destroy(); - } - }); + private static final String TAG = "PdfConverter"; + private static PdfConverter sInstance; + + private Context mContext; + private String mHtmlString; + private File mPdfFile; + private PrintAttributes mPdfPrintAttrs; + private boolean mIsCurrentlyConverting; + private WebView mWebView; + + private PdfConverter() {} + + public static synchronized PdfConverter getInstance() { + if (sInstance == null) + sInstance = new PdfConverter(); + + return sInstance; + } + + @Override + public void run() { + mWebView = new WebView(mContext); + mWebView.setWebViewClient(new WebViewClient() { + @Override + public void onPageFinished(WebView view, String url) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) + throw new RuntimeException("call requires API level 19"); + else { + PrintDocumentAdapter documentAdapter = + mWebView.createPrintDocumentAdapter(); + documentAdapter.onLayout( + null, getPdfPrintAttrs(), null, + new PrintDocumentAdapter.LayoutResultCallback() {}, null); + documentAdapter.onWrite( + new PageRange[] {PageRange.ALL_PAGES}, getOutputFileDescriptor(), + null, new PrintDocumentAdapter.WriteResultCallback() { + @Override + public void onWriteFinished(PageRange[] pages) { + destroy(); } - } - }); - mWebView.loadData(mHtmlString, "text/HTML", "UTF-8"); - } - - public PrintAttributes getPdfPrintAttrs() { - return mPdfPrintAttrs != null ? mPdfPrintAttrs : getDefaultPrintAttrs(); - } - - public void setPdfPrintAttrs(PrintAttributes printAttrs) { - this.mPdfPrintAttrs = printAttrs; - } - - public void convert(Context context, String htmlString, File file) { - if (context == null) - throw new IllegalArgumentException("context can't be null"); - if (htmlString == null) - throw new IllegalArgumentException("htmlString can't be null"); - if (file == null) - throw new IllegalArgumentException("file can't be null"); - - if (mIsCurrentlyConverting) - return; - - mContext = context; - mHtmlString = htmlString; - mPdfFile = file; - mIsCurrentlyConverting = true; - runOnUiThread(this); - } - - private ParcelFileDescriptor getOutputFileDescriptor() { - try { - mPdfFile.createNewFile(); - return ParcelFileDescriptor.open(mPdfFile, ParcelFileDescriptor.MODE_TRUNCATE | ParcelFileDescriptor.MODE_READ_WRITE); - } catch (Exception e) { - Log.d(TAG, "Failed to open ParcelFileDescriptor", e); + }); } - return null; + } + }); + mWebView.loadData(mHtmlString, "text/HTML", "UTF-8"); + } + + public PrintAttributes getPdfPrintAttrs() { + return mPdfPrintAttrs != null ? mPdfPrintAttrs : getDefaultPrintAttrs(); + } + + public void setPdfPrintAttrs(PrintAttributes printAttrs) { + this.mPdfPrintAttrs = printAttrs; + } + + public void convert(Context context, String htmlString, File file, + final ReadableMap options) { + if (context == null) + throw new IllegalArgumentException("context can't be null"); + if (htmlString == null) + throw new IllegalArgumentException("htmlString can't be null"); + if (file == null) + throw new IllegalArgumentException("file can't be null"); + + if (mIsCurrentlyConverting) + return; + + setOptions(options); + + mContext = context; + mHtmlString = htmlString; + mPdfFile = file; + mIsCurrentlyConverting = true; + runOnUiThread(this); + } + + private ParcelFileDescriptor getOutputFileDescriptor() { + try { + mPdfFile.createNewFile(); + return ParcelFileDescriptor.open( + mPdfFile, ParcelFileDescriptor.MODE_TRUNCATE | + ParcelFileDescriptor.MODE_READ_WRITE); + } catch (Exception e) { + Log.d(TAG, "Failed to open ParcelFileDescriptor", e); } - - private PrintAttributes getDefaultPrintAttrs() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return null; - - return new PrintAttributes.Builder() - .setMediaSize(PrintAttributes.MediaSize.NA_GOVT_LETTER) - .setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600)) - .setMinMargins(PrintAttributes.Margins.NO_MARGINS) - .build(); - + return null; + } + + private PrintAttributes getDefaultPrintAttrs() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) + return null; + + return new PrintAttributes.Builder() + .setMediaSize(PrintAttributes.MediaSize.NA_GOVT_LETTER) + .setResolution(new PrintAttributes.Resolution( + "RESOLUTION_ID", "RESOLUTION_ID", 600, 600)) + .setMinMargins(PrintAttributes.Margins.NO_MARGINS) + .build(); + } + + private PrintAttributes.MediaSize getMediaSize(String size, + String orientation) { + PrintAttributes.MediaSize mediaSize = null; + switch (size) { + case "A0": + mediaSize = PrintAttributes.MediaSize.ISO_A0; + break; + case "A1": + mediaSize = PrintAttributes.MediaSize.ISO_A1; + break; + case "A2": + mediaSize = PrintAttributes.MediaSize.ISO_A2; + break; + case "A3": + mediaSize = PrintAttributes.MediaSize.ISO_A3; + break; + case "A4": + mediaSize = PrintAttributes.MediaSize.ISO_A4; + break; + case "A5": + mediaSize = PrintAttributes.MediaSize.ISO_A5; + break; + case "A6": + mediaSize = PrintAttributes.MediaSize.ISO_A6; + break; + case "A7": + mediaSize = PrintAttributes.MediaSize.ISO_A7; + break; + case "A8": + mediaSize = PrintAttributes.MediaSize.ISO_A8; + break; + case "UsGovernmentLetter": + mediaSize = PrintAttributes.MediaSize.NA_GOVT_LETTER; + break; + case "UsLetter": + mediaSize = PrintAttributes.MediaSize.NA_LETTER; + break; + case "UsLegal": + mediaSize = PrintAttributes.MediaSize.NA_LEGAL; + break; + default: + mediaSize = PrintAttributes.MediaSize.ISO_A4; + break; } - - private void runOnUiThread(Runnable runnable) { - Handler handler = new Handler(mContext.getMainLooper()); - handler.post(runnable); + if (orientation.equals("Landscape")) { + return mediaSize.asLandscape(); } - - private void destroy() { - mContext = null; - mHtmlString = null; - mPdfFile = null; - mPdfPrintAttrs = null; - mIsCurrentlyConverting = false; - mWebView = null; + return mediaSize; + } + + private void setOptions(final ReadableMap options) { + + ReadableMap page = options.hasKey("page") ? options.getMap("page") : null; + String size = "A4"; + String orientation = "Portrait"; + if (page != null) { + size = page.hasKey("size") ? page.getString("size") : size; + orientation = page.hasKey("orientation") ? page.getString("orientation") + : orientation; + Log.d(TAG, String.format("size.......: %s", size)); + Log.d(TAG, String.format("orientation: %s", orientation)); } + + PrintAttributes.MediaSize mediaSize = getMediaSize(size, orientation); + PrintAttributes printAttributes = + new PrintAttributes.Builder() + .setMediaSize(mediaSize) + .setResolution(new PrintAttributes.Resolution( + "RESOLUTION_ID", "RESOLUTION_ID", 600, 600)) + .setMinMargins(PrintAttributes.Margins.NO_MARGINS) + .build(); + + setPdfPrintAttrs(printAttributes); + } + + private void runOnUiThread(Runnable runnable) { + Handler handler = new Handler(mContext.getMainLooper()); + handler.post(runnable); + } + + private void destroy() { + mContext = null; + mHtmlString = null; + mPdfFile = null; + mPdfPrintAttrs = null; + mIsCurrentlyConverting = false; + mWebView = null; + } } diff --git a/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java b/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java index 0596955..798df73 100644 --- a/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java +++ b/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java @@ -59,7 +59,7 @@ public void convert(final ReadableMap options, final Promise promise) { destinationFile = getTempFile(fileName); } - String filePath = convertToPDF(htmlString, destinationFile); + String filePath = convertToPDF(htmlString, destinationFile, options); String base64 = ""; if (options.hasKey("base64") && options.getBoolean("base64") == true) { @@ -77,10 +77,10 @@ public void convert(final ReadableMap options, final Promise promise) { } } - private String convertToPDF(String htmlString, File file) throws Exception { + private String convertToPDF(String htmlString, File file, ReadableMap options) throws Exception { try { PdfConverter.getInstance() - .convert(mReactContext, htmlString, file); + .convert(mReactContext, htmlString, file, options); String absolutePath = file.getAbsolutePath(); return absolutePath; diff --git a/index.js b/index.js index 70e9b6e..8239278 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,34 @@ import { NativeModules } from 'react-native'; -export default NativeModules.RNHTMLtoPDF; +// What is cleanest way to export constants in a native module ? +const page = { + + orientation: { + Landscape: 'Landscape', + Portrait: 'Portrait', + }, + + // Maybe use these + // https://developer.android.com/reference/android/print/PrintAttributes.MediaSize.html + size: { + A0: 'A0', + A1: 'A1', + A2: 'A2', + A3: 'A3', + A4: 'A4', + A5: 'A5', + A6: 'A6', + A7: 'A7', + A8: 'A8', + UsGovernmentLetter: 'UsGovernmentLetter', + UsLetter: 'UsLetter', + UsLegal: 'UsLegal', + }, +}; + +const { RNHTMLtoPDF } = NativeModules; + +module.exports = { + RNHTMLtoPDF, + page, +}; From 92405b635a6040f261e3ff16f32d850c98c4ae10 Mon Sep 17 00:00:00 2001 From: Edward Sutton Date: Thu, 15 Feb 2018 11:33:17 -0600 Subject: [PATCH 03/26] Document page options --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dae7251..7eab191 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,6 @@ class Example extends Component { | `fileName` | `string` | Random | Custom Filename excluding .pdf extension | `base64` | boolean | false | return base64 string of pdf file (not recommended) - #### iOS Only | Param | Type | Default | Note | @@ -111,3 +110,13 @@ class Example extends Component { | Param | Type | Default | Note | |---|---|---|---| | `fonts` | Array | | Allow custom fonts `['/fonts/TimesNewRoman.ttf', '/fonts/Verdana.ttf']` + +### Options: page + +Android Only. Plan to add support to iOS. + +| Param | Type | Default | Note | +|---|---|---|---| +| `orientation` | `string` | Portrait | Landscape, Portrait +| `size` | `string` | A4 | A0 - A8, UsGovernmentLetter, UsLetter, UsLegal + From ff9a3ee62cb72efb02319664c61554817efd8138 Mon Sep 17 00:00:00 2001 From: Eddie Date: Sat, 17 Feb 2018 10:25:14 -0600 Subject: [PATCH 04/26] This close #1 Add support for loading images from Android assets #1 --- android/src/main/java/android/print/PdfConverter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/android/print/PdfConverter.java b/android/src/main/java/android/print/PdfConverter.java index 9764512..bdf74b7 100644 --- a/android/src/main/java/android/print/PdfConverter.java +++ b/android/src/main/java/android/print/PdfConverter.java @@ -69,7 +69,7 @@ public void onWriteFinished(PageRange[] pages) { } } }); - mWebView.loadData(mHtmlString, "text/HTML", "UTF-8"); + mWebView.loadDataWithBaseURL(null, mHtmlString, "text/html", "utf-8",null); } public PrintAttributes getPdfPrintAttrs() { From 650bbdbb59d31e598634b7f299e02eaae3c0ec38 Mon Sep 17 00:00:00 2001 From: Eddie Date: Sat, 17 Feb 2018 11:03:30 -0600 Subject: [PATCH 05/26] Add docs for images from Android assets --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 7eab191..730a833 100644 --- a/README.md +++ b/README.md @@ -120,3 +120,10 @@ Android Only. Plan to add support to iOS. | `orientation` | `string` | Portrait | Landscape, Portrait | `size` | `string` | A4 | A0 - A8, UsGovernmentLetter, UsLetter, UsLegal +## Images + +```````` + +### Android Assets + +```````` From 06661ed50dcb8e5b764221b9294dc952b998a6b0 Mon Sep 17 00:00:00 2001 From: Eddie Date: Sun, 18 Feb 2018 15:43:23 -0600 Subject: [PATCH 06/26] Add iOS support for page option size and orientation --- ios/RNHTMLtoPDF/RNHTMLtoPDF.m | 74 ++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/ios/RNHTMLtoPDF/RNHTMLtoPDF.m b/ios/RNHTMLtoPDF/RNHTMLtoPDF.m index d52eed6..b325d9e 100644 --- a/ios/RNHTMLtoPDF/RNHTMLtoPDF.m +++ b/ios/RNHTMLtoPDF/RNHTMLtoPDF.m @@ -9,7 +9,55 @@ #import #import "RNHTMLtoPDF.h" -#define PDFSize CGSizeMake(612,792) +// #define PDFSize CGSizeMake(612,792) + +NSString *const PageDefaultSize = @"A4"; +NSString *const PageDefaultOrientation = @"Portrait"; + +typedef struct PageStruct{ + const char * const key; + int width; + int height; +} PageStruct; + + +// http://www.printernational.org/iso-paper-sizes.php +// http://www.printernational.org/american-paper-sizes.php +// +// A0 841 mm x 1189 mm 33 in x 46.81 in 2384 pt x 3370 pt +// A1 594 mm x 841 mm 23.39 in x 33 in 1684 pt x 2384 pt +// A2 420 mm x 594 mm 16.54 in x 23.36 in 1191 pt x 1684 pt +// A3 297 mm x 420 mm 11.69 in x 16.54 in 842 pt x 1191 pt +// A4 210 mm 297 mm 8.27 in x 11.69 in 595 pt x 842 pt +// A5 148 mm x 210 mm 5.83 in x 8.27 in 420 pt x 595 pt +// A6 105 mm x 148 mm 4.13 in x 5.83 in 298 pt x 420 pt +// A7 74 mm x 105 mm 2.91 in x 4.13 in 210 pt x 298 pt +// A8 52 mm x 74 mm 2.05 in x 2.91 in 147 pt x 210 pt +// A9 37 mm x 52 mm 1.46 in x 2.05 in 105 pt x 147 pt +// A10 26 mm x 37 mm 1.02 in x 1.46 in 74 pt x 105 pt +// +// ANSI-A (Letter) 792 pt x 612 pt +// US Government 279 mm x 203 mm 11 in x 8 in 792 pt x 575 pt +// Legal (Legal-2) 356 mm x 216 mm 14 in x 8.5 in 1008 pt x 612 pt +// +const PageStruct pageTableLookup[] = { + { "A0", 2384, 3370, }, + { "A1", 1684, 2384, }, + { "A2", 1191, 1684, }, + { "A3", 842, 1191, }, + { "A4", 595, 842, }, // <- Default + { "A5", 420, 595, }, + { "A6", 298, 420, }, + { "A7", 210, 298, }, + { "A8", 147, 210, }, + { "A9", 105, 147, }, + { "A10", 74, 105, }, + { "UsLetter", 792, 612, }, + { "UsGovernmentLetter", 792, 575, }, + { "Legal", 1008, 612, } +}; + + @implementation UIPrintPageRenderer (PDF) - (NSData*) printToPDF @@ -95,7 +143,7 @@ - (instancetype)init float height = [RCTConvert float:options[@"height"]]; _PDFSize = CGSizeMake(width, height); } else { - _PDFSize = PDFSize; + _PDFSize = [self getMediaSize:options]; } if (options[@"padding"]) { @@ -149,4 +197,26 @@ - (void)webViewDidFinishLoad:(UIWebView *)awebView } } +- (CGSize) getMediaSize:(NSDictionary *)options { + PageStruct pageStruct = pageTableLookup[4]; // Default to A4 if page option not valid or found + NSString* pageSize = PageDefaultSize; + NSString* pageOrientation = PageDefaultOrientation; + if (options[@"page"]) { + NSDictionary * pageOptions = [RCTConvert NSDictionary:options[@"page"]]; + pageSize = pageOptions[@"size"] ? [RCTConvert NSString:pageOptions[@"size"]] : PageDefaultSize; + pageOrientation = pageOptions[@"orientation"] ? [RCTConvert NSString:pageOptions[@"orientation"]] : PageDefaultOrientation; + } + for (int i = 0; i < (sizeof(pageTableLookup) / sizeof(PageStruct)); ++i) { + PageStruct pg = pageTableLookup[i]; + if (strcmp(pg.key, pageSize.UTF8String) == 0) { + pageStruct = pg; + break; + } + } + if ([pageOrientation isEqualToString:@"Landscape"]) { + return CGSizeMake(pageStruct.height, pageStruct.width); + } + return CGSizeMake(pageStruct.width, pageStruct.height); +} + @end From a4240b999e3903738f8c3d3dda12ca4b27077dd8 Mon Sep 17 00:00:00 2001 From: Eddie Date: Sun, 18 Feb 2018 16:27:17 -0600 Subject: [PATCH 07/26] Refactor variable name --- ios/RNHTMLtoPDF/RNHTMLtoPDF.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ios/RNHTMLtoPDF/RNHTMLtoPDF.m b/ios/RNHTMLtoPDF/RNHTMLtoPDF.m index b325d9e..8216c32 100644 --- a/ios/RNHTMLtoPDF/RNHTMLtoPDF.m +++ b/ios/RNHTMLtoPDF/RNHTMLtoPDF.m @@ -57,7 +57,7 @@ { "Legal", 1008, 612, } }; - +const int PageStructIndexA4 = 4; @implementation UIPrintPageRenderer (PDF) - (NSData*) printToPDF @@ -198,13 +198,13 @@ - (void)webViewDidFinishLoad:(UIWebView *)awebView } - (CGSize) getMediaSize:(NSDictionary *)options { - PageStruct pageStruct = pageTableLookup[4]; // Default to A4 if page option not valid or found + PageStruct pageStruct = pageTableLookup[PageStructIndexA4]; NSString* pageSize = PageDefaultSize; NSString* pageOrientation = PageDefaultOrientation; if (options[@"page"]) { - NSDictionary * pageOptions = [RCTConvert NSDictionary:options[@"page"]]; - pageSize = pageOptions[@"size"] ? [RCTConvert NSString:pageOptions[@"size"]] : PageDefaultSize; - pageOrientation = pageOptions[@"orientation"] ? [RCTConvert NSString:pageOptions[@"orientation"]] : PageDefaultOrientation; + NSDictionary * optionsPage = [RCTConvert NSDictionary:options[@"page"]]; + pageSize = optionsPage[@"size"] ? [RCTConvert NSString:optionsPage[@"size"]] : PageDefaultSize; + pageOrientation = optionsPage[@"orientation"] ? [RCTConvert NSString:optionsPage[@"orientation"]] : PageDefaultOrientation; } for (int i = 0; i < (sizeof(pageTableLookup) / sizeof(PageStruct)); ++i) { PageStruct pg = pageTableLookup[i]; From 543b2bd395b6c4730ed8d02f871bb748761b32a9 Mon Sep 17 00:00:00 2001 From: Eddie Date: Sun, 18 Feb 2018 16:29:34 -0600 Subject: [PATCH 08/26] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 730a833..bfdae3a 100644 --- a/README.md +++ b/README.md @@ -113,8 +113,6 @@ class Example extends Component { ### Options: page -Android Only. Plan to add support to iOS. - | Param | Type | Default | Note | |---|---|---|---| | `orientation` | `string` | Portrait | Landscape, Portrait From 343f92d02e480400ea7f6a5db1272a3c250b4376 Mon Sep 17 00:00:00 2001 From: Eddie Date: Sun, 18 Feb 2018 16:57:53 -0600 Subject: [PATCH 09/26] Explain 792 x 612 on iOS equals US letter Landscape --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bfdae3a..5a35868 100644 --- a/README.md +++ b/README.md @@ -100,8 +100,8 @@ class Example extends Component { | Param | Type | Default | Note | |---|---|---|---| -| `height` | number | 612 | Set document height (points) -| `width` | number | 792 | Set document width (points) +| `height` | number | 612 | Set document height (points) ( US Letter Landscape ) +| `width` | number | 792 | Set document width (points) ( US Letter Landscape ) | `padding` | number | 10 | Outer padding (points) From 46c9e6f07ffcbb6e36f275988a27bf466a3ea420 Mon Sep 17 00:00:00 2001 From: Eddie Date: Sun, 18 Feb 2018 16:59:04 -0600 Subject: [PATCH 10/26] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5a35868..4f305e0 100644 --- a/README.md +++ b/README.md @@ -100,8 +100,8 @@ class Example extends Component { | Param | Type | Default | Note | |---|---|---|---| -| `height` | number | 612 | Set document height (points) ( US Letter Landscape ) -| `width` | number | 792 | Set document width (points) ( US Letter Landscape ) +| `height` | number | 612 | Set document height points to US Letter, Landscape +| `width` | number | 792 | Set document width points to US Letter, Landscape | `padding` | number | 10 | Outer padding (points) From ee7bd54d106f4055322ba536f23c76c482e4f917 Mon Sep 17 00:00:00 2001 From: Eddie Date: Sun, 18 Feb 2018 17:11:05 -0600 Subject: [PATCH 11/26] Change default from A4 to US Letter portrait --- ios/RNHTMLtoPDF/RNHTMLtoPDF.m | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ios/RNHTMLtoPDF/RNHTMLtoPDF.m b/ios/RNHTMLtoPDF/RNHTMLtoPDF.m index 8216c32..0911fa5 100644 --- a/ios/RNHTMLtoPDF/RNHTMLtoPDF.m +++ b/ios/RNHTMLtoPDF/RNHTMLtoPDF.m @@ -9,11 +9,6 @@ #import #import "RNHTMLtoPDF.h" -// #define PDFSize CGSizeMake(612,792) - -NSString *const PageDefaultSize = @"A4"; -NSString *const PageDefaultOrientation = @"Portrait"; - typedef struct PageStruct{ const char * const key; int width; @@ -45,19 +40,25 @@ { "A1", 1684, 2384, }, { "A2", 1191, 1684, }, { "A3", 842, 1191, }, - { "A4", 595, 842, }, // <- Default + { "A4", 595, 842, }, { "A5", 420, 595, }, { "A6", 298, 420, }, { "A7", 210, 298, }, { "A8", 147, 210, }, { "A9", 105, 147, }, { "A10", 74, 105, }, - { "UsLetter", 792, 612, }, + { "UsLetter", 792, 612, }, // <- Default to US Letter { "UsGovernmentLetter", 792, 575, }, { "Legal", 1008, 612, } }; const int PageStructIndexA4 = 4; +const int PageStructIndexUsLetter = 11; + +// Google search returns more hits for "US Letter" than "A4" +// Portrait is more common than landscape +NSString *const PageDefaultSize = @"UsLetter"; +NSString *const PageDefaultOrientation = @"Portrait"; @implementation UIPrintPageRenderer (PDF) - (NSData*) printToPDF @@ -198,7 +199,7 @@ - (void)webViewDidFinishLoad:(UIWebView *)awebView } - (CGSize) getMediaSize:(NSDictionary *)options { - PageStruct pageStruct = pageTableLookup[PageStructIndexA4]; + PageStruct pageStruct = pageTableLookup[PageStructIndexUsLetter]; NSString* pageSize = PageDefaultSize; NSString* pageOrientation = PageDefaultOrientation; if (options[@"page"]) { From 05b168258671d31a0e413e6d512579480100d353 Mon Sep 17 00:00:00 2001 From: Eddie Date: Sun, 18 Feb 2018 17:12:02 -0600 Subject: [PATCH 12/26] size defaults to UsLetter --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f305e0..67aa58c 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ class Example extends Component { | Param | Type | Default | Note | |---|---|---|---| | `orientation` | `string` | Portrait | Landscape, Portrait -| `size` | `string` | A4 | A0 - A8, UsGovernmentLetter, UsLetter, UsLegal +| `size` | `string` | UsLetter | A0 - A8, UsGovernmentLetter, UsLetter, UsLegal ## Images From 4efd6a3f1f2a78fb6227c220d5d0097dc94c0ffd Mon Sep 17 00:00:00 2001 From: Eddie Date: Sun, 18 Feb 2018 19:03:14 -0600 Subject: [PATCH 13/26] define page size constants in index.js --- index.js | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 8239278..cb4cf3a 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ import { NativeModules } from 'react-native'; -// What is cleanest way to export constants in a native module ? +const { RNHTMLtoPDF } = NativeModules; + const page = { orientation: { @@ -26,9 +27,66 @@ const page = { }, }; -const { RNHTMLtoPDF } = NativeModules; +const RNHTMLtoPDF2 = { + page: { + orientation: { + Landscape: 'Landscape', + Portrait: 'Portrait', + }, + + // Define page size constants in mm : w x h + // + // Convert to iOS point = 0.352778 * mm + // + // https://developer.android.com/reference/android/print/PrintAttributes.MediaSize.html + // + // Android page size units are mm + // https://developer.android.com/reference/android/print/PrintAttributes.MediaSize.html + // iOS page size units are points + // + // 1 mm = 2.834646 point; 1 point = 0.352778 mm + // + size: { + A0: { id: 'A0', mm: { w: 841, h: 1189 }}, + A1: { id: 'A1', mm: { w: 594, h: 841 }}, + A2: { id: 'A2', mm: { w: 420, h: 594 }}, + A3: { id: 'A3', mm: { w: 297, h: 420 }}, + A4: { id: 'A4', mm: { w: 210, h: 297 }}, + A5: { id: 'A5', mm: { w: 148, h: 210 }}, + A6: { id: 'A6', mm: { w: 105, h: 148 }}, + A7: { id: 'A7', mm: { w: 74, h: 105 }}, + A8: { id: 'A8', mm: { w: 52, h: 74 }}, + UsGovernmentLetter: { id: 'UsGovernmentLetter', mm: { w: 279, h: 203 }}, + UsLetter: { id: 'UsLetter', mm: { w: 279, h: 216 }}, + UsLegal: { id: 'UsLegal', mm: { w: 356, h: 216 }}, + }, + }, + + // Maintain default page options in JS + // to make easier to maintain + convert(options) { + if(!options.page) { + options.page = { + size: RNHTMLtoPDF2.page.size.UsLetter, + orientation: RNHTMLtoPDF2.page.orientation.Portrait, + }; + } + if(!options.page.size) { + options.page.size = RNHTMLtoPDF2.page.size.UsLetter; + } + if(!options.page.orientation) { + orientation = RNHTMLtoPDF2.page.orientation.Portrait; + } + return RNHTMLtoPDF.convert(options).then(result => { + return result; + }); + }, +}; module.exports = { RNHTMLtoPDF, + RNHTMLtoPDF2, // <- New export page, -}; +} + + From b3c3517607b85d66eb633be38f93f3b788bfd77a Mon Sep 17 00:00:00 2001 From: Eddie Date: Mon, 19 Feb 2018 11:29:21 -0600 Subject: [PATCH 14/26] Parses page options --- .../main/java/android/print/PdfOptions.java | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 android/src/main/java/android/print/PdfOptions.java diff --git a/android/src/main/java/android/print/PdfOptions.java b/android/src/main/java/android/print/PdfOptions.java new file mode 100644 index 0000000..88cb052 --- /dev/null +++ b/android/src/main/java/android/print/PdfOptions.java @@ -0,0 +1,147 @@ +/* + * + * Ed Sutton + */ + +package android.print; + +import com.facebook.react.bridge.ReadableMap; + +import android.content.Context; +import android.os.Build; +import android.os.Handler; +import android.os.ParcelFileDescriptor; +import android.util.Log; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import java.io.File; + +/** + * Parses page options + */ +public class PdfOptions { + + private static final String TAG = "PdfOptions"; + + private static final String OrientationLandscape = "landscape"; + + private static final double MillimetersToInches = 0.0393701; + private static final double MillimetersToPoints = 2.83465; + + private static String _pageOrientation = "Portrait"; + private static String _pageId = ""; + private static double _pageHeightMm = 0; + private static double _pageWidthMm = 0; + + // Missing option default values should have been added by JS + public PdfOptions(final ReadableMap options) { + if (!options.hasKey("page")) { + throw new IllegalArgumentException("option not found: page"); + } + final ReadableMap page = options.getMap("page"); + _pageOrientation = page.hasKey("orientation") ? page.getString("orientation") : _pageOrientation; + if (!page.hasKey("size")) { + throw new IllegalArgumentException("option not found: page.size"); + } + final ReadableMap pageSize = page.getMap("size"); + _pageId = pageSize.hasKey("id") ? pageSize.getString("id") : _pageId; + if (!pageSize.hasKey("mm")) { + throw new IllegalArgumentException("option not found: page.size.mm"); + } + final ReadableMap pageSizeMm = pageSize.getMap("mm"); + _pageHeightMm = pageSizeMm.hasKey("h") ? pageSizeMm.getDouble("h") : _pageHeightMm; + _pageWidthMm = pageSizeMm.hasKey("w") ? pageSizeMm.getDouble("w") : _pageWidthMm; + } + + public String getPageOrientation() { + return _pageOrientation; + } + + // "A4", "UsLetter", etc + public String getPageId() { + return _pageId; + } + + public double getPageHeightMm() { + return _pageHeightMm; + } + + public double getPageWidthMm() { + return _pageWidthMm; + } + + public String toString() { + return String.format("%s Page: %s, %f inch x %f inch ( %f pt x %f pt ) ( %f mm x %f mm )", + _pageOrientation, + _pageId, + _pageWidthMm * MillimetersToInches, + _pageHeightMm * MillimetersToInches, + _pageWidthMm * MillimetersToPoints, + _pageHeightMm * MillimetersToPoints, + _pageWidthMm, + _pageHeightMm); + } + + // How to create a PrintAttributes.MediaSize from page data w x h declared in JS? + // This switch statement smells like it will be hard to maintain + public static PrintAttributes.MediaSize getMediaSize(String pageId, + String orientation) { + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + throw new RuntimeException("call requires API level 19"); + } + + PrintAttributes.MediaSize mediaSize = null; + switch (pageId) { + case "A0": + mediaSize = PrintAttributes.MediaSize.ISO_A0; + break; + case "A1": + mediaSize = PrintAttributes.MediaSize.ISO_A1; + break; + case "A2": + mediaSize = PrintAttributes.MediaSize.ISO_A2; + break; + case "A3": + mediaSize = PrintAttributes.MediaSize.ISO_A3; + break; + case "A4": + mediaSize = PrintAttributes.MediaSize.ISO_A4; + break; + case "A5": + mediaSize = PrintAttributes.MediaSize.ISO_A5; + break; + case "A6": + mediaSize = PrintAttributes.MediaSize.ISO_A6; + break; + case "A7": + mediaSize = PrintAttributes.MediaSize.ISO_A7; + break; + case "A8": + mediaSize = PrintAttributes.MediaSize.ISO_A8; + break; + case "UsGovernmentLetter": + mediaSize = PrintAttributes.MediaSize.NA_GOVT_LETTER; + break; + case "UsLetter": + mediaSize = PrintAttributes.MediaSize.NA_LETTER; + break; + case "UsLegal": + mediaSize = PrintAttributes.MediaSize.NA_LEGAL; + break; + default: + mediaSize = PrintAttributes.MediaSize.ISO_A4; + break; + } + if (orientation.equals(OrientationLandscape)) { + return mediaSize.asLandscape(); + } + return mediaSize; + } + + public PrintAttributes.MediaSize getMediaSize() { + return getMediaSize(_pageId, _pageOrientation); + } + +} From 0ed1da8b0103f5c0514eb8a0993a4a602bb451de Mon Sep 17 00:00:00 2001 From: Eddie Date: Mon, 19 Feb 2018 11:54:27 -0600 Subject: [PATCH 15/26] Move parsing to PdfOptions --- .../main/java/android/print/PdfConverter.java | 75 ++----------------- 1 file changed, 8 insertions(+), 67 deletions(-) diff --git a/android/src/main/java/android/print/PdfConverter.java b/android/src/main/java/android/print/PdfConverter.java index bdf74b7..740f16f 100644 --- a/android/src/main/java/android/print/PdfConverter.java +++ b/android/src/main/java/android/print/PdfConverter.java @@ -17,6 +17,7 @@ import java.io.File; + /** * Converts HTML to PDF. *

@@ -38,9 +39,9 @@ public class PdfConverter implements Runnable { private PdfConverter() {} public static synchronized PdfConverter getInstance() { - if (sInstance == null) + if (sInstance == null) { sInstance = new PdfConverter(); - + } return sInstance; } @@ -92,7 +93,9 @@ public void convert(Context context, String htmlString, File file, if (mIsCurrentlyConverting) return; - setOptions(options); + PdfOptions pdfOptions = new PdfOptions(options); + Log.d(TAG, pdfOptions.toString()); + setOptions(pdfOptions); mContext = context; mHtmlString = htmlString; @@ -125,70 +128,8 @@ private PrintAttributes getDefaultPrintAttrs() { .build(); } - private PrintAttributes.MediaSize getMediaSize(String size, - String orientation) { - PrintAttributes.MediaSize mediaSize = null; - switch (size) { - case "A0": - mediaSize = PrintAttributes.MediaSize.ISO_A0; - break; - case "A1": - mediaSize = PrintAttributes.MediaSize.ISO_A1; - break; - case "A2": - mediaSize = PrintAttributes.MediaSize.ISO_A2; - break; - case "A3": - mediaSize = PrintAttributes.MediaSize.ISO_A3; - break; - case "A4": - mediaSize = PrintAttributes.MediaSize.ISO_A4; - break; - case "A5": - mediaSize = PrintAttributes.MediaSize.ISO_A5; - break; - case "A6": - mediaSize = PrintAttributes.MediaSize.ISO_A6; - break; - case "A7": - mediaSize = PrintAttributes.MediaSize.ISO_A7; - break; - case "A8": - mediaSize = PrintAttributes.MediaSize.ISO_A8; - break; - case "UsGovernmentLetter": - mediaSize = PrintAttributes.MediaSize.NA_GOVT_LETTER; - break; - case "UsLetter": - mediaSize = PrintAttributes.MediaSize.NA_LETTER; - break; - case "UsLegal": - mediaSize = PrintAttributes.MediaSize.NA_LEGAL; - break; - default: - mediaSize = PrintAttributes.MediaSize.ISO_A4; - break; - } - if (orientation.equals("Landscape")) { - return mediaSize.asLandscape(); - } - return mediaSize; - } - - private void setOptions(final ReadableMap options) { - - ReadableMap page = options.hasKey("page") ? options.getMap("page") : null; - String size = "A4"; - String orientation = "Portrait"; - if (page != null) { - size = page.hasKey("size") ? page.getString("size") : size; - orientation = page.hasKey("orientation") ? page.getString("orientation") - : orientation; - Log.d(TAG, String.format("size.......: %s", size)); - Log.d(TAG, String.format("orientation: %s", orientation)); - } - - PrintAttributes.MediaSize mediaSize = getMediaSize(size, orientation); + private void setOptions(final PdfOptions pdfOptions) { + PrintAttributes.MediaSize mediaSize = pdfOptions.getMediaSize(); PrintAttributes printAttributes = new PrintAttributes.Builder() .setMediaSize(mediaSize) From da8a018ee6a78a72094ecb68a815cf6b814f75e0 Mon Sep 17 00:00:00 2001 From: Eddie Date: Mon, 19 Feb 2018 11:55:35 -0600 Subject: [PATCH 16/26] Rename package RNHTMLtoPDF to RnHtmlToPdf so can maintain RNHTMLtoPDF in index.js --- .../christopherdro/htmltopdf/RNHTMLtoPDFModule.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java b/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java index 798df73..0e1ea7a 100644 --- a/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java +++ b/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java @@ -23,6 +23,8 @@ public class RNHTMLtoPDFModule extends ReactContextBaseJavaModule { private final ReactApplicationContext mReactContext; + private ReadableMap mIntializerList; + public RNHTMLtoPDFModule(ReactApplicationContext reactContext) { super(reactContext); mReactContext = reactContext; @@ -30,9 +32,11 @@ public RNHTMLtoPDFModule(ReactApplicationContext reactContext) { @Override public String getName() { - return "RNHTMLtoPDF"; + //return "RNHTMLtoPDF"; + return "RnHtmlToPdf"; } + @ReactMethod public void convert(final ReadableMap options, final Promise promise) { try { @@ -79,10 +83,9 @@ public void convert(final ReadableMap options, final Promise promise) { private String convertToPDF(String htmlString, File file, ReadableMap options) throws Exception { try { - PdfConverter.getInstance() - .convert(mReactContext, htmlString, file, options); + PdfConverter pdfConverter = PdfConverter.getInstance(); + pdfConverter.convert(mReactContext, htmlString, file, options); String absolutePath = file.getAbsolutePath(); - return absolutePath; } catch (Exception e) { throw new Exception(e); From 7a4282aa2c5720135393b3756ea8c7f9b2d82769 Mon Sep 17 00:00:00 2001 From: Eddie Date: Mon, 19 Feb 2018 11:56:40 -0600 Subject: [PATCH 17/26] Expose pageOptions through RNHTMLtoPDF --- index.js | 94 ++++++++++++++++++++------------------------------------ 1 file changed, 34 insertions(+), 60 deletions(-) diff --git a/index.js b/index.js index cb4cf3a..b0e6ef7 100644 --- a/index.js +++ b/index.js @@ -1,83 +1,59 @@ import { NativeModules } from 'react-native'; -const { RNHTMLtoPDF } = NativeModules; - -const page = { +const { RnHtmlToPdf } = NativeModules; +const pageOptions = { orientation: { Landscape: 'Landscape', Portrait: 'Portrait', }, - // Maybe use these + // Define page size constants in mm : w x h + // // https://developer.android.com/reference/android/print/PrintAttributes.MediaSize.html + // + // Android uses mm, iOS page size units are points + // 1 mm = 2.834646 point; 1 point = 0.352778 mm size: { - A0: 'A0', - A1: 'A1', - A2: 'A2', - A3: 'A3', - A4: 'A4', - A5: 'A5', - A6: 'A6', - A7: 'A7', - A8: 'A8', - UsGovernmentLetter: 'UsGovernmentLetter', - UsLetter: 'UsLetter', - UsLegal: 'UsLegal', + A0: { id: 'A0', mm: { w: 841, h: 1189 }}, + A1: { id: 'A1', mm: { w: 594, h: 841 }}, + A2: { id: 'A2', mm: { w: 420, h: 594 }}, + A3: { id: 'A3', mm: { w: 297, h: 420 }}, + A4: { id: 'A4', mm: { w: 210, h: 297 }}, + A5: { id: 'A5', mm: { w: 148, h: 210 }}, + A6: { id: 'A6', mm: { w: 105, h: 148 }}, + A7: { id: 'A7', mm: { w: 74, h: 105 }}, + A8: { id: 'A8', mm: { w: 52, h: 74 }}, + UsGovernmentLetter: { id: 'UsGovernmentLetter', mm: { w: 203.2, h: 266.7 }}, + UsLetter: { id: 'UsLetter', mm: { w: 215.9, h: 279.4 }}, + UsLegal: { id: 'UsLegal', mm: { w: 279.4, h: 355.6 }}, }, }; -const RNHTMLtoPDF2 = { +// Initialize defaults in JS to reduce maintenance in native modules +const pdfOptionsDefault = { page: { - orientation: { - Landscape: 'Landscape', - Portrait: 'Portrait', - }, - - // Define page size constants in mm : w x h - // - // Convert to iOS point = 0.352778 * mm - // - // https://developer.android.com/reference/android/print/PrintAttributes.MediaSize.html - // - // Android page size units are mm - // https://developer.android.com/reference/android/print/PrintAttributes.MediaSize.html - // iOS page size units are points - // - // 1 mm = 2.834646 point; 1 point = 0.352778 mm - // - size: { - A0: { id: 'A0', mm: { w: 841, h: 1189 }}, - A1: { id: 'A1', mm: { w: 594, h: 841 }}, - A2: { id: 'A2', mm: { w: 420, h: 594 }}, - A3: { id: 'A3', mm: { w: 297, h: 420 }}, - A4: { id: 'A4', mm: { w: 210, h: 297 }}, - A5: { id: 'A5', mm: { w: 148, h: 210 }}, - A6: { id: 'A6', mm: { w: 105, h: 148 }}, - A7: { id: 'A7', mm: { w: 74, h: 105 }}, - A8: { id: 'A8', mm: { w: 52, h: 74 }}, - UsGovernmentLetter: { id: 'UsGovernmentLetter', mm: { w: 279, h: 203 }}, - UsLetter: { id: 'UsLetter', mm: { w: 279, h: 216 }}, - UsLegal: { id: 'UsLegal', mm: { w: 356, h: 216 }}, - }, - }, + orientation: pageOptions.orientation.Portrait, + size: pageOptions.size.UsLetter, + }, +}; + +const RNHTMLtoPDF = { + page: pageOptions, - // Maintain default page options in JS - // to make easier to maintain convert(options) { + // Create default options if user did not specify if(!options.page) { - options.page = { - size: RNHTMLtoPDF2.page.size.UsLetter, - orientation: RNHTMLtoPDF2.page.orientation.Portrait, - }; + options.page = pdfOptionsDefault.page; } if(!options.page.size) { - options.page.size = RNHTMLtoPDF2.page.size.UsLetter; + options.page.size = pdfOptionsDefault.page.size; } if(!options.page.orientation) { - orientation = RNHTMLtoPDF2.page.orientation.Portrait; + options.page.orientation = pdfOptionsDefault.orientation; } - return RNHTMLtoPDF.convert(options).then(result => { + + return RnHtmlToPdf.convert(options).then(result => { return result; }); }, @@ -85,8 +61,6 @@ const RNHTMLtoPDF2 = { module.exports = { RNHTMLtoPDF, - RNHTMLtoPDF2, // <- New export - page, } From 710c391f04c8ca682d5c78641ac6f9bc502558ae Mon Sep 17 00:00:00 2001 From: Edward Sutton Date: Mon, 19 Feb 2018 15:31:27 -0600 Subject: [PATCH 18/26] Wrap native call to RnHtmlToPdf.convert in a JS wrapper in index.js --- .../main/java/android/print/PdfOptions.java | 4 +- index.js | 4 +- ios/RNHTMLtoPDF/PdfOptions.h | 20 +++++++ ios/RNHTMLtoPDF/PdfOptions.m | 55 +++++++++++++++++++ 4 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 ios/RNHTMLtoPDF/PdfOptions.h create mode 100644 ios/RNHTMLtoPDF/PdfOptions.m diff --git a/android/src/main/java/android/print/PdfOptions.java b/android/src/main/java/android/print/PdfOptions.java index 88cb052..8423e91 100644 --- a/android/src/main/java/android/print/PdfOptions.java +++ b/android/src/main/java/android/print/PdfOptions.java @@ -24,7 +24,7 @@ public class PdfOptions { private static final String TAG = "PdfOptions"; - private static final String OrientationLandscape = "landscape"; + private static final String OrientationLandscape = "Landscape"; private static final double MillimetersToInches = 0.0393701; private static final double MillimetersToPoints = 2.83465; @@ -134,7 +134,7 @@ public static PrintAttributes.MediaSize getMediaSize(String pageId, mediaSize = PrintAttributes.MediaSize.ISO_A4; break; } - if (orientation.equals(OrientationLandscape)) { + if (orientation.equalsIgnoreCase(OrientationLandscape)) { return mediaSize.asLandscape(); } return mediaSize; diff --git a/index.js b/index.js index b0e6ef7..d4f38b5 100644 --- a/index.js +++ b/index.js @@ -51,12 +51,12 @@ const RNHTMLtoPDF = { } if(!options.page.orientation) { options.page.orientation = pdfOptionsDefault.orientation; - } - + } return RnHtmlToPdf.convert(options).then(result => { return result; }); }, + }; module.exports = { diff --git a/ios/RNHTMLtoPDF/PdfOptions.h b/ios/RNHTMLtoPDF/PdfOptions.h new file mode 100644 index 0000000..38e17c1 --- /dev/null +++ b/ios/RNHTMLtoPDF/PdfOptions.h @@ -0,0 +1,20 @@ + + +@interface PdfOptions : NSObject { + +NSString *pageOrientation; +NSString *pageId; +double pageSizeHeightMm; +double pageSizeWidthMm; + +} + +-(id)initWithOptions:(NSDictionary *)options; +- (CGSize) getMediaSize; + +@property NSString *pageOrientation; +@property NSString *pageId; +@property double pageSizeHeightMm; +@property double pageSizeWidthMm; + +@end \ No newline at end of file diff --git a/ios/RNHTMLtoPDF/PdfOptions.m b/ios/RNHTMLtoPDF/PdfOptions.m new file mode 100644 index 0000000..f1455df --- /dev/null +++ b/ios/RNHTMLtoPDF/PdfOptions.m @@ -0,0 +1,55 @@ +#import + +#import "PdfOptions.h" + +@implementation PdfOptions + +// 1 millimeter [mm] = 2.83464566929134 point +const double MillimeterToPoints = 2.83464566929134; + +-(void)parseOptions:(NSDictionary *)options { + if (!options[@"page"]){ + return; + } + NSDictionary * page = [RCTConvert NSDictionary:options[@"page"]]; + self.pageOrientation = page[@"orientation"] ? [RCTConvert NSString:page[@"orientation"]] : self.pageOrientation; + if (!page[@"size"]){ + return; + } + NSDictionary * pageSize = [RCTConvert NSDictionary:page[@"size"]]; + self.pageId = pageSize[@"id"] ? [RCTConvert NSString:pageSize[@"id"]] : self.pageId; + if (!pageSize[@"mm"]){ + return; + } + NSDictionary * pageSizeMm = [RCTConvert NSDictionary:pageSize[@"mm"]]; + self.pageSizeHeightMm = pageSizeMm[@"h"] ? [RCTConvert float:pageSizeMm[@"h"]] : self.pageSizeHeightMm; + self.pageSizeWidthMm = pageSizeMm[@"w"] ? [RCTConvert float:pageSizeMm[@"w"]] : self.pageSizeWidthMm; +} + + +-(id)initWithOptions:(NSDictionary *)options { + self = [super init]; + if (self) { + self.pageOrientation = @"Portrait"; + self.pageId = @""; + self.pageSizeHeightMm = 0; + self.pageSizeWidthMm = 0; + + [self parseOptions:options]; + } + return self; +} + +// UsLetter: { id: 'UsLetter', mm: { w: 279, h: 216 }}, +- (CGSize) getMediaSize { + // ANSI-A (Letter) 279 mm x 216 mm 11 in x 8.5 in 792 pt x 612 pt + double widthPoints = MillimeterToPoints * self.pageSizeHeightMm; + double heightPonts = MillimeterToPoints * self.pageSizeHeightMm; + if ([pageOrientation caseInsensitiveCompare:@"Landscape"]) { + return CGSizeMake(heightPonts, widthPoints); + } + return CGSizeMake(widthPoints, heightPonts); +} + +@end + From 17d16834671e65ebce2b490c7822dfc6f35edf52 Mon Sep 17 00:00:00 2001 From: Edward Sutton Date: Thu, 22 Feb 2018 09:52:38 -0600 Subject: [PATCH 19/26] Manually merge inventrix PdfConverter.java async fixes #3 --- .../main/java/android/print/PdfConverter.java | 44 ++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/android/src/main/java/android/print/PdfConverter.java b/android/src/main/java/android/print/PdfConverter.java index 740f16f..e2f9aa4 100644 --- a/android/src/main/java/android/print/PdfConverter.java +++ b/android/src/main/java/android/print/PdfConverter.java @@ -5,8 +5,6 @@ package android.print; -import com.facebook.react.bridge.ReadableMap; - import android.content.Context; import android.os.Build; import android.os.Handler; @@ -16,7 +14,13 @@ import android.webkit.WebViewClient; import java.io.File; +import android.util.Base64; +import java.io.IOException; +import java.io.RandomAccessFile; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableMap; /** * Converts HTML to PDF. @@ -35,6 +39,9 @@ public class PdfConverter implements Runnable { private PrintAttributes mPdfPrintAttrs; private boolean mIsCurrentlyConverting; private WebView mWebView; + private boolean mShouldEncode; + private WritableMap mResultMap; + private Promise mPromise; private PdfConverter() {} @@ -64,13 +71,26 @@ null, getPdfPrintAttrs(), null, null, new PrintDocumentAdapter.WriteResultCallback() { @Override public void onWriteFinished(PageRange[] pages) { - destroy(); + try { + String base64 = ""; + if (mShouldEncode) { + base64 = encodeFromFile(mPdfFile); + } + mResultMap.putString("filePath", + mPdfFile.getAbsolutePath()); + mResultMap.putString("base64", base64); + mPromise.resolve(mResultMap); + } catch (IOException e) { + mPromise.reject(e.getMessage()); + } finally { + destroy(); + } } }); } } }); - mWebView.loadDataWithBaseURL(null, mHtmlString, "text/html", "utf-8",null); + mWebView.loadData(mHtmlString, "text/HTML", "UTF-8"); } public PrintAttributes getPdfPrintAttrs() { @@ -82,7 +102,8 @@ public void setPdfPrintAttrs(PrintAttributes printAttrs) { } public void convert(Context context, String htmlString, File file, - final ReadableMap options) { + boolean shouldEncode, WritableMap resultMap, + Promise promise) { if (context == null) throw new IllegalArgumentException("context can't be null"); if (htmlString == null) @@ -101,6 +122,9 @@ public void convert(Context context, String htmlString, File file, mHtmlString = htmlString; mPdfFile = file; mIsCurrentlyConverting = true; + mShouldEncode = shouldEncode; + mResultMap = resultMap; + mPromise = promise; runOnUiThread(this); } @@ -153,5 +177,15 @@ private void destroy() { mPdfPrintAttrs = null; mIsCurrentlyConverting = false; mWebView = null; + mShouldEncode = false; + mResultMap = null; + mPromise = null; + } + + private String encodeFromFile(File file) throws IOException { + RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r"); + byte[] fileBytes = new byte[(int)randomAccessFile.length()]; + randomAccessFile.readFully(fileBytes); + return Base64.encodeToString(fileBytes, Base64.DEFAULT); } } From 706ec3788a216089d50eb53cb329d06f65824781 Mon Sep 17 00:00:00 2001 From: Eddie Date: Thu, 22 Feb 2018 10:37:30 -0600 Subject: [PATCH 20/26] Increment version from 0.5.0 to 0.5.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5575c24..993a97a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-html-to-pdf", - "version": "0.5.0", + "version": "0.5.1", "scripts": { "start": "node_modules/react-native/packager/packager.sh" }, From 3cdcdc4efda87c3095e59e7abc39092efb95f71b Mon Sep 17 00:00:00 2001 From: Edward Sutton Date: Mon, 26 Feb 2018 11:41:21 -0600 Subject: [PATCH 21/26] Fix async merge issues --- .../main/java/android/print/PdfConverter.java | 6 ++-- .../main/java/android/print/PdfOptions.java | 9 +++++ .../htmltopdf/RNHTMLtoPDFModule.java | 36 ++++++++----------- index.js | 7 ++-- 4 files changed, 30 insertions(+), 28 deletions(-) diff --git a/android/src/main/java/android/print/PdfConverter.java b/android/src/main/java/android/print/PdfConverter.java index e2f9aa4..43d5253 100644 --- a/android/src/main/java/android/print/PdfConverter.java +++ b/android/src/main/java/android/print/PdfConverter.java @@ -90,7 +90,7 @@ public void onWriteFinished(PageRange[] pages) { } } }); - mWebView.loadData(mHtmlString, "text/HTML", "UTF-8"); + mWebView.loadDataWithBaseURL(null, mHtmlString, "text/html", "utf-8", null); } public PrintAttributes getPdfPrintAttrs() { @@ -102,7 +102,7 @@ public void setPdfPrintAttrs(PrintAttributes printAttrs) { } public void convert(Context context, String htmlString, File file, - boolean shouldEncode, WritableMap resultMap, + final ReadableMap options, WritableMap resultMap, Promise promise) { if (context == null) throw new IllegalArgumentException("context can't be null"); @@ -122,7 +122,7 @@ public void convert(Context context, String htmlString, File file, mHtmlString = htmlString; mPdfFile = file; mIsCurrentlyConverting = true; - mShouldEncode = shouldEncode; + mShouldEncode = pdfOptions.getShouldEncode(); mResultMap = resultMap; mPromise = promise; runOnUiThread(this); diff --git a/android/src/main/java/android/print/PdfOptions.java b/android/src/main/java/android/print/PdfOptions.java index 8423e91..b340589 100644 --- a/android/src/main/java/android/print/PdfOptions.java +++ b/android/src/main/java/android/print/PdfOptions.java @@ -33,9 +33,12 @@ public class PdfOptions { private static String _pageId = ""; private static double _pageHeightMm = 0; private static double _pageWidthMm = 0; + private static boolean _shouldEncode = false; // Missing option default values should have been added by JS public PdfOptions(final ReadableMap options) { + _shouldEncode = options.hasKey("base64") ? options.getBoolean("base64") : _shouldEncode; + if (!options.hasKey("page")) { throw new IllegalArgumentException("option not found: page"); } @@ -71,6 +74,12 @@ public double getPageWidthMm() { return _pageWidthMm; } + public boolean getShouldEncode() { + return _shouldEncode; + } + + + public String toString() { return String.format("%s Page: %s, %f inch x %f inch ( %f pt x %f pt ) ( %f mm x %f mm )", _pageOrientation, diff --git a/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java b/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java index 0e1ea7a..d99c0dd 100644 --- a/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java +++ b/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java @@ -63,28 +63,28 @@ public void convert(final ReadableMap options, final Promise promise) { destinationFile = getTempFile(fileName); } - String filePath = convertToPDF(htmlString, destinationFile, options); - String base64 = ""; - - if (options.hasKey("base64") && options.getBoolean("base64") == true) { - base64 = encodeFromFile(destinationFile); - } - - - WritableMap resultMap = Arguments.createMap(); - resultMap.putString("filePath", filePath); - resultMap.putString("base64", base64); - - promise.resolve(resultMap); + convertToPDF( + htmlString, + destinationFile, + options, + Arguments.createMap(), + promise + ); } catch (Exception e) { promise.reject(e.getMessage()); } } - private String convertToPDF(String htmlString, File file, ReadableMap options) throws Exception { + private String convertToPDF(String htmlString, File file, ReadableMap options, WritableMap resultMap, Promise promise) throws Exception { try { PdfConverter pdfConverter = PdfConverter.getInstance(); - pdfConverter.convert(mReactContext, htmlString, file, options); + pdfConverter.convert( + mReactContext, + htmlString, + file, + options, + resultMap, + promise); String absolutePath = file.getAbsolutePath(); return absolutePath; } catch (Exception e) { @@ -104,10 +104,4 @@ private File getTempFile(String fileName) throws Exception { } } - private String encodeFromFile(File file) throws IOException{ - RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r"); - byte[] fileBytes = new byte[(int)randomAccessFile.length()]; - randomAccessFile.readFully(fileBytes); - return Base64.encodeToString(fileBytes, Base64.DEFAULT); - } } diff --git a/index.js b/index.js index d4f38b5..bf4d12f 100644 --- a/index.js +++ b/index.js @@ -41,7 +41,7 @@ const pdfOptionsDefault = { const RNHTMLtoPDF = { page: pageOptions, - convert(options) { + async convert(options) { // Create default options if user did not specify if(!options.page) { options.page = pdfOptionsDefault.page; @@ -52,9 +52,8 @@ const RNHTMLtoPDF = { if(!options.page.orientation) { options.page.orientation = pdfOptionsDefault.orientation; } - return RnHtmlToPdf.convert(options).then(result => { - return result; - }); + const result = await RnHtmlToPdf.convert(options); + return result; }, }; From 35c834423a0270040b1d3c687a889bade82bc477 Mon Sep 17 00:00:00 2001 From: Eddie Date: Mon, 26 Feb 2018 13:24:00 -0600 Subject: [PATCH 22/26] 0.5.1 to 0.5.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 993a97a..4adef15 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-html-to-pdf", - "version": "0.5.1", + "version": "0.5.2", "scripts": { "start": "node_modules/react-native/packager/packager.sh" }, From 96dc8d393119272adfcc92488c5cc6f33ae9f224 Mon Sep 17 00:00:00 2001 From: Edward Sutton Date: Thu, 1 Mar 2018 08:29:02 -0600 Subject: [PATCH 23/26] Fix iOS parsing of page size options --- ios/RNHTMLtoPDF/RNHTMLtoPDF.h | 2 +- ios/RNHTMLtoPDF/RNHTMLtoPDF.m | 9 ++++++--- package.json | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ios/RNHTMLtoPDF/RNHTMLtoPDF.h b/ios/RNHTMLtoPDF/RNHTMLtoPDF.h index 4594beb..6551508 100644 --- a/ios/RNHTMLtoPDF/RNHTMLtoPDF.h +++ b/ios/RNHTMLtoPDF/RNHTMLtoPDF.h @@ -4,6 +4,6 @@ #import #import -@interface RNHTMLtoPDF : RCTView +@interface RnHtmlToPdf : RCTView @end diff --git a/ios/RNHTMLtoPDF/RNHTMLtoPDF.m b/ios/RNHTMLtoPDF/RNHTMLtoPDF.m index 0911fa5..84b299c 100644 --- a/ios/RNHTMLtoPDF/RNHTMLtoPDF.m +++ b/ios/RNHTMLtoPDF/RNHTMLtoPDF.m @@ -81,7 +81,7 @@ - (NSData*) printToPDF } @end -@implementation RNHTMLtoPDF { +@implementation RnHtmlToPdf { RCTEventDispatcher *_eventDispatcher; RCTPromiseResolveBlock _resolveBlock; RCTPromiseRejectBlock _rejectBlock; @@ -204,8 +204,11 @@ - (CGSize) getMediaSize:(NSDictionary *)options { NSString* pageOrientation = PageDefaultOrientation; if (options[@"page"]) { NSDictionary * optionsPage = [RCTConvert NSDictionary:options[@"page"]]; - pageSize = optionsPage[@"size"] ? [RCTConvert NSString:optionsPage[@"size"]] : PageDefaultSize; - pageOrientation = optionsPage[@"orientation"] ? [RCTConvert NSString:optionsPage[@"orientation"]] : PageDefaultOrientation; + pageOrientation = optionsPage[@"orientation"] ? [RCTConvert NSString:optionsPage[@"orientation"]] : pageOrientation; + if (optionsPage[@"size"]) { + NSDictionary * optionsPageSize = [RCTConvert NSDictionary:optionsPage[@"size"]]; + pageSize = optionsPageSize[@"id"] ? [RCTConvert NSString:optionsPageSize[@"id"]] : pageSize; + } } for (int i = 0; i < (sizeof(pageTableLookup) / sizeof(PageStruct)); ++i) { PageStruct pg = pageTableLookup[i]; diff --git a/package.json b/package.json index 4adef15..4319520 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-html-to-pdf", - "version": "0.5.2", + "version": "0.5.3", "scripts": { "start": "node_modules/react-native/packager/packager.sh" }, From 6270cee66a15def575ce5c34a88c1299929c5738 Mon Sep 17 00:00:00 2001 From: Edward Sutton Date: Thu, 1 Mar 2018 11:05:21 -0600 Subject: [PATCH 24/26] Add requiresMainQueueSetup --- ios/RNHTMLtoPDF/RNHTMLtoPDF.m | 14 ++++++++++++++ package.json | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ios/RNHTMLtoPDF/RNHTMLtoPDF.m b/ios/RNHTMLtoPDF/RNHTMLtoPDF.m index 84b299c..16e8fc4 100644 --- a/ios/RNHTMLtoPDF/RNHTMLtoPDF.m +++ b/ios/RNHTMLtoPDF/RNHTMLtoPDF.m @@ -99,6 +99,20 @@ @implementation RnHtmlToPdf { @synthesize bridge = _bridge; +// Is this the correct approach? +// +// Returning methodQueue dispatch_get_main_queue fixed concurrency issue with TCMWSessionController writeDataInternal +// +- (dispatch_queue_t)methodQueue +{ + return dispatch_get_main_queue(); +} + ++ (BOOL)requiresMainQueueSetup +{ + return YES; +} + - (instancetype)init { if (self = [super init]) { diff --git a/package.json b/package.json index 4319520..c956dc2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-html-to-pdf", - "version": "0.5.3", + "version": "0.5.4", "scripts": { "start": "node_modules/react-native/packager/packager.sh" }, From c6a2ae8a27547c075c3fbf36bc0ad5fa762077a6 Mon Sep 17 00:00:00 2001 From: Eddie Date: Fri, 2 Mar 2018 12:16:27 -0600 Subject: [PATCH 25/26] swap width and height in PageStruct to fix Landscape and Portrait modes --- ios/RNHTMLtoPDF/RNHTMLtoPDF.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RNHTMLtoPDF/RNHTMLtoPDF.m b/ios/RNHTMLtoPDF/RNHTMLtoPDF.m index 16e8fc4..a4e4d5b 100644 --- a/ios/RNHTMLtoPDF/RNHTMLtoPDF.m +++ b/ios/RNHTMLtoPDF/RNHTMLtoPDF.m @@ -11,8 +11,8 @@ typedef struct PageStruct{ const char * const key; - int width; int height; + int width; } PageStruct; From 970a7220aaec4f7a17398e1e26e596b4837eacb0 Mon Sep 17 00:00:00 2001 From: Edward Sutton Date: Mon, 19 Mar 2018 10:07:13 -0500 Subject: [PATCH 26/26] Copied current production code --- README.md | 0 android/src/main/java/android/print/PdfConverter.java | 0 android/src/main/java/android/print/PdfOptions.java | 0 .../main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java | 0 .../java/com/christopherdro/htmltopdf/RNHTMLtoPDFPackage.java | 0 index.js | 0 ios/RNHTMLtoPDF/PdfOptions.h | 0 ios/RNHTMLtoPDF/PdfOptions.m | 0 ios/RNHTMLtoPDF/RNHTMLtoPDF.h | 0 ios/RNHTMLtoPDF/RNHTMLtoPDF.m | 0 package.json | 0 11 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 README.md mode change 100644 => 100755 android/src/main/java/android/print/PdfConverter.java mode change 100644 => 100755 android/src/main/java/android/print/PdfOptions.java mode change 100644 => 100755 android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java mode change 100644 => 100755 android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFPackage.java mode change 100644 => 100755 index.js mode change 100644 => 100755 ios/RNHTMLtoPDF/PdfOptions.h mode change 100644 => 100755 ios/RNHTMLtoPDF/PdfOptions.m mode change 100644 => 100755 ios/RNHTMLtoPDF/RNHTMLtoPDF.h mode change 100644 => 100755 ios/RNHTMLtoPDF/RNHTMLtoPDF.m mode change 100644 => 100755 package.json diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/android/src/main/java/android/print/PdfConverter.java b/android/src/main/java/android/print/PdfConverter.java old mode 100644 new mode 100755 diff --git a/android/src/main/java/android/print/PdfOptions.java b/android/src/main/java/android/print/PdfOptions.java old mode 100644 new mode 100755 diff --git a/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java b/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFModule.java old mode 100644 new mode 100755 diff --git a/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFPackage.java b/android/src/main/java/com/christopherdro/htmltopdf/RNHTMLtoPDFPackage.java old mode 100644 new mode 100755 diff --git a/index.js b/index.js old mode 100644 new mode 100755 diff --git a/ios/RNHTMLtoPDF/PdfOptions.h b/ios/RNHTMLtoPDF/PdfOptions.h old mode 100644 new mode 100755 diff --git a/ios/RNHTMLtoPDF/PdfOptions.m b/ios/RNHTMLtoPDF/PdfOptions.m old mode 100644 new mode 100755 diff --git a/ios/RNHTMLtoPDF/RNHTMLtoPDF.h b/ios/RNHTMLtoPDF/RNHTMLtoPDF.h old mode 100644 new mode 100755 diff --git a/ios/RNHTMLtoPDF/RNHTMLtoPDF.m b/ios/RNHTMLtoPDF/RNHTMLtoPDF.m old mode 100644 new mode 100755 diff --git a/package.json b/package.json old mode 100644 new mode 100755