AndroidでPDFを作成してみる



こんにちは。久しぶりのブログ更新です。


今回はAndroidアプリから、PDFファイルを作成する方法を紹介したいと思います。



実現方法としては・・・

  1. 既存ライブラリを活用する
  2. 自前でスクリプトを書く
  3. PDFを生成してくれるWebサービスを利用する
  4. 他アプリからインテントを使い生成する
僕自身、全て試したわけではありませんが、手っ取り早いのは(1)既存のライブラリを活用する事だと思います。実装が一筋縄ではありませんが・・・


(2)に関しては、PDFの仕様を理解していないとイバラの道になると思います。
でも仕様を理解することは勉強にもなるし、時間に余裕のある人はこちらをオススメします。(日本語訳の公式リファレンスが5、6千円で売ってます。英語のリファレンスはWebで無料でダウンロードできます)
(3)に関しては2ch仕入れた情報ですが、面倒臭そうなので調べていません…
(4)調べたんですが、今のところ無さそうです。。。(もしあれば教えてください)

既存のライブラリを利用してみる

これより先はライブラリの利用方法について説明しますが、フリーのライブラリを利用する際、
いくつか注意する事があります。

  1. ライブラリが利用しているjavaパッケージ
  2. ライブラリが利用しているJDKのバージョン(JDK6を使ってたらアウト)
  3. 日本語等の出力
  4. ライセンス
これらすべての条件を満たすライブラリとなると、かなり数が限られてきそうです。
特にライセンスは重要です。調べれば分かることですが、GPL関連のライセンスだと利用するのが難しいでしょう。
うろ覚えですが、「GPLライセンスのライブラリを利用する際の条約の一つとして、アプリに組み込まれたライブラリが改変された場合はソースコードを開示しなければいけない。Androidではこの条約を満たすことが出来ないから、結局ソースコードを開示する必要がある」どこかのブログに書いてあった気がします。。。回避策としては、PDFに関連する処理だけを抜き出し、別アプリで公開後、インテント経由で利用するということが考えられます。でもユーザーにアプリのインストール促す必要もあり、いろいろ面倒ですね。。。

なんとなく使えそうなライブラリ

java PDF ライブラリ」でググルと結構ヒットしますが、どれもコレも一筋縄ではいきません。

java用のPDFライブラリ
ライブラリ名 packageのサポート JDKバージョン 日本語出力 ライセンス
iText × ×
iText for Android ×
PDF Box ×
Android PDF Write ×


iText
iTextはドキュメントも豊富で、ブログ等で使い方も紹介されているぐらいメジャー?なライブラリのようですが、
awt等のAndroidではサポートされないパッケージを使ってます。
実際にiTextを実装する際、この事に気づくまで1週間ぐらいハマってしまいました。
しかもGPLの派生ライセンスを採用しています。


iText for Android
iTextAndroidで使えるようにしてるらしいですが、どうやらまだ未完成のようです。
実際試しましたが、結局ビルドが通りませんでした。


PDF Box
こちらは試してませんが、やっぱりパッケージ関連の問題で無理なようです。
http://www.kaede-software.com/2011/04/pdfbox.html


Android PDF Write
恐らくつい最近に公開されたAndroid用のライブラリですが、外国の方が作られたライブラリなので日本語等の出力が無理なようです。英語のドキュメントのみ生成するのであれば、十分利用出来ます。


色々なライブラリを調べた結果、「androidで利用出来るjavaのPDFライブラリ」は今のところ無さそうです・・・

NDKを利用する

それからかなり悩んだのですが、javaが無理ならCのライブラリはどうだ?と色々探してみたところ、
libHaru free PDF library」を見つけました。
ドキュメント等は全て英語のなのですが、製作者は日本の方なので、日本語の出力も可能です。
ライセンスは zlib/libpngライセンスなので、商用・非商用を問わずアプリに組み込めそうです。
ダウンロード・ドキュメントはこちら
http://libharu.org/wiki/Main_Page


これよりNDKの環境構築とビルドに関して説明していきます。環境を整えるのが結構面倒ですが、それに見合った価値はあると思います。
(とりあえず動きを確認したい場合は、ページ最下部にプロジェクトをダウンロードできるURLを貼りつけています)

NDKの開発環境を整える

