CAD日記

AutoCAD,DXF,DWG,SXFなどCADのことから、仮想通貨や投資関係、PC関係、プログラミング、国内海外旅行情報など何でもござれ。@caddiary

ソフト開発

PDFium第2弾はPDFを画像化するWindowsフォームアプリケーションなり

投稿日:2018年9月9日 更新日:

「PDFium ViewerによるPDFレンダリングがイケてる」では、最低限のWindowsフォームアプリケーションを作ったわけだが、その第2弾は普通の人(非プログラマー)でも使えるPDFの画像変換アプリまで仕上げてみた。

PDFアレコレ紹介ページ
zip解凍後、exeダブルクリックして実行してみたまえ。PDFファイルを指定して画像変換ボタンを押せば、PDFと同一フォルダ内にページ名が付加されたJpegファイルができあがる。解像度と画像形式の指定ができるから、ファイルサイズを小さい画像にすることもできる。変換に要した時間まで明示するあたりはおいらのこだわり。動作要件は.NET Framework 4.6が入っていること。もしかしたら4.6.1以上じゃないとダメかも。Windows 10であれば動くだろうが、Windows 7あたりでは素直には動かないと思われる。なにぶん、.NETアプリを作るのははじめてなもんだからわからんことが多い。以下はお決まりの文言なので、一応書いておく。
≪著作権および免責事項≫
本ソフトはフリーソフトです。個人/団体/社内利用を問わず、ご自由にお使い下さい。なお,著作権は作者である caddiary が保有しています。このソフトウェアを使用したことによって生じたすべての障害・損害・不具合等に関しては、私と私の関係者および私の所属するいかなる団体・組織とも、一切の責任を負いません。各自の責任においてご使用ください。

いちいちダウンロードしてまでどんな性能なのかを確認したくない人もいるだろうから、仕様を書いてみる。
●PDFファイル
「…」ボタンでファイルを選ぶことができるし、エクスプローラからドラッグ&ドロップしてもよし。
●解像度
初期値300で100~600の切りのいい数値を選択。数値入力も可能なので1200とかとんでもない値を入れても64bit環境なら動くだろう。上限も下限もないので10000や-100だと落ちるはず。ちゃんと入力値チェックすればよかったと今さらながら思う。
●画像形式
Bitmapフルカラーはアホみたいにデカいファイルができる。Bitmapグレースケールは8bit256色の白黒画像になる。Bimap白黒2値は、しきい値を基準に白黒はっきりつけるから見事に小さいファイルができる。Jpegは品質値に応じた適度なファイルサイズになり、最も一般的な画像形式なのでデフォルトにした。PNGはそこそこデカいサイズになるから実用的ではないかもしれんが、新しい画像形式なので気分で導入。
●変換結果
成功か失敗を表示。
●結果詳細
失敗時の原因を表示。入力値のチェックが中心で、PDFiumや画像処理のあたりはtry,catchで例外エラーとしただけ。
●所要時間
スタートから終了までの時間計測してミリ秒単位まで表示。

ソースコードについては、主要なところ(画像変換ボタン押下時処理)だけ公開する。PDFiumの処理は全体の中のほんの一部で、Load・PageSizes・Render・Disposeの4つだけ。Loadで読み込んで、PageSizesでページごとの用紙サイズを取得してピクセル数に反映、RenderでImage化して、Disposeでファイルロック解除。このレベルだったら短時間で組めるレベルだったが、そこに各種画像形式の保存を盛り込んだのが苦労のポイント(ここはソース公開せず)。Jpegの品質を考慮した保存は序の口で、グレースケールはネットに落ちていたからそのまま適用した。白黒2値が最も苦労した。最初に見つけたサイトのやり口でやったら変換スピードが出ず、さらに調べて「.NETによる画像処理の高速化Tips:非unsafe編」にたどり着いた。Bitmap::GetPixcelが遅い原因ということで、素晴らしい記事だった。今後もお世話になることだろう。

