pcorless / icepdf

PDF Rendering and Viewing API in Java
Apache License 2.0
81 stars 21 forks source link

loadOrReadSystemFonts throughing exception on failure #346

Closed sonideft closed 6 months ago

sonideft commented 7 months ago

In my configuration, calling this function is generating an exception when it fails to retrieve fonts from the system. Ideally it should log an error or warning message, but not generate an exception. I am running Java 20 on Windows 10 and I call this function prior to trying to open a pdf document in the Swing Viewer. This is the exception: java.io.IOException: 'head' table is mandatory at org.apache.fontbox.ttf.TTFParser.parseTables(TTFParser.java:198) at org.apache.fontbox.ttf.TTFParser.parse(TTFParser.java:165) at org.apache.fontbox.ttf.TTFParser.parse(TTFParser.java:110) [catch] at org.icepdf.core.pobjects.fonts.zfont.fontFiles.ZFontTrueType.(ZFontTrueType.java:60) at org.icepdf.core.pobjects.fonts.zfont.fontFiles.ZFontTrueType.(ZFontTrueType.java:48) at org.icepdf.core.pobjects.fonts.FontFactory.createFontFile(FontFactory.java:151) at org.icepdf.core.pobjects.fonts.FontFactory.createFontFile(FontFactory.java:139) at org.icepdf.core.pobjects.fonts.FontManager.buildFont(FontManager.java:872) at org.icepdf.core.pobjects.fonts.FontManager.buildFont(FontManager.java:855) at org.icepdf.core.pobjects.fonts.FontManager.evaluateFontForInsertion(FontManager.java:448) at org.icepdf.core.pobjects.fonts.FontManager.loadSystemFont(FontManager.java:426) at org.icepdf.core.pobjects.fonts.FontManager.readSystemFonts(FontManager.java:397) at org.icepdf.core.pobjects.fonts.FontManager.readSystemFonts(FontManager.java:410) at org.icepdf.ri.util.FontPropertiesManager.readDefaultFontProperties(FontPropertiesManager.java:91) at org.icepdf.ri.util.FontPropertiesManager.loadOrReadSystemFonts(FontPropertiesManager.java:75)

Here is the relevant code: controller = new SwingController(); controller.setIsEmbeddedComponent(true); // read stored system font properties. FontPropertiesManager fontPropertiesManager = FontPropertiesManager.getInstance(); fontPropertiesManager.loadProperties(); fontPropertiesManager.loadOrReadSystemFonts();

        ViewerPropertiesManager properties = ViewerPropertiesManager.getInstance();
        properties.getPreferences().putFloat(ViewerPropertiesManager.PROPERTY_DEFAULT_ZOOM_LEVEL, 1.25f);
        factory = new SwingViewBuilder(controller, properties);
        // add interactive mouse link annotation support via callback
        controller.getDocumentViewController().setAnnotationCallback(
                new org.icepdf.ri.common.MyAnnotationCallback(controller.getDocumentViewController()));

Any suggestions welcome

pcorless commented 7 months ago

There are a lot of try/catches along the way, I can't see a way that exception would bubble all way the way up to fontPropertiesManager.loadOrReadSystemFonts(); Which version of the library are you using?

There can be a lot of noisy logs when reading the systems fonts but it should carry on with reading the various font directories. Perhaps there is some other error occurring when loading the PDF file. I'd recommend enabling 'fine' level logging via the provided log config using the system property -Djava.util.logging.config.file="./logging.properties".

Failing that can you post the the code you use the open the PDF?

sonideft commented 7 months ago

I am using icepdf-core-7.2.0, icepdf-viewer-7.2.0 and fontbox-2.0.27. I also have itext-4.2.0 on the classpath, in case that matters.

The exception doesn't happen all the time, but when it does, it happens when I am initializing the window. The user action to actually open the pdf happens later after a user file-selects a pdf to display. Here is the code to open the pdf from a byte stream (loaded elsewhere): JPanel viewerComponentPanel = factory.buildViewerPanel(); jPanel42.removeAll(); jPanel42.add(viewerComponentPanel, BorderLayout.CENTER); controller.openDocument(buffer,0,buffer.length,Bundle.STRUCTURE_NOTES_EDITOR_PDF_DOCUMENT(),text); jPanel42.validate();

So, the exception only happens when my window is initially opening; which is one window within a NetBeans RCP application that is already open. This window presents a toolbar of pdf icons for all pdfs found in a directory. So I only open one pdf at a time, based on the user selecting one from the toolbar. On the surface it seems like org.icepdf.ri.util.FontPropertiesManager.loadOrReadSystemFonts is having difficulty with reading system fonts from Windows 10, from time to time. I may not need to call this function, but I thought it would be safer in case some pdfs try to load without their own fonts in the file?

I have seen this exception sporadically during testing. On the deployed app I had one user see it right away, which is not what I want to have happen (Dialog with exception popping up, etc.). If the library could prevent the exception from being raised and put more into the log of issues it encountered, that would be one possible solution. If this doesn't help clarify, I can look into how I can generate finer logs on icepdf.*

pcorless commented 7 months ago

In the font loading block

FontPropertiesManager fontPropertiesManager = FontPropertiesManager.getInstance();
fontPropertiesManager.loadProperties();
fontPropertiesManager.loadOrReadSystemFonts();

You can remove the loadProperties(), it's redundant in this case. The FontPropertiesManager just needs to run once when the application loads, I usually suggest putting it in a static block. The first scan of system fonts will take a few seconds to complete. Subsequent calls will pull from the cache greatly speeding up the libraries load/render time. I wonder if there is some permission issue that is keeping the cache from being created and every load is reading from the file system. But I'm still not sure how that would show up in your main app.

At the root of the libraries home on github there there a logging.properties file which is the default config for the library for java.util.logging. There are two areas that need to be edited:

.level=FINEST
java.util.logging.ConsoleHandler.level=FINEST

Once you've made the changes that best match your setup you can point the JDK or your IDE at the config.

pcorless commented 6 months ago

closing do to inactivity.