環境構築に関しては、分かりやすく解説されているサイトが多数存在しますので、頑張って調べてください。
僕はこちらのサイトを参考にさせていただきました。
http://www.usefullcode.net/2010/12/android_sdk_inst05.html
http://d.hatena.ne.jp/bs-android/20090324/1237864333

ネィティブモジュールを呼び出す準備

クラスファイルにネィティブを使うことを宣言します。

static {
    System.loadLibrary("CreatePDF");
}
private native int createPDF(String fpath);



exportボタンを押すと、SyncTaskが起動してPDFを作成するようにします。

@Override
public void onCreate(Bundle savedInstanceState) {
    
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    
    Button b = (Button)this.findViewById(R.id.Button01);
    b.setOnClickListener(new OnClickListener() {
        
        @Override
        public void onClick(View v) {
            
            switch (v.getId()) {
            case R.id.Button01:
                
                export();
                break;
            default:
                break;
            }
        }
    });
}

プログレスダイアログを表示して、ネイティブに処理を任せる。

private void export() {
    
    final ProgressDialog mProgress =
        new ProgressDialog(this);
    mProgress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
    mProgress.setMessage(getResources().getString(R.string.wait));
    mProgress.setCancelable(false);
    
    Runnable successRun = new Runnable() {
        public void run() {
            
            Toast.makeText(getApplicationContext(),
                    getResources().getString(R.string.success),
                    Toast.LENGTH_SHORT).show();
            mProgress.dismiss();
            setResult(RESULT_OK);
        };
    };
    Runnable errorRun = new Runnable() {
        public void run() {
            
            Toast.makeText(getApplicationContext(),
                    getResources().getString(R.string.error),
                    Toast.LENGTH_SHORT).show();
            mProgress.dismiss();
        };
    };
    
    
    mProgress.show();
    ExportSyncTask task = new ExportSyncTask(
            this.getApplicationContext(),
            successRun, errorRun);
    task.execute();
}

private String getSavePath(String catStr) throws IOException {
    
    String pathSd = new StringBuilder()
        .append(Environment.getExternalStorageDirectory().getPath())
        .append("/")
        .append(this.getPackageName())
        .toString();
    File filePathToSaved = new File(pathSd);
    
    if (!filePathToSaved.exists() && !filePathToSaved.mkdirs()) {
        throw new IOException("FAILED_TO_CREATE_PATH_ON_SD");
    }
    
    return pathSd + "/" + catStr;
}

public int exportPDF () throws FileNotFoundException, IOException {
    
    String savePath;
    savePath = getSavePath("helloPDF.pdf");
    createPDF(savePath);

    return 0;
}

private class ExportSyncTask extends AsyncTask<Void, Void, Integer> {

    private Handler mHandler;
    private Handler mHandler2;
    private Thread mSuccessT;
    private Thread mErrorT;
    
    public ExportSyncTask(Context context, final Runnable r1, final Runnable r2) {
        
        mHandler = new Handler();
        mHandler2 = new Handler();
        
        mSuccessT = new Thread(new Runnable() {
            public void run() {
                mHandler.post(r1);
            }
        });
        
        mErrorT = new Thread(new Runnable() {
            public void run() {
                mHandler2.post(r2);
            }
        });
    }
    
    @Override
    protected Integer doInBackground(Void... arg0) {
        
        try {
            exportPDF();
        } catch (FileNotFoundException e) {
            Log.e("PDF_sampleActivity", e.toString());
            return -1;
        } catch (IOException e) {
            Log.e("PDF_sampleActivity", e.toString());
            return -1;
        }
        
        return 0;
    }
    
    @Override
    protected void onPostExecute(Integer result) {
        
        if (result == null || result < 0) {
            
            mErrorT.start();
        } else {
            
            mSuccessT.start();
        }
    }
}



マニフェストパーミッションを追加しておきます。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>



「CreatePDF」はこれから作成するライブラリの名前になります。
javad側の処理はこれで完了です。
ここで一旦ビルドしてください。

ソースコードをダウンロードする

AndroidでlibHaruPDFを使うには、ソースコードコンパイルしてAndroid用の共有ライブラリを作成する必要があります。
libHaruPDFはlibpngライブラリーを使用しておりますので、libHaruPDFとlibpngのソースコードをダウンロードしましょう。
libHaruPDF
http://libharu.org/wiki/Downloads
(Latest Versionをダウンロードして下さい)


