Annoying bug in Quartz PDFContext font handling

I’ve been battling a PDF-generation problem on iOS for the last couple of days: PDFs generated on iPhone or iPad using the Quartz PDFContext Apple supply cause an error to pop up and then don’t look right in Adobe Reader. I had presumed it to be a problem in my code, but have now found that Pages, Numbers and Keynote on iPad have exactly the same issue.

Update: iOS 4.2 fixes this issue; it is important that you do not use any of the techniques in this post on that release or later as doing so will degrade a correct PDF rather than improving an invalid PDF.

While a PDF is being generated on the iOS device, you can see these messages on the device console if you run it in Xcode:

<Error>: invalid Type1 font: unable to stream font.

This message appears every time you change font.  I tried each of the fonts on the device, and then an OTF font which Font Book on my Mac says is really an OTF wrapper around a Type1 font: each of them provoked that error message and each of them caused the same behaviour from Adobe Reader.

Inspecting the generated PDF file reveals why Adobe Reader doesn’t like it.  The font object is specified thus:

7 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /ZTANHK+Helvetica-Bold /FontDescriptor
135 0 R /Widths 136 0 R /FirstChar 32 /LastChar 122 /Encoding /MacRomanEncoding
>>
endobj

This is fine. The strange-looking name /ZTANHK+Helvetica-Bold indicates that the parts of the font required to render the document are included within the PDF; it would be /Helvetica-Bold if the font was external or completely included in the document. There are two other PDF objects referenced by this declaration, by /FontDescriptor and /Widths in the above, so a working hypothesis is that one of those is wrong. The /Widths object looks fine, so I concentrated on the /FontDescriptor, object 135:

135 0 obj
<< /Type /FontDescriptor /Ascent 770 /CapHeight 720 /Descent -230 /Flags 4
/FontBBox [-1018 -481 1437 1160] /FontName /ZTANHK+Helvetica-Bold /ItalicAngle
0 /StemV 0 /AvgWidth 479 /MaxWidth 1500 /MissingWidth 479 /XHeight 532 /FontFile
133 0 R >>
endobj

Again that’s fine. It defines a bunch of other data about the font, and the /FontFile says that object 133 contains the font data. So let’s look at that:

133 0 obj
<< /Length 134 0 R /Length1 130 0 R /Length2 131 0 R /Length3 132 0 R /Filter
/FlateDecode >>
stream
Hex: 7801 0300 0000 0001
endstream
endobj

Aha, now I see the problem. That object should contain a Type1 font that specifies at least all the glyphs used by text object which use object 7 as their /Font; whereas it actually contains the result of compressing a zero-length buffer with the deflate algorithm and adding the usual headers.

I have reported this bug to Apple.

Temporary workaround

For some fonts, there is a way to deal with the problem. If the font is in this list:

  • Times-Roman
  • Helvetica
  • Courier
  • Symbol
  • Times-Bold
  • Helvetica-Bold
  • Courier-Bold
  • ZapfDingbats
  • Times-Italic
  • Helvetica-Oblique
  • Courier-Oblique
  • Times-BoldItalic
  • Helvetica-BoldOblique
  • Courier-BoldOblique

You can do some relatively minor surgery to the PDF file and have it display correctly everywhere. These fonts are known as the standard 14 fonts. All PDF viewers are required to know about these fonts without them being embedded in the document. To exploit this facility we need to change the /Font object to this:

7 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold /FontDescriptor
135 0 R /Widths 136 0 R /FirstChar 32 /LastChar 122 /Encoding /MacRomanEncoding
>>
endobj

And the /FontDescriptor to this:

135 0 obj
<< /Type /FontDescriptor /Ascent 770 /CapHeight 720 /Descent -230 /Flags 4
/FontBBox [-1018 -481 1437 1160] /FontName /Helvetica-Bold /ItalicAngle
0 /StemV 0 /AvgWidth 479 /MaxWidth 1500 /MissingWidth 479 /XHeight 532 >>
endobj

In summary the changes are to unmangle the font name in both objects and to remove the /FontFile attribute from the /FontDescriptor. You can also remove the object referenced by /FontFile if no other objects refer to it.

You can make the same changes when the font is not one of the standard 14 fonts, and it will be displayed correctly on machines which have that font installed. Unfortunately it will not look good on machines which do not have that font installed.

13 Responses to “Annoying bug in Quartz PDFContext font handling”

  1. Nikhil Rastogi

    Hi,

    “In summary the changes are to unmangle the font name in both objects and to remove the /FontFile attribute from the /FontDescriptor. You can also remove the object referenced by /FontFile if no other objects refer to it.

    You can make the same changes when the font is not one of the standard 14 fonts, and it will be displayed correctly on machines which have that font installed. Unfortunately it will not look good on machines which do not have that font installed.”

    Can you tell where I have to make these changes?

    Reply
  2. erwin

    Dear Phil,
    First, thanks for your sharing.
    But i have some question, i use Quartz framework to generate a new pdf, the font is ZBUYOI+ArialM, then i modify pdf through your solution, it still have text garbled. I would be very appreciated that if you can give me a hand.

    Original Context:
    261 0 obj
    <>
    endobj
    ….
    156 0 obj
    <>
    endobj

    Modify Result:
    261 0 obj
    <>
    endobj
    ….j
    156 0 obj
    <>

    Reply
  3. netfruit

    Hi! How can I change these properties at runtime using quartz methods? Where or how can I find the information about the pdf metadata and how can I change them?

    Thank you very much!

    Reply
  4. s3cc0

    Hello, i have found this page because i have the same problem, but i dont understand what u mean? or what did i change (in runtime) … i send this pdf with the mail to my customers. Pls help :)
    I look forward to hearing from u.

    Reply
  5. Phil

    If you want code to post-process PDF files in this way, and you cannot write it yourself, I recommend you pay someone else to write it for you. Many companies, including mine, supply code and coders on a commercial basis.

    Reply
  6. Nicolas

    I am using the latest 4.2 SDK and I still get those error messages… I am drawing all my texts with the [NSString drawInRect:withFont:lineBreakMode:alignment] method and they don’t display correctly on windows. What is your source concerning the fix in iOS 4.2 ?

    Reply
    • Phil

      Apple said it was fixed in a note on my bug report, and my own testing confirmed that it was fixed.

      The SDK version is irrelevant, the runtime version of the device is what determines whether this bug is present or absent.

      I use CoreText routines to draw text in my PDFs, as I suspect do the iWork apps, so it is always possible that there is still a problem here when the routine you mention is used.

      Reply
      • Nicolas

        Hey Phil thanks for the quick reply !
        I was wondering if you use CoreText, how do you manage text alignment ? The way I see it I have do it myself. I didn’t find any documented solution on this

        Reply
  7. Nicolas

    Sorry nevermind I found a way of keeping my system and using CoreText. Thanks for the tip it was useful.
    Cheers

    Reply
  8. Sapana

    Please where i want do this change. For removing the error “: invalid Type1 font: unable to stream font.”

    Reply

Leave a Reply

  • (will not be published)

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>