/* * Wrap text around images: * Place images within a Textflow * * Case 1: * Place an image at a fixed position on the page. Use the "matchbox" option of * fit_image() to define the matchbox rectangle. Use the "usematchbox" option of * fit_textflow() to wrap the text around the matchbox rectangle for the image. * Case 2: * Place an image left-aligned and an image right-aligned at defined positions * within the Textflow. Use the "matchbox" option of fit_image() to define the * matchbox rectangle of the image. Use specific return values of fit_textflow() * for indicating the text line for the image to be placed. * Case 3: * To place some small icons at the beginning of some text lines in a * Textflow use the inline options "matchbox" and "matchbox end" within the * Textflow as well as the info_matchbox() function to retrieve the matchbox * instances and dimensions. * Case 4: * Place some images at certain text positions within a Textflow by using the * "matchbox" and "matchbox end" inline options when placing the Textflow for * indicating the image positions. * Case 5: * Place an image which covers several lines of text at a certain text position * within a Textflow. Use the "matchbox" and "matchbox end" inline options when * placing the Textflow for indicating the image position. Use the * "createwrapbox" option to indicate that the matchbox will be inserted as wrap * box in the Textflow for the text to wrap around. * * Required software: PDFlib/PDFlib+PDI/PPS 9 * Required data: image file */ package com.pdflib.cookbook.pdflib.textflow; import com.pdflib.pdflib; import com.pdflib.PDFlibException; public class wrap_text_around_images { public static void main (String argv[]) { pdflib p = null; String searchpath = "../input"; String outfile = "wrap_text_around_images.pdf"; String title = "Wrap Text around Images"; int i, m, tf = -1, image, icon, numberOfMatchbox; String result; String imageoptlist = "", numoptlist = "", textoptlist = ""; final double llx = 100, lly = 50, urx = 450, ury = 800; double x1, y1, width, height; double posx = 0, posy = 0; String text; int exitcode = 0; 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"); p.set_option("charref=true"); if (p.begin_document(outfile, "") == -1) throw new Exception("Error: " + p.get_errmsg()); p.set_info("Creator", "PDFlib Cookbook"); p.set_info("Title", title); /* ------------------------------------------------------------------ * Case 1: * Place an image at a fixed position on the page. Use the "matchbox" * option of fit_image() to define the matchbox rectangle. Use the * "usematchbox" option of fit_textflow() to wrap the text around the * matchbox rectangle for the image. * ------------------------------------------------------------------ */ /* Text to be placed on the page. Soft hyphens are marked with the * character reference "­" (character references are enabled by the * "charref" option). */ text = "Our paper planes are the ideal way of passing the time. We " + "offer revolutionary new develop­ments of the traditional " + "common paper planes. If your lesson, conference, or lecture " + "turn out to be deadly boring, you can have a wonderful time " + "with our planes. All our models are fol­ded from one paper " + "sheet. They are exclu­sively folded with­out using any " + "adhesive. Several models are equipped with a folded landing " + "gear enabling a safe landing on the intended loca­tion " + "provided that you have aimed well. Other models are able to fly " + "loops or cover long distances. Let them start from a vista " + "point in the mountains and see where they touch the ground. "; /* Option list for the output of a number */ numoptlist = "fontname=NotoSerif-Bold fontsize=14 encoding=unicode " + "fillcolor={rgb 0.6 0.6 0.8} charref"; /* Option list for the text output */ textoptlist = "fontname=NotoSerif-Regular fontsize=10.5 encoding=unicode " + "fillcolor={gray 0} alignment=justify"; /* Load the image. Assign a matchbox called "img" to it to indicate the * rectangle for the text to wrap around later. */ image = p.load_image("auto", "kraxi_logo_text.tif", ""); if (image == -1) throw new Exception("Error: " + p.get_errmsg()); /* Repeat some dummy text to produce more contents, place a number * before each text and feed them to a Textflow object with alternating * options. */ final int count = 7; for (i=1; i<=count; i++) { String num = i + " "; tf = p.add_textflow(tf, num, numoptlist); if (tf == -1) throw new Exception("Error: " + p.get_errmsg()); tf = p.add_textflow(tf, text, textoptlist); 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. */ p.create_bookmark("Case 1: \"matchbox\" option of fit_image() and " + "\"wrap\" option of fit_textflow()", ""); do { p.begin_page_ext(0, 0, "width=a4.width height=a4.height"); /* Place the image on a fixed position on the page. Assign a matchbox * called "img" to it to indicate the image rectangle to wrap the text * around later. */ p.fit_image(image, 200, 370, "boxsize={300 200} fitmethod=meet " + "position=center matchbox={name=img margin=-10}"); /* Place the text while wrapping it around the matchbox called "img" */ result = p.fit_textflow(tf, llx, lly, urx, ury, "verticalalign=justify linespreadlimit=120% " + "wrap={usematchboxes={{img}}}"); 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.close_image(image); p.delete_textflow(tf); /* --------------------------------------------------------------------- * Case 2: * Place an image left-aligned and an image right-aligned at defined * positions within the Textflow. Use the "matchbox" option of * fit_image() to define the matchbox rectangle of the image. Use * specific return values of fit_textflow() for indicating the text line * for the image to be placed. * --------------------------------------------------------------------- */ /* Text to be placed on the plage. Soft hyphens are marked with the * character reference "­" (character references are enabled by the * "charref" option). */ text = "Our paper planes are the ideal way of passing the time. We " + "offer revolutionary new develop­ments of the traditional " + "common paper planes. If your lesson, conference, or lecture " + "turn out to be deadly boring, you can have a wonderful time " + "with our planes. All our models are fol­ded from one paper " + "sheet. They are exclu­sively folded with­out using any " + "adhesive. Several models are equipped with a folded landing " + "gear enabling a safe landing on the intended loca­tion " + "provided that you have aimed well. Other models are able to fly " + "loops or cover long distances. Let them start from a vista " + "point in the mountains and see where they touch the ground. "; /* Option list for the text to be added */ textoptlist = "fontname=NotoSerif-Regular fontsize=10.5 encoding=unicode " + "fillcolor={gray 0} alignment=justify"; /* Add some text to the Textflow. Then add two nextlines and define the * return value "imageleft". Later, the Textflow portion defined above * will be placed with fit_textflow() and the "imageleft" value will be * returned indicating that now the left-aligned image should be placed. */ tf = -1; tf = p.add_textflow(tf, text, textoptlist); if (tf == -1) throw new Exception("Error: " + p.get_errmsg()); tf = p.add_textflow(tf, "", "nextline nextline return imageleft"); if (tf == -1) throw new Exception("Error: " + p.get_errmsg()); /* Add some more text to the Textflow. Similar to the "imageleft" * return value above define the "imageright" return value to indicate * that now the right-aligned image should be placed. */ tf = p.add_textflow(tf, text, textoptlist); if (tf == -1) throw new Exception("Error: " + p.get_errmsg()); tf = p.add_textflow(tf, "", "nextline nextline return imageright"); if (tf == -1) throw new Exception("Error: " + p.get_errmsg()); tf = p.add_textflow(tf, text, textoptlist); if (tf == -1) throw new Exception("Error: " + p.get_errmsg()); image = p.load_image("auto", "kraxi_logo.tif", ""); if (image == -1) throw new Exception("Error: " + p.get_errmsg()); p.begin_page_ext(0, 0, "width=a4.width height=a4.height"); p.create_bookmark("Case 2: Specific Textflow return values to " + "indicate image positions", ""); posy = ury; boolean ismatchbox = false; do { /* Fit the text and wrap it around the matchbox called "image" * if it is defined yet */ if (ismatchbox) { textoptlist = "verticalalign=justify linespreadlimit=120% " + "wrap={usematchboxes={{image}}} "; } else { textoptlist = "verticalalign=justify linespreadlimit=120% "; } result = p.fit_textflow(tf, llx, lly, urx, posy, textoptlist); /* Retrieve the current text position */ posy = p.info_textflow(tf, "textendy"); if (result.equals("imageleft")){ /* Textflow interrupted returning the keyword "imageleft". * Place the image on the current left position of the Textflow * fitbox. */ posx = llx; imageoptlist = "position {0 100} matchbox={name=image " + "offsetright=10 offsettop=10 offsetbottom=-10}"; /* Reduce the posy position by a value similar to the * "offsettop" value defined above to create some distance * from the previous text */ p.fit_image(image, posx, posy-10, imageoptlist); ismatchbox = true; } if (result.equals("imageright")){ /* Textflow interrupted with the keyword "imageleft". * Place the image to the current left position of the fitbox. */ posx = urx; imageoptlist = "position {100 100} matchbox={name=image " + "offsetleft=-10 offsettop=10 offsetbottom=-10}"; /* Reduce the posy position by a value similar to the * "offsettop" value defined above to create some distance from * the previous text */ p.fit_image(image, posx, posy-10, imageoptlist); ismatchbox = true; } /* Create a new page if the text cannot be fit completely into the * box */ if (result.equals("_boxfull") || result.equals( "_boxempty")){ p.end_page_ext(""); p.begin_page_ext(0, 0, "width=a4.width height=a4.height"); posy = ury; } /* Go ahead with the rest of the text, until the text has been * finished */ } while (!result.equals("_stop")); p.delete_textflow(tf); p.end_page_ext(""); p.close_image(image); /* ------------------------------------------------------------------ * Case 3: * Place some small icons at the beginning of the lines in a Textflow * using the inline options "matchbox" and "matchbox end" within the * Textflow. * ------------------------------------------------------------------ */ /* Text containing the macros defined in the option list below */ text = "Our paper planes are the ideal way of passing the time. We " + "offer revolutionary new developments of the traditional common " + "paper planes. If your lesson, conference, or lecture turn out " + "to be deadly boring, you can have a wonderful time with our " + "planes. All our models are folded from one paper sheet. They " + "are exclusively folded without using any adhesive. Several " + "models are equipped with a folded landing gear enabling a safe " + "landing on the intended location provided that you have aimed " + "well. Other models are able to fly loops or cover long " + "distances. Let them start from a vista point in the mountains " + "and see where they touch the ground." + "" + "Have a look at our new paper plane models!" + "" + "<&new><&end>Long Distance Glider "+ "With this paper rocket you can send all your messages even when " + "sitting in a hall or in the cinema pretty near the back. " + "" + "<&arrow><&end>Giant Wing" + "An unbelievable sailplane! It is amazingly robust and can even " + "do aerobatics. But it best suited to gliding." + "" + "<&new><&end>Cone Head Rocket" + "This paper arrow can be thrown with big swing. We launched it " + "from the roof of a hotel. It stayed in the air a long time and " + "covered a considerable distance. " + "" + "<&arrow><&end>Super Dart" + "The super dart can fly giant loops with a radius of 4 or 5 " + "metres and cover very long distances. Its heavy cone point is " + "slightly bowed upwards to get the lift required for loops." + "" + "<&arrow><&end>German Bi-Plane" + "Brand-new and ready for take-off. If you have lessons in the " + "history of aviation you can show your interest by letting it " + "land on your teacher's desk." + "" + "To fold the famous rocket looper proceed as follows:" + "" + "Take a A4 sheet." + "Fold it lengthwise in the middle." + "Then, fold the upper corners down. " + "Fold the long sides inwards " + "that the points A and B meet on the central fold." + "" + "Fold the points C and D that the upper " + "corners meet with the central fold as well. " + "Fold the plane in the middle. Fold the wings " + "down that they close with the lower border of the plane."; /* Option list with some text options and the three macros "arrow", * "new", and "end" to be used as inline options in the "features" text * below to indicate where to leave some space for the respective images * to be placed and the text to wrap around it. */ textoptlist = "macro {" + "new {matchbox={name=new boxwidth=15 boxheight=" + " {ascender descender}} leftindent=15 " + " parindent=-15} " + "arrow {matchbox={name=arrow boxwidth=15 boxheight={ascender " + " descender}} leftindent=15 parindent=-15} " + "end {matchbox={end}} } " + "fontname=NotoSerif-Regular fontsize=10.5 encoding=unicode " + "fillcolor={gray 0} alignment=justify"; String[][] matchboxname = { {"new", "new.jpg"}, {"arrow", "arrow.jpg"} }; /* Start page */ p.begin_page_ext(0, 0, "width=a4.width height=a4.height"); /* Create a bookmark on the current page */ p.create_bookmark("Case 3: Inline options \"matchbox\" and " + "\"matchbox end\" for create_textflow()", ""); /* Create a Textflow containing inline options to define the matchboxes * "arrow" and "new" which indicates the positions for the arrow and the * new image to be placed. */ tf = p.create_textflow(text, textoptlist); if (tf == -1) throw new Exception("Error: " + p.get_errmsg()); do { /* Fit the Textflow */ result = p.fit_textflow(tf, llx, lly, urx, ury, "verticalalign=justify linespreadlimit=120% "); /* Loop over all icons ("new" and "arrow" in our case) to be placed * in the respective matchboxes */ for (m=0; m < (int) matchboxname.length; m++){ icon = p.load_image("auto", matchboxname[m][1], ""); if (icon == -1) throw new Exception("Error: " + p.get_errmsg()); /* Retrieve the number of instances of the matchbox */ numberOfMatchbox = (int) p.info_matchbox(matchboxname[m][0], 0, "count"); /* Iterate over all matchbox instances and fill them with the * icon */ for (i=1; i<= numberOfMatchbox; i++) { x1 = p.info_matchbox(matchboxname[m][0], i, "x1"); y1 = p.info_matchbox(matchboxname[m][0], i, "y1"); width = p.info_matchbox(matchboxname[m][0], i, "width"); height = p.info_matchbox(matchboxname[m][0], i, "height"); p.fit_image(icon, x1, y1, "boxsize {" + width + " " + height + "} fitmethod meet"); } } if (result.equals("_boxfull")){ p.end_page_ext(""); p.begin_page_ext(0, 0, "width=a4.width height=a4.height"); posy = ury; } } while (!result.equals("_stop")); p.delete_textflow(tf); p.end_page_ext(""); /* ------------------------------------------------------------------ * Case 4: * Place images at certain text positions within a line of a Textflow * by using the "matchbox" and "matchbox end" inline options when * placing the Textflow for indicating the image positions. * ------------------------------------------------------------------ */ /* Text containing the macros defined in the option list below */ text = "Have a look at our new paper plane models!" + "" + "Long Distance Glider "+ "With this paper rocket you can send all your messages even " + "when sitting in a hall or in the cinema pretty near the back. " + "Print a photo of the paper plane by pressing the " + "<&print><&end> button. " + "Save a description of the paper plane by pressing the "+ "<&saveas><&end> button."; /* Options list for creating the Textflow. * For each image to be placed within the Textflow a macro is defined * to specify the matchbox rectangle for the image to be placed in and * the Textflow to wrap around. * The macro "print" specifies a matchbox called "print". * "boxwidth=40" defines the width of the matchbox rectangle. * "boxheight {ascender descender}" defines the vertical extent of the * matchbox rectangle using the ascender of the font on the top and the * descender at the bottom. "offsettop=2" adds an offset of 2 on the top * of the rectangle. * The macro "saveas" specifies a matchbox called "saveas" with similar * options. * The macro "end" is used to finish the matchbox. */ textoptlist = "macro {" + "print {matchbox={name=print boxwidth=40 " + "boxheight={ascender descender} offsettop=2}} " + "saveas {matchbox={name=saveas boxwidth=60 " + "boxheight={ascender descender} offsettop=2}} " + "end {matchbox={end}} } " + "fontname=NotoSerif-Regular fontsize=14 encoding=unicode " + "fillcolor={gray 0} leading=140% alignment=justify"; String[][] matchboxnames = { {"print", "fileprint.jpg"}, {"saveas", "filesaveas.jpg"} }; /* Add some text to the Textflow */ tf = p.create_textflow(text, textoptlist); if (tf == -1) throw new Exception("Error: " + p.get_errmsg()); p.begin_page_ext(0, 0, "width=a4.width height=a4.height"); /* Create a bookmark on the current page */ p.create_bookmark("Case 4: Inline options \"matchbox\" and " + "\"matchbox end\" for create_textflow()", ""); posy = ury; do { /* Fit the Textflow */ result = p.fit_textflow(tf, llx, lly, urx, ury, "verticalalign=justify linespreadlimit=120% "); /* Loop over all icons ("print" and "saveas" in our case) to be * placed in the respective matchboxes */ for (m=0; m < (int) matchboxnames.length; m++){ icon = p.load_image("auto", matchboxnames[m][1], ""); if (icon == -1) throw new Exception("Error: " + p.get_errmsg()); /* Retrieve the number of instances of the matchbox */ numberOfMatchbox = (int) p.info_matchbox(matchboxnames[m][0], 0, "count"); /* Iterate over all matchbox instances and fill them with the * icon */ for (i=1; i<= numberOfMatchbox; i++) { x1 = p.info_matchbox(matchboxnames[m][0], i, "x1"); y1 = p.info_matchbox(matchboxnames[m][0], i, "y1"); width = p.info_matchbox(matchboxnames[m][0], i, "width"); height = p.info_matchbox(matchboxnames[m][0], i, "height"); p.fit_image(icon, x1, y1, "boxsize {" + width + " " + height + "} fitmethod meet position=center"); } } if (result.equals("_boxfull")){ p.end_page_ext(""); p.begin_page_ext(0, 0, "width=a4.width height=a4.height"); posy = ury; } else 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"); } } } while (!result.equals("_stop")); p.delete_textflow(tf); p.end_page_ext(""); p.close_image(image); /* -------------------------------------------------------------------- * Case 5: * Place an image which covers several lines of text at a certain text * position within a Textflow. Use the "matchbox" and "matchbox end" * inline options when placing the Textflow for indicating the image * position. Use the "createwrapbox" option to indicate that the * matchbox will be inserted as wrap box in the Textflow for the text * to wrap around. * -------------------------------------------------------------------- */ /* Text which is placed on the page. Soft hyphens are marked * with the character reference "­" (character references are * enabled by the charref option). */ text = "Our paper planes are the ideal way of passing the time. We " + "offer revolutionary new develop­ments of the traditional " + "common paper planes. If your lesson, conference, or lecture " + "turn out to be deadly boring, you can have a wonderful time " + "with our planes. All our models are fol­ded from one paper " + "sheet.<&plane><&end>They are exclu­sively folded " + "with­out using any ad­hesive. Several models are " + "equipped with a folded landing gear enabling a safe landing on " + "the intended loca­tion provided that you have aimed well. " + "Other models are able to fly loops or cover long distances. " + "Let them start from a vista point in the mountains and see " + "where they touch the ground. "; /* Options list for creating the Textflow. * For the image to be placed within the Textflow a macro is defined * to specify the matchbox rectangle for the image to be placed in and * the Textflow to wrap around. * The macro "plane" specify a matchbox called "plane". * "boxwidth=70" defines the width of the matchbox rectangle. * "boxheight {12 24}" defines the vertical extent of the matchbox * rectangle with 12 above and 24 below the baseline of the text line. * "offsetleft=4" and "offsetright=-4" add some empty space on the left * and right of the matchbox rectangle. * "createwrapbox" indicates that the matchbox will be inserted as wrap * box in the Textflow for the text to wrap around. * The macro "end" is used to finish the matchbox. */ textoptlist = "macro {" + "plane {matchbox={name=plane boxwidth=70 boxheight={12 24} " + "offsetleft=4 offsetright=-4 createwrapbox}} " + "end {matchbox={end}} } " + "fontname=NotoSerif-Regular fontsize=12 encoding=unicode " + "fillcolor={gray 0} leading=140% alignment=justify"; /* Add some text to the Textflow */ tf = p.create_textflow(text, textoptlist); if (tf == -1) throw new Exception("Error: " + p.get_errmsg()); p.begin_page_ext(0, 0, "width=a4.width height=a4.height"); p.create_bookmark("Case 5: \"createwrapbox\" option of " + "create_textflow() to wrap text around image covering several " + "text lines", ""); posy = ury; do { /* Fit the Textflow */ result = p.fit_textflow(tf, llx, lly, urx, ury, "verticalalign=justify linespreadlimit=120% "); image = p.load_image("auto", "kraxi_logo.tif", ""); if (image == -1) throw new Exception("Error: " + p.get_errmsg()); /* Retrieve the number of instances of the matchbox */ numberOfMatchbox = (int) p.info_matchbox("plane", 0, "count"); /* Iterate over all matchbox instances and fill them with the * image. In our case just one instance is present. */ for (i=1; i<= numberOfMatchbox; i++) { x1 = p.info_matchbox("plane", i, "x1"); y1 = p.info_matchbox("plane", i, "y1"); width = p.info_matchbox("plane", i, "width"); height = p.info_matchbox("plane", i, "height"); p.fit_image(image, x1, y1, "boxsize {" + width + " " + height + "} fitmethod meet position=center"); } if (result.equals("_boxfull")){ p.end_page_ext(""); p.begin_page_ext(0, 0, "width=a4.width height=a4.height"); posy = ury; } else 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"); } } } while (!result.equals("_stop")); p.delete_textflow(tf); p.end_page_ext(""); 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.toString()); exitcode = 1; } finally { if (p != null) { p.delete(); } System.exit(exitcode); } } }