Looking at FPDF and at my PDF tutorial, it is clear that there are a few things that PDF's can do that aren't part of the API of FPDF. However, FPDF is easily extensible to include everything I might find useful, so I put together a package of those routines.
See the code.
See the sample output.
See the code that produced the sample output.
Continue reading ‘Paths, Vector Graphics and PHP images in FPDF’ »
Posted by Danny on April 11, 2011 at 10:47 am under PDF, PHP.
14 Comments.
Now we need to add text. That's the most useful part of a PDF, and the easiest. Also the hardest. Sometimes life is like that.
See the code.
Continue reading ‘Creating PDFs with PHP, part 5: Text’ »
Posted by Danny on April 1, 2011 at 5:21 pm under PDF, PHP.
2 Comments.
Now that we can draw in our PDF, we want to add images. There are two kinds of images, bitmapped and vector. In PDF, images are called XObject
s (The X stands for external, meaning defined outside the page). Vector images are easier, since they are just packages of PDF drawing commands, a sort of macro. PDF calls them Form
s, since they were originally used to draw the boxes on a printed form.
See the code.
Continue reading ‘Creating PDFs with PHP, part 4: Images’ »
Posted by Danny on April 1, 2011 at 2:10 am under PDF, PHP.
1 Comment.
Now that we can create blank PDF's, it's time to add some stuff. Vector drawing commands (lines and shapes) are simple; you just add the commands to the page content stream. In terms of the original class that would be:
$this->pages[count($this->pages)-1]->contents .= "the command\n";
// we just need some whitespace at the end, but the newline makes it easier to read the resulting PDF
But to make things easier, we can keep track of the last page:
function newpage(){
parent::newpage();
$this->currentPage = $this->pages[count($this->pages)-1];
}
// and now adding commands is:
$this->currentPage->contents .= "the command\n";
// this also has the advantage that we can manipulate currentPage to add commands to other content streams
There are lots of commands, all of which are postfix (parameters come before operators). There are no math operators or stack manipulation operators; any calculation has to be done before generating the PDF and numbers inserted directly.
See the code.
Continue reading ‘Creating PDFs with PHP, part 3: Drawing’ »
Posted by Danny on March 31, 2011 at 9:18 pm under PDF, PHP.
Comment on this post.
Continuing my attempt to dissect FDPF to understand PDF's, we'll create the simplest PDF: a blank page.
We need a couple of objects:
- Catalog
- This serves as the root object and describes the data structures in the document, which for our purposes is just the collection of printed pages. Other things, like the data for interactive forms, Javascript routines and metadata (author, subject, keywords) would go here.
1 0 obj
<<
/Type /Catalog
/Pages 0 2 R % reference to object number 2
>>
endobj
- One useful optional entry in the catalog is the
/OpenAction
that can be used to set the zoom level and opening page.
/OpenAction [3 0 R /Fit]
starts at the page described in object 3 and zooms in to fit the page on the screen.
See the code.
Continue reading ‘Creating PDFs with PHP, part 2: A Blank Page’ »
Posted by Danny on March 24, 2011 at 10:25 pm under PDF, PHP.
Comment on this post.
I wanted to allow my webservices to create PDF files, and I figured it couldn't be too hard—after all, it's just a bunch of graphics commands in a text file, right? Foolish me. The reference manual is 756 pages long, not including the javascript reference, another 769 pages. The place to start is fPDF, which is open source and pretty easy to understand, and its derivative tFPDF that lets you use and embed True Type fonts (it's the 21st century; who uses anything but True Type fonts?). Using it is simple:
define('_SYSTEM_TTFONTS', '/path/to/your/truetype/fonts/'); // Took a bit of experimenting to find the right values for these
define('FPDF_FONTPATH', _SYSTEM_TTFONTS);
putenv('GDFONTPATH='._SYSTEM_TTFONTS); // so we can use GD images as well
$pdf=new tFPDF();
$pdf->AddPage();
$pdf->SetFont('Arial','B',16);
$pdf->Cell(40,10,'Hello World!');
$pdf->Output();
One gotcha is that you need to create the unifont
directory within the fonts folder, and copy tFPDF's ttfonts.php
file into that.
The result is here.
Continue reading ‘Creating PDFs with PHP: Syntax’ »
Posted by Danny on March 18, 2011 at 5:06 am under PDF, PHP.
Comment on this post.
I've been trying on and off to get my head around continuations in Scheme, which is the language that gnucash uses for reports. It's one of the modern versions of Lisp. And then I came across a throwaway line in the YQL documentation about JSONP with a callback is a also called continuation-passing style. A little Googling finds this fascinating lecture by Douglas Crockford, a short summary by John Lam that makes it clear that the continuation idea is obvious to anyone who's done any asynchronous Javascript like AJAX, and a more intellectual discussion by Matt Might that goes through the Lisp side.
Now that it turns out that I already understand continuations, I'll have to go back and prove that to myself. And yes, Javascript is Lisp in C's clothing.
Posted by Danny on March 3, 2011 at 1:25 pm under Javascript.
Comment on this post.
I've been playing with search engines and for the search API I'm going with Bing; Google limits their free API to 100 queries a day and requires creating a custom search engine. Bing requires signing up and getting an "AppID" but from there it's unlimited. Documentation is, well, Microsoftian: impossible to find and hard to use when you get it, but there's a PDF (!) that explains things pretty well. I decided to do everything on the server rather than being fancy with AJAX; the user has to wait either way and usually wants to leave the current page anyway (that's why he's searching!). Continue reading ‘A Search Box for the Website’ »
Posted by Danny on February 25, 2011 at 2:10 am under PHP.
3 Comments.
I'm not a fan of having to create a Google Custom Search Engine to limit searches to one site with an HTML form (which seems to be necessary for mobile sites), so let's play with Bing:
<form method="get" action="http://www.bing.com/search" >
<input name="q" type="text"/>
<input type="submit" value="Search with Bing"/>
<input name="q1" value="site:http://bililite.nfshost.com/blog" type="hidden"/>
</form>
And it works, but fails again on the mobile site, just like Google. This may get better as the search engines figure it out, but I'm going to have to write my own search engine portal. What a pain.
Actually, not such a pain. Something like:
header('Location: http://www.bing.com/search?q='.urlencode($_GET['q']).'+'.urlencode($_GET['q1']))
for Bing and
header('Location: http://www.google.com/search?q='.urlencode($_GET['q']).'+site:'.urlencode($_GET['sitesearch']))
for Google. And that's what I did for the Young Israel site
Posted by Danny on February 24, 2011 at 12:21 pm under Web Design.
Comment on this post.
Earlier, I noted that the old, simple Google search:
<form method="get" action="http://www.google.com/search" >
<input name="q" type="text"/>
<input type="submit" value="Search with Google"/>
<input name="sitesearch" value="http://bililite.nfshost.com/blog" type="hidden"/>
</form>
is deprecated and doesn't work from Google's mobile site. Google does have an API for custom searches that has all sorts of fancy parameters to manipulate, but it requires signing up for a key and constructing the search ahead of time. However, some experimentation shows that not including a key brings back the old, simple search query (with a new URL and some new parameters), so we're back in business:
<form method="get" action="http://www.google.com/cse" >
<input name="q" type="text"/>
<input type="submit" value="Search with Google"/>
<input name="as_sitesearch" value="http://bililite.nfshost.com/blog" type="hidden"/>
</form>
And there's all sorts of interesting things hidden in there, like sorting by date (Google tries to guess that, but doesn't do so well):
<form method="get" action="http://www.google.com/cse" >
<input name="q" type="text"/>
<input type="submit" value="Search with Google"/>
<input name="as_sitesearch" value="http://bililite.nfshost.com/blog" type="hidden"/>
<input name="sort" value="date:d" type="hidden"/>
</form>
And the entire Web Search API is deprecated, so I'll have to change the googleSearch widget to use the JSON Custom Search API eventually.
Overall, sweet. At least until Google changes things again.
Addendum: it looks as though the mobile site does require the cx
parameter to limit the search to a specific site. Oh, well. It's not that hard to create a custom search.
Posted by Danny on February 23, 2011 at 5:20 pm under Web Design.
1 Comment.