仕事PDF出力ボタン制作時のハマった話2019.12.23行程さんというサービスを運営しています。共有したくなる旅のしおりを簡単に作成できるサービスです。このサービスで、しおりを印刷してもらいたいために、前回、段組の話を書きました。今回は、どんな環境でもウェブページを見たままのPDFを出力するためにPDF出力ボタンの機能を作ったときの話をします。印刷プレビューページがあるが、PCのChromeでしか再現できないiPhoneからでもコンビニ印刷できるように、PCのChromeで再現できている見た目のままPDF出力をしたい解決案サーバーサイド側でライブラリを用いてPDFを出力する(easyPDF、TCPDF、mPDFなど)しかしこれらのフレームワークは、見たままを出力できない実際に取った方法ヘッドレスChrome+Puppeteer+Node.jsこれであれば、Chromeで見たままを出力できます。ヘッドレスChromeは画面のないChromeです。サーバーにインストールしたり、画面キャプチャの自動化を行う際に便利です。気をつけることといえば、PCのChromeで表示しているときも同じものを出力しないといけないため、ウェブフォントを通常のページかえらも、サーバーサイドからも表示させられるようにしなければいけない。なければ、文字間の違いで、意図したものからずれたものになってしまいます。絵文字と顔文字が表示されない絵文字もフォントですし、特殊な顔文字もフォントをインストールしていないといけない場合があります。解決いろいろフォントをインストールかなり特殊(つまり特定の媒体上でしかインストールされていないよう)なものはあきらめました。絵文字も様々な種類があるため、決め打ちで設定することにしました。結論としては拡張子「php」でプログラムに処理をさせることは不具合が多く利用に向きません。ここで注目していただきたいのは、アプリ内からだとPOSTやリファラーの内容が消えるということです。これはリクエストが2回投げられていて1回目はPOSTの内容があるのに対して、特定のアプリケーションで開こうとするときに2回目のリクエストが投げられ、そのときに情報が削ぎ落とされているようです。Android端末+LINE等のアプリ内+ダウンロード時のファイル名にも注目していただきたいですが、ファイル名の拡張子が「php」になるため、使い物になりません。方法2:リンク先を「xxx.pdf」(プログラムに渡す)結論をいうと、毎回生成する必要があって日本語の名前をつけたい場合はこの方法が向いています。日本語のファイル名をつけることができます。ファイル名に絵文字があった場合、ファミリーマート・ローソン系のプリンターで印刷できません。そのため、絵文字を入れさせないようにする必要があります。方法3:リンク先を「xxx.pdf」(通常のPDFファイル)こちらは物理的なPDFファイルを配置している場合です。インジケーターの表示も変わってきます。ここまですべての方法でもiPhoneのSafariはバックグラウンドで「ダウンロード」というものができないので、ダウンロードはあきらめましょう。※上記3つの検証結果は参考程度に見てください。絵文字を使わない(ファイル名に絵文字があるとファミマ・ローソン系のプリンターで印刷できない)絵文字が表示されない、重い問題PDFに絵文字が入っていると、ファミリーマート・ローソン系のプリンターで印刷されない絵文字1種類につき1MBほど増える(絵文字が100個あれば100MB)なぜ1種類1MBも増えるのかは謎です。1種類を100個使うのであればそれほど増えません。使った技術GhostscriptヘッドレスChromeで出力されたPDFを、Ghostscriptを使ってアウトラインや圧縮などの変換を行います。ダウンロードまでの時間は多少犠牲になってしまいます。PDFのページ数が多ければ多いほど時間がかかります。同時に、ファミリーマート・ローソン系のプリンターでも絵文字の印刷可能になりますGhostscriptのバージョンは9.25を使うと、絵文字の背景が真っ黒になってしまうので9.5以上であれば解決されました。