private void button2_Click(object sender, EventArgs e)
{
    // 結果コントロール初期化
    UpdateResult("", "");
    textBox5.Text = "";
    Update();

    // 入力コントロールチェック
    int type = comboBox1.SelectedIndex;
    string strSrc = textBox1.Text;
    string strKzd = comboBox2.Text;
    float kzd = 0;
    string strQuality = textBox4.Text;
    int quality = 0;
    string strSki = textBox6.Text;
    int ski = 0;
    if (!CheckCntrol(type, strSrc, strKzd, ref kzd, strQuality, ref quality, strSki, ref ski))
        return;

    // 変換先ファイル名
    int pos = strSrc.LastIndexOf('.');
    string strDst = strSrc.Substring(0, pos) + "[{0}]";
    if (type == 0 || type == 1 || type == 2)
        strDst += ".bmp";
    else if (type == 3)
        strDst += ".jpg";
    else if (type == 4)
        strDst += ".png";
    else
        return;

    // Waitカーソル
    Cursor preCursor = Cursor.Current;
    Cursor.Current = Cursors.WaitCursor;

    // 時間計測開始
    System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    sw.Start();

    // 画像変換
    bool stat = true;
    try
    {
        pdfDoc = PdfDocument.Load(strSrc);
        for (int i = 0; i < pdfDoc.PageCount; i++)
        {
            SizeF size = pdfDoc.PageSizes[i];
            int w = Point2Pixel(size.Width, (double)kzd);
            int h = Point2Pixel(size.Height, (double)kzd);
            Image img = pdfDoc.Render(i, w, h, kzd, kzd, false);
            string output = string.Format(strDst, i + 1);
            if (type == 0)  // Bitmap(フルカラー)
                img.Save(output, ImageFormat.Bmp);
            else if (type == 1)  // Bitmap(グレースケール)
                SaveBmpGraycale(img, output);
            else if (type == 2)  // Bitmap(白黒2値)
                SaveBmp1bpp(img, output, ski);
            else if (type == 3)  // Jpeg
                SaveJpeg(img, output, quality);
            else if (type == 4)  // PNG
                img.Save(output, ImageFormat.Png);
        }
    }
    catch(Exception)
    {
        UpdateResult("失敗", "PDFiumで例外エラー");
        stat = false;
    }
    finally
    {
        if(stat)
            UpdateResult("成功", "");
        Cursor.Current = preCursor;  // Waitカーソル解除
        if (!pdfDoc.Equals(null))
        {
            pdfDoc.Dispose();  // 明示的に破棄する必要あり(PDFがロックされてしまう)
            pdfDoc = null;
        }
    }
    // 時間計測終了
    sw.Stop();
    TimeSpan ts = sw.Elapsed;
    int t1 = (int)ts.TotalMilliseconds;
    double t2 = t1 / 1000.0;
    textBox5.Text = t2.ToString();
}

とにかくC#は実装が楽。わからないことはググればすぐに出てくるのが最高。C++のような難解な仕組みがないので、サンプルコードの適用が容易。Visual Studioは2017 Communityを使いはじめただけど、これがちょー便利。コードの自動成形、呼び出し関数のリストアップ、usingの自動挿入なんてことをやってくれるので、タイピングの手間を省けるし、タイピングミスやらビルド時にエラーが出る箇所をリアルタイムで明示してくれる。おいらのVisualStudio使い込み期は2005だったから、2017の便利さに驚愕した。しかも今はVisual Studioって無料なんですな。高額なMSDNの契約してないと使えないって思い込んでたけど、時代は変わったもんだ。

さて、フォームアプリ(つまりWindowsアプリ)としてはこのへんにしといて、今後はWebアプリの開発に着手する。だって、イマドキわざわざアプリをダウンロードして使うなんて人はマレで、昭和または平成中期までをメインに生きた人間くらい。ブラウザからサクサクと操作したくなる人間の目を引き実際に使わせれば、本ブログのアクセス数が増えて広告収入がガッツリ入ってくるという目算。いずれはCADデータ(AutoCADやJw_cad)をPDF化するとかできるとおもしろい。とにかくPDFiumに魅せられているところなので、その活用方法を模索していく所存なり。

-ソフト開発

執筆者:


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

関連記事

no image

複数ファイルの名前やパスを取得するのに便利なフリーソフト

ファイル名の一覧を作りたいときに使えるものはこれだ。 NameToClipboard64 インストーラは付いていないが、以下の簡単な操作でセットアップができる。 1.zipをダウンロード後解凍して適当 …

no image

アプリでzip圧縮と解凍をやりたくてzlibを組み込んでみたんだけど。。

でかいファイルは、圧縮してコンパクトに扱いたくなる。 テキスト形式で定義されているファイルをアプリで読み書きする。 テキストは圧縮すれば1/5くらいになるので、その結果小さくなった ファイルをアプリの …

no image

テキストファイルの最大行数

バカでかいテキストファイルを作る必要があって、結果約2GBにもなった。 CADから出力するんだけど、7.5時間もかかってしまった。 中身を見ようと思って、おなじみ秀丸くんで開こうとしたら開けなかった。 …

no image

軌道に乗ったか!?

 この11月の売り上げ本数が、10本の大台にのりました。私が最も力を入れているCAD関連ツールがです。喜ばしいことです。関係各位への感謝がつのります。  思えば半年前、あるユーザーの要望から始まったこ …

no image

簡単インストーラ

インストーラと言えば、Install Shield です。最新バージョンは11.0で価格は44万1千円。高いんです。高機能版(Premier Edition)で、多国語(全33ヶ国語)対応という代物だ …