From Administrator

Sc.sho to PDF を公開しました

"Sc.sho to PDF"は、複数の画像ファイルをまとめて1つのPDFファイルにできるサービスです。主にスクリーンショットをまとめる目的で使えるので、この名前にしています。

既にこういったサービスは幾つか公開されていますが、"Sc.sho to PDF"は次のような点で優れています。

  • JPEGファイルをそのまま埋め込みます
    PDFフォーマットにはJPEGファイルはそのまま格納できます。全く変換していないので、PDFから取り出すと元に戻ります。
  • PNG,GIFをロスレス圧縮
    PNGやGIFフォーマットの優れている点のひとつに、ロスレス圧縮であるということがあります。境界がぼやけることが無い点はJPEGよりも優れます。特に色数が限られた画像の場合は圧縮率でも有利です。JPEGが写真などの自然画の圧縮に適している一方で、PNGやGIFはスクリーンショットなど境界線がはっきりして、グラデーションの少ない画像の圧縮に適しています。"Sc.sho to PDF"でも、PNGやGIFの利点を生かすため、ロスレス圧縮を用います。PDFフォーマットのロスレス圧縮であるDeflate圧縮を用いています。
    JPEGに変換しているものと比べて優れています。
  • ページの回転
    PDFフォーマットには、ページの表示時に回転が指定できます。これを利用しています。画像そのものは元の方向のままで格納しPDF内のコマンドで回転することにより、できるだけ元の画像を触らずに格納できています。
  • 情報漏れなし
    全ての処理が端末のブラウザ内で行われるため、情報漏れの心配がありません。サイトを運営する立場からも「受け取らないことが情報漏れを防ぐ最善策」なので安心です。

動作環境

WindowsとAndroidのブラウザで動作確認しています。 Firefox, Chrome, Edgeで使ってください。 Internet Explorer 11でも使えますが、レイアウトが崩れることがあります。

iOS (iPhpne, iPad) のSafariでも動作しますが、沢山のページは扱えません。 iOS用のFirefoxを使ってください。

MAC OSでは動作確認できていません。多分iOSと同じ状況だと思います。

このサービスは全ての作業をブラウザの中で行います。 このため、使っている端末のメモリーの空き状況や処理能力に応じて扱えるページ数や画像の大きさが異なります。 スマホで処理できなかった場合は、PCで試してみることをお勧めします。

PDFとして取り出す時はブラウザの blob という機能を使いますがSafariブラウザは blob からファイルを取り出すことができません。 このためSafariブラウザでは生成したPDFをbase64エンコードして、新しいWebページとして送り付けることで取出せるようにしています。 ここで扱えるページの大きさに上限があるため、あまり大きなサイズの情報はSafariでは扱えません。

生成するPDFの仕様

生成するPDFはLinearizeされていません。Linearizeとは、PDFの最初のページだけ高速に表示するためのPDFの構造です。Adobe Readerで開いてから保存しなおすことでLinearizeされます。大きなPDFを作った場合は、一度Adobe Readerで開いて一度保存しなおすことをおすすめします。

PDF内でのページのサイズは元になる画像のドット数を元に単純計算します。縦横ともに、ドット数÷108 インチに設定しています。長辺が1,000ドット強の画像であれば、概ね A4サイズ弱です。

作ってみた感想など

ImageMagicという有名な画像処理ライブラリがあります。これに付属しているconvertというコマンドを使えばほぼ同等のことが行えます。ただ、PCに慣れていないと気軽に使えないツールでもあります。自分自身でも少し不便を感じていたので「すぐ使える」サービスとして作ってみました。余談ですが、ImageMagicが生成するPDFもLinearizeされていません。実装は結構難しい(面倒)です。

作っていて苦労したのはマルチブラウザ対応です。作成当初は、あとでbabelやpolyfilを使う想定でES6の構文を多用していましたが、各ブラウザでのデコボコが収まらず、結局は古い記法で書き直した上、継承を集約に変更するといった変更まで必要になりました。他にも、JSで苦労して対応したIEでbootstrapの互換性も怪しいことがわかり、IEでのサムネイルのレイアウトは悲惨な状態のままリリースしています。

この「継承を集約に変更した」点ですが、EdgeとSafariにあった制約(バグ?)の回避のため必要になったものです。調べた限りではこの情報を掲載しているサイトが無かったので、ご参考にここで公開しておきます。

EdgeとSafariでは、組み込みクラスのImageを継承すると、サブクラスで定義したメソッドが呼び出せません。
以下のようなコードで定義したFooクラスを使って、let foo = new Foo(10); とした後、foo.getPage();を実行すると、getPageが未定義とのエラーになります。 FirefoxやChromeでは正常に動作し、IE11はbabelで変換するなどすれば動作します。
babelで変換後のコードもEdge, Safariでは同じエラーに至ります。

export class Foo extends Image {
    constructor(x_page){
        super();
        this.page = x_page;
    }

    getPage(){
        return this.page;
    }
}
このため、Imageを継承する代わりにImageを集約したクラスを作って対応しました。その結果できあがったJSはメンテナンス性が悪いものになってしまいました。
最初にも書きましたが、こういったブラウザの癖に1つ1つ対応するのは非常に時間がかかります。作り手の気持ちとしては、ブラウザの動作を統一して欲しいですね。