Thursday, April 17, 2014

Linux command line notes/helpers

I just decided I need to start writing this stuff down and maybe it will help others. This is just stuff I tried to Google for, but found I didn't have the terms or people decided to post their own opinionated answers ("Well, you should..."). SED and then GREP + SED My search: Bash to find line and insert new multi-line (an if block in my actual use case) content after line in same file. Answer:
#!/bin/bash
sed -i '/search for me regex/a \
\
 new line1 with preceeding tab spacing \
 new line2 also with tab before just fyi \
 new line3 next line adds space after block \
\n' /path/to/file.txt

#end script. look at man sed for -i and /a.
Extended question: ...make sure change to file isn't already made. If it is made, then say so. If not, do change.
#!/bin/bash

if grep -Fq "new line1 with pre" /path/to/file.txt
 then 
  echo "This change is already applied."
 else
  echo "Writing to file..."
  sed -i '/search for me regex/a \
  \
   new line1 with preceeding tab spacing \
   new line2 also with tab before just fyi \
   new line3 next line adds space after block \
         \n' /path/to/file.txt
fi

#end script. look at man grep for the -F and the -q flags.

Tuesday, July 17, 2012

Bytes to gigs, megs, kilos, and bytes

A units-to-readable conversion. My usage wraps this with a check for zero or null bytes and skips this function altogether.

function convertBytesGMKB(bytes){
 try{     
  var message = "";
  var gigs = Math.floor(bytes/Math.pow(1024,3));
  var divisorForMegs = bytes % Math.pow(1024,3);
  var megs = Math.floor(divisorForMegs / Math.pow(1024,2));
  var divisorForKilos = divisorForMegs % Math.pow(1024,2);
  var kilos = Math.floor(divisorForKilos / 1024);
  var divisorForBytes = divisorForKilos % 1024;
  var finalBytes = divisorForBytes;
  message = ((gigs > 0)?gigs+"g ":"")+((megs > 0)?megs+"m ":"")+((kilos > 0)?kilos+"k ":"")+finalBytes+"b";
  return message;
 }catch(e){
  console.log('convertBytesGMKB error: ', e);
 }
}

var content = convertBytesGMKB(Number(value));

Seconds to Weeks, Days, Hours, Minutes, Seconds

Seems converting to one unit is all over the interwebz. But, I couldn't find this so I posted my solution... This converts seconds to weeks, days, hours, minutes, seconds for readablity. In my usage it is wrapped in a check that skips it entirely if the seconds value is 0 or null.

function convertSecondsWDHMS(seconds){
 try{
  var message = "";
  var weeks = Math.floor(seconds/604800);
  var divisorForDays = seconds % 604800;
  var days = Math.floor(divisorForDays/86400);
  var divisorForHours = divisorForDays % 86400;
  var hours = Math.floor(divisorForHours / 3600);
  var divisorForMinutes = divisorForHours % 3600;
  var minutes = Math.floor(divisorForMinutes / 60);
  var divisorForSeconds = divisorForMinutes % 60;
  var finalSeconds = divisorForSeconds;
  message = ((weeks > 0)?weeks+"w ":"")+((days > 0)?days+"d ":"")+((hours > 0)?hours+"h ":"")+((minutes > 0)?minutes+"m ":"")+finalSeconds+"s";
  return message;
 }catch(e){
  console.log('convertSecondsWDHMS error: ', e);
 }
}

var content = convertSecondsWDHMS(Number(value));

Wednesday, August 24, 2011

PDFlib & PHP (11) TOC w/ proper dot leaders

This is just the dot-leader example from PDFlib site converted to a working PHP example.



