PDF Font embedding problem in Magento / Zend Framework

Tweet about this on TwitterShare on LinkedInShare on Google+Share on FacebookEmail this to someone

Have you ever had problems with custom fonts embedding, while trying to generate PDF ducoments in Magento or using Zend Framework. May be I found solution for you, If you get next error message:

This font cannot be embedded in the PDF document. If you would like to use it anyway, you must pass Zend_Pdf_Font::EMBED_SUPPRESS_EMBED_EXCEPTION in the $options parameter of the font constructor.

As a result of my research I decided, that the problem comes from Zend Framework core and seems, that it doesn’t recognize correctly if your custom font can be embedded if has some embedding permissions.

What I mean, when say embedding permissions:

  • Licensed for print and preview embedding
  • Licensed for editable embedding
  • Licensed for modification

I am suggesting next workaround / quick fix:

There is a file Zend/Pdf/Resource/Font/FontDescriptor.php in Zend Framework core. My suggestion is to comment from line 161 to line 173 and also we need to comment line 199. By this modification we pass the check if our custom font can’t be embedded.

Notice: Never modify core files!!!

For reference take a look at next code in file Zend/Pdf/Resource/Font/FontDescriptor.php from line 161 to line 199 :

//            if (! $fontParser->isEmbeddable) {
//                /* This exception may be suppressed if the developer decides that
//                 * it's not a big deal that the font program can't be embedded.
//                 */
//                if (!($embeddingOptions & Zend_Pdf_Font::EMBED_SUPPRESS_EMBED_EXCEPTION)) {
//                    $message = 'This font cannot be embedded in the PDF document. If you would like to use '
//                             . 'it anyway, you must pass Zend_Pdf_Font::EMBED_SUPPRESS_EMBED_EXCEPTION '
//                             . 'in the $options parameter of the font constructor.';
//                    #require_once 'Zend/Pdf/Exception.php';
//                    throw new Zend_Pdf_Exception($message, Zend_Pdf_Exception::FONT_CANT_BE_EMBEDDED);
//                }
//
//            } else {
                /* Otherwise, the default behavior is to embed all custom fonts.
                 */
                /* This section will change soon to a stream object data
                 * provider model so that we don't have to keep a copy of the
                 * entire font in memory.
                 *
                 * We also cannot build font subsetting until the data provider
                 * model is in place.
                 */
                $fontFile = $fontParser->getDataSource()->readAllBytes();
                $fontFileObject = $font->getFactory()->newStreamObject($fontFile);
                $fontFileObject->dictionary->Length1 = new Zend_Pdf_Element_Numeric(strlen($fontFile));
                if (!($embeddingOptions & Zend_Pdf_Font::EMBED_DONT_COMPRESS)) {
                    /* Compress the font file using Flate. This generally cuts file
                     * sizes by about half!
                     */
                    $fontFileObject->dictionary->Filter = new Zend_Pdf_Element_Name('FlateDecode');
                }
                if ($fontParser instanceof Zend_Pdf_FileParser_Font_OpenType_Type1 /* not implemented now */) {
                    $fontDescriptor->FontFile  = $fontFileObject;
                } else if ($fontParser instanceof Zend_Pdf_FileParser_Font_OpenType_TrueType) {
                    $fontDescriptor->FontFile2 = $fontFileObject;
                } else {
                    $fontDescriptor->FontFile3 = $fontFileObject;
                }
//            }

I experienced this problem in Magento, while was trying to create some invoice PDF documents. So what we need to do is to copy /lib/Zend/Pdf/Resource/Font/FontDescriptor.php to /app/code/local/Zend/Pdf/Resource/Font/FontDescriptor.php and to apply the change to /app/code/local/Zend/Pdf/Resource/Font/FontDescriptor.php

Hope, that may help to somebody.

Cheers :)

How came?

My client sent me examples how generated PDF documents should look and he wanted custom font to be used. The font name is Gill Sans.

So I did everything needed to embed it:

    protected function _setFontBold($object, $size = 10)
    {
        $font = Zend_Pdf_Font::fontWithPath(Mage::getBaseDir() . '/lib/GillSans/GillSans.ttf');
        $object->setFont($font, $size);
        return $font;
    }

but got the error:

This font cannot be embedded in the PDF document. If you would like to use it anyway, you must pass Zend_Pdf_Font::EMBED_SUPPRESS_EMBED_EXCEPTION in the $options parameter of the font constructor.

I googled about Gill Sans embed permissions and landed on next page:
http://www.adobe.com/type/browser/legal/additional_licenses.html

From this page I understand, that I have the permission to embed Gill Sans for print and preview, but I am not allowed to embed it for edit or modifications … but seems, that Zend Framework doesn’t allow me to embed it for print and preview.

I had no time for deep research about the problem, but found the code in /lib/Zend/Pdf/FileParser/Font/OpenType.php from line 570 to line 597:

        /* Describes the font embedding licensing rights. We can only embed and
         * subset a font when given explicit permission.
         *
         * NOTE: We always interpret these bits according to the rules defined
         * in version 3 of this table, regardless of the actual version. This
         * means we will perform our checks in order from the most-restrictive
         * to the least.
         */
        $embeddingFlags = $this->readUInt(2);
        $this->_debugLog('Embedding flags: %d', $embeddingFlags);
        if ($this->isBitSet(9, $embeddingFlags)) {
            /* Only bitmaps may be embedded. We don't have the ability to strip
             * outlines from fonts yet, so this means no embed.
             */
            $this->isEmbeddable = false;
        } else if ($this->isBitSet(1, $embeddingFlags)) {
            /* Restricted license embedding. We currently don't have any way to
             * enforce this, so interpret this as no embed. This may be revised
             * in the future...
             */
            $this->isEmbeddable = false;
        } else {
            /* The remainder of the bit settings grant us permission to embed
             * the font. There may be additional usage rights granted or denied
             * but those only affect the PDF viewer application, not our code.
             */
            $this->isEmbeddable = true;
        }

The comment, that disturbed me is:

            /* Restricted license embedding. We currently don't have any way to
             * enforce this, so interpret this as no embed. This may be revised
             * in the future...
             */

So community, do you have some experience in this area? May be you can share your thoughts.

Tweet about this on TwitterShare on LinkedInShare on Google+Share on FacebookEmail this to someone

Tsvetan Stoychev

Tsvetan aka. Cecko is the founder of Cecko's Lab. He is Magento addicted since Magento CE 1.2.1.2 and has worked on over 30 Magento projects. At the moment he is in charge to take care about the money flow of the company, to keep constant communication with the clients and to keep the people in the office busy.

More Posts

Follow Me:
TwitterLinkedIn

  • A Fulde

    Hi Tsvetan,

    thanks for your post. Where do I embed the protected function and set the name (in my example ‘Calibri’) to use it in pdf?

    Cheers Andy

  • ceckoslab

    Hi Andy,

    In my case I did this for the Invoices … I extended Mage_Sales_Model_Order_Pdf_Invoice
    and embed the font in _setFontRegular(), _setFontBold(), _setFontItalic() … 

    You also can do search for Zend_Pdf_Font to see, where in Magento we embed the fonts.

    Thanks.