This tutorial is intended for the PHP programmer who needs to incorporate PDF generation in a script without using external libraries such as PDFlib (often unavailable due to licensing restrictions or lack of funds). This tutorial is the second of two parts, and builds on what was covered in the first part. Therefore, if you have not yet gone through Part 1, you are advised to do so (or at least read through it), before going through this tutorial (Part 2). Apart from what was dealt with in Part 1, no knowledge of PDF file structure is required to understand this tutorial, as all references are explained.
To keep this example simple the file checking is rather crude. We guess the image type according to what its extension is. Ideally we should be using a better way to check the image type, regardless of extension.
The _parseJPG() method does a further check to make sure we are dealing with a JPEG file.
We will need to add a few other functions to handle the inserting of images. First of all there is the _parseJPG() method we saw in the function above:
function _parseJPG
($file) { /* Extract info from the JPEG file. */ $img = @getimagesize($file); if (!$img) { die(sprintf('Missing or incorrect image file: %s', $file)); } /* Check if dealing with an actual JPEG. */ if ($img[2] != 2) { die(sprintf('Not a JPEG file: %s', $file)); } /* Get the image colorspace. */ if (!isset($img['channels']) || $img['channels'] == 3) { $colspace = 'DeviceRGB'; } elseif ($img['channels'] == 4) { $colspace = 'DeviceCMYK'; } else { $colspace = 'DeviceGray'; } $bpc = isset($img['bits']) ? $img['bits'] : 8; /* Read the whole file. */ $f = fopen($file, 'rb'); $data = fread($f, filesize($file)); fclose($f); return array('w' => $img[0], 'h' => $img[1], 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'DCTDecode', 'data' => $data); }
All that this function does is to check that the file format is JPEG, get the colorspace, and read the file data. It returns an array containing width, height, colorspace, bits, filter (always 'DCTDecode' for JPEG), and the actual data.
Our _putResources() function that we set up in Part 1 of this tutorial, now needs to add images as well. This is how the modified function should look. Note the added call to _putImages(), the extra parameters in the 'ProcSet' line, and the loop to output the image objects.
function _putResources
() { $this->_putFonts(); // Output any fonts. $this->_putImages(); // Output any images. /* Resources are always object number 2. */ $this->_offsets[2] = strlen($this->_buffer); $this->_out('2 0 obj'); $this->_out('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); $this->_out('/Font <<'); foreach ($this->_fonts as $font) { $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R'); } $this->_out('>>'); if (count($this->_images)) { // Loop through any images $this->_out('/XObject <<'); // and output the objects. foreach ($this->_images as $image) { $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R'); } $this->_out('>>'); } $this->_out('>>'); $this->_out('endobj'); }
The above function calls the _putImages() to output the actual image data: