RTF to PDF conversion problem

Hello,

I am currently using Aspose.Words 20.6 for Java and have a problem when converting RTF files to PDF files. Our web application is running on an Ubuntu server. When converting RTF files, the resulting PDF file has totally different fonts and spacing.

I have tried:

try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {

    final Document document = new Document(new ByteArrayInputStream(rtfFileByteArray));
    final PdfSaveOptions saveOptions = new PdfSaveOptions();
    saveOptions.setEmbedFullFonts(true);
    document.save(outputStream, saveOptions);

    return outputStream.toByteArray();

} catch (final Exception ex) {

}

I have also tried to use
saveOptions.setFontEmbeddingMode(PdfFontEmbeddingMode.EMBED_ALL);
or
saveOptions.setFontEmbeddingMode(PdfFontEmbeddingMode.EMBED_NONE);
but it makes no difference.

I have installed the ttf-mscorefonts-installer package on Ubuntu and fonts are located in the expected directory /usr/share/fonts/truetype/msttcorefonts/ but it still doesn’t work.

What do I have to do, so that the PDF file converted by Aspose.Words looks exactly the same as if had saved the RTF file directly in MS Office as PDF file?

Many thanks in advance.

@einkaufidv The problem on your side might occur because the fonts used in the source document are not available in the environment where the document is rendered to PDF. If Aspose.Words cannot find the fonts used in the document the fonts are substituted . This might lead into the layout difference, since substitution fonts might have different font metrics. You can implement IWarningCallback to get a notification when font substitution is performed.
The following articles can be useful for you:
https://docs.aspose.com/words/java/specify-truetype-fonts-location/
https://docs.aspose.com/words/java/install-truetype-fonts-on-linux/

ttf-mscorefonts-installer package includes only a very little part of MS fonts, it does not include them all, so there still might be missed fonts after installing this package on Linux.

Thanks for the response.

I have already read the two articles that is why I have installed ttf-mscorefonts-installer package as recommended in the article. However, it was not successful. Regarding the article about truetype font location, as far as I understand the article I don’t need to specify the location since fonts are located in a directory that aspose is checking by default. Is that true?

What else can I do?

@einkaufidv Have you tried implementing IWarningCallback to detect what fonts are missed? Also, could you please attach your source and output documents here for our reference? We will check the conversion on our side and provide you more information.

The fonts might be installed in different locations. By default, Aspose.Words looks for the fonts in all of the following locations: /usr/share/fonts, /usr/local/share/fonts, /usr/X11R6/lib/X11/fonts.

Thanks for the advice of implementing IWarningCallback. That is really helpful for testing. So far I get 3 warnings.

Font 'Arial' has not been found. Using 'Fanwood' font instead. Reason: first available font.
Font 'Symbol' ...
Font 'Times New Roman' ...

I would expect that at least Arial and Times New Roman can be found, since they are located under /usr/share/fonts/truetype/msttcorefonts/
Or does Aspose only look in /usr/share/fonts and not in its subdirectories by default?

I have attached the documents that I use for testing. documents.zip (55.8 KB)

Many thanks in advance.

@einkaufidv You can specify the folder with fonts explicitly. For example see the following code:

Document doc = new Document("/temp/in.docx");

doc.setFontSettings(new FontSettings());
doc.getFontSettings().setFontsSources(
    new FontSourceBase[] {
        new SystemFontSource(), // Search for fonts in the default system locations
        new FolderFontSource("/temp/fonts", true) // Search for fonts in the specified folder
    });

doc.save("/temp/out.pdf");

Thanks for your example code. I have tried it and I have also used the following code snippet to print all fonts found on the system and the folder with the additional fonts.

log.info("Available system fonts:");
for (PhysicalFontInfo fontInfo : (Iterable<PhysicalFontInfo>)new SystemFontSource().getAvailableFonts())
{
    log.info("FontFamilyName : " + fontInfo.getFontFamilyName());
    log.info("FullFontName  : " + fontInfo.getFullFontName());
    log.info("Version  : " + fontInfo.getVersion());
    log.info("FilePath : " + fontInfo.getFilePath());
}

// Get available fonts in folder
log.info("Fonts in folder:");
for (PhysicalFontInfo fontInfo : (Iterable<PhysicalFontInfo>)new FolderFontSource("/usr/share/fonts", true).getAvailableFonts())
{
    log.info("FontFamilyName : " + fontInfo.getFontFamilyName());
    log.info("FullFontName  : " + fontInfo.getFullFontName());
    log.info("Version  : " + fontInfo.getVersion());
    log.info("FilePath : " + fontInfo.getFilePath());
}

