{"id":1699,"date":"2011-03-24T22:25:37","date_gmt":"2011-03-25T04:25:37","guid":{"rendered":"http:\/\/bililite.nfshost.com\/blog\/?p=1699"},"modified":"2011-04-01T17:23:12","modified_gmt":"2011-04-01T23:23:12","slug":"creating-pdfs-with-php-part-2","status":"publish","type":"post","link":"https:\/\/bililite.com\/blog\/2011\/03\/24\/creating-pdfs-with-php-part-2\/","title":{"rendered":"Creating PDFs with PHP, part 2: A Blank Page"},"content":{"rendered":"<p>Continuing <a href=\"\/blog\/2011\/03\/18\/creating-pdfs-with-php\/\">my attempt<\/a> to dissect <a href=\"http:\/\/fpdf.org\">FDPF<\/a> to understand PDF's, we'll create the simplest PDF: a blank page.<\/p>\r\n<p>We need a couple of objects:<\/p>\r\n<dl>\r\n<dt><a href=\"http:\/\/www.adobe.com\/content\/dam\/Adobe\/en\/devnet\/pdf\/pdfs\/PDF32000_2008.pdf?page=73\">Catalog<\/a><\/dt>\r\n<dd>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.<\/dd>\r\n<dd><pre><code class=\"language-pdf\">1 0 obj\r\n&lt;&lt;\r\n  \/Type \/Catalog\r\n  \/Pages 0 2 R % reference to object number 2\r\n&gt;&gt;\r\nendobj<\/code><\/pre><\/dd>\r\n<dd>One useful optional entry in the catalog is the <code class=\"language-pdf\">\/OpenAction<\/code> that can be used to set the <a href=\"http:\/\/www.adobe.com\/content\/dam\/Adobe\/en\/devnet\/pdf\/pdfs\/PDF32000_2008.pdf?page=365\">zoom level and opening page<\/a>. \r\n <code class=\"language-pdf\">\/OpenAction [3 0 R \/Fit]<\/code> starts at the page described in object 3 and zooms in to fit the page on the screen.<\/dd>\r\n<\/dl><!--need to split the DL to put the more comment in-->\r\n<p><a href=\"\/blog\/blogfiles\/pdf\/pdftest.php?which=1&amp;output=source\">See the code<\/a>.<\/p>\r\n<!--more-->\r\n<dl>\r\n<dt><a href=\"http:\/\/www.adobe.com\/content\/dam\/Adobe\/en\/devnet\/pdf\/pdfs\/PDF32000_2008.pdf?page=76\">Pages<\/a><\/dt>\r\n<dd>The collection of pages. This is just an array of references to the actual pages or to sub-collections of pages. The manual talks about organizing the pages in a balanced tree to make skipping around faster, but we're not that fancy. Our tree is flat. It also includes a <code class=\"language-pdf\">\/Count<\/code> entry with the total number of pages (which is not the same as the number of items in the array, since the array could contain references to other Pages collections).<\/dd>\r\n<dd><pre><code class=\"language-pdf\">2 0 obj\r\n&lt;&lt;\r\n  \/Type \/Pages\r\n  \/Kids [ 4 0 R ] % One page. They were too cute by half, calling the child objects \"Kids\"\r\n  \/Count 1\r\n&gt;&gt;\r\nendobj<\/code><\/pre><\/dd>\r\n<dt><a href=\"http:\/\/www.adobe.com\/content\/dam\/Adobe\/en\/devnet\/pdf\/pdfs\/PDF32000_2008.pdf?page=83\">Resources<\/a><\/dt>\r\n<dd>The resource dictionary that assigns names to all the \"stuff\" we need on the page&mdash;images, fonts, \"graphic states\" (sets of graphic commands to set the color, pen size, line styles, transparency, etc.) and other things. The page-drawing language (called a \"content stream\" does not refer to objects in the PDF by number (like <code class=\"language-pdf\">2 0 R<\/code>) but by the name given in the page's resource dictionary. Since our page doesn't have any content, the dictionary is empty:<\/dd>\r\n<dd><pre><code class=\"language-pdf\">3 0 obj\r\n&lt;&lt;\r\n&gt;&gt;\r\nendobj<\/code><\/pre><\/dd>\r\n<dd>PDF originally required a <code class=\"language-pdf\">\/ProcSet<\/code> entry listing the types of commands used on a page, but <a href=\"http:\/\/www.adobe.com\/content\/dam\/Adobe\/en\/devnet\/pdf\/pdfs\/PDF32000_2008.pdf?page=547\">that's now obsolete<\/a>; all the commands are always available. fPDF still includes it, though.<\/dd>\r\n<dt><a href=\"http:\/\/www.adobe.com\/content\/dam\/Adobe\/en\/devnet\/pdf\/pdfs\/PDF32000_2008.pdf?page=77\">Page<\/a><\/dt>\r\n<dd>A description of a single page. Mostly just a reference to its contents, which is a stream and as such cannot be directly included (the definition could have allowed the page itself  to be the content stream, but that would have been too easy), and the page size, as a rectangle of point (1\/72 inch) measures that sets the coordinate system for drawing. Also includes references to its parent <code>Pages<\/code> collection and the resource dictionary (you could have a separate resource dictionary for every page, but I can't imagine why you'd want to ).<\/dd>\r\n<dd><pre><code class=\"language-pdf\">4 0 obj\r\n&lt;&lt;\r\n  \/Type \/Page\r\n  \/Parent 2 0 R\r\n  \/Resources 3 0 R\r\n  \/Contents 5 0 R\r\n  \/MediaBox [ 0 0 612 792 ] % letter-size, in points.\r\n&gt;&gt;\r\nendobj<\/code><\/pre><\/dd>\r\n<dt><a href=\"http:\/\/www.adobe.com\/content\/dam\/Adobe\/en\/devnet\/pdf\/pdfs\/PDF32000_2008.pdf?page=81\">Contents<\/a><\/dt>\r\n<dd>The actual content stream for drawing the page. We don't do anything, so this is empty:<\/dd>\r\n<dd><pre><code class=\"language-pdf\">5 0 obj\r\n&lt;&lt;\r\n  \/Length 0\r\n&gt;&gt;\r\nstream\r\nendstream\r\nendobj\r\n<\/code><\/pre><\/dd>\r\n<\/dl>\r\n<p>We can put these parts together to create a <a href=\"\/blog\/blogfiles\/pdf\/pdftest.php?which=1&amp;output=source\">class that produces blank pages<\/a>:<\/p>\r\n<pre><code class=\"language-php\">$pdf = new bililitePDF_1();\r\n$pdf->newPage();\r\n$pdf->output();\r\n<\/code><\/pre>\r\n<p>And you can see the result <a href=\"\/blog\/blogfiles\/pdf\/pdftest.php?which=1&count=1\">here<\/a>. Or even create <a href=\"\/blog\/blogfiles\/pdf\/pdftest.php?which=1&count=3\">multiple pages<\/a>. 150 lines of code to do nothing! Whoohoo! But it's a start to putting some real content in those pages.<\/p>\r\n<p><a href=\"\/blog\/2011\/03\/31\/creating-pdfs-with-php-part-3\/\">Continued&hellip;<\/a><\/p>","protected":false},"excerpt":{"rendered":"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 [&hellip;]","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[15,9],"tags":[],"_links":{"self":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/1699"}],"collection":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/comments?post=1699"}],"version-history":[{"count":27,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/1699\/revisions"}],"predecessor-version":[{"id":1784,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/1699\/revisions\/1784"}],"wp:attachment":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/media?parent=1699"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/categories?post=1699"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/tags?post=1699"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}