set_option("searchpath={" . $searchpath . "}"); /* This means we must check return values of load_font() etc. */ $p->set_option("errorpolicy=return"); if ($p->begin_document("", "") == 0) throw new Exception("Error: " . $p->get_errmsg()); $p->set_info("Creator", "PDFlib Cookbook"); $p->set_info("Title", $title); $pagewidth = 500; $pageheight = 500; $header_fontsize = 24; /* * Text that together with the specified fontsize below provokes * an orphan. */ $orphan_explanation = str_repeat("This text provokes an \"orphan\" at the end of the " . "first fitbox. ", 10); $orphan = str_repeat("Unless action is taken, the first line of this paragraph appears " . "as an orphan at the end of the first fitbox. ", 2); $orphan_more_text = str_repeat("This is text after the paragraph with the orphan. ", 2); $orphan_text = $orphan_explanation . "" . $orphan . "" . $orphan_more_text; /* * Format the text that provokes an orphan without any special * action to avoid widows and orphans. */ format_text_simple($p, $orphan_text, 13.1, $pagewidth, $pageheight, $header_fontsize, "Orphan"); /* * Format the same text with an algorithm that avoids widows and * orphans. */ format_text_widow_orphan_aware($p, $orphan_text, 13.1, $pagewidth, $pageheight, $header_fontsize, "Orphan avoided"); /* * Text that together with the specified fontsize below provokes * a widow. */ $widow_explanation = str_repeat("This text provokes a \"widow\" at the start of the " . "second fitbox. ", 7); $widow = str_repeat("Unless action is taken, the last line of this paragraph appears " . "as a widow at the start of the second fitbox. ", 2); $widow_more_text = str_repeat("This is text after the paragraph with the widow. ", 2); $widow_text = $widow_explanation . "" . $widow . "" . $widow_more_text; /* * Format the text that provokes a widow without any special * action to avoid widows and orphans. */ format_text_simple($p, $widow_text, 13.6, $pagewidth, $pageheight, $header_fontsize, "Widow"); /* * Format the same text with an algorithm that avoids widows and * orphans. */ format_text_widow_orphan_aware($p, $widow_text, 13.6, $pagewidth, $pageheight, $header_fontsize, "Widow avoided"); $p->end_document(""); $buf = $p->get_buffer(); $len = strlen($buf); header("Content-type: application/pdf"); header("Content-Length: $len"); header("Content-Disposition: inline; filename=" . $outfile); print $buf; } catch (PDFlibException $e) { echo("PDFlib exception occurred:\n". "[" . $e->get_errnum() . "] " . $e->get_apiname() . ": " . $e->get_errmsg() . "\n"); exit(1); } catch (Throwable $e) { echo("PHP exception occurred: " . $e->getMessage() . "\n"); exit(1); } /** * Format the textflow into the fitboxes over multiple pages, without doing * anything to avoid widows and orphans. */ function format_text_simple($p, $text, $fontsize, $pagewidth, $pageheight, $header_fontsize, $title) { $optlist = "fontname=NotoSerif-Regular " . "fontsize=" . $fontsize . " " . "alignment=left adjustmethod=nofit"; $tf = $p->create_textflow($text, $optlist); if ($tf == 0) { throw new Exception("Error: Unable to create textflow: " . $p->get_errmsg()); } $fitbox_width = $pagewidth * 0.5; $fitbox_height = $pageheight * 0.5; $llx = ($pagewidth - $fitbox_width) / 2; $lly = ($pageheight - $fitbox_height) / 2; $urx = $llx + $fitbox_width; $ury = $lly + $fitbox_height; $header_options = "fontname=NotoSerif-Regular fontsize=" . $header_fontsize . " position={center} boxsize={" . $pagewidth . " " . $header_fontsize . "}"; /* * Simple algorithm to format the Textflow into as many fitboxes * as necessary. */ for ($result = "_boxfull", $pagecount = 1; $result == "_boxfull"; $pagecount += 1) { $p->begin_page_ext($pagewidth, $pageheight, ""); $p->fit_textline($title . " (page " . $pagecount . ")", 0, $pageheight - 2 * $header_fontsize, $header_options); $result = $p->fit_textflow($tf, $llx, $lly, $urx, $ury, "showborder=true"); $p->end_page_ext(""); } $p->delete_textflow($tf); } /** * Format the textflow into the fitboxes over multiple pages, while * applying an algorithm that avoids widows and orphans. */ function format_text_widow_orphan_aware($p, $text, $fontsize, $pagewidth, $pageheight, $header_fontsize, $title) { /* * Same option list as in format_text_simple(), but with * minlinecount=2 to avoid orphans. */ $optlist = "minlinecount=2 fontname=NotoSerif-Regular " . "fontsize=" . $fontsize . " " . "alignment=left adjustmethod=nofit"; $tf = $p->create_textflow($text, $optlist); if ($tf == 0) { throw new Exception("Error: Unable to create textflow: " . $p->get_errmsg()); } $fitbox_width = $pagewidth * 0.5; $fitbox_height = $pageheight * 0.5; $llx = ($pagewidth - $fitbox_width) / 2; $lly = ($pageheight - $fitbox_height) / 2; $urx = $llx + $fitbox_width; $ury = $lly + $fitbox_height; $header_options = "fontname=NotoSerif-Regular fontsize=" . $header_fontsize . " position={center} boxsize={" . $pagewidth . " " . $header_fontsize . "}"; for ($result = "_boxfull", $pagecount = 1; $result == "_boxfull"; $pagecount += 1) { $p->begin_page_ext($pagewidth, $pageheight, ""); /* * Fit the the remaining Textflow into the first fitbox in blind * mode (option blind=true), i.e. without creating any real output, * while setting "minlinecount=2" to avoid an orphan. Query the * number of lines in the fitbox by using keyword "boxlinecount". */ $result = $p->fit_textflow($tf, $llx, $lly, $urx, $ury, "blind=true"); $boxlinecount = (int) $p->info_textflow($tf, "boxlinecount"); /* * Count how many times the textflow must be rewound: At least * one time for the first blind fit, and another time if a second * blind fit is performed because the fitbox is full. */ $rewindcount = 1; if ($result == "_boxfull") { /* * Fit the next part of the Textflow into the second fitbox in * blind mode. We don't care here that the second fitbox will * actually be placed on the next page in the output file. */ $p->fit_textflow($tf, $llx, $lly, $urx, $ury, "blind=true"); /* * Query the number of lines of the first paragraph in the * second fitbox. If the count is equal to one, we found a * single-line "widow". In order to avoid that, we reduce the * number of lines for the first fitbox by one. */ $firstparalinecount = (int) $p->info_textflow($tf, "firstparalinecount"); if ($firstparalinecount == 1) { $boxlinecount -= 1; } $rewindcount += 1; } /* Place header line */ $p->fit_textline($title . " (page " . $pagecount . ")", 0, $pageheight - 2 * $header_fontsize, $header_options); /* * Now do the actual output on the page. * Rewind the Textflow one or two steps (determined by * rewindcount) and set the calculated maximum number of lines. */ $result = $p->fit_textflow($tf, $llx, $lly, $urx, $ury, "rewind=-" . $rewindcount . " maxlines=" . $boxlinecount . " showborder=true"); $p->end_page_ext(""); } $p->delete_textflow($tf); } ?>