PDFlib Cookbook

cookbook

textflow/textflow_with_shading

Create multi-column output with text and use a shading where the geometry of each shading matches the respective text column.

Download PHP Code  Switch to Java Code  Show Output 

<?php
/*
 * Textflow with shading:
 * Create multi-column text output which may span multiple pages.
 * The text columns are colorized with a shading which matches the
 * geometry of each column. To emphasize the effect we create a radial
 * shading which starts in the middle of the fitbox.
 *
 * Required software: PDFlib/PDFlib+PDI/PPS 10
 * Required data: none
 */

function create_shading($p, $tf) {
    /*
     * Query formatting results of the Textflow (coordinates of the placed
     * text)
     */
    $llx = $p->info_textflow($tf, "x1");
    $lly = $p->info_textflow($tf, "y1");
    $urx = $p->info_textflow($tf, "x3");
    $ury = $p->info_textflow($tf, "y3");
    
    /*
     * Create axial shading from red to blue. The start and end circles have
     * their centers in the center of the fitbox. The radius of the start
     * circle is zero, the radius of the end circle is chosen so that the
     * full fitbox is covered (half of the diagonal).
     */
    $sh = $p->shading("radial", 
                ($llx + $urx) / 2, ($lly + $ury) / 2, 
                ($llx + $urx) / 2, ($lly + $ury) / 2, 
                0, 0, 0, 0,                      // unused color parameters
                "startcolor=red endcolor=blue " . 
                "r0=0 r1=" . (0.5 * sqrt(pow($ury - $lly, 2) + pow($urx - $llx, 2))));
    
    return $p->shading_pattern($sh, "");
}
/* This is where the data files are. Adjust as necessary. */
$searchpath = dirname(__FILE__,3)."/input";

$title = "Starter Textflow";
$tf = 0;
$llx1 = 50;
$lly1 = 50;
$urx1 = 250;
$ury1 = 800;
$llx2 = 300;
$lly2 = 50;
$urx2 = 500;
$ury2 = 800;
$exitcode = 0;

/* Repeat the dummy text to produce more contents */
$count = 50;

$optlist1 = "fontname=NotoSerif-Regular fontsize=10.5 " .
                 "fillcolor={gray 0} alignment=justify hyphenchar=U+002D";

/*
 * Dummy text for filling the columns. Soft hyphens are marked with the
 * character reference "&shy;" (character references are enabled by the
 * charref option).
 */
$text = "Lorem ipsum dolor sit amet, consectetur adi&shy;pi&shy;sicing elit, " .
         "sed do eius&shy;mod tempor incidi&shy;dunt ut labore et dolore " .
         "magna ali&shy;qua. Ut enim ad minim ve&shy;niam, quis nostrud " .
         "exer&shy;citation ull&shy;amco la&shy;bo&shy;ris nisi ut " .
         "ali&shy;quip ex ea commodo con&shy;sequat. Duis aute irure dolor " .
         "in repre&shy;henderit in voluptate velit esse cillum dolore eu " .
         "fugiat nulla pari&shy;atur. Excep&shy;teur sint occae&shy;cat " .
         "cupi&shy;datat non proident, sunt in culpa qui officia " .
         "dese&shy;runt mollit anim id est laborum. ";

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("", "") == 0)
        throw new Exception("Error: " . $p->get_errmsg());
    
    $p->set_info("Creator", "PDFlib Cookbook");
    $p->set_info("Title", $title);
    
    $optlist2 = "fontname=NotoSerif-Bold fontsize=14 charref hyphenchar=U+002D";
    
    /*
     * Create some amount of dummy text and feed it to a Textflow object
     * with alternating options.
     */
    for ($i = 1; $i <= $count; $i ++) {
        $num = $i . " ";
        
        $tf = $p->add_textflow($tf, $num, $optlist2);
        if ($tf == 0)
            throw new Exception("Error: " . $p->get_errmsg());
        
        $tf = $p->add_textflow($tf, $text, $optlist1);
        if ($tf == 0)
            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. Two columns will be created on all
     * pages.
     */
    do {
        /* Add "showborder" to visualize the fitbox borders */
        $optlist = "verticalalign=justify linespreadlimit=120% ";
        
        $p->begin_page_ext(0, 0, "width=a4.width height=a4.height");
        
        /* Place the first column in blind mode (for formatting only) */
        $result = $p->fit_textflow($tf, $llx1, $lly1, $urx1, $ury1, 
                        $optlist . " blind");
        
        /* handle for shading pattern */
        $shp = create_shading($p, $tf);
        
        /*
         * Place the first column in real mode and replace the gray fill
         * color with the shading pattern. We must rewind the Textflow
         * to undo the result of the "blind" formatting.
         */
        $result = $p->fit_textflow($tf, $llx1, $lly1, $urx1, $ury1, 
                    $optlist .
                         "rewind=-1 exchangefillcolors={{gray 0} {pattern " .
                         $shp . "}}");
        
        /* Process the second column if we have more text */
        if ($result != "_stop") {
            /* Place second column in "blind" mode */
            $result = $p->fit_textflow($tf, $llx2, $lly2, $urx2, $ury2, 
                            $optlist . " blind");
            
            $shp = create_shading($p, $tf);
            
            /*
             * Place second column in real mode and replace the gray
             * fill color with the shading pattern.
             */
            $result = $p->fit_textflow($tf, $llx2, $lly2, $urx2, $ury2, 
                    $optlist .
                         "rewind=-1 exchangefillcolors={{gray 0} {pattern " .
                         $shp . "}}");
        }
        
        $p->end_page_ext("");
        
        /*
         * "_boxfull" means we must continue because there is more text;
         * "_nextpage" is interpreted as "start new column"
         */
    } while ( $result == "_boxfull" || $result == "_nextpage" );
    
    /* Check for errors */
    if ($result != "_stop") {
        /*
         * "_boxempty" happens if the box is very small and doesn't hold
         * any text at all.
         */
        if ($result == "_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->delete_textflow($tf);
    
    $p->end_document("");
    $buf = $p->get_buffer();
    $len = strlen($buf);
    
    header("Content-type: application/pdf");
    header("Content-Length: $len");
    header("Content-Disposition: inline; filename=textflow_with_shading.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;
?>