// Get available fonts from FontSettings
ArrayList<FolderFontSource> fontSources = new ArrayList(
            Arrays.asList(FontSettings.getDefaultInstance().getFontsSources()));

// Convert the Arraylist of source back into a primitive array of FontSource
// objects.
FontSourceBase[] updatedFontSources = (FontSourceBase[])fontSources
        .toArray(new FontSourceBase[fontSources.size()]);

log.info("Fonts from FontSettings:");
for (PhysicalFontInfo fontInfo : (Iterable<PhysicalFontInfo>)updatedFontSources[0].getAvailableFonts())
{
    log.info("FontFamilyName : " + fontInfo.getFontFamilyName());
    log.info("FullFontName  : " + fontInfo.getFullFontName());
    log.info("Version  : " + fontInfo.getVersion());
    log.info("FilePath : " + fontInfo.getFilePath());
}

However, no fonts at all could be found.

@einkaufidv Could you please try to put the fonts into a separate folder and use it as font source? Can Aspose.Words find the fonts in this case? On my side the following code prints the available fonts properly:

Document doc = new Document("/temp/in.docx");

doc.setFontSettings(new FontSettings());
doc.getFontSettings().setFontsSources(
    new FontSourceBase[] {
        new SystemFontSource(), // Search for fonts in the default system locations
        new FolderFontSource("/temp/fonts/", true) // Search for fonts in the specified folder
    });

// Print the fonts available in the sources specified in FontSettings
for (FontSourceBase fsb : doc.getFontSettings().getFontsSources())
{
    for (PhysicalFontInfo fontInfo : fsb.getAvailableFonts())
    {
        System.out.println("FontFamilyName : " + fontInfo.getFontFamilyName());
        System.out.println("FullFontName  : " + fontInfo.getFullFontName());
        System.out.println("Version  : " + fontInfo.getVersion());
        System.out.println("FilePath : " + fontInfo.getFilePath());
    }
    System.out.println("=========================");
}

doc.save("/temp/out.pdf");

When I run the application as JAR locally on my Windows computer everything looks fine. I can print the font information and the rendered PDF looks as expected.

However, when I deploy the WAR file in a Tomcat on an Ubuntu server, no fonts can be found. I doesn’t matter in which folder I put the fonts. The print statements are empty.

I was thinking of storing the fonts maybe in a folder within the project and loading them as InputStream. Is there a way of directing to a font source folder, where the fonts are loaded as InputStream?

@einkaufidv You can read only a single font into a stream font source. Please see our documentation for more information:
https://reference.aspose.com/words/java/com.aspose.words/streamfontsource/

Is the folder with fonts accessible to your application on the server?

Many thanks for your help. Now it is working. When I used a java method to open and print out the content of the font folder, an exception was thrown. Obviously, I had no access to that folder.

java.security.AccessControlException: access denied ("java.io.FilePermission" "/usr/share/fonts" "read")

After adapting the java policy file and granting access to the folder the pdf file is generated as expected.

I was wondering why Aspose.Words is silently ignoring that kind of exceptions when accessing a folder with missing permissions and instead behaving like the folder was empty. IWarningCallback was very helpful for testing, maybe there should be another method where you can switch on printing/logging of missing permission exceptions.

Thanks again for all the effort and your help and also for the quick responses.

@einkaufidv Thank you for your suggestion. I have logged a feature request WORDSNET-25625. We will consider adding such warnings.

@einkaufidv You can use FontSourceBase.WarningCallback property to get notification when an issue is detected while loading fronts from the font source.

FontSettings settings = new FontSettings();
settings.SetFontsFolder("bad folder?", false);

FontSourceBase source = settings.GetFontsSources()[0];
IWarningCallback wc = new CustomWarningCallback();
source.WarningCallback = wc;

IList<PhysicalFontInfo> fontInfos = source.GetAvailableFonts();

Console.WriteLine((wc as IList<WarningInfo>)[0].Description);

Output will be:

Error loading font from the folder “bad folder?”: Illegal characters in path.

So we have closed WORDSNET-25625 as not a bug.

The issues you have found earlier (filed as WORDSNET-25625) have been fixed in this Aspose.Words for Java 23.8 update.