path_objects/clipping
Demonstrate the effect of different PDF clipping rules.
Download PHP Code Switch to Java Code Show Output
<?php
/**
*
*
* Demonstrate the effect of the different PDF clipping rules.
*
* Demonstrate how to perform "inverse" clipping, e.g. create a rectangle on a
* page that is exempted from drawing.
*
* Required software: PDFlib/PDFlib+PDI/PPS 9
* Required data: none
*/
/**
* Create a path in the shape of a pentagram to have a shape that intersects
* itself.
*/
function pentagram_path($p, $length) {
/* The angle for which to turn at each po$to form the star */
$angle = 144;
/*
* Initial angle so the pentagram is constructed with the first point at the
* top.
*/
$initial_angle = - 3 * $angle / 4;
/*
* Construct the pentagram with polar coordinates. The path will be closed
* automatically when using it as a clipping path.
*/
$i;
$path = 0;
for ($i = 0; $i < 4; $i += 1) {
$path = $p->add_path_point($path, $length, $initial_angle + $angle * $i,
"line", "polar=true relative=true");
}
return $path;
}
/**
* Create a path that consists of two nested circles that are either
* oriented in the same direction or in opposite directions.
*/
function nested_circles_path($p, $outer_radius, $inner_radius, $same_direction) {
/*
* The circle is constructed of two half-circles. Type "elliptical" is used
* insted of type "circle" or "circular" because it allows to use the
* "clockwise" option to specify the direction. Outer circle is always
* oriented clockwise
*/
$outer_direction = "clockwise=true";
$path = $p->add_path_point(0, - $outer_radius, 0, "move", "");
$p->add_path_point($path, $outer_radius, 0, "elliptical",
"radius=" . $outer_radius . " " . $outer_direction);
$p->add_path_point($path, - $outer_radius, 0, "elliptical",
"radius=" . $outer_radius . " " . $outer_direction);
/*
* Inner circle is oriented in the same or opposite direction, depending on
* "same_direction" parameter.
*/
$inner_direction = "clockwise=" . ($same_direction ? "true" : "false");
$p->add_path_point($path, - $inner_radius, 0, "move", "");
$p->add_path_point($path, $inner_radius, 0, "elliptical",
"radius=" . $inner_radius . " " . $inner_direction);
$p->add_path_point($path, - $inner_radius, 0, "elliptical",
"radius=" . $inner_radius . " " . $inner_direction);
return $path;
}
/**
* Draw the clipped shapes into the specified box while using the specified
* clip rule.
*/
function clipped_shapes($p, $cliprule, $font, $ypos, $boxwidth, $boxheight,
$unit, $penta, $nested_circles_same_dir,
$nested_circles_different_dir) {
/* Save graphics state before translation */
$p->save();
/* Position box vertically on page */
$p->translate(0, $ypos);
/* Step that is incremented to position the shapes horizontally */
$step = $unit;
/* Dimensions of text box for displaying clip rule */
$textbox_height = $boxheight / 3.0;
$text_lly = $boxheight * 2.0 / 3.0;
$p->fit_textline("cliprule=" . $cliprule, 0, $text_lly,
"position=center font=" . $font . " fontsize=20 " .
"boxsize={" . $boxwidth . " " .
$textbox_height . "}");
/* Dimensions of caption for each shape */
$caption_lly = $boxheight / 2.0;
$caption_fontsize = 10;
$caption_height = 3 * $caption_fontsize;
/* Caption for pentagram */
$optlist = "alignment=center font=" . $font . " fontsize=" .
$caption_fontsize;
$tf = $p->create_textflow("Self-intersecting pentagram", $optlist);
$p->fit_textflow($tf, $step, $caption_lly, $step + $unit,
$caption_lly + $caption_height, "");
/* Save graphics state before setting the clipping path */
$p->save();
/* Use pentagram path as clipping path with specified clip rule */
$p->draw_path($penta, $step + $unit / 2, 2 * $unit,
"clip cliprule=" . $cliprule);
/*
* Fill a rectangle that has the size of the box with blue, affected by the
* clipping path.
*/
$p->set_graphics_option("fillcolor=blue");
$p->rect(0, 0, $boxwidth, $boxheight);
$p->fill();
/* Restore graphics state without clipping path */
$p->restore();
$p->delete_textflow($tf);
$step += 2 * $unit;
$tf = $p->create_textflow("Nested circles, same direction", $optlist);
$p->fit_textflow($tf, $step, $caption_lly, $step + $unit,
$caption_lly + $caption_height, "");
/*
* Same steps as above to demonstrate the effect of nested circles with same
* orientation to set the clipping path with the specified clip rule.
*/
$p->save();
$p->draw_path($nested_circles_same_dir, $step + $unit / 2, 1.5 * $unit,
"clip cliprule=" . $cliprule);
$p->set_graphics_option("fillcolor=blue");
$p->rect(0, 0, $boxwidth, $boxheight);
$p->fill();
$p->restore();
$p->delete_textflow($tf);
$step += 2 * $unit;
$tf = $p->create_textflow("Nested circles, different direction", $optlist);
$p->fit_textflow($tf, $step, $caption_lly, $step + $unit,
$caption_lly + $caption_height, "");
/*
* Same steps as above to demonstrate the effect of nested circles with
* opposite orientation to set the clipping path with the specified clip
* rule.
*/
$p->save();
$p->draw_path($nested_circles_different_dir, $step + $unit / 2, 1.5 * $unit,
"clip cliprule=" . $cliprule);
$p->set_graphics_option("fillcolor=blue");
$p->rect(0, 0, $boxwidth, $boxheight);
$p->fill();
$p->restore();
$p->delete_textflow($tf);
/* Restore graphics state before translate */
$p->restore();
}
/**
* Demonstrate the effects of the "Nonzero Winding Number" and "Even-Odd"
* clipping rules.
*/
function clippingrules($p, $font, $pagewidth, $pageheight) {
/*
* Divide the page horizontally into seven parts to place the three shapes
* evenly spaced.
*/
$unit = $pagewidth / 7;
/* Path for pentagram */
$penta = pentagram_path($p, $unit);
/* Path for nested circles oriented in same direction */
$nested_circles_same_dir = nested_circles_path($p, $unit / 2, $unit / 4,
true);
/* Path for nested circles oriented in opposite direction */
$nested_circles_different_dir = nested_circles_path($p, $unit / 2,
$unit / 4, false);
$p->begin_page_ext($pagewidth, $pageheight, "");
/* Define dimension of box that covers half the page vertically */
$boxheight = $pageheight / 2;
$boxwidth = $pagewidth;
/* Y position of upper box on page */
$ypos = $pageheight / 2;
/* Use paths for clipping with "Nonzero Winding Number Rule" */
clipped_shapes($p, "winding", $font, $ypos, $boxwidth, $boxheight, $unit,
$penta, $nested_circles_same_dir,
$nested_circles_different_dir);
/* Y position of lower box on page */
$ypos = 0;
/* Use paths for clipping with "Even-Odd Rule" */
clipped_shapes($p, "evenodd", $font, $ypos, $boxwidth, $boxheight, $unit,
$penta, $nested_circles_same_dir,
$nested_circles_different_dir);
/* Clean up path handles */
$p->delete_path($penta);
$p->delete_path($nested_circles_same_dir);
$p->delete_path($nested_circles_different_dir);
$p->end_page_ext("");
}
/**
* Demonstrate "inverse" clipping: Define rectangles where the interior
* is not painted when performing graphics operations.
*/
function inverse_clipping($p, $font, $pagewidth, $pageheight) {
$p->begin_page_ext($pagewidth, $pageheight, "");
/* Define position and dimensions of "inverse" clip rectangle */
$clip_llx = $pagewidth / 4;
$clip_lly = $pageheight / 4;
$clip_width = $pagewidth / 2;
$clip_height = $pageheight / 4;
/* Create explanation */
$optlist = "alignment=center font=" . $font . " fontsize=20";
$tf = $p->create_textflow(
"This rectangle is exempted from drawing by clipping",
$optlist);
/*
* Fit the explanation in the rectangle that later will be exempted from
* drawing by clipping.
*/
$p->fit_textflow($tf, $clip_llx, $clip_lly, $clip_llx + $clip_width,
$clip_lly + $clip_height,
"matchbox={margin=10} verticalalign=center");
$p->delete_textflow($tf);
/*
* We want to exempt the inner rectangle from drawing, when the nested
* rectangles are drawn in the same direction.
*/
$p->set_graphics_option("cliprule=evenodd");
/*
* To exempt the inner of a rectangle from painting on the page, first the
* whole page must be set as a clipping rectangle.
*/
$p->rect(0, 0, $pagewidth, $pageheight);
/*
* Now define the smaller rectangle that shall be exempted from drawing.
*/
$p->rect($clip_llx, $clip_lly, $clip_width, $clip_height);
/* Use the nested rectangles as clipping path */
$p->clip();
/* Create a textflow that shall be used to fill the page */
$text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " .
"sed do eiusmod tempor incididunt ut labore et dolore magna " .
"aliqua. Ut enim ad minim veniam, quis nostrud exercitation " .
"ullamco laboris nisi ut aliquip ex ea commodo consequat. " .
"Duis aute irure dolor in reprehenderit in voluptate velit " .
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint " .
"occaecat cupidatat non proident, sunt in culpa qui officia " .
"deserunt mollit anim id est laborum. ";
$optlist = "font=" . $font . " fontsize=7 alignment=justify fillcolor=blue";
$tf = 0;
$i;
for($i = 0; $i < 60; $i += 1) {
$tf = $p->add_textflow($tf, $text, $optlist);
}
/* Fill whole page with text while clipping is in effect */
$p->fit_textflow($tf, 0, 0, $pagewidth, $pageheight, "");
$p->delete_textflow($tf);
$p->end_page_ext("");
}
/* This is where the data files are. Adjust as necessary. */
$searchpath = dirname(__FILE__,3)."/input";
$title = "Clipping Path Variants";
$pageheight = 852;
$pagewidth = 595;
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("", "") == - 1)
throw new Exception("Error: " . $p->get_errmsg());
$p->set_info("Creator", "PDFlib Cookbook");
$p->set_info("Title", $title);
$font = $p->load_font("NotoSerif-Regular", "unicode", "");
if ($font == 0)
throw new Exception("Error: " . $p->get_errmsg());
clippingrules($p, $font, $pagewidth, $pageheight);
inverse_clipping($p, $font, $pagewidth, $pageheight);
$p->end_document("");
$buf = $p->get_buffer();
$len = strlen($buf);
header("Content-type: application/pdf");
header("Content-Length: $len");
header("Content-Disposition: inline; filename=clipping.pdf");
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);
}
$p = 0;
?>