# PHP-PDF-to-browser example of dot_leaders_with_tabs
# [currently in PDFlib Cookbook in Java only]
$file_name = "blog_11.pdf";
# number reflect an A4 sized document.
$doc_width = 595;
$doc_height = 842;
#
try{
$p = new PDFlib();
$p->set_parameter("logging", "filename {PDFlib.log}");
$p->set_parameter("errorpolicy", "exception");
# set textformat
$p->set_parameter("textformat", "utf8");
#
$optlist = "";
if ($p->begin_document("", $optlist) == 0)
throw new Exception("Error@begin_document: " . $p->get_errmsg());
# add some meta data on file
$p->set_info("Creator", "Neil Lindberg");
$p->set_info("Title", "dot-leaders-with-tabs");
# loading font (that most will have)
$font = $p->load_font("Helvetica", "unicode", "");
// if ($p->setfont($font, 12) == 0)
// throw new Exception("Error@setfont: " . $p->get_errmsg());
# add the toc page(s)
$optlist = "fontname=Helvetica fontsize=12 ".
"encoding=unicode leading=160% ruler=100% ".
"hortabmethod=ruler tabalignment=right";
$text = "Introduction".
"\t7".
"Chapter 1".
"\t25".
"Chapter 2".
"\t107".
"Chapter 3".
"\t219".
"Appendix\t240";
$text_flow = $p->create_textflow($text, $optlist);
do{
$p->begin_page_ext($doc_width, $doc_height, "");
$p->setfont($font, 12);
$p->fit_textline("Table of Contents", 50, 740, "");
$p->fit_textflow($text_flow, 50, 600, 500, 700, "");
$p->end_page_ext("");
} while($result == "_boxfull" || $result == "_nextpage");
#
$p->end_document("");
# get and send buffer
$buf = $p->get_buffer();
$len = strlen($buf);
header("Content-type: application/pdf");
header("Content-Length: $len");
header("Content-Disposition: inline; filename=$file_name");
print $buf;
} catch (PDFlibException $e) {
die("PDFlib exception occurred:\n".
"[" . $e->get_errnum() . "] " . $e->get_apiname() .
": " . $e->get_errmsg() . "\n");
} catch (Exception $e) {
die($e->getMessage());
}

Tuesday, August 16, 2011

PDFlib & PHP - (9) Formatting - Wrap Image

Yo! I need to wrap an image w/ text. Here is how it is done in PHP with PDFlib. Get your own, bigger chunk o' lorem if you want. It was five paragraphs of lorem ipsum, but it was an ugly paste, so I cut a few out. Also, the image is from the web and may not be at that address one day.


Using Matchbox optlist of optlist of... to Wrap Image



# wrap image with text using the "usematchbox" option
# of fit_image() - [available in Java only @Cookbook].
$file_name = "blog_9.pdf";
# number reflect an A4 sized document.
$doc_width = 595;
$doc_height = 842;
#
$chunk_o_lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam condimentum suscipit arcu in pharetra. Pellentesque ac purus diam. Proin in orci in diam auctor laoreet. Quisque vel mauris urna, ut aliquet nunc. Nullam diam justo, semper in suscipit vitae, rutrum quis ligula. Proin nec lectus purus. Praesent ut consectetur elit. In a nulla vel orci pretium vehicula at quis dui.

Integer consectetur faucibus hendrerit. Ut ac ante arcu, a fringilla orci. Donec vel sapien enim, a facilisis ipsum. Sed malesuada adipiscing eros a porta. Sed luctus elit id urna faucibus quis mollis risus commodo. Mauris sodales diam vitae mi vulputate placerat. Sed sodales nisi quis orci volutpat sit amet gravida lectus congue. In nec sapien ut mi sodales eleifend. Suspendisse ipsum diam, auctor id consequat sed, rutrum suscipit lacus. Vivamus diam nisi, fringilla nec pharetra id, commodo vel nunc. Quisque aliquam porttitor mi id blandit. Vestibulum et iaculis risus. Suspendisse consectetur, eros quis blandit varius, purus purus venenatis mauris, eu ultrices tortor justo at magna. Vestibulum nulla orci, tincidunt a varius at, dictum sit amet ante. Vestibulum ac lectus ante, ac fermentum erat. Donec nec ante quis neque lacinia viverra id quis tellus.

Nunc et sapien in lacus ultrices mollis. Maecenas pharetra magna lobortis nulla euismod sit amet consequat odio dictum. Donec euismod lorem diam. Ut rutrum urna pharetra lacus hendrerit vestibulum. Vivamus fermentum nunc sed nunc accumsan condimentum ac sit amet ante. Cras quis tortor vitae dolor scelerisque commodo. Aliquam quis diam nibh, a consectetur ante.

