1
1
/* global Plotly:false */
2
2
3
- const cst = require ( './constants' )
4
3
const semver = require ( 'semver' )
4
+ const remote = require ( '../../util/remote' )
5
+ const cst = require ( './constants' )
5
6
6
7
/**
7
8
* @param {object } info : info object
@@ -12,6 +13,7 @@ const semver = require('semver')
12
13
* - scale
13
14
* @param {object } opts : component options
14
15
* - mapboxAccessToken
16
+ * - batik
15
17
* @param {function } sendToMain
16
18
* - errorCode
17
19
* - result
@@ -40,26 +42,34 @@ function render (info, opts, sendToMain) {
40
42
// - figure out if we still need this:
41
43
// https://github.com/plotly/streambed/blob/7311d4386d80d45999797e87992f43fb6ecf48a1/image_server/server_app/main.js#L224-L229
42
44
// - increase pixel ratio images (scale up here, scale down in convert) ??
45
+ // + scale down using https://github.com/oliver-moran/jimp ??
43
46
// - does webp (via batik) support transparency now?
44
47
48
+ const PDF_OR_EPS = ( format === 'pdf' || format === 'eps' )
49
+ const PRINT_TO_PDF = PDF_OR_EPS && ! opts . batik
50
+
45
51
const imgOpts = {
46
- format : ( format === 'pdf' || format === 'eps' ) ? 'svg' : format ,
52
+ format : PDF_OR_EPS ? 'svg' : format ,
47
53
width : info . scale * info . width ,
48
54
height : info . scale * info . height ,
49
55
// return image data w/o the leading 'data:image' spec
50
- imageDataOnly : true ,
56
+ imageDataOnly : ! PRINT_TO_PDF ,
51
57
// blend jpeg background color as jpeg does not support transparency
52
58
setBackground : format === 'jpeg' ? 'opaque' : ''
53
59
}
54
60
55
61
let promise
56
62
57
63
if ( semver . gte ( Plotly . version , '1.30.0' ) ) {
58
- promise = Plotly . toImage ( {
59
- data : figure . data ,
60
- layout : figure . layout ,
61
- config : config
62
- } , imgOpts )
64
+ promise = Plotly
65
+ . toImage ( { data : figure . data , layout : figure . layout , config : config } , imgOpts )
66
+ . then ( ( imgData ) => {
67
+ if ( PRINT_TO_PDF ) {
68
+ return toPDF ( imgData , imgOpts )
69
+ } else {
70
+ return imgData
71
+ }
72
+ } )
63
73
} else if ( semver . gte ( Plotly . version , '1.11.0' ) ) {
64
74
const gd = document . createElement ( 'div' )
65
75
@@ -69,13 +79,20 @@ function render (info, opts, sendToMain) {
69
79
. then ( ( imgData ) => {
70
80
Plotly . purge ( gd )
71
81
72
- switch ( imgOpts . format ) {
82
+ switch ( format ) {
73
83
case 'png' :
74
84
case 'jpeg' :
75
85
case 'webp' :
76
86
return imgData . replace ( cst . imgPrefix . base64 , '' )
77
87
case 'svg' :
78
- return decodeURIComponent ( imgData . replace ( cst . imgPrefix . svg , '' ) )
88
+ return decodeSVG ( imgData )
89
+ case 'pdf' :
90
+ case 'eps' :
91
+ if ( PRINT_TO_PDF ) {
92
+ return toPDF ( imgData , imgOpts , info )
93
+ } else {
94
+ return decodeSVG ( imgData )
95
+ }
79
96
}
80
97
} )
81
98
} else {
@@ -95,4 +112,59 @@ function render (info, opts, sendToMain) {
95
112
} )
96
113
}
97
114
115
+ function decodeSVG ( imgData ) {
116
+ return window . decodeURIComponent ( imgData . replace ( cst . imgPrefix . svg , '' ) )
117
+ }
118
+
119
+ /**
120
+ * See https://github.com/electron/electron/blob/master/docs/api/web-contents.md#contentsprinttopdfoptions-callback
121
+ * for other available options
122
+ */
123
+ function toPDF ( imgData , imgOpts , info ) {
124
+ const win = remote . getCurrentWindow ( )
125
+
126
+ // TODO
127
+ // - how to (robustly) get pixel to microns (for pageSize) conversion factor
128
+ // - this work great, except runner app can't get all pdf to generate
129
+ // when parallelLimit > 1 ???
130
+ // + figure out why???
131
+ // + maybe restrict that in coerce-opts?
132
+ const printOpts = {
133
+ marginsType : 1 ,
134
+ printSelectionOnly : true ,
135
+ pageSize : {
136
+ width : ( imgOpts . width ) / 0.0035 ,
137
+ height : ( imgOpts . height ) / 0.0035
138
+ }
139
+ }
140
+
141
+ return new Promise ( ( resolve , reject ) => {
142
+ const div = document . createElement ( 'div' )
143
+ const img = document . createElement ( 'img' )
144
+
145
+ document . body . appendChild ( div )
146
+ div . appendChild ( img )
147
+
148
+ img . addEventListener ( 'load' , ( ) => {
149
+ window . getSelection ( ) . selectAllChildren ( div )
150
+
151
+ win . webContents . printToPDF ( printOpts , ( err , pdfData ) => {
152
+ document . body . removeChild ( div )
153
+
154
+ if ( err ) {
155
+ return reject ( new Error ( 'electron print to PDF error' ) )
156
+ }
157
+ return resolve ( pdfData )
158
+ } )
159
+ } )
160
+
161
+ img . addEventListener ( 'error' , ( ) => {
162
+ document . body . removeChild ( div )
163
+ return reject ( new Error ( 'image failed to load' ) )
164
+ } )
165
+
166
+ img . src = imgData
167
+ } )
168
+ }
169
+
98
170
module . exports = render
0 commit comments