libpng
http://www.libpng.org/pub/png/libpng.html
(バージョン1.2.46のsource codeよりダウンロードして下さい)


ではeclipseにフォルダを作って、ファイルを移動しましょう。
jniフォルダを作り、その中にlibharu,libpng,pdftestの3フォルダを作ります。
フォルダ構成は次のようになってると思います。(*.c,*.hのみ移動させます。その他のmakeとか必要ないです)

top
  src
  gen
  assets
  libs
  res
  jni
  --libharu
    --include
      --hpdf_annotation.h
      --hpdf_catalog.h
      --hpdf_conf.h
      --...
    --hpdf_annotation.c
    --hpdf_array.c
    --hpdf_binary.c
    --...
  --libpng
    --<*.hと*.cを全て>
  --pdftest

pdftestフォルダにCreatePDFとヘッダファイルを配置します。
こちらのブログを参考にヘッダファイルを作成します。(「JNIヘッダファイルの生成」の項を参照)
http://d.hatena.ne.jp/bs-android/20090324/1237864333
次にCreatePDF.cを作成してください。
下記URLのサンプルコードを試してみます。(コピペでは動きません)
http://libharu.org/wiki/Documentation/Examples

/*
 * << Haru Free PDF Library 2.0.0 >> -- font_demo.c
 *
 * Copyright (c) 1999-2006 Takeshi Kanno <takeshi_kanno@est.hi-ho.ne.jp>
 *
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.
 * It is provided "as is" without express or implied warranty.
 *
 */

#include <sample_pdf_PDFsampleActivity.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
#include "hpdf.h"
#include <android/log.h>

jmp_buf env;

static char* jstr2cp(JNIEnv *e, jstring str);
static void jstrfree(JNIEnv *e, jstring str, char *cp);
static void log_print(char *str);

#ifdef HPDF_DLL
void  __stdcall
#else
void
#endif
error_handler (HPDF_STATUS   error_no,
               HPDF_STATUS   detail_no,
               void         *user_data)
{
    __android_log_print(ANDROID_LOG_DEBUG, "CreatePDF",
    			"ERROR: error_no=%04X, detail_no=%u\n", (HPDF_UINT)error_no,
                (HPDF_UINT)detail_no);
    longjmp(env, 1);
}

void
draw_line  (HPDF_Page    page,
            float        x,
            float        y,
            const char  *label)
{
    HPDF_Page_BeginText (page);
    HPDF_Page_MoveTextPos (page, x, y - 10);
    HPDF_Page_ShowText (page, label);
    HPDF_Page_EndText (page);

    HPDF_Page_MoveTo (page, x, y - 15);
    HPDF_Page_LineTo (page, x + 220, y - 15);
    HPDF_Page_Stroke (page);
}

void
draw_line2  (HPDF_Page    page,
             float       x,
             float       y,
             const char  *label)
{
    HPDF_Page_BeginText (page);
    HPDF_Page_MoveTextPos (page, x, y);
    HPDF_Page_ShowText (page, label);
    HPDF_Page_EndText (page);

    HPDF_Page_MoveTo (page, x + 30, y - 25);
    HPDF_Page_LineTo (page, x + 160, y - 25);
    HPDF_Page_Stroke (page);
}

void
draw_rect (HPDF_Page     page,
           double        x,
           double        y,
           const char   *label)
{
    HPDF_Page_BeginText (page);
    HPDF_Page_MoveTextPos (page, x, y - 10);
    HPDF_Page_ShowText (page, label);
    HPDF_Page_EndText (page);

    HPDF_Page_Rectangle(page, x, y - 40, 220, 25);
}

