PDFlib

高度なPDFアプリケーションの開発を支援する定番プログラムライブラリー Supported by インフォテック株式会社

PDFlib サンプル集(クックブック)

本サンプルプログラムは、PDF 文書生成ライブラリーの実装である PDFlib の基本的な機能を実際のプログラムで紹介したものです。

本サイトでダウンロードした PDFlib は、一部機能の制限を除き、評価版として無償でお使いいただけます。

PDF/A クローン

PDF/A、PDF/X 標準ドキュメントのクローン。スタンプ、XMP メタデータの追加、ページコンテンツの追加などの拡張処理のための簡単な使用方法を示します。次の挙げる入力文書の内容によりクローンを作ります。

  • PDF/A および PDF/X バージョン(PDFlib によりサポートされる場合)PDF/A-1a:2005 および PDF/X-5n 標準はクローンを作ることができません。
  • インテントを出力します(提供される場合)。参照される PDF/X-4p および PDF/X-5pg のためのインテント出力もクローンされます。
  • ページ幾何学(ページボックスやローテートキーなど)。参照される PDF/X-5g および PDF/X-5pg のための拡張ページもクローンされます。
  • XMP 文書メタデータ

新しいページコンテンツを追加する必要のある変換をデモしています。このトピックでは、全てのページに横断するスタンプを加えています。

入力文書は、PDF/A と PDF/X に同時に従くかもしれません。

注意:入力および出力文書の名前を除いて、PDF/X クローンクックブックのコピーです。

必要な製品:PDFlib+PDI または PPS


/*
 * Clone PDF/A, PDF/UA and PDF/X standard documents
 * This is useful as basis for additional processing,
 * such as stamping, adding XMP metadata, adding page content, etc.
 *
 * The following aspects of the input document are cloned:
 * - PDF/A, PDF/UA and PDF/X version
 * - PDF/A or PDF/X output intent (if present)
 * - document language (if present)
 * - all pages including page geometry, i.e. page boxes and Rotate key
 * - the structure elements (tags); if required, an additional
 *   tag is inserted on top of the imported page elements
 * - XMP document metadata
 *   This will generally also clone document info fields since these are
 *   synchronized with XMP in the majority of modern PDF documents.
 *
 * To demonstrate coordinate transformations which may be required
 * to add new page content this topic adds a stamp across all pages.
 *
 * Input documents may conform to any combination of PDF/A, PDF/UA 
 * and PDF/X simultaneously.
 *
 * Note: Except for the names of the input and output documents the three
 * Cookbook topics clone_pdfa, clone_pdfua and clone_pdfx are exact copies.
 * They are included multiply so that they can easily be found in the
 * PDF/A, PDF/UA and PDF/X categories.
 *
 * required software: PDFlib+PDI/PPS 10
 * required data: PDF/A, PDF/UA or PDF/X input document
 */

package com.pdflib.cookbook.pdflib.pdfa;

import com.pdflib.pdflib;
import com.pdflib.PDFlibException;

