差分表示


#freeze
*&date(Y-n-j[lL],2016/2/28); libharu を使ってjpg画像を右綴じpdfに変換

本の自炊で右綴じ化のために Acrobat を立ち上げるのは面倒で、他のフリーのpdfツールもたいていGUIで面倒そうで手頃なのが見つからないのでコマンドラインツールを作ってみることにした。

pdf作成で手頃そうなライブラリとして libharu(libhpdf.lib)というのがあったのでそれを採用... なんだけど、pdf 読込がよくわからず(出来ないのか出来ても面倒なのか...)。

もっとも jpg画像からpdf化に imagemagick を使ってるのだからその工程も自作ツールでやればよい話、と気づけばわりと簡単だった。(imagemagick では空白や日本語のあるファイル名の扱いに難ありだったし)

まず複数のjpgから1つのpdf生成するのは jpeg_demo.c あたりをいじって以下

 #include <stdio.h>
 #include <setjmp.h>
 #include <hpdf.h>
 
 static jmp_buf s_jmp_buf_env;
 
 static void errorHandlerForHaru(HPDF_STATUS err, HPDF_STATUS   detNo, void *udat) {
     printf ("ERROR: err=%04X, detNo=%u\n", (HPDF_UINT)err, (HPDF_UINT)detNo);
     longjmp(s_jmp_buf_env, 1);
 }
 
 int main (int argc, char *argv[]) {
     if (argc < 2) {
         printf("usage> jpg2pdf jpgfile(s).jpg ...\n");
         return 1;
     }
     HPDF_Doc    pdf = HPDF_New (&errorHandlerForHaru, NULL);
     if (!pdf) {
         printf ("error: cannot create PdfDoc object\n");
         return 1;
     }
     if (setjmp(s_jmp_buf_env)) {
         HPDF_Free (pdf);
         return 1;
     }
     HPDF_SetCompressionMode (pdf, HPDF_COMP_ALL);
     /*☆*/
     for (size_t i = 1; i < argc; ++i) {
         HPDF_Page   page = HPDF_AddPage (pdf);
         if (!page)
             return 1;
         HPDF_Image  image   = HPDF_LoadJpegImageFromFile(pdf, argv[i]);
         if (!image) {
             printf("load error %s\n", argv[i]);
             return 1;
         }
         HPDF_REAL img_w = HPDF_REAL(HPDF_Image_GetWidth(image));
         HPDF_REAL img_h = HPDF_REAL(HPDF_Image_GetHeight(image));
         HPDF_Page_SetWidth (page, img_w);
         HPDF_Page_SetHeight(page, img_h);
         HPDF_Page_DrawImage (page, image, 0, 0, img_w, img_h);
     }
     HPDF_SaveToFile (pdf, "a.pdf");
     HPDF_Free (pdf);
     return 0;
 }

コマンドライン引数で渡された jpgファイル(名) を順に突っ込んでるだけ。(コマンドライン引数なんで1オリジンだったり、出力ファイル名無精して a.pdf だったりするけれど)。
これだけで画像複数頁のpdfができちゃうので... ライブラリ、ありがたいです。

次に頁の開き方を設定。/*☆*/あたりに
     HPDF_SetPageLayout(pdf, HPDF_PAGE_LAYOUT_TWO_PAGE_RIGHT);

を挿入。ここでは見開き奇数ページ始まりにしてみた。

で、右綴じ。これについては[[ここら>http://kb2.adobe.com/jp/cps/511/511204.html]]あたりをみて "ViewerPreferences" の Direction"に"R2L"を設定すりゃいいとのこと、libharuの HPDF_Catalog_SetViewerPreference が用途的にはそれなのだけど残念ながら"Direction"には未対応だったので見よう見まねで改造。

 HPDF_STATUS  addR2L(HPDF_Doc pdf) {
     HPDF_Catalog    catalog     = pdf->catalog;
     HPDF_Dict       preferences = HPDF_Dict_New(catalog->mmgr);
     if (!preferences)
         return catalog->error->error_no;
     HPDF_STATUS ret = HPDF_Dict_Add(catalog, "ViewerPreferences", preferences);
     if (ret != HPDF_OK)
         return ret;
     ret = HPDF_Dict_AddName(preferences, "Direction", "R2L");
     if (ret != HPDF_OK)
         return ret;
     return HPDF_OK;
 }

というのを用意、/*☆*/ の位置に呼び出しの addR2L(pdf); を挿入でok。


タイトルと著者名は (これも /*☆*/付近)
     HPDF_SetInfoAttr(pdf, HPDF_INFO_TITLE , "本のタイトル");
     HPDF_SetInfoAttr(pdf, HPDF_INFO_AUTHOR, "著者名");

と用意されたもので楽ちん... なんだが日本語が化けてしまう。

日本語関係の設定が必要のようだ。jfont_demo.c 等いろいろみて
     HPDF_UseJPEncodings(pdf);
     HPDF_UseJPFonts(pdf);
     HPDF_SetCurrentEncoder(pdf, "90msp-RKSJ-H");

を タイトルや著者を設定する前に記述しとく。~
(3行目の"90msp-RKSJ-H"指定は、HPDF_UseJPEncodings(pdf);内で設定されているモノからプロポーショナルなゴシック体を選んだ)~
これでacrobatのプロパティでタイトル&著者がちゃんと日本語で見れたので、めでたしめでたし、としておく。

※ ''HPDF_SetCurrentEncoder'' が肝、というか気づけずにここが一番苦労した。他のツールで生成したpdfとバイナリ見比べて、TitleやAuthorは7bit範囲はasciiだけどそれ以上だとUTF16(big endian)ベースになってるとか、utf8で別のxmlな記述スタイルになってるものとか... 結局utf16扱ってる処理から遡ってSetCurrentEncoderに行き着いた、と.

~

ということで、上記をもとに作ってみたコマンドラインツールは[[こちら>http://www.6809.net/tenk/html/lib/cnvToPdf-0.1b.zip]]。~
ということで、上記をもとに作ってみたコマンドラインツールは[[こちら>http://www.6809.net/tenk/html/lib/cnvToPdf-0.1c.zip]]。~
(※2/29追記: libharuビルド・バッチの不具合修正. exeは前と同じ)