JNIEXPORT jint JNICALL Java_sample_pdf_PDFsampleActivity_createPDF
  (JNIEnv *jenv, jobject jobj, jstring file_name)
{
    const char* page_title = "Line Example";

    HPDF_Doc  pdf;
    HPDF_Font font;
    HPDF_Page page;
    char fname[256];
    char *path_str;

    const HPDF_UINT16 DASH_MODE1[] = {3};
    const HPDF_UINT16 DASH_MODE2[] = {3, 7};
    const HPDF_UINT16 DASH_MODE3[] = {8, 7, 2, 7};

    double x;
    double y;
    double x1;
    double y1;
    double x2;
    double y2;
    double x3;
    double y3;

    float tw;

    path_str = jstr2cp(jenv, file_name);
	strcpy (fname, path_str);

    pdf = HPDF_New (error_handler, NULL);
    if (!pdf) {
        log_print ("error: cannot create PdfDoc object\n");
        return 1;
    }

    if (setjmp(env)) {
        HPDF_Free (pdf);
        return 1;
    }

    /* create default-font */
    font = HPDF_GetFont (pdf, "Times-Roman", NULL);

    /* add a new page object. */
    page = HPDF_AddPage (pdf);
    
    log_print("new page");

    /* print the lines of the page. */
    HPDF_Page_SetLineWidth (page, 1);
    HPDF_Page_Rectangle (page, 50, 50, HPDF_Page_GetWidth(page) - 100,
                HPDF_Page_GetHeight (page) - 110);
    HPDF_Page_Stroke (page);

    /* print the title of the page (with positioning center). */
    HPDF_Page_SetFontAndSize (page, font, 24);
    tw = HPDF_Page_TextWidth (page, page_title);
    HPDF_Page_BeginText (page);
    HPDF_Page_MoveTextPos (page, (HPDF_Page_GetWidth(page) - tw) / 2,
                HPDF_Page_GetHeight (page) - 50);
    HPDF_Page_ShowText (page, page_title);
    HPDF_Page_EndText (page);

    HPDF_Page_SetFontAndSize (page, font, 10);

    /* Draw verious widths of lines. */
    HPDF_Page_SetLineWidth (page, 0);
    draw_line (page, 60, 770, "line width = 0");

    HPDF_Page_SetLineWidth (page, 1.0);
    draw_line (page, 60, 740, "line width = 1.0");

    HPDF_Page_SetLineWidth (page, 2.0);
    draw_line (page, 60, 710, "line width = 2.0");

    /* Line dash pattern */
    HPDF_Page_SetLineWidth (page, 1.0);

    HPDF_Page_SetDash (page, DASH_MODE1, 1, 1);
    draw_line (page, 60, 680, "dash_ptn=[3], phase=1 -- "
                "2 on, 3 off, 3 on...");

    HPDF_Page_SetDash (page, DASH_MODE2, 2, 2);
    draw_line (page, 60, 650, "dash_ptn=[7, 3], phase=2 -- "
                "5 on 3 off, 7 on,...");

    HPDF_Page_SetDash (page, DASH_MODE3, 4, 0);
    draw_line (page, 60, 620, "dash_ptn=[8, 7, 2, 7], phase=0");

    HPDF_Page_SetDash (page, NULL, 0, 0);

    HPDF_Page_SetLineWidth (page, 30);
    HPDF_Page_SetRGBStroke (page, 0.0, 0.5, 0.0);

    /* Line Cap Style */
    HPDF_Page_SetLineCap (page, HPDF_BUTT_END);
    draw_line2 (page, 60, 570, "PDF_BUTT_END");

    HPDF_Page_SetLineCap (page, HPDF_ROUND_END);
    draw_line2 (page, 60, 505, "PDF_ROUND_END");

    HPDF_Page_SetLineCap (page, HPDF_PROJECTING_SCUARE_END);
    draw_line2 (page, 60, 440, "PDF_PROJECTING_SCUARE_END");

    /* Line Join Style */
    HPDF_Page_SetLineWidth (page, 30);
    HPDF_Page_SetRGBStroke (page, 0.0, 0.0, 0.5);

    HPDF_Page_SetLineJoin (page, HPDF_MITER_JOIN);
    HPDF_Page_MoveTo (page, 120, 300);
    HPDF_Page_LineTo (page, 160, 340);
    HPDF_Page_LineTo (page, 200, 300);
    HPDF_Page_Stroke (page);

    HPDF_Page_BeginText (page);
    HPDF_Page_MoveTextPos (page, 60, 360);
    HPDF_Page_ShowText (page, "PDF_MITER_JOIN");
    HPDF_Page_EndText (page);

    HPDF_Page_SetLineJoin (page, HPDF_ROUND_JOIN);
    HPDF_Page_MoveTo (page, 120, 195);
    HPDF_Page_LineTo (page, 160, 235);
    HPDF_Page_LineTo (page, 200, 195);
    HPDF_Page_Stroke (page);

    HPDF_Page_BeginText (page);
    HPDF_Page_MoveTextPos (page, 60, 255);
    HPDF_Page_ShowText (page, "PDF_ROUND_JOIN");
    HPDF_Page_EndText (page);

    HPDF_Page_SetLineJoin (page, HPDF_BEVEL_JOIN);
    HPDF_Page_MoveTo (page, 120, 90);
    HPDF_Page_LineTo (page, 160, 130);
    HPDF_Page_LineTo (page, 200, 90);
    HPDF_Page_Stroke (page);

    HPDF_Page_BeginText (page);
    HPDF_Page_MoveTextPos (page, 60, 150);
    HPDF_Page_ShowText (page, "PDF_BEVEL_JOIN");
    HPDF_Page_EndText (page);

    /* Draw Rectangle */
    HPDF_Page_SetLineWidth (page, 2);
    HPDF_Page_SetRGBStroke (page, 0, 0, 0);
    HPDF_Page_SetRGBFill (page, 0.75, 0.0, 0.0);

    draw_rect (page, 300, 770, "Stroke");
    HPDF_Page_Stroke (page);

    draw_rect (page, 300, 720, "Fill");
    HPDF_Page_Fill (page);

    draw_rect (page, 300, 670, "Fill then Stroke");
    HPDF_Page_FillStroke (page);

    /* Clip Rect */
    HPDF_Page_GSave (page);  /* Save the current graphic state */
    draw_rect (page, 300, 620, "Clip Rectangle");
    HPDF_Page_Clip (page);
    HPDF_Page_Stroke (page);
    HPDF_Page_SetFontAndSize (page, font, 13);

    HPDF_Page_BeginText (page);
    HPDF_Page_MoveTextPos (page, 290, 600);
    HPDF_Page_SetTextLeading (page, 12);
    HPDF_Page_ShowText (page,
                "Clip Clip Clip Clip Clip Clipi Clip Clip Clip");
    HPDF_Page_ShowTextNextLine (page,
                "Clip Clip Clip Clip Clip Clip Clip Clip Clip");
    HPDF_Page_ShowTextNextLine (page,
                "Clip Clip Clip Clip Clip Clip Clip Clip Clip");
    HPDF_Page_EndText (page);
    HPDF_Page_GRestore (page);

    /* Curve Example(CurveTo2) */
    x = 330;
    y = 440;
    x1 = 430;
    y1 = 530;
    x2 = 480;
    y2 = 470;
    x3 = 480;
    y3 = 90;

    HPDF_Page_SetRGBFill (page, 0, 0, 0);

    HPDF_Page_BeginText (page);
    HPDF_Page_MoveTextPos (page, 300, 540);
    HPDF_Page_ShowText (page, "CurveTo2(x1, y1, x2. y2)");
    HPDF_Page_EndText (page);

    HPDF_Page_BeginText (page);
    HPDF_Page_MoveTextPos (page, x + 5, y - 5);
    HPDF_Page_ShowText (page, "Current point");
    HPDF_Page_MoveTextPos (page, x1 - x, y1 - y);
    HPDF_Page_ShowText (page, "(x1, y1)");
    HPDF_Page_MoveTextPos (page, x2 - x1, y2 - y1);
    HPDF_Page_ShowText (page, "(x2, y2)");
    HPDF_Page_EndText (page);

    HPDF_Page_SetDash (page, DASH_MODE1, 1, 0);

    HPDF_Page_SetLineWidth (page, 0.5);
    HPDF_Page_MoveTo (page, x1, y1);
    HPDF_Page_LineTo (page, x2, y2);
    HPDF_Page_Stroke (page);

    HPDF_Page_SetDash (page, NULL, 0, 0);

    HPDF_Page_SetLineWidth (page, 1.5);

    HPDF_Page_MoveTo (page, x, y);
    HPDF_Page_CurveTo2 (page, x1, y1, x2, y2);
    HPDF_Page_Stroke (page);

    /* Curve Example(CurveTo3) */
    y -= 150;
    y1 -= 150;
    y2 -= 150;

    HPDF_Page_BeginText (page);
    HPDF_Page_MoveTextPos (page, 300, 390);
    HPDF_Page_ShowText (page, "CurveTo3(x1, y1, x2. y2)");
    HPDF_Page_EndText (page);

    HPDF_Page_BeginText (page);
    HPDF_Page_MoveTextPos (page, x + 5, y - 5);
    HPDF_Page_ShowText (page, "Current point");
    HPDF_Page_MoveTextPos (page, x1 - x, y1 - y);
    HPDF_Page_ShowText (page, "(x1, y1)");
    HPDF_Page_MoveTextPos (page, x2 - x1, y2 - y1);
    HPDF_Page_ShowText (page, "(x2, y2)");
    HPDF_Page_EndText (page);

    HPDF_Page_SetDash (page, DASH_MODE1, 1, 0);

    HPDF_Page_SetLineWidth (page, 0.5);
    HPDF_Page_MoveTo (page, x, y);
    HPDF_Page_LineTo (page, x1, y1);
    HPDF_Page_Stroke (page);

    HPDF_Page_SetDash (page, NULL, 0, 0);

    HPDF_Page_SetLineWidth (page, 1.5);
    HPDF_Page_MoveTo (page, x, y);
    HPDF_Page_CurveTo3 (page, x1, y1, x2, y2);
    HPDF_Page_Stroke (page);

    /* Curve Example(CurveTo) */
    y -= 150;
    y1 -= 160;
    y2 -= 130;
    x2 += 10;

    HPDF_Page_BeginText (page);
    HPDF_Page_MoveTextPos (page, 300, 240);
    HPDF_Page_ShowText (page, "CurveTo(x1, y1, x2. y2, x3, y3)");
    HPDF_Page_EndText (page);

    HPDF_Page_BeginText (page);
    HPDF_Page_MoveTextPos (page, x + 5, y - 5);
    HPDF_Page_ShowText (page, "Current point");
    HPDF_Page_MoveTextPos (page, x1 - x, y1 - y);
    HPDF_Page_ShowText (page, "(x1, y1)");
    HPDF_Page_MoveTextPos (page, x2 - x1, y2 - y1);
    HPDF_Page_ShowText (page, "(x2, y2)");
    HPDF_Page_MoveTextPos (page, x3 - x2, y3 - y2);
    HPDF_Page_ShowText (page, "(x3, y3)");
    HPDF_Page_EndText (page);

    HPDF_Page_SetDash (page, DASH_MODE1, 1, 0);

    HPDF_Page_SetLineWidth (page, 0.5);
    HPDF_Page_MoveTo (page, x, y);
    HPDF_Page_LineTo (page, x1, y1);
    HPDF_Page_Stroke (page);
    HPDF_Page_MoveTo (page, x2, y2);
    HPDF_Page_LineTo (page, x3, y3);
    HPDF_Page_Stroke (page);

    HPDF_Page_SetDash (page, NULL, 0, 0);

    HPDF_Page_SetLineWidth (page, 1.5);
    HPDF_Page_MoveTo (page, x, y);
    HPDF_Page_CurveTo (page, x1, y1, x2, y2, x3, y3);
    HPDF_Page_Stroke (page);
    
    log_print("end Stroke");

    /* save the document to a file */
    log_print (fname);
    HPDF_SaveToFile (pdf, fname);
    log_print ("save success");

    /* clean up */
    HPDF_Free (pdf);
    jstrfree(jenv, file_name, path_str);

    return 0;
}


