モチベーション
ElectronではwebContents.print()
関数やwebContents.printToPDT()
関数を使って簡単に印刷やPDF作成ができます。この時、CSSで印刷サイズをmm等の実物長さで指定することで、実際の印刷時の各種要素の大きさを指定できるので便利です。が、注意しないと余分な余白が入ってしまいます。経験則からくる注意点を情報共有します。
※2020/2/19:色々試行錯誤して、@page
との関連、print()
とprintToPDF()
の違いなど大幅に改定しました。
最重要注意点
- ChromeおよびChromium系ブラウザ、Electron(7.1.9~8.0.1で確認)において、
@page
内に記述したmargin
,margin-left
,margin-right
,margin-top
,margin-bottom
については、単位の変換におそらくbugがあり、設定値よりも1.5~1.8倍程度大きく設定されてしまう。- 確認したversion(これ以外も確認していないだけでおそらくbugがある)
- Chrome: 80.0.3987.106
- Electron: 7.1.9~8.0.1
- Edge (Chromium): 80.0.361.54
- 確認したversion(これ以外も確認していないだけでおそらくbugがある)
- 回避策として、
@page
内ではmargin
系の設定値の 単位として%
を使う。 - Firefox、Edge(Legacy)では
%
以外の単位も問題なく動く。 -
margin-top
、margin-bottom
に%
を使う際は、ブラウザによって解釈が異なる- Chrome, Firefox, Edge(Chromium):ページ横幅に対する割合を設定する
- Edge(Legacy):ページ縦幅に対する割合を設定する
注意点(試行錯誤の結果)
- CSSで
padding
やmargin
を正しく設定する。特に設定しない時は、明示的に0mm
を設定すること。デフォルトでは0mm
でないことがある。 - body要素にも
padding
とmargin
を明示的に設定する事。実際に余分な余白が消えずに悩んだが、body要素のmargin
がデフォルトで0mm
ではなかったことが原因だった。 - 印刷時だけ設定したいCSSは
@media print
項目で設する。 - ブラウザ上の表示はどれだけ長くても縦に長い1枚ページであるのに対し、印刷時は縦幅も固定で複数ページに分割される。
- 印刷時のページ毎のマージンは、HTML要素のプロパティーではなく、
@page
のプロパティーとして設定するべき。さもなくば、 改ページ部分での上下マージンが反映されない。 -
webContents.print()
はElectron 7.xではmarginType:"custom"
を設定するとクラッシュする。 -
webContents.print()
のmarginType
に"default"以外の値を設定しても、"default"と表示が変わらない。(バグとも思える。Electron version 8.0.1)。 -
webContents.printToPDF()
でmarginsType:0
(デフォルトマージン)にすると CSSの@page
に設定したmargin
,margin-left
,margin-right
,margin-top
,margin-bottom
が適用される。marginsType:1
(マージンなし)にすると、これらのCSS設定も無視される。 -
webContents.printToPDF()
のmarginsType:0
と、webContents.print()
のmarginType: "default"
はCSSの適用と表示に関して(おそらく)同じ挙動。
例
body要素の中にdiv要素があり、その中に文章が書かれている場合のCSS記述は次のようになります。
@page{
size: A4;
/* 本来は以下の記述で良いはずが、Chromium系バグで設定値より大きくなってしまう
margin-left: 15mm;
margin-right: 15mm;
margin-top: 20mm;
margin-bottom: 20mm;
回避策として以下のように%で指定する
*/
margin-left: 7.143%; /* = 15mm / 210mm */
margin-right: 7.143%;
margin-top: 9.524%; /* = 20mm / 210mm "横幅"に対する割合*/
margin-bottom: 9.524%;
}
@media print{
body{
padding: 0mm;
margin: 0mm; /* これが無いと余分な余白が入る */
}
div{
padding: 0mm;
margin: 0mm;
width:100%;
}
}
上記の様なCSSに対して、印刷のJavascriptコードはprint()
関数のoptionとして次のようにmarginType:"default"
を指定する。
const wc = browserWindow.webContents;
wc.print({margins:{marginType:"default"}},
(success, error) => {
if(success){
console.log('Print successfully.');
}else{
console.log(error);
}
});
また、PDF出力時のJavascriptコードはprintToPDF()
関数のoptionとして次のようにmarginsType:0
を指定する。
const wc = browserWindow.webContents;
wc.printToPDF({pageSize:"A4", marginsType:0}).then(data => {
fs.writeFile(result.filePath, data, (error) => {
if (error) throw error;
console.log('Write PDF successfully.');
})
}).catch(error => {
console.log(error);
});
雑感
Electronの印刷はとても楽でいいですね。CSSで微調整できるところも素敵です。すごい時代になってますね。
子供の頃、親父にPCを買ってもらった際、弟と協力して年賀状印刷ソフトを作ったのを思い出しました。当時はVisual Basic6で印刷物の位置合わせをするのに苦労しました。
雑感(改定時)
Chrome,Chromiumのバグと気づくまで今回は時間が掛かりました。Firefoxがあってよかった。Edge(Legacy)が無くなってしまった弊害として、今回の様なブラウザエンジンのバグに気づきにくくなりますね。そういう意味で復活して欲しいなぁ、EHTMLエンジン。