1.1.3 カスタムスタンプ注釈作成(日付のスタンプ)

images/AppendAnnotStampDate-top.png

狙い・効果

カスタムスタンプ日付入り日付入りのオリジナルのスタンプを描画し、カスタムアイコンとしてスタンプ注釈を挿入します。

処理の概要

ラバースタンプ注釈に使用するカスタムアイコンはプログラムで作成もできます。これを使って、例えばPDFに挿入するスタンプの日付を毎回変更したり、機械的に取得した日付の指定をしたりできます。

本サンプルプログラムでは、指定した日付と名前が記載された円形のカスタムアイコンを持つラバースタンプ注釈をプログラム上で描画して挿入します。ラバースタンプ注釈は入力PDFの1ページ目に挿入されます。

なお、PtlDateを用いた日付指定に関して、『PDF Tool API V7.0』以降のバージョンでは日付の有効性チェックが可能になりました。詳細は「『PDF CookBook』(第5巻)10.3 日付有効性チェック」を確認してください。

PDF Tool APIの主な機能

プログラム例

package cookbook;

import java.io.*;
import jp.co.antenna.ptl.*;

public class AppendAnnotStampDate {
    // そのクラスのusageを表示する関数
    private static void printUsage(){
        System.out.println("usage: java AppendAnnotStamp in-pdf-file" +
                           " out-pdf-file date-in-stamp name-in-stamp");
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        if (args.length < 4) {
            printUsage();
            return;
        }

        // コマンドライン引数の判定
        String dateInStamp = args[2];
        String nameInStamp = args[3];

        try (PtlParamInput inputFile = new PtlParamInput(args[0]);
             PtlParamOutput outputFile = new PtlParamOutput(args[1]);
             PtlPDFDocument doc = new PtlPDFDocument()) {
            // PDFファイルをロードします。
            doc.load(inputFile);

            try (PtlPages pages = doc.getPages()) { //ページコンテナの取得
                // ページコンテナが空かどうか
                if (pages.isEmpty()) {
                    System.out.println("ページコンテナが空\n");
                    return;
                }

                try (PtlPage page = pages.get(0);
                     PtlAnnots annots = page.getAnnots()) {
                    // 日付印を外観として描画
                    addCustomStampAnnotFromDrawContent(annots, dateInStamp, nameInStamp);
                }
            }

            // ファイルに保存します。
            doc.save(outputFile);
        }
	...【AppendAnnotStampDefault.javaと同じ処理のため省略
	  ・エラーメッセージ処理と出力】...
    }

    public static void addCustomStampAnnotFromDrawContent(PtlAnnots annots,
                                                          String dateInStamp,
                                                          String nameInStamp)
        throws PtlException, Exception, Error {
        float sizeStamp = 30.0f;
        try (PtlAnnotStamp stampAnnot = new PtlAnnotStamp();
             PtlRect rect = new PtlRect(10.0f, 260.0f, 10.0f + sizeStamp,
                                        260.0f + sizeStamp)) {
            stampAnnot.setRect(rect);
            stampAnnot.setIconType(PtlAnnotStamp.ICON_TYPE.ICON_CUSTOM);
            stampAnnot.setAnnotFlags(PtlAnnot.FLAG_PRINT);

            //日付の図形部分を設定(描画領域を「ページ」として作成してスタンプに追加する)
            try (PtlPage pageCustomStamp = new PtlPage();
                 PtlRect rectMedia = new PtlRect(0.0f, 0.0f, sizeStamp, sizeStamp);
                 PtlContent content = pageCustomStamp.getContent()) {
                // ページサイズ
                pageCustomStamp.setMediaBox(rectMedia);

                // コンテントに日付印を描画
                drawDateStamp(content, sizeStamp, dateInStamp, nameInStamp);

                // 画像ページを注釈に追加する
                stampAnnot.setPage(pageCustomStamp);
            }

            stampAnnot.setIconName("dateStamp");

            annots.append(stampAnnot);
        }
    }

