Skip to Content
Sep 13, 2017 at 10:24 PM

Extra characters when exporting Crystal Report to PDF


Hi, I'm experiencing the problem described in this KB article when using Crystal Reports Developer for Visual Studio SP21 (which I think is the latest version currently available). The KB article says the cause is usp10.dll being loaded from the Windows System directory instead of from C:\Program Files (x86)\SAP BusinessObjects\Crystal Reports for .NET Framework 4.0\Common\SAP BusinessObjects Enterprise XI 4.0\win32_x86, but I've checked with Process Explorer and Process Monitor, and it's using the DLL from the Crystal directory.

This problem has been reported on the forums numerous times, e.g., here, here, here, and here, but there never seems to be a real fix, only workarounds :( The "best" workaround being Vitaly Vedmetskiy's comment in this thread, where he suggests a specific version of usp10.dll to use (as a followup to a comment from someone at SAP who said that "We need a very specific version of usp10.dll for our text rendering to work correctly." Which raises the questions of why SAP is distributing version 1.626.7601.23259 if CR's text rendering doesn't work properly with that version) But as I said, that's just a workaround—Crystal shouldn't need a very specific version of usp10.dll, especially not one from all the way back in 2005 (which is the date of usp10.dll 1.422.3790.1830). There's nothing wrong with the newer versions usp10.dll.

The reason newer versions of usp10.dll don't work is that they now use an OpenType font's Standard Ligature ('liga') table to do automatic ligature substitution. E.g., if some text has the characters "fi", the font can tell the renderer (e.g., usp10.dll) to display that as the ligature fi. The bug in Crystal's PDF export is that it doesn't handle that substitution correctly. When it generates a subset of the font to embed in the PDF, it maps the first character of the ligature to the glyph of the whole ligature. For example, if the text contains "fi", it maps "f" to the "fi" ligature, turning all other "f"s (even when not followed by "i") to the "fi" ligature.

To demonstrate, I created a simple report, which just has a single text box with the text "ta ti fa fi" in Calibri font (most of the other "C" fonts that were introduced with Windows Vista will show the same problem—Candara, Constantia, and Corbel). Here's how it looks in the report design view. Notice how the "ti" and "fi" are connected.

If you click in it to edit the text, they change to separate letters:

Then if you go to the Report Preview tab, right-click and Export to a PDF file, it turns into this:

The PDF is compressed, but there are various utilities that can uncompress it... if you do that and look at the text that's being displayed, you'll see:

[t, 13, a t , f, 19, a f] TJ

That means display a "t", move an extra 13 units to the right, display "a t ", display "f", move an extra 19 units to the right, display "a f". Put that together and you see it thinks it should be displaying "ta t fa f". And indeed, if you copy the text from Acrobat Reader and paste it, that's exactly what you get. So if it thinks it's displaying "ta t fa f", why does it look like "tia ti fia fi"? Because there's a mapping in the PDF between characters and the glyph (image) that should be displayed for that character. And the PDF generated by CR maps "t" to the glyph for the "ti" ligature, and it maps "f" to the glyph for the "fi" ligature.

It appears that CR's PDF export is calling usp10.dll's ScriptShape function to determine the list of glyphs for a piece of text, but it doesn't seem to be doing the right thing when multiple characters are replaced by a single glyph. Ideally, the export would be fixed so it handles that case properly. But I guess a quick and dirty fix would be to tell usp10 to disable processing of the "liga" table. And the reason why old versions of usp10.dll "fix" the problem is because they don't process the "liga" table... disabling "liga" processing on a new usp10.dll would give the effect of reverting to an old usp10.dll, without the hassle of having to actually get an old version of the DLL.

Anyways, I hope the Crystal Reports developers will fix this once and for all.