PDFlib Cookbook

cookbook

textflow/text_with_image_clipping_path

Use the clipping path from a TIFF or JPEG image to shape text output.

Download Java Code  Switch to PHP Code  Show Output 

/*
 * Text and image clipping paths:
 * Use the clipping path from a TIFF or JPEG image to shape text output.
 * 
 * Case 1:
 *      Fit image with clipping path into the center of two text columns
 * 
 * Case 2:
 *      Wrap text inside an image clipping path.
 *      
 * Case 3:
 *      Use clipping path to flow text around it
 *
 * Required software: PDFlib/PDFlib+PDI/PPS 10
 * Required data: image file
 */
package com.pdflib.cookbook.pdflib.textflow;

import java.util.ArrayList;
import java.util.List;

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

public class text_with_image_clipping_path {
    /**
     * Create some amount of dummy text and feed it to a Textflow object with
     * alternating options.
     */
    static int create_textflow(pdflib p) throws PDFlibException, Exception {
        /* Repeat the dummy text to produce more contents */
        final int count = 20;
        final String optlist1 = 
            "fontname=NotoSerif-Regular fontsize=10.5 "
                + "fillcolor={gray 0} alignment=justify";

        final String optlist2 = 
            "fontname=NotoSerif-Regular fontsize=10.5 "
                + "fillcolor={rgb 1 0 0} charref";

        /*
         * 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. ";

        int tf = -1;
        for (int i = 1; i <= count; i++) {
            String num = i + " ";

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

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

        return tf;
    }

    /**
     * Interface for the different use cases.
     */
    interface use_case {
        void create_page_contents(pdflib p, int tf) throws PDFlibException;

        String use_case_description();
    }

    public static void main(String argv[]) {
        pdflib p = null;

        final String outfile = "text_with_image_clipping_path.pdf";
        final String title = "Text With Image Clipping Path";
        final String imagefile = "child_clipped.jpg";
        final String searchpath = "../input";
        int exitcode = 0;

        try {
            p = new pdflib();

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

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

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

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

            final int image = p.load_image("auto", imagefile, "");
            if (image == -1)
                throw new Exception("Error: " + p.get_apiname() + ": "
                        + p.get_errmsg());

            final int path = (int) p.info_image(image, "clippingpath", "");
            if (path == -1)
                throw new Exception(
                        "Error: The image does not contain a clipping path");

            /*
             * Coordinates for laying out the text and the image.
             */

            /* The page dimensions */
            final double a4_width = 595, a4_height = 842;

            /* The margin at the left- and right-hand sides of the page */
            final double margin = 50;

            /* The distance between the two columns */
            final double column_distance = margin / 2;

            /* Positions and sizes of the columns */
            final double column_width = 
                (a4_width - (2 * margin) - column_distance) / 2;
            final double column_height = a4_height / 3;

            final double llx1 = margin, lly1 = a4_height / 3;
            final double urx1 = llx1 + column_width, ury1 = lly1
                    + column_height;

            final double llx2 = margin + column_width + column_distance, 
                    lly2 = lly1;
            final double urx2 = llx2 + column_width, ury2 = ury1;

            /* Size of the box that covers the two columns */
            final double bbox_width = urx2 - llx1, bbox_height = ury2 - lly1;

            /*
             * The image will be centered into a box that covers a quarter of
             * the text box.
             */
            final double image_width = bbox_width / 2, 
                    image_height = bbox_height / 2;
            final String with_clipping_opts = "boxsize={" + image_width + " "
                    + image_height + "} " + "position=center fitmethod=meet";
            final String no_clipping_opts = with_clipping_opts
                    + " ignoreclippingpath";

            /*
             * The position for displaying the title for the use case.
             */
            final double title_llx = llx1, title_lly = ury1;
            final double title_urx = title_llx + bbox_width, 
                        title_ury = title_lly + 100;
            /*
             * Box position for placing the image
             */
            final double image_llx = llx1 + (bbox_width / 4);
            final double image_lly = lly1 + (bbox_height / 4);

            /*
             * Determine reference point for the image after it was placed into
             * the center of the bounding box of the two columns.
             */
            final double placed_image_llx = image_llx
                    + p.info_image(image, "x1", with_clipping_opts);
            final double placed_image_lly = image_lly
                    + p.info_image(image, "y1", with_clipping_opts);

            /*
             * Determine the scaling factor for the image. "fitmethod=meet"
             * scales uniformly in x and y direction, so it is sufficient to
             * fetch one scaling factor.
             */
            final double image_scale_factor = p.info_image(image, "fitscalex",
                    with_clipping_opts);
            final String scale_option = "scale=" + image_scale_factor;

            List<use_case> use_cases = new ArrayList<use_case>();

            /*
             * Use case 1:
             * 
             * Fit the image with clipping into the center of the text box. Fit
             * the text into the text box, and wrap it around the path retrieved
             * from the image. The path must be scaled in the same manner as the
             * image was scaled.
             */
            use_cases.add(new use_case() {
                public String use_case_description() {
                    return "Fit image with clipping path into the center "
                            + "of two text columns";
                }

                public void create_page_contents(pdflib p, int tf)
                        throws PDFlibException {
                    p.fit_image(image, image_llx, image_lly,
                                    with_clipping_opts);

                    final String textflow_opts = "wrap={offset=5 paths={{path="
                            + path + " refpoint={" + placed_image_llx + " "
                            + placed_image_lly + "} " + scale_option + "}}}";

                    /* Fill the first column */
                    final String result = p.fit_textflow(tf, llx1, lly1, urx1,
                            ury1, textflow_opts);

                    /* Fill the second column if we have more text */
                    if (!result.equals("_stop"))
                        p.fit_textflow(tf, llx2, lly2, urx2, ury2,
                                textflow_opts);
                }
            });

            /*
             * Use case 2:
             * 
             * Use the inversefill option to wrap text inside the path instead
             * of wrapping the text around the path (i.e. the path serves as
             * text container instead of creating a hole in the Textflow). For
             * creating a "hole" in the image, the image is placed without
             * honoring the clipping path, and the clipping path is used to draw
             * a white area inside the image
             */
            use_cases.add(new use_case() {
                public String use_case_description() {
                    return "Wrap text inside the clipping path of an image";
                }

                public void create_page_contents(pdflib p, int tf)
                        throws PDFlibException {
                    p.fit_image(image, image_llx, image_lly, no_clipping_opts);

                    p.draw_path(path, placed_image_llx, placed_image_lly,
                            "fill=true fillcolor=white " + scale_option);

                    p.fit_textflow(tf, llx1, lly1, urx2, ury2,
                            "wrap={offset=5 inversefill paths={{path=" + path
                                    + " refpoint={" + placed_image_llx + " "
                                    + placed_image_lly + "} " + scale_option
                                    + "}}}");
                }
            });

            /*
             * Use case 3:
             * 
             * Do not place the image, but use its clipping path to flow text
             * around it. The reference point for the clipping path is specified
             * relatively to the fitbox of the textflow by percentages of the
             * width and height of the fitbox in the "refpoint" suboption.
             */
            use_cases.add(new use_case() {
                public String use_case_description() {
                    return "Use clipping path to flow text around it";
                }

                public void create_page_contents(pdflib p, int tf)
                        throws PDFlibException {
                    p.fit_textflow(tf, llx1, lly1, urx2, ury2,
                            "wrap={offset=5 paths={{path=" + path
                                    + " refpoint={25% 25%} " + scale_option
                                    + "}}}");
                }
            });

            /*
             * Create one page for each use case.
             */
            for (int i = 0; i < use_cases.size(); i += 1) {
                final use_case c = use_cases.get(i);

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

                /*
                 * Add a description for each use case.
                 */
                final String desc = "Use case " + (i + 1) + ": "
                        + c.use_case_description();
                final int title_tf = p.create_textflow(desc,
                        "fontname=NotoSerif-Regular fontsize=16 ");
                p.fit_textflow(title_tf, title_llx, title_lly, title_urx,
                        title_ury, "");
                p.delete_textflow(title_tf);

                /*
                 * Create a textflow and pass that to the create_page_contents()
                 * method to put the contents on the page.
                 */
                final int tf = create_textflow(p);
                c.create_page_contents(p, tf);
                p.delete_textflow(tf);

                p.end_page_ext("");
            }

            p.delete_path(path);
            p.close_image(image);

            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);
        }
    }
}