Whether you’re creating a new invoice layout or adding extra details to your delivery note, Magento PDFs are notoriously a pain in the arse to modify. The reason for this is that they are built from the class Zend_Pdf which positions most of its data using co-ordinates. You’re gonna need the orienteering nous of a deep-sea fisherman to make the changes you’re hoping for!
The class Zend_Pdf is an excellent framework for building PDF documents because it give you all the tools necessary for setting the page size, adding text, changing font colours, inserting images and so on. All elements are positioned with co-ordinates just like a vector canvas.
Which files should I extend?
I’m going to focus on the sales PDFs used to create PDF invoices, delivery notes and credit memos.
Navigate to app/code/core/Mage/Sales/Model/Order/Pdf
From here we have an abstract class called ‘Abstract.php’ and several other object classes from which the others extend from. They are:
From here you can obviously decide which file you’d like to extend based on which file you want to alter. I don’t recommend ever extending abstract classes because you can override those methods in the object classes if you need to.
Ok so if I asked you to point to 70:50 on a piece of A4 paper, you’d probably count 70mm down and 50mm across. These PDFs work differently. The starting point for all co-ordinates is the bottom left corner. If you navigate to the Zend_Pdf_Page class you can see the sizes of each page:
const SIZE_A4 = '595:842:'; const SIZE_A4_LANDSCAPE = '842:595:'; const SIZE_LETTER = '612:792:'; const SIZE_LETTER_LANDSCAPE = '792:612:';
There are no units or context for these dimensions that I am aware of. If you take a look at the picture below, it demonstrates where the dimensions start and end.
Alongside the $order object instance which is obviously quite useful for a PDF about your order, the object that most methods are applied to is $page which is just an instance of the page we’re creating.
This actually prints out text on your page. The parameters are text, x, y, format. So the follow text would appear near the top left of the page:
$page->drawText("My Text", 35, 770, 'UTF-8');
Before adding the text you may want to set the font size and colour. The following will set the font to a regular style rather than bold and in size 6. The next sets it to bold, and the next to italic.
$this->_setFontRegular($page, 6); $this->_setFontBold($page, 6); $this->_setFontItalic($page, 6);
It’s entirely likely that you’ll want to write text, but constrain it into a certain area without it running off the page. This helper method will count the characters and split your string onto as many lines as necessary. You just pass your text as a string into the function, then decide on a character count.
Mage::helper('core/string')->str_split($text, 100, true, true);
Drawing Boxes & Lines
It’s common to need to draw boxes and lines to separate information. You first decide if you’d like to fill it with a colour. Then you simply enter the X & Y co-ordinates of the box for each of the four points.
$page->setFillColor(new Zend_Pdf_Color_Rgb(0.93, 0.92, 0.92)); $page->setLineWidth(0.5); $page->drawRectangle(30, 30, 50, 50); $page->drawLine(380, 30, 380, 40);
This is how it works, the first two arguments are the x & y co-ordinates of the bottom-left corner of the box, and the final two arguments are the x & y co-ordinates of the top-right corner of the box. So the following code would create a 20×20 box in the bottom-left corner of the page and a rectangle in the top-right corner.
$page->drawRectangle(30, 30, 50, 50); // a) $page->drawRectangle(400, 600, 590, 830); // b)
Which would look like this:
Adding images is very similar to drawing a rectangle except this time you pass in a fifth argument, which is obviously the path to the image.
$image = Zend_Pdf_Image::imageWithPath("path/to/your/image.jpg"); $page->drawImage($image, 0, 750, 595, 842);
The above example will put an image which will stretch across the top of the page, like so:
Increment and Decrement Y
My final tip is about incrementing a decrement Y. Remember the length of Y is 842 on an A4 document. So at the start of your class you’ll have Y set to somewhere near this point. I think by default it is 820. As you start adding elements to your page you’ll want to start moving down the page (easier than building upwards).
If I want to set Y to a value, it’s simply like this:
$this->y = 820;
If I want to decrement the Y value by 10 as I move down the page, it’s this:
So rather than putting an element on a specific point on a page, I can choose the current Y position and build from there by passing the Y value as an argument. For example:
$page->drawRectangle(25, $this->y, 275, $this->y-25);
Thanks for reading, I’d like to hear any feedback you may have.