Duis ultrices, felis et placerat placerat, dui risus lobortis enim, quis commodo turpis massa sed diam. Curabitur rutrum sapien ac tortor ultricies commodo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin eu dolor lacus. Duis placerat, velit nec rhoncus volutpat, eros purus auctor diam, non eleifend velit tortor nec nunc. Cras consectetur eleifend massa nec tempor. Aenean euismod sem quis mauris ultrices feugiat. Sed ultrices tincidunt tincidunt. Pellentesque velit dolor, tristique a varius non, ultrices non nisi. Fusce adipiscing purus arcu, ac sollicitudin ipsum.";
#
try{
$p = new PDFlib();
$p->set_parameter("logging", "filename {PDFlib.log}");
$p->set_parameter("errorpolicy", "exception");
# set textformat
$p->set_parameter("textformat", "utf8");
#
$optlist = "";
if ($p->begin_document("", $optlist) == 0)
throw new Exception("Error@begin_document: " . $p->get_errmsg());
# add some meta data on file
$p->set_info("Creator", "Neil Lindberg");
$p->set_info("Title", "SVM User Guide (2.1)");
# loading font (that most will have)
$font = $p->load_font("Helvetica", "unicode", "");
$p->begin_page_ext($doc_width, $doc_height, "");
if ($p->setfont($font, 24) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
# random pic, big enough to show wrapping...
$an_otter_pic = "http://carinbondar.com/wp-content/uploads/2010/11/seaotter2.jpg";
$image_data = file_get_contents($an_otter_pic);
$p->create_pvf("/pvf/image", $image_data, "");
$image = $p->load_image("auto", "/pvf/image", "");
if($image == 0) die("Failed at load_image");
$p->delete_pvf("/pvf/image");
$image_width = $p->get_value("imagewidth", $image);
$image_height = $p->get_value("imageheight", $image);
$matchbox_name = "_image_matchbox";
#
# THERE IS NO create_matchbox. It is always created as
# a part of the optlist, for various elements, but does
# have its own string optlist - see API section 6.2.
#
# here, because i have the width and height of image
# i will just use that for boxsize and fitmethod auto, at 40%
$fit_image_opts = "matchbox={name=$matchbox_name margin=-7 } ".
"boxsize={".($image_width*.4)." ".($image_height*.4)."} fitmethod=auto showborder=true";
# the auto fitmethod may not serve your wants
# there are several in the API reference
# fitmethod=clip position={left center}";
$p->fit_image($image, $doc_width*.5-100, 600, $fit_image_opts);
$p->close_image($image);
# now, wrap the text(_flow)!
$tf = $p->add_textflow(0, $chunk_o_lorem, "fontname=Helvetica fontsize=10.5 encoding=unicode");
$result = $p->fit_textflow($tf, 50, 50, 550, 800,
"verticalalign=justify linespreadlimit=150% ".
"wrap={usematchboxes={{$matchbox_name}}}");
$p->end_page_ext("");
#
$p->end_document("");
# get and send buffer
$buf = $p->get_buffer();
$len = strlen($buf);
header("Content-type: application/pdf");
header("Content-Length: $len");
header("Content-Disposition: inline; filename=$file_name");
print $buf;
} catch (PDFlibException $e) {
die("PDFlib exception occurred:\n".
"[" . $e->get_errnum() . "] " . $e->get_apiname() .
": " . $e->get_errmsg() . "\n");
} catch (Exception $e) {
die($e->getMessage());
}

PDFlib & PHP (8) Combo #1 Large

Finally, I need to have text flow and while I was going to use a tables-only approach it turns out fit_textflow returns _boxfull and knows where to resume the text of a text flow, on the next page (just like fit_table when fitting added cells).

What I did to make my data-set big enough was to go find the lyrics of the favoriteSong listed in the bands.xml and paste those lyrics into a new tag under band called lyrics.



#########
$file_name = "blog_8.pdf";
# number reflect an A4 sized document.
$doc_width = 595;
$doc_height = 842;
function buildTOC($pdf, $table_of_contents, $font){
global $doc_width, $doc_height, $file_name;
$p = $pdf;
$toc = $table_of_contents;
if ($p->setfont($font, 12) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
###### TABLE TIME ###########
$table=0;
$num_columns = 3;
$num_rows = count($toc);
#llx = lower left x, whereas ury = upper right y
$llx= 30; $lly=50; $urx=550; $ury=760;
# flipping the process to per row, per col.
$row_num = 0;
$widths = array(150, 370, 30);
# keep from ugly via tagging left and right with center, i.e. right center.
$positions = array("left center", "right center", "right center");
do{
$row_num++;
$col_num = 0;
do{
$col_num++;
$position = $positions[$col_num-1];
#addnameddest() may be great for a more complex document, i.e. having sub-sections in the
# middle of a page/section. but, going to the page where a section starts requires laying
# an annotation over each row in the TOC that we have w/o sub-section._this is how:
# create_action w/ type GoTo, create_annotation w/ type: Link
$total_line_length = 100;
list($section, $page_num) = $toc[$row_num-1];
# using groups we can point at the group's page_num.
$link_optlist = "filename=$file_name destination={group=content page=$page_num type=fitwindow}";
$action = $p->create_action("GoTo", $link_optlist);
# the x positions are all good for these table rows to match the fit_table.
# but, the y positions need to change by 20, each, per row...
$anno_ury = $ury-(20*($row_num-1));
$annotation = $p->create_annotation($llx, $anno_ury-20, $urx, $anno_ury, "Link", "linewidth=0 action {activate $action}");
$periods = str_repeat('.', ($total_line_length-(strlen($section)+strlen($page_num))));
$optlist = "fittextline={position={".$position."} font=" . $font .
" fontsize=14} rowheight=20 colwidth=".($widths[$col_num-1]);//.$cell_border_opt;
$value = (($col_num-1) == 0)?$toc[$row_num-1][0]:((($col_num-1)==1)?$periods:$toc[$row_num-1][1]);
$table = $p->add_table_cell($table, $col_num, $row_num, $value, $optlist);
} while($col_num < $num_columns);
} while ($row_num < $num_rows);
###### fit_table optlist. time to place table.
$optlist = "";
//"stroke={{line=other}} header=0 fill={{area=rowodd fillcolor={gray 0.9}}} stroke={{line=other}} ";
$result = $p->fit_table($table, $llx, $lly, $urx, $ury, $optlist);
if ($result == "_error") {
die("Couldn't place table: " . PDF_get_errmsg($p));
}
}
###### END FUNC LIST ###########
try{
# image tag of xml has url to image like so:
# http://img.karaoke-lyrics.net/img/artists/32670/the-pogues-164114.jpg
$xml = new SimpleXMLElement($xmlstr);
# create a new instance of PDFlib.
$p = new PDFlib();
$p->set_parameter("logging", "filename {PDFlib.log}");
$p->set_parameter("errorpolicy", "exception");
# set textformat
$p->set_parameter("textformat", "utf8");
# SPACES are important here, at end of concatenated lines.
# all we really need for example to work are the groups and labels chunk.
$optlist = "groups={title toc content index} ".
"labels={{group=title prefix=title} ".
"{group=toc prefix={toc } start=1 style=r} ".
"{group=content start=1 style=D} ".
"{group=index prefix={index } start=1 style=r} } ".
"destination={ type=fixed zoom=.5 } " .
"viewerpreferences={displaydoctitle=true direction=l2r} ".
"openmode=thumbnails ".
"pagelayout=twocolumnleft ";
if ($p->begin_document("", $optlist) == 0)
throw new Exception("Error@begin_document: " . $p->get_errmsg());
# add some meta data on file
$p->set_info("Creator", "Neil Lindberg");
$p->set_info("Title", "SVM User Guide (2.1)");
# loading font (that most will have)
$font = $p->load_font("Helvetica", "unicode", "");
$p->begin_page_ext($doc_width, $doc_height, "group=title");
if ($p->setfont($font, 24) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
# add line of text, to center of page, approximately :)
$message = "Bands XML Breakdown";
$message_width = $p->stringwidth($message, $font, 24);
$p->show_xy($message, ($doc_width*.5)-($message_width*.5), $doc_height*.5);
#
$p->end_page_ext("");
# make page per band... suspend to later add page footer/num.
$num_bands = count($xml->band);
$count = 0;
$toc = array();
// TODO: Add text to the point of run-on to next page...
foreach($xml->band as $x){
$count++;
# TOC will be a breeze knowing the count reflects the
# page number of the content section, and we only have
# one page per band...
$toc[] = array($x->name, $count);
$p->begin_page_ext($doc_width, $doc_height, "group=content");
if ($p->setfont($font, 24) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
# put name of band in upper left-aligned corner.
$message = $x->name;
$p->show_xy($message, 24, $doc_height-48);
if ($p->setfont($font, 12) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
# add band info in a rectangular container, align center.
$band_info = "Genre: $x->genre\nFavorite song: $x->favoriteSong";
# NOTE: using fillcolor rather than ->setcolor does
# not require setting back to black.
$band_info_font = "font=$font fontsize=12 alignment=center ".
"fillcolor={spotname {PANTONE 222 U} 1}";
$textflow = $p->create_textflow($band_info, $band_info_font);
$p->fit_textflow($textflow, 50, 120, 550, 720, "");
# loading image from url is a bit more work. this section is that...
# we will load it and then put it in a temp pvf file
$image_data = file_get_contents($x->image);
$p->create_pvf("/pvf/image", $image_data, "");
# load image. auto == automatically detect type. could be jpeg, etc.
# NOTE: if image were local none of the pvf would be needed.
# instead the "/pvf/image" would be the image local name...
$image = $p->load_image("auto", "/pvf/image", "");
# temp pvf used, clear it for next run.
$p->delete_pvf("/pvf/image");
# finally place image.
$matchbox_name = $count."_image";
# options say: matchbox (for future access), boxsize for w/h, and finally,
# boxsize wouldn't work w/o some fitmethod. meet == scale to boxsize.
$fit_image_opts = "matchbox={name=$matchbox_name} ".
"boxsize={200 200} fitmethod=meet";
$p->fit_image($image, 200, 400, $fit_image_opts);
$p->close_image($image);
# add the url to the bottom of image using matchbox
if($p->info_matchbox($matchbox_name, 1, "exists")){
# x1, y1 = lower left. x2, y2 = lower right, etc.
$lower_left_x = $p->info_matchbox($matchbox_name, 1, "x1");
$lower_left_y = $p->info_matchbox($matchbox_name, 1, "y1");
$image_nm = explode("/", $x->image);
$p->show_xy($image_nm[count($image_nm)-1],
$lower_left_x,
$lower_left_y-12);
}
# add textflow, track pages.
$textflow_optlist = "font=$font fontsize=12";
$textflow = $p->create_textflow($x->lyrics, $textflow_optlist);
# can we just use the same return strings to continue here?
# as with fit_table? we can!
$result = $p->fit_textflow($textflow, 50, 50, 550, 370, "");
if ($result == "_error") {
die("Couldn't place table: " . PDF_get_errmsg($p));
}
# states of result of fit_table...
# I'm not finding this in the documentation, yet.
if($result == "_boxfull"){
if ($p->setfont($font, 12) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
$message = "Page $count";
$message_width = $p->stringwidth($message, $font, 12);
# cause to right-align in bottom corner.
$page_num_x = ($doc_width-$message_width)-24;
$page_num_y = $doc_height-($doc_height-24);
$p->show_xy($message, $page_num_x, $page_num_y);
$p->end_page_ext("");
do{
$p->begin_page_ext($doc_width, $doc_height, "group=content");
$count++;
if ($p->setfont($font, 24) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
$result = $p->fit_textflow($textflow, 50, 120, 550, 720, "");
if ($result == "_error") {
die("Couldn't place table: " . PDF_get_errmsg($p));
}
if ($p->setfont($font, 12) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
$message = "Page $count";
$message_width = $p->stringwidth($message, $font, 12);
# cause to right-align in bottom corner.
$page_num_x = ($doc_width-$message_width)-24;
$page_num_y = $doc_height-($doc_height-24);
$p->show_xy($message, $page_num_x, $page_num_y);
$p->end_page_ext("");
}while ($result == "_boxfull");
}else{
if ($p->setfont($font, 12) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
$message = "Page $count";
$message_width = $p->stringwidth($message, $font, 12);
# cause to right-align in bottom corner.
$page_num_x = ($doc_width-$message_width)-24;
$page_num_y = $doc_height-($doc_height-24);
$p->show_xy($message, $page_num_x, $page_num_y);
$p->end_page_ext("");
}
// $p->end_page_ext("");
}
# TOC information is ready, add page and contents.
$p->begin_page_ext($doc_width, $doc_height, "group=toc");
if ($p->setfont($font, 24) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
# put TOC label in upper left-aligned corner.
$message = "Table of Contents";
$p->show_xy($message, 24, $doc_height-48);
#
if ($p->setfont($font, 12) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
# we will make it pretty with these two:
#string str_repeat ( string $input , int $multiplier )
#int strlen ( string $string )
buildTOC($p, $toc, $font);
$p->end_page_ext("");
#
$p->end_document("");
# get and send buffer
$buf = $p->get_buffer();
$len = strlen($buf);
header("Content-type: application/pdf");
header("Content-Length: $len");
header("Content-Disposition: inline; filename=$file_name");
print $buf;
} catch (PDFlibException $e) {
die("PDFlib exception occurred:\n".
"[" . $e->get_errnum() . "] " . $e->get_apiname() .
": " . $e->get_errmsg() . "\n");
} catch (Exception $e) {
die($e->getMessage());
}

Friday, August 12, 2011

PDFlib & PHP - (7) Combo #1

Now to combine what I've learned about PDFlib & PHP thus far:


  • group/label in optlist for begin doc to be used with suspend/resume_page.

  • tables know when they are full, so we can use that in a sort of template manner and for a well-formatted TOC, as well as in tracking what pages are what section

There are a few changes to the "standard" create PDF file I've been building on since the (1) HELLO WERLD in this code. Nothing too complex. I change the file name of the output PDF to a variable outside the try catch and use it in the header/file= instead of the hard-casted way, and I put the document width/height also outside the try/catch so I can call them global in a function I tagged on to do all the work.

That said, the most important change of the last TOC code (5) is cutting out the building of a TOC by show_xy and replacing with a singular call to: buildTOC. I'll paste the entire thing last in this blog entry.


Change from show_xy to use of buildTOC function



// $total_line_length = 70;
// for($i = 0; $i < count($toc); $i++){
# the layout didn't work out with: $message = $section.str_repeat('.', $periods).$page_num;
# because the '.' character just is not taking up the space of alpha-chars of same size font.
# and if it is font based we have no flexibility (have to stick to Helvetica, 12) so, it looks
# like TABLES are the answer.?
// $section = $toc[$i][0];
// $page_num = $toc[$i][1];
// $periods = $total_line_length-(strlen($section)+strlen($page_num));
// syslog(LOG_ERR, "strlen(section): ".strlen($section));
// syslog(LOG_ERR, "strlen(page_num): ".strlen($page_num));
// syslog(LOG_ERR, "PERIODS: ".$periods);
// $message_width = $p->stringwidth($message, $font, 12);
// $p->show_xy($message, 36, $doc_height-(24*($i+1))-60);
// }
buildTOC($p, $toc, $font);
$p->end_page_ext("");

Function buildTOC()


There was a bunch of work and reading API and even some experimenting. I am obviously trying to use PDFlib, and I think it is powerful, but the optlist vs. documentaion combined with many Java-only examples is just a real time-burner. So, I hope this helps somebody because I did not find one single plain example of how to make a TOC with links to pages IN DOCUMENT. You'd think it would be out there, but I can find how to open and goto a place in ANOTHER DOCUMENT, or open a URL, but f-me if you can find an example of: Here is a clickable linked-to-page example using PDFlib.

On the other hand, I finally got it and that feels pretty good :)

As with all the code I've been pasting into this blog; make sure you read the comments if you want to know what is going on.



$file_name = "blog_7.pdf";
# number reflect an A4 sized document.
$doc_width = 595;
$doc_height = 842;
function buildTOC($pdf, $table_of_contents, $font){
global $doc_width, $doc_height, $file_name;
$p = $pdf;
$toc = $table_of_contents;
if ($p->setfont($font, 12) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
###### TABLE TIME ###########
$table=0;
$num_columns = 3;
$num_rows = count($toc);
#llx = lower left x, whereas ury = upper right y
$llx= 30; $lly=50; $urx=550; $ury=760;
# flipping the process to per row, per col.
$row_num = 0;
$widths = array(150, 370, 30);
# keep from ugly via tagging left and right with center, i.e. right center.
$positions = array("left center", "right center", "right center");
do{
$row_num++;
$col_num = 0;
do{
$col_num++;
$position = $positions[$col_num-1];
#addnameddest() may be great for a more complex document, i.e. having sub-sections in the
# middle of a page/section. but, going to the page where a section starts requires laying
# an annotation over each row in the TOC that we have w/o sub-section. _this is how:
# create_action w/ type GoTo, create_annotation w/ type: Link
$total_line_length = 100;
list($section, $page_num) = $toc[$row_num-1];
# using groups we can point at the group's page_num.
$link_optlist = "filename=$file_name destination={group=content page=$page_num type=fitwindow}";
$action = $p->create_action("GoTo", $link_optlist);
# the x positions are all good for these table rows to match the fit_table.
# but, the y positions need to change by 20, each, per row...
$anno_ury = $ury-(20*($row_num-1));
$annotation = $p->create_annotation($llx, $anno_ury-20, $urx, $anno_ury, "Link", "linewidth=0 action {activate $action}");
$periods = str_repeat('.', ($total_line_length-(strlen($section)+strlen($page_num))));
$optlist = "fittextline={position={".$position."} font=" . $font .
" fontsize=14} rowheight=20 colwidth=".($widths[$col_num-1]);//.$cell_border_opt;
$value = (($col_num-1) == 0)?$toc[$row_num-1][0]:((($col_num-1)==1)?$periods:$toc[$row_num-1][1]);
$table = $p->add_table_cell($table, $col_num, $row_num, $value, $optlist);
} while($col_num < $num_columns);
} while ($row_num < $num_rows);
###### fit_table optlist. time to place table.
$optlist = "";
//"stroke={{line=other}} header=0 fill={{area=rowodd fillcolor={gray 0.9}}} stroke={{line=other}} ";
$result = $p->fit_table($table, $llx, $lly, $urx, $ury, $optlist);
if ($result == "_error") {
die("Couldn't place table: " . PDF_get_errmsg($p));
}
}

The Whole Enchillada #1 Combo


Using same XML (bands/band) from other examples.



$file_name = "blog_7.pdf";
# number reflect an A4 sized document.
$doc_width = 595;
$doc_height = 842;
function buildTOC($pdf, $table_of_contents, $font){
global $doc_width, $doc_height, $file_name;
$p = $pdf;
$toc = $table_of_contents;
if ($p->setfont($font, 12) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
###### TABLE TIME ###########
$table=0;
$num_columns = 3;
$num_rows = count($toc);
#llx = lower left x, whereas ury = upper right y
$llx= 30; $lly=50; $urx=550; $ury=760;
# flipping the process to per row, per col.
$row_num = 0;
$widths = array(150, 370, 30);
# keep from ugly via tagging left and right with center, i.e. right center.
$positions = array("left center", "right center", "right center");
do{
$row_num++;
$col_num = 0;
do{
$col_num++;
$position = $positions[$col_num-1];
#addnameddest() may be great for a more complex document, i.e. having sub-sections in the
# middle of a page/section. but, going to the page where a section starts requires laying
# an annotation over each row in the TOC that we have w/o sub-section._this is how:
# create_action w/ type GoTo, create_annotation w/ type: Link
$total_line_length = 100;
list($section, $page_num) = $toc[$row_num-1];
# using groups we can point at the group's page_num.
$link_optlist = "filename=$file_name destination={group=content page=$page_num type=fitwindow}";
$action = $p->create_action("GoTo", $link_optlist);
# the x positions are all good for these table rows to match the fit_table.
# but, the y positions need to change by 20, each, per row...
$anno_ury = $ury-(20*($row_num-1));
$annotation = $p->create_annotation($llx, $anno_ury-20, $urx, $anno_ury, "Link", "linewidth=0 action {activate $action}");
$periods = str_repeat('.', ($total_line_length-(strlen($section)+strlen($page_num))));
$optlist = "fittextline={position={".$position."} font=" . $font .
" fontsize=14} rowheight=20 colwidth=".($widths[$col_num-1]);//.$cell_border_opt;
$value = (($col_num-1) == 0)?$toc[$row_num-1][0]:((($col_num-1)==1)?$periods:$toc[$row_num-1][1]);
$table = $p->add_table_cell($table, $col_num, $row_num, $value, $optlist);
} while($col_num < $num_columns);
} while ($row_num < $num_rows);
###### fit_table optlist. time to place table.
$optlist = "";
//"stroke={{line=other}} header=0 fill={{area=rowodd fillcolor={gray 0.9}}} stroke={{line=other}} ";
$result = $p->fit_table($table, $llx, $lly, $urx, $ury, $optlist);
if ($result == "_error") {
die("Couldn't place table: " . PDF_get_errmsg($p));
}
}
###### END FUNC LIST ###########
###### END FUNC LIST ###########
try{
# image tag of xml has url to image like so:
# http://img.karaoke-lyrics.net/img/artists/32670/the-pogues-164114.jpg
$xml = new SimpleXMLElement($xmlstr);
# create a new instance of PDFlib.
$p = new PDFlib();
$p->set_parameter("logging", "filename {PDFlib.log}");
$p->set_parameter("errorpolicy", "exception");
# set textformat
$p->set_parameter("textformat", "utf8");
# SPACES are important here, at end of concatenated lines.
# all we really need for example to work are the groups and labels chunk.
$optlist = "groups={title toc content index} ".
"labels={{group=title prefix=title} ".
"{group=toc prefix={toc } start=1 style=r} ".
"{group=content start=1 style=D} ".
"{group=index prefix={index } start=1 style=r} } ".
"destination={ type=fixed zoom=.5 } " .
"viewerpreferences={displaydoctitle=true direction=l2r} ".
"openmode=thumbnails ".
"pagelayout=twocolumnleft ";
if ($p->begin_document("", $optlist) == 0)
throw new Exception("Error@begin_document: " . $p->get_errmsg());
# add some meta data on file
$p->set_info("Creator", "Neil Lindberg");
$p->set_info("Title", "SVM User Guide (2.1)");
# loading font (that most will have)
$font = $p->load_font("Helvetica", "unicode", "");
$p->begin_page_ext($doc_width, $doc_height, "group=title");
if ($p->setfont($font, 24) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
# add line of text, to center of page, approximately :)
$message = "Bands XML Breakdown";
$message_width = $p->stringwidth($message, $font, 24);
$p->show_xy($message, ($doc_width*.5)-($message_width*.5), $doc_height*.5);
#
$p->end_page_ext("");
# make page per band... suspend to later add page footer/num.
$num_bands = count($xml->band);
$count = 0;
$toc = array();
foreach($xml->band as $x){
$count++;
# TOC will be a breeze knowing the count reflects the
# page number of the content section, and we only have
# one page per band...
$toc[] = array($x->name, $count);
$p->begin_page_ext($doc_width, $doc_height, "group=content");
if ($p->setfont($font, 24) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
# put name of band in upper left-aligned corner.
$message = $x->name;
$p->show_xy($message, 24, $doc_height-48);
if ($p->setfont($font, 12) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
# add band info in a rectangular container, align center.
$band_info = "Genre: $x->genre\nFavorite song: $x->favoriteSong";
# NOTE: using fillcolor rather than ->setcolor does
# not require setting back to black.
$band_info_font = "font=$font fontsize=12 alignment=center ".
"fillcolor={spotname {PANTONE 222 U} 1}";
$textflow = $p->create_textflow($band_info, $band_info_font);
$p->fit_textflow($textflow, 50, 120, 550, 720, "");
# loading image from url is a bit more work. this section is that...
# we will load it and then put it in a temp pvf file
$image_data = file_get_contents($x->image);
$p->create_pvf("/pvf/image", $image_data, "");
# load image. auto == automatically detect type. could be jpeg, etc.
# NOTE: if image were local none of the pvf would be needed.
# instead the "/pvf/image" would be the image local name...
$image = $p->load_image("auto", "/pvf/image", "");
# temp pvf used, clear it for next run.
$p->delete_pvf("/pvf/image");
# finally place image.
$matchbox_name = $count."_image";
# options say: matchbox (for future access), boxsize for w/h, and finally,
# boxsize wouldn't work w/o some fitmethod. meet == scale to boxsize.
$fit_image_opts = "matchbox={name=$matchbox_name} ".
"boxsize={200 200} fitmethod=meet";
$p->fit_image($image, 200, 400, $fit_image_opts);
$p->close_image($image);
# add the url to the bottom of image using matchbox
if($p->info_matchbox($matchbox_name, 1, "exists")){
# x1, y1 = lower left. x2, y2 = lower right, etc.
$lower_left_x = $p->info_matchbox($matchbox_name, 1, "x1");
$lower_left_y = $p->info_matchbox($matchbox_name, 1, "y1");
$image_nm = explode("/", $x->image);
$p->show_xy($image_nm[count($image_nm)-1],
$lower_left_x,
$lower_left_y-12);
}
# add page n of E.
$message = "Page $count of $num_bands";
$message_width = $p->stringwidth($message, $font, 12);
# cause to right-align in bottom corner.
$page_num_x = ($doc_width-$message_width)-24;
$page_num_y = $doc_height-($doc_height-24);
$p->show_xy($message,
$page_num_x,
$page_num_y);
$p->end_page_ext("");
}
# TOC information is ready, add page and contents.
$p->begin_page_ext($doc_width, $doc_height, "group=toc");
if ($p->setfont($font, 24) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
# put TOC label in upper left-aligned corner.
$message = "Table of Contents";
$p->show_xy($message, 24, $doc_height-48);
#
if ($p->setfont($font, 12) == 0)
throw new Exception("Error@setfont: " . $p->get_errmsg());
# we will make it pretty with these two:
#string str_repeat ( string $input , int $multiplier )
#int strlen ( string $string )
// $total_line_length = 70;
// for($i = 0; $i < count($toc); $i++){
# the layout didn't work out with: $message = $section.str_repeat('.', $periods).$page_num;
# because the '.' character just is not taking up the space of alpha-chars of same size font.
# and if it is font based we have no flexibility (have to stick to Helvetica, 12) so, it looks
# like TABLES are the answer.?
// $section = $toc[$i][0];
// $page_num = $toc[$i][1];
// $periods = $total_line_length-(strlen($section)+strlen($page_num));
// syslog(LOG_ERR, "strlen(section): ".strlen($section));
// syslog(LOG_ERR, "strlen(page_num): ".strlen($page_num));
// syslog(LOG_ERR, "PERIODS: ".$periods);
// $message_width = $p->stringwidth($message, $font, 12);
// $p->show_xy($message, 36, $doc_height-(24*($i+1))-60);
// }
buildTOC($p, $toc, $font);
$p->end_page_ext("");
#
$p->end_document("");
# get and send buffer
$buf = $p->get_buffer();
$len = strlen($buf);
header("Content-type: application/pdf");
header("Content-Length: $len");
header("Content-Disposition: inline; filename=$file_name");
print $buf;
} catch (PDFlibException $e) {
die("PDFlib exception occurred:\n".
"[" . $e->get_errnum() . "] " . $e->get_apiname() .
": " . $e->get_errmsg() . "\n");
} catch (Exception $e) {
die($e->getMessage());
}