static void jstrfree(JNIEnv *e, jstring str, char *cp)
{
	(*e)->ReleaseStringUTFChars(e, str, cp);
}

static char* jstr2cp(JNIEnv *e, jstring str)
{
	return (*e)->GetStringUTFChars(e, str, NULL);
}

static void log_print(char *str)
{
	__android_log_print(ANDROID_LOG_DEBUG, "CreatePDF", "%s", str);
}

Android.mkの書き方
モジュールをビルドするためのmakeファイルも書きますが、今回は自分の書いたmakeファイルを載せておきますので活用してください。
makeファイルの書き方は、こちらを参考にさせていただきました。
http://android.g.hatena.ne.jp/n4_t/20090703/1246674762
http://playwithopencv.blogspot.com/2011/06/androidopencv23.html

############### libpng ###############
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := png
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -lz -ldl -llog

LOCAL_CFLAGS := -I$(LOCAL_PATH)/libpng
LOCAL_SRC_FILES := \
libpng/pngwrite.c \
libpng/pngrutil.c \
libpng/pngrtran.c \
libpng/pngread.c \
libpng/pngmem.c \
libpng/pngrio.c \
libpng/pngpread.c \
libpng/pngvcrd.c \
libpng/pngtrans.c \
libpng/pnggccrd.c \
libpng/pngwutil.c \
libpng/pngwio.c \
libpng/png.c \
libpng/pngwtran.c \
libpng/pngget.c \
libpng/pngset.c \
libpng/pngerror.c \