    public static void drawDateStamp(PtlContent content, float sizeStamp,
                                     String textDate, String textName)
        throws PtlException, Exception, Error {
        try (PtlParamDrawShape paramDrawShape = new PtlParamDrawShape();
             // スタンプの色(赤色)
             PtlColorDeviceRGB color = new PtlColorDeviceRGB(1.0f, 0.0f, 0.0f);
             PtlColorNone colorNone = new PtlColorNone();
             PtlRect rectStamp = new PtlRect(0.0f, 0.0f, sizeStamp, sizeStamp)) {

            // スタンプの円/線を描画するパラメーター
            paramDrawShape.setLineStyle(PtlParamDrawShape.LINE_STYLE.LINE_STYLE_SOLID);
            paramDrawShape.setLineWidth(PtlParamDrawShape.LINE_WIDTH.LINE_WIDTH_THIN);
            paramDrawShape.setLineColor(color);
            paramDrawShape.setFillColor(colorNone);

            // スタンプの円を描画
            content.drawCircle(rectStamp, paramDrawShape);

            // 円の中心から15度で線と円が交わるとする
            double rad = 15.0f * Math.PI / 180.0f;
            // 円の半径
            float r = sizeStamp / 2;
            // 円の中心から交点へのx方向の長さ
            float xx = r * (float)Math.cos(rad);
            // 円の中心から交点へのy方向の長さ
            float yy = r * (float)Math.sin(rad);
            // 上線左端のx座標
            float from_x = r - xx;
            // 上線左端のy座標
            float to_x = r + xx;
            // 下線左端のx座標
            float upper_y = r + yy;
            // 下線左端のy座標
            float lower_y = r - yy;

            try (PtlPoint posFrom1 = new PtlPoint(from_x, upper_y);
                 PtlPoint posTo1 = new PtlPoint(to_x, upper_y);
                 PtlPoint posFrom2 = new PtlPoint(from_x, lower_y);
                 PtlPoint posTo2 = new PtlPoint(to_x, lower_y)) {
                // 円の中に上線を描画
                content.drawLine(posFrom1, posTo1, paramDrawShape);
                // 円の中に下線を描画
                content.drawLine(posFrom2, posTo2, paramDrawShape);
            }

            // 日付のフォントサイズ
            float fontSizeDate = sizeStamp / 2.15f;    // yyyy/mm/dd を想定
            try (PtlParamWriteString paramWriteStringDate = new PtlParamWriteString();
                 PtlRect rectDate = new PtlRect(from_x, lower_y, to_x, upper_y);
                 PtlParamFont font = new PtlParamFont("Helvetica",
                                                      fontSizeDate,
                                                      PtlParamFont.WEIGHT.WEIGHT_NORMAL,
                                                      false, true)) {
                paramWriteStringDate.setFont(font);
                paramWriteStringDate.setTextColor(color);
                paramWriteStringDate.setOutlineColor(color);

                // 日付を描画
                content.writeString(rectDate, PtlContent.ALIGN.ALIGN_CENTER,
                                    textDate, paramWriteStringDate);
            }

            // 下線から名前を描画する矩形までのマージン
            float margin =sizeStamp / 40.0f;

            // 名前のフォントサイズ
            float fontSizeName = sizeStamp / 1.5f;
            try (PtlParamWriteString paramWriteStringName = new PtlParamWriteString();
                 PtlRect rectName = new PtlRect(from_x,
                                                lower_y - (upper_y - lower_y) - margin,
                                                to_x,
                                                lower_y - margin);
                 PtlParamFont font = new PtlParamFont("Helvetica", fontSizeDate,
                                                      PtlParamFont.WEIGHT.WEIGHT_NORMAL,
                                                      false, true)) {
                // 名前を書く矩形の高さ
                float heightNameBase = upper_y - lower_y;
                float heightName = fontSizeName * 25.4f / 72.0f;
                while (heightName > heightNameBase) {
                    fontSizeName -= 0.5f;
                    heightName = fontSizeName * 25.4f / 72.0f;
                }

                // 線の幅
                float widthLine = 0.5f;
                // 線幅を減じた円の半径
                float rr = r - widthLine;
                // 名前の高さのラジアン
                float d = (float)Math.asin(((heightName + yy + margin) / rr));
                // 名前をおさめる矩形の幅
                float widthName = rr * (float)Math.cos(d) * 2;

                // テキストの長さ
                float textWidthName = font.getStringWidth(textName);

                // 名前の長さによるフォントサイズの調整
                while (textWidthName > widthName) {
                    fontSizeName -= 0.5f;
                    font.setSize(fontSizeName);
                    textWidthName = font.getStringWidth(textName);
                    heightName = fontSizeName * 25.4f / 72.0f;
                    d = (float)Math.asin((heightName + yy + margin) / rr);
                    widthName = rr * (float)Math.cos(d) * 2;
                }

                paramWriteStringName.setFont(font);
                paramWriteStringName.setTextColor(color);
                paramWriteStringName.setOutlineColor(color);

                // 名前を描画
                content.writeString(rectName, PtlContent.ALIGN.ALIGN_CENTER,
                                    textName, paramWriteStringName);
            }
        }
    }
}

プログラムファイル名

AppendAnnotStampDate.java

入出力操作の例

C:\samples>java cookbook.AppendAnnotStampDate 
usage: java AppendAnnotStamp in-pdf-file out-pdf-file date-in-stamp name-in-stamp

C:\samples>java cookbook.AppendAnnotStampDate blank.pdf blank-date.pdf 2019/10/30 CookBook4 
-- 完了 --

次図はPDFに貼り付けた日付のカスタムスタンプ注釈をダブルクリックしてポップアップ注釈を表示したところです。

カスタムスタンプ注釈作成(日付のスタンプ)