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, "destination={type=fitwindow}") == 0) throw new Exception("Error: " . $p->get_errmsg()); $p->set_info("Creator", "PDFlib Cookbook"); $p->set_info("Title", $title); /* Create page */ $p->begin_page_ext(0, 0, "width=a4.width height=a4.height"); // For simplicity we name the matchboxes according to the // corresponding annotation type that they will hold. $text = "Lorem " . "caret " . "ipsum dolor sit amet, consectetur adi­pi­sicing elit, " . "sed do eius­mod" . " circle " . "tempor incidi­dunt ut labore et dolore magna ali­qua. Ut " . "highlight " . "enim ad minim ve­niam, quis nostrud " . "line " . "exer­citation ull­amco la­bo­ris nisi ut " . "square " . "ali­quip ex ea commodo con­sequat. Duis aute irure dolor in " . "squiggly " . "repre­henderit in voluptate velit esse cillum dolore eu " . "strikeout " . "fugiat nulla pari­atur. Excep­teur sint occae­cat " . "cupi­datat non proident, sunt in culpa qui officia dese­runt " . "underline " . "mollit anim id est laborum. "; $tf = $p->create_textflow($text, "fontname=NotoSerif-Regular fontsize=20 leading=140% charref"); if ($tf == 0) throw new Exception("Error: " . $p->get_errmsg()); // Place the Textflow on the page $result = $p->fit_textflow($tf, 50, 50, 550, 550, "fitmethod=auto"); if ($result != "_stop") { /* Check for errors */ } /* * $p->info_matchbox() returns box coordinates in user coordinates * which we use in calls to create_annotation(). If the user * coordinate system has been transformed we need this method to * accept user coordinates. Instead of supplying "usercoordinate=true" * to individual calls we set it here globally. */ $p->set_option("usercoordinates=true"); // Create some annotation types with explicit rectangle coordinates $font = $p->load_font("NotoSerif-Bold", "unicode", ""); $p->create_annotation(300, 750, 500, 800, "Stamp", "contents={Stamp annotation} font=" . $font); $p->create_annotation(50, 750, 75, 800, "Text", "contents={My little note...} open=false iconname=comment annotcolor=red"); /* File attachment annotation */ $asset = $p->load_asset("Attachment", "af1.txt", "description={Simple text file}"); if ($asset == 0) throw new Exception("Error: " . $p->get_errmsg()); $p->create_annotation(50, 700, 75, 725, "FileAttachment", "attachment=" . $asset . " contents={My file attachment} iconname=pushpin annotcolor=blue"); /* FreeText annotation with a callout line pointing to the * top left corner of the Textflow box. */ $llx = 200; $lly = 600; $urx = 350; $ury = 650; $font = $p->load_font("NotoSerif-Regular", "unicode", ""); $p->create_annotation($llx, $lly, $urx, $ury, "FreeText", "contents={FreeText with callout line} calloutline={" . "50 550 " . // start point (what it points to) ($llx+50)/2 . " " . ($lly + $ury)/2 . " " . // optional knee point $llx . " " . ($lly + $ury)/2 . "} " . // end point (on the annotation border) "endingstyles={closedarrow none} fontsize=12 font=" . $font . " annotcolor=yellow fillcolor=red"); /* Create various annotation types in the corresponding matchboxes * in the Textflow. Since we use matchboxes as target rectangles * we can supply the annotation coordinates as 0, 0, 0, 0. */ $p->create_annotation(0, 0, 0, 0, "Caret", "usematchbox=caret annotcolor=blue"); $p->create_annotation(0, 0, 0, 0, "Circle", "usematchbox=circle linewidth=2 annotcolor=purple interiorcolor=purple opacity=0.25"); // Attach Popup to the Highlight annotation via name $p->create_annotation(0, 0, 0, 0, "Highlight", "name=my_highlight title={My highlight} contents={My comment in the Popup...} usematchbox=highlight linewidth=3 annotcolor=red"); /* Create a Popup annotation for the Highlight annotation. * Fetch corner coordinates of the parent Highlight annotation so * that we can place the corresponding Popup close to it. */ $llx = $p->info_matchbox("highlight", 1, "x1") + 50; $lly = $p->info_matchbox("highlight", 1, "y1") + 150; $p->create_annotation($llx, $lly, $llx+150, $lly+100, "Popup", "parentname=my_highlight open"); // Fetch corner coordinates so that we can draw a diagonal line $llx = $p->info_matchbox("line", 1, "x1"); $lly = $p->info_matchbox("line", 1, "y1"); $urx = $p->info_matchbox("line", 1, "x3"); $ury = $p->info_matchbox("line", 1, "y3"); $p->create_annotation(0, 0, 0, 0, "Line", "usematchbox=line line={" . $llx . " " . $lly . " " . $urx . " " . $ury . "} linewidth=3 annotcolor=green"); $p->create_annotation(0, 0, 0, 0, "Square", "usematchbox=square cloudy=1 linewidth=2 annotcolor=magenta"); $p->create_annotation(0, 0, 0, 0, "Squiggly", "usematchbox=squiggly annotcolor=blue"); $p->create_annotation(0, 0, 0, 0, "Strikeout", "usematchbox=strikeout annotcolor=red"); $p->create_annotation(0, 0, 0, 0, "Underline", "usematchbox=underline annotcolor=purple"); $p->end_page_ext(""); $p->end_document(""); $buf = $p->get_buffer(); $len = strlen($buf); header("Content-type: application/pdf"); header("Content-Length: $len"); header("Content-Disposition: inline; filename=markup_annotations.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; ?>