include $(BUILD_STATIC_LIBRARY)


############### libharu PDF Library ###############
include $(CLEAR_VARS)

LOCAL_MODULE := haru
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -lz -ldl -llog \
-L$(TARGET_OUT) -lpng

LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/libpng \
$(LOCAL_PATH)/libharu/include

LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%)

LOCAL_SRC_FILES := \
libharu/hpdf_xref.c \
libharu/hpdf_annotation.c \
libharu/hpdf_array.c \
libharu/hpdf_binary.c \
libharu/hpdf_boolean.c \
libharu/hpdf_catalog.c \
libharu/hpdf_destination.c \
libharu/hpdf_dict.c \
libharu/hpdf_doc.c \
libharu/hpdf_doc_png.c \
libharu/hpdf_encoder.c \
libharu/hpdf_encoder_cns.c \
libharu/hpdf_encoder_cnt.c \
libharu/hpdf_encoder_jp.c \
libharu/hpdf_encoder_kr.c \
libharu/hpdf_encrypt.c \
libharu/hpdf_encryptdict.c \
libharu/hpdf_error.c \
libharu/hpdf_ext_gstate.c \
libharu/hpdf_font.c \
libharu/hpdf_font_cid.c \
libharu/hpdf_font_tt.c \
libharu/hpdf_font_type1.c \
libharu/hpdf_fontdef.c \
libharu/hpdf_fontdef_base14.c \
libharu/hpdf_fontdef_cid.c \
libharu/hpdf_fontdef_cns.c \
libharu/hpdf_fontdef_cnt.c \
libharu/hpdf_fontdef_jp.c \
libharu/hpdf_fontdef_kr.c \
libharu/hpdf_fontdef_tt.c \
libharu/hpdf_fontdef_type1.c \
libharu/hpdf_gstate.c \
libharu/hpdf_image.c \
libharu/hpdf_image_png.c \
libharu/hpdf_info.c \
libharu/hpdf_list.c \
libharu/hpdf_mmgr.c \
libharu/hpdf_name.c \
libharu/hpdf_namedict.c \
libharu/hpdf_null.c \
libharu/hpdf_number.c \
libharu/hpdf_objects.c \
libharu/hpdf_outline.c \
libharu/hpdf_page_label.c \
libharu/hpdf_page_operator.c \
libharu/hpdf_pages.c \
libharu/hpdf_pdfa.c \
libharu/hpdf_real.c \
libharu/hpdf_streams.c \
libharu/hpdf_string.c \
libharu/hpdf_u3d.c \
libharu/hpdf_utils.c \


LOCAL_STATIC_LIBRARIES := png
include $(BUILD_STATIC_LIBRARY)


############### pdf export ###############
include $(CLEAR_VARS)

LOCAL_MODULE := CreatePDF
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -lz -ldl -llog
# -L$(TARGET_OUT) -lharu

LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/pdf_export \
$(LOCAL_PATH)/libharu/include

LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%)

LOCAL_SRC_FILES := pdf_export/CreatePDF.c

LOCAL_STATIC_LIBRARIES := haru

include $(BUILD_SHARED_LIBRARY)



Cygwinを起動して、Android.mkがあるフォルダにて「ndk-build」を実行すれば、ソースがコンパイルされます。


コンパイルが完了するとlibsに共有ライブラリが作成されているはずです。
うまく行ったことが確認できたら、ビルドを実行して実機にインストールしてください。


作成されたPDFは、AdobeReaderにて確認してみてください。


プロジェクトはダウンロードする場合はこちら

https://sites.google.com/site/devkorsakov/files/android_pdf_export.zip?attredirects=0&d=1