public class clone_pdfa {
    public static void main(String argv[]) {
        /* This is where the data files are. Adjust as necessary. */
        String searchpath = "../input";

        /* By default annotations are also imported. In some cases this
         * requires the Noto fonts for creating annotation appearance streams.
         * We therefore set the searchpath to also point to the font directory.
         */
        String fontpath = "../resource/font";

        pdflib p = null;
        
        String pdfinputfile = "PLOP-datasheet-PDFA-1b.pdf";
        String title = "clone_pdfa";
        
        String pdfaversion, pdfuaversion, pdfxversion, inputlang;
        boolean taggedinput;
        String optlist = "";
        byte xmp[];

        /* The following standard flavors can be cloned: */
        String supportedflavors[] = {
            "PDF/A-1a:2005", "PDF/A-1b:2005", 
            "PDF/A-2a", "PDF/A-2b", "PDF/A-2u",
            "PDF/A-3a", "PDF/A-3b", "PDF/A-3u",
            
            "PDF/X-3:2003",
            "PDF/X-4", "PDF/X-4p", 
            "PDF/X-5g", "PDF/X-5pg", "PDF/X-5n",
            
            "PDF/UA-1",
            "none",
        };

        int indoc, endpage, pageno, i;
        double x, y, phi, width, height;
        int exitcode = 0;

        try {
            p = new pdflib();

            p.set_option("searchpath={" + searchpath + "}");

            p.set_option("searchpath={" + fontpath + "}");

            /* This means we must check return values of load_font() etc. */
            p.set_option("errorpolicy=return");

            /*
             * Open the input PDF, preserve tags if present (for cloning
             * PDF/A-1/2/3a and PDF/UA)
             */
            indoc = p.open_pdi_document(pdfinputfile, "usetags=true");
            if (indoc == -1) {
                throw new Exception("Error: " + p.get_apiname() + ": "
                    + p.get_errmsg());
            }

            /*
             * Read PDF/A, PDF/UA and PDF/X version of the input document
             */
            pdfaversion = p.pcos_get_string(indoc, "pdfa");
            pdfuaversion = p.pcos_get_string(indoc, "pdfua");
            pdfxversion = p.pcos_get_string(indoc, "pdfx");

            for (i = 0; i < supportedflavors.length; i++) {
                if (pdfaversion.equals(supportedflavors[i])) {
                    optlist += " pdfa=" + pdfaversion;
                    break;
                }
            }
            if (i == supportedflavors.length)
                System.err.println("Error: Cannot clone " + pdfaversion
                    + " documents");

            for (i = 0; i < supportedflavors.length; i++) {
                if (pdfuaversion.equals(supportedflavors[i])) {
                    optlist += " pdfua=" + pdfuaversion;
                    break;
                }
            }
            if (i == supportedflavors.length)
                System.err.println("Error: Cannot clone " + pdfuaversion
                    + " documents");

            for (i = 0; i < supportedflavors.length; i++) {
                if (pdfxversion.equals(supportedflavors[i])) {
                    optlist += " pdfx=" + pdfxversion;
                    break;
                }
            }
            if (i == supportedflavors.length)
                System.err.println("Error: Cannot clone " + pdfxversion
                    + " documents");

            /*
             * Read language entry of the input document if present
             */

            if (p.pcos_get_string(indoc, "type:/Root/Lang").equals("string")) {
                inputlang = p.pcos_get_string(indoc, "/Root/Lang");
                optlist += " lang=" + inputlang;
            }
            else if (pdfuaversion.equals("PDF/UA-1"))
            {
                /* PDF/UA documents don't necessarily need the /Lang entry
                 * in the Catalog, but PDFlib requires the "lang" option.
                 * We supply a default language (which may be wrong) to
                 * ensure that such documents can be cloned nevertheless.
                 */
            	final String DEFAULT_LANGUAGE = "en";
            	optlist += " lang=" + DEFAULT_LANGUAGE;
            }
            else
                inputlang = "";

            /*
             * Clone XMP metadata of input document if present
             */
            if (p.pcos_get_string(indoc, "type:/Root/Metadata")
                                                    .equals("stream")) {
                xmp = p.pcos_get_stream(indoc, "", "/Root/Metadata");
                p.create_pvf("/xmp/document.xmp", xmp, "");
                optlist += " metadata={filename=/xmp/document.xmp}";
            }

            /*
             * Read Tagged status of input document
             */
            taggedinput = p.pcos_get_string(indoc, "tagged").equals("true");

            if (taggedinput)
                optlist += " tag={tagname=Document}";

            /*
             * Create a new document and clone PDF/A, PDF/UA and PDF/X status
             */
            if (p.begin_document(title + ".pdf", optlist) == -1)
                throw new Exception("Error: " + p.get_apiname() + ": "
                                                        + p.get_errmsg());

            p.set_info("Creator", "PDFlib Cookbook");
            p.set_info("Title", title);

            /*
             * Clone PDF/A or PDF/X output intent
             */
            if (p.process_pdi(indoc, -1, "action=copyoutputintent") == -1)
                throw new Exception("Error: " + p.get_apiname() + ": "
                    + p.get_errmsg());

            /* Create a bookmark with the name of the input document */
            p.create_bookmark(pdfinputfile, "");

            endpage = (int) p.pcos_get_number(indoc, "length:pages");

            /* Copy all pages of the input document */
            for (pageno = 1; pageno <= endpage; pageno++) {
                String lowerleftcorner[][] = {
                    { "x1", "y1" }, /* 0 degrees */
                    { "x2", "y2" }, /* 90 degrees */
                    { "x3", "y3" }, /* 180 degrees */
                    { "x4", "y4" }, /* 270 degrees */
                };

                int page = p.open_pdi_page(indoc, pageno, "cloneboxes");

                if (page == -1) {
                    System.err.println("Error: " + p.get_errmsg());
                    continue;
                }

                /*
                 * Query the geometry of the cloned page. This is required to
                 * account for translated or rotated pages if we want to add
                 * more contents to the page.
                 */
                phi = p.info_pdi_page(page, "rotate", "");

                /*
                 * Select the lower left corner depending on the rotation angle
                 */
                x = p.info_pdi_page(page, lowerleftcorner[(int) (phi / 90)][0],
                    "");
                y = p.info_pdi_page(page, lowerleftcorner[(int) (phi / 90)][1],
                    "");

                boolean fittingpossible = true;
                String additionaltag = "";

                if (taggedinput) {
                    int topleveltagcount = (int) p.info_pdi_page(page,
                        "topleveltagcount", "");

                    if (topleveltagcount == 0) {
                        /*
                         * The page doesn't contain any structure elements, i.e.
                         * it is empty or contains only Artifacts. Some
                         * applications may decide to skip such pages.
                         * 
                         * We add an "Artifact" tag to work around an Acrobat
                         * bug.
                         */
                        additionaltag = "tag={tagname=Artifact} ";
                    }
                    else if (p.info_pdi_page(page, "fittingpossible", "")
                                                                        == 0) {
                        /*
                         * Try to place the page without any additional tag; if
                         * this doesn't work we insert another tag.
                         */
                        additionaltag = "tag={tagname=P} ";
                        if (p.info_pdi_page(page, "fittingpossible",
                            additionaltag) == 0) {
                            fittingpossible = false;
                        }
                    }
                }

                if (fittingpossible) {
                    /* Page size will be adjusted by "cloneboxes" option */
                    p.begin_page_ext(0, 0, "width=a4.width height=a4.height");

                    optlist = "cloneboxes ";
                    if (taggedinput)
                        optlist += additionaltag;

                    p.fit_pdi_page(page, 0, 0, optlist);

                    /*
                     * Adjust the coordinate system to facilitate adding new
                     * page content on top of the cloned page.
                     */
                    p.translate(x, y);
                    p.rotate(phi);

                    width = p.info_pdi_page(page, "pagewidth", "");
                    height = p.info_pdi_page(page, "pageheight", "");

                    /*
                     * Add some text on each page and tag it as Artifact.
                     */
                    optlist = "fontname=NotoSerif-Regular "
                        + "textrendering=1 stamp=ll2ur "
                        + "boxsize={" + width + " " + height + "}";

                    if (taggedinput)
                        optlist += " tag={tagname=Artifact}";

                    p.fit_textline("Cloned page", 0, 0, optlist);

                    p.end_page_ext("");
                }
                else {
                    System.err.println("Skipping page " + pageno + " of '"
                        + pdfinputfile + "': " + p.get_errmsg());
                }
                
                p.close_pdi_page(page);
            }

            p.end_document("");
            p.delete_pvf("/xmp/document.xmp");
            p.close_pdi_document(indoc);
        }
        catch (PDFlibException e) {
            System.err.println("PDFlib exception occurred:");
            System.err.println("[" + e.get_errnum() + "] " + e.get_apiname() +
                ": " + e.get_errmsg());
            exitcode = 1;
        }
        catch (Exception e) {
            System.err.println(e);
            exitcode = 1;
        }
        finally {
            if (p != null) {
                p.delete();
            }
            System.exit(exitcode);
        }
    }
}
(Apr 3, 2007 - Jun 25, 2024)