@@ -10,7 +10,7 @@ const url = require('url')
1010const _ = require ( 'lodash' )
1111const EventEmitter = require ( 'eventemitter2' ) . EventEmitter2
1212const electron = require ( 'electron' )
13- var uuid = require ( 'uuid' )
13+ const uuid = require ( 'uuid' )
1414
1515// Logging
1616const debug = require ( 'debug' )
@@ -24,7 +24,8 @@ const MICRONS_INCH_RATIO = 25400
2424const MAX_EVENT_WAIT = 10000
2525
2626const DEFAULT_OPTIONS = {
27- closeWindow : true
27+ closeWindow : true ,
28+ inMemory : false
2829}
2930
3031class ExportJob extends EventEmitter {
@@ -33,18 +34,22 @@ class ExportJob extends EventEmitter {
3334 *
3435 * @param {Array } input The path to the HTML or url, or a markdown file
3536 * with 'md' or 'markdown' extension.
37+ *
3638 * @param output The name of the file to export to. If the extension is
3739 * '.png' then a PNG image will be generated instead of a PDF.
40+ *
3841 * @param args {Object} the minimist arg object
42+ *
3943 * @param options {Object} electron-pdf options
4044 * @param options.closeWindow default:true - If set to false, the window will
4145 * not be closed when the job is complete. This can be useful if you wish
4246 * to reuse a window by passing it to the render function.
47+ * @param options.inMemory default:false - If set to true then `output` will be
48+ * ignored and the results array will contain the Buffer object of the PDF
4349 *
44- * @fires ExportJob#export-complete after each export is available on the
45- * filesystem
46- * @fires ExportJob#job-complete after all export resources are available on
47- * the filesystem
50+ * @fires ExportJob#window.capture.end after each resource is captured (use this with inMemory)
51+ * @fires ExportJob#export-complete after each resource is available in memory or on the filesystem
52+ * @fires ExportJob#job-complete after all export resources are available on the filesystem
4853 */
4954 constructor ( input , output , args , options ) {
5055 super ( )
@@ -139,10 +144,12 @@ class ExportJob extends EventEmitter {
139144 * args[0]: the details object from CustomEvent
140145 *
141146 * @fires PDFExporter#window.observer.start when the observer is invoked
142- * @fires PDFExporter#window.observer.timeout when the promise is not observed by
143- * the maximum wait time (default: 10 seconds). The process will continue on and
144- * capture the page, it is up to the caller to handle this event accordingly.
145- * @fires PDFExporter#window.observer.end when the observer fulfills the promise
147+ * @fires PDFExporter#window.observer.timeout when the promise is not
148+ * observed by the maximum wait time (default: 10 seconds). The process
149+ * will continue on and capture the page, it is up to the caller to handle
150+ * this event accordingly.
151+ * @fires PDFExporter#window.observer.end when the observer fulfills the
152+ * promise
146153 */
147154 observeReadyEvent ( handler ) {
148155 this . readyEventObserver = handler
@@ -163,6 +170,18 @@ class ExportJob extends EventEmitter {
163170 this . args [ arg ] = value
164171 }
165172
173+ /**
174+ * Invoke this method to ensure that any allocated resources are destroyed
175+ * Resources managed:
176+ * - this.window
177+ */
178+ destroy ( ) {
179+ logger ( 'job is tearing down' )
180+ if ( this . window ) {
181+ this . window . close ( )
182+ }
183+ }
184+
166185 // ***************************************************************************
167186 // ************************* Private Functions *******************************
168187 // ***************************************************************************
@@ -464,23 +483,23 @@ class ExportJob extends EventEmitter {
464483 window . webContents . executeJavaScript ( 'document.documentElement.outerHTML' , result => {
465484 const target = path . resolve ( outputFile )
466485 fs . writeFile ( target , result , function ( err ) {
467- this . emit ( 'window.capture.end' , { file : target , error : err } )
468- this . emit ( 'export-complete' , { file : target } )
469- done ( err , target )
486+ this . _emitResourceEvents ( err , target , done )
470487 } . bind ( this ) )
471488 } )
472489 }
473490
474491 _captureImage ( window , outputFile , done ) {
475492 window . webContents . capturePage ( image => {
476- const target = path . resolve ( outputFile )
477- fs . writeFile ( target , image . toPNG ( ) , function ( err ) {
478- this . emit ( 'window.capture.end' , { file : target , error : err } )
479- this . emit ( 'export-complete' , { file : target } )
480- // REMOVE pdf-complete in 2.0 - keeping for backwards compatibility
481- this . emit ( 'pdf-complete' , { file : target } )
482- done ( err , target )
483- } . bind ( this ) )
493+ // http://electron.atom.io/docs/api/native-image/#imagetopng
494+ const pngBuffer = image . toPNG ( )
495+ if ( this . options . inMemory ) {
496+ this . _emitResourceEvents ( undefined , pngBuffer , done )
497+ } else {
498+ const target = path . resolve ( outputFile )
499+ fs . writeFile ( target , pngBuffer , function ( err ) {
500+ this . _emitResourceEvents ( err , target , done )
501+ } . bind ( this ) )
502+ }
484503 } )
485504 }
486505
@@ -493,31 +512,55 @@ class ExportJob extends EventEmitter {
493512 pageSize : args . pageSize ,
494513 landscape : args . landscape
495514 }
515+ window . webContents . printToPDF ( pdfOptions , this . _handlePDF . bind ( this , outputFile , done ) )
516+ }
496517
497- window . webContents . printToPDF ( pdfOptions , ( err , data ) => {
498- if ( err ) {
499- this . emit ( 'window.capture.end' , { error : err } )
500- done ( err )
501- } else {
502- const target = path . resolve ( outputFile )
503- fs . writeFile ( target , data , ( err ) => {
504- if ( ! err ) {
505- // REMOVE in 2.0 - keeping for backwards compatibility
506- this . emit ( 'pdf-complete' , { file : target } )
507- /**
508- * Generation Event - fires when an export has be persisted to
509- * disk
510- * @event PDFExporter#export-complete
511- * @type {object }
512- * @property {String } file - Path to the File
513- */
514- this . emit ( 'export-complete' , { file : target } )
515- }
516- this . emit ( 'window.capture.end' , { file : target , error : err } )
517- done ( err , target )
518- } )
519- }
520- } )
518+ /**
519+ * The callback function for when printToPDF is complete
520+ * @param err
521+ * @param data
522+ * @private
523+ */
524+ _handlePDF ( outputFile , done , err , data ) {
525+ if ( this . options . inMemory || err ) {
526+ this . _emitResourceEvents ( err , data , done )
527+ } else {
528+ const target = path . resolve ( outputFile )
529+ fs . writeFile ( target , data , ( fileWriteErr ) => {
530+ // REMOVE in 2.0 - keeping for backwards compatibility
531+ this . emit ( 'pdf-complete' , { file : target , error : fileWriteErr } )
532+ this . _emitResourceEvents ( fileWriteErr , target , done )
533+ } )
534+ }
535+ }
536+
537+ /**
538+ * Emits events when a resource has been captured or an error has occurred
539+ * while attempting the capture.
540+ *
541+ * @param err
542+ * @param data
543+ * @param done
544+ * @private
545+ */
546+ _emitResourceEvents ( err , data , done ) {
547+ /**
548+ * Window Event - fires when an export has captured the window (succesfully
549+ * or not)
550+ * @event PDFExporter#export-complete
551+ * @type {object }
552+ * @property {Buffer } data - The Buffer holding the PDF file
553+ * @property {Object } error - If an error occurred, undefined otherwise
554+ */
555+ this . emit ( 'window.capture.end' , { data : data , error : err } )
556+ /**
557+ * Generation Event - fires when an export has be persisted to disk
558+ * @event PDFExporter#export-complete
559+ * @type {object }
560+ * @property {String } file - Path to the File
561+ */
562+ this . emit ( 'export-complete' , { data : data } )
563+ done ( err , data )
521564 }
522565
523566 /**
0 commit comments