PDFlib Cookbook

cookbook

textflow/textflow_with_shading

Create multi-column output with text and use a shading where the geometry of each shading matches the respective text column.

Download Java Code  Switch to PHP Code  Show Output 

/*
 * Textflow with shading:
 * Create multi-column text output which may span multiple pages.
 * The text columns are colorized with a shading which matches the
 * geometry of each column. To emphasize the effect we create a radial
 * shading which starts in the middle of the fitbox.
 *
 * Required software: PDFlib/PDFlib+PDI/PPS 10
 * Required data: none
 */
package com.pdflib.cookbook.pdflib.textflow;

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

public class textflow_with_shading {
    
    static int create_shading(pdflib p, int tf) throws PDFlibException {
        /*
         * Query formatting results of the Textflow (coordinates of the placed
         * text)
         */
        double llx = p.info_textflow(tf, "x1");
        double lly = p.info_textflow(tf, "y1");
        double urx = p.info_textflow(tf, "x3");
        double ury = p.info_textflow(tf, "y3");

        /*
         * Create axial shading from red to blue. The start and end circles have
         * their centers in the center of the fitbox. The radius of the start
         * circle is zero, the radius of the end circle is chosen so that the
         * full fitbox is covered (half of the diagonal).
         */
        int sh = p.shading("radial",
            (llx + urx) / 2, (lly + ury) / 2,
            (llx + urx) / 2, (lly + ury) / 2,
            0, 0, 0, 0,                 // unused color parameters
            "startcolor=red endcolor=blue " +
            "r0=0 r1=" + 0.5 * Math.sqrt(Math.pow(ury - lly, 2) + Math.pow(urx - llx, 2)));

        return p.shading_pattern(sh, "");
    }

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

        String outfile = "textflow_with_shading.pdf";
        String title = "Starter Textflow";
        int i, tf = -1;
        String result;
        final double llx1 = 50, lly1 = 50, urx1 = 250, ury1 = 800;
        final double llx2 = 300, lly2 = 50, urx2 = 500, ury2 = 800;
        int exitcode = 0;

        /* Repeat the dummy text to produce more contents */
        final int count = 50;

        final String optlist1 = "fontname=NotoSerif-Regular " 
            + "fontsize=10.5 fillcolor={gray 0} alignment=justify "
            + "hyphenchar=U+002D";

        /*
         * Dummy text for filling the columns. Soft hyphens are marked with the
         * character reference "­" (character references are enabled by the
         * charref option).
         */
        final String text = 
            "Lorem ipsum dolor sit amet, consectetur adi­pi­sicing elit, "
            + "sed do eius­mod tempor incidi­dunt ut labore et dolore "
            + "magna ali­qua. Ut enim ad minim ve­niam, quis nostrud "
            + "exer­citation ull­amco la­bo­ris nisi ut "
            + "ali­quip ex ea commodo con­sequat. Duis aute irure dolor "
            + "in repre­henderit in voluptate velit esse cillum dolore eu "
            + "fugiat nulla pari­atur. Excep­teur sint occae­cat "
            + "cupi­datat non proident, sunt in culpa qui officia "
            + "dese­runt mollit anim id est laborum. ";

        pdflib p = null;
        
        try {
            p = new pdflib();

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

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

            if (p.begin_document(outfile, "") == -1)
                throw new Exception("Error: " + p.get_errmsg());

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

            final String optlist2 = "fontname=NotoSerif-Bold fontsize=14 " 
                + " charref hyphenchar=U+002D";

            /*
             * Create some amount of dummy text and feed it to a Textflow object
             * with alternating options.
             */
            for (i = 1; i <= count; i++) {
                String num = i + " ";

                tf = p.add_textflow(tf, num, optlist2);
                if (tf == -1)
                    throw new Exception("Error: " + p.get_errmsg());

                tf = p.add_textflow(tf, text, optlist1);
                if (tf == -1)
                    throw new Exception("Error: " + p.get_errmsg());
            }

            /*
             * Loop until all of the text is placed; create new pages as long as
             * more text needs to be placed. Two columns will be created on all
             * pages.
             */
            do {
                /* Add "showborder" to visualize the fitbox borders */
                String optlist = "verticalalign=justify linespreadlimit=120% ";

                p.begin_page_ext(0, 0, "width=a4.width height=a4.height");

                /* Place the first column in blind mode (for formatting only) */
                result = p.fit_textflow(tf, llx1, lly1, urx1, ury1,
                    optlist + " blind");
                
                /* handle for shading pattern */
                int shp = create_shading(p, tf);

                /*
                 * Place the first column in real mode and replace the gray fill
                 * color with the shading pattern. We must rewind the Textflow
                 * to undo the result of the "blind" formatting.
                 */
                result = p.fit_textflow(tf, llx1, lly1, urx1, ury1,
                    optlist + "rewind=-1 exchangefillcolors={{gray 0} {pattern "
                        + shp + "}}");

                /* Process the second column if we have more text */
                if (!result.equals("_stop")) {
                    /* Place second column in "blind" mode */
                    result = p.fit_textflow(tf, llx2, lly2, urx2, ury2,
                        optlist + " blind");

                    shp = create_shading(p, tf);

                    /*
                     * Place second column in real mode and replace the gray
                     * fill color with the shading pattern.
                     */
                    result = p.fit_textflow(tf, llx2, lly2, urx2, ury2,
                        optlist
                            + "rewind=-1 exchangefillcolors={{gray 0} {pattern "
                            + shp + "}}");
                }

                p.end_page_ext("");

                /*
                 * "_boxfull" means we must continue because there is more text;
                 * "_nextpage" is interpreted as "start new column"
                 */
            }
            while (result.equals("_boxfull") || result.equals("_nextpage"));

            /* Check for errors */
            if (!result.equals("_stop")) {
                /*
                 * "_boxempty" happens if the box is very small and doesn't hold
                 * any text at all.
                 */
                if (result.equals("_boxempty"))
                    throw new Exception("Error: Textflow box too small");
                else {
                    /*
                     * Any other return value is a user exit caused by the
                     * "return" option; this requires dedicated code to deal
                     * with.
                     */
                    throw new Exception(
                        "User return '" + result + "' found in Textflow");
                }
            }

            p.delete_textflow(tf);

            p.end_document("");
        }
        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);
        }
    }
}