How to use custom fonts in DOCX to PDF conversion in docker image using Aspose.Words REST API

Product: docker aspose/words-cloud:20.11

We have an aspose.cloud docker image with external mounted volumes (one for /data, other for /fonts)
The mounts are working correctly as I can see the uploaded files in the /data external volume.
I have uploaded several custom .ttf fonts to the /fonts volume and can see the fonts from the container terminal.
I have a DOCX using custom fonts and when I try to convert it into PDF, it doesn’t use the fonts. I have checked the PDF properties and all it has is the DejaVuSans fonts.
In fact, if you use fc-list the container ONLY listas DejaVuSans (no other common Windows fonts there)
I can see that the docker server identifies and tries to access the fonts, because if I use the ‘fontsLocation=/fonts’ query parameter I get an error:

"Error": {

        "Code": "InternalError",

        "Message": "Error while get files in folder '/fonts' from storage: Could not find file '/XXSansCd_Bd.ttf'.",

        "Description": "Operation Failed. Internal error.",

        "InnerError": {

            "Message": "Could not find file '/XXSansCd_Bd.ttf'."

        }

    }

This seems to indicate the server understands the DOC uses a certain font, but can’t find it at /fonts

Thanks

@techteam

Please share your input document along with custom fonts as a zip file. We will investigate the issue and will share our findings with you.

1 Like

Here are the files and the steps to reproduce (using Postman)

  • Note that we are using a LICENSED docker image, with public/private key and all features
  • Copy all Noto ttf files to the /fonts folder (no subfolders, all files on /fonts)
  • DELETE /words/fonts/cache (to clear the cache)
  • Restart container just in case
  • PUT /words/storage/Noto.docx
  • GET /words/Noto.docx?format=pdf

Notes:

  • I am able to convert from HTML to DOCX and DOCX keeps the custom fonts. Problem seems to be HTML > PDF and DOCX > PDF
  • To reduce file size I have included just the Noto fonts used. If you need the whole package, you can download from Google here: https://noto-website-2.storage.googleapis.com/pkgs/NotoSans-hinted.zip
  • Noto.docx is the Word file with proper fonts
  • Note.pdf was generated using the steps above. Notice it only includes the DejaVu font.

Thanks!

NotoFiles.zip (5.6 MB)

@tilal.ahmad – one more thing:
If you get the list of fonts without specifying the fontsLocation query parameter:

GET {{baseUrl}}/words/fonts/available

You only get the list of system fonts

{

    "SystemFonts": [

        {

            "FontFamilyName": "DejaVu Sans",

            "FullFontName": "DejaVu Sans Bold",

            "Version": "Version 2.37",

            "FilePath": "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"

        },

        {

            "FontFamilyName": "DejaVu Sans",

            "FullFontName": "DejaVu Sans",

            "Version": "Version 2.37",

            "FilePath": "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"

        },

        {

            "FontFamilyName": "DejaVu Sans Mono",

            "FullFontName": "DejaVu Sans Mono Bold",

            "Version": "Version 2.37",

            "FilePath": "/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf"

        },

        {

            "FontFamilyName": "DejaVu Sans Mono",

            "FullFontName": "DejaVu Sans Mono",

            "Version": "Version 2.37",

            "FilePath": "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf"

        },

        {

            "FontFamilyName": "DejaVu Serif",

            "FullFontName": "DejaVu Serif Bold",

            "Version": "Version 2.37",

            "FilePath": "/usr/share/fonts/truetype/dejavu/DejaVuSerif-Bold.ttf"

        },

        {

            "FontFamilyName": "DejaVu Serif",

            "FullFontName": "DejaVu Serif",

            "Version": "Version 2.37",

            "FilePath": "/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf"

        }

    ],

    "RequestId": "56b8c1e3-ec68-4a42-9301-d5c73a0e43c5"

}

If you get the list of fonts specifying the fontsLocation query parameter as fonts it tries to get the fonts relative to the /data folder:

GET {{baseUrl}}/words/fonts/available?fontsLocation=fonts

{

    "Error": {

        "Code": "InternalError",

        "Message": "Error while get files in folder 'fonts' from storage: Error while get file list in folder 'fonts' from storage: Could not find a part of the path '/data/fonts'.",

        "Description": "Operation Failed. Internal error.",

        "InnerError": {

            "Code": "InternalError",

            "Message": "Error while get file list in folder 'fonts' from storage: Could not find a part of the path '/data/fonts'.",

            "Description": "Operation Failed. Internal error.",

            "InnerError": {

                "Message": "Could not find a part of the path '/data/fonts'."

            }

        }

    },

    "RequestId": "c8969c6e-4056-4845-b0e7-19c6773b5df7"

}

If you get the list of fonts specifying the fontsLocation query parameter as /fonts it seems to look on the right location, but it returns a “file not found” error for the first font, although the font is physically in the /fonts folder.:

GET {{baseUrl}}/words/fonts/available?fontsLocation=/fonts

{

    "Error": {

        "Code": "InternalError",

        "Message": "Error while get files in folder '/fonts/' from storage: Could not find file '/NotoSans-ExtraCondensedSemiBold.ttf'.",

        "Description": "Operation Failed. Internal error.",

        "InnerError": {

            "Message": "Could not find file '/NotoSans-ExtraCondensedSemiBold.ttf'."

        }

    },

    "RequestId": "718809ab-b8bf-43b7-af89-96786d70100e"

}

Thanks!

And here is yet more information (apologies for the piecemeal)

If you look at the Aspose.Cloud documentation for GET list of fonts:
https://docs.aspose.cloud/words/fonts/gets-the-list-of-fonts/
It says fontsLocation is a a folder in file storage with custom fonts. Does it mean it should be under /data ?
The docker documentation clearly separates /data and /fonts in two volumes.

https://hub.docker.com/r/aspose/words-cloud

To test, I copied the fonts from /fonts to /data/_fonts and then ran the GET list using _fonts (no slash at beginning, making it relative to /data).

GET {{baseUrl}}/words/fonts/available?fontsLocation=_fonts

This time the server returned a list of SystemFonts and CustomFonts

{
    "SystemFonts": [
        {
            "FontFamilyName": "DejaVu Sans",
            "FullFontName": "DejaVu Sans Bold",
            "Version": "Version 2.37",
            "FilePath": "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
        },
        .....
    ],
    "CustomFonts": [
        {
            "FontFamilyName": "Noto Sans ExtCond SemBd",
            "FullFontName": "Noto Sans ExtraCondensed SemiBold",
            "Version": "Version 2.000;GOOG;noto-source:20170915:90ef993387c0; ttfautohint (v1.7)"
        },
    .....
  ]
.....
}

However, the DOCX > PDF conversion still fails and only returns the DejaVu fonts.

Let me know if you need more information.

@techteam

Yes, the custom fonts should be in a folder at storage(/data).

I have tested the scenario using your shared fonts and unable to notice the issue.Noto (1).pdf (42.6 KB)

curl -X GET "http://localhost:8888/v4/words/Noto.docx?format=pdf&fontsLocation=Fonts" -H "accept: application/octet-stream" -H "Authorization: Bearer [Access_Token]"

Please double check the availability of your fonts folder by listing all the folder/files on the root(of /data) as following.

curl -X GET "http://localhost:8888/v4/words/storage/folder/." -H "accept: application/json" -H "Authorization: Bearer [AccessToken]"

Thanks @tilal.ahmad

1 - The documentation on Docker Hub is incorrect, stating that fonts should be on /fonts and mapped to their own volume, separate from /data

https://hub.docker.com/r/aspose/words-cloud

RequiredVolumes.png (8.5 KB)

DockerCompose.png (7.1 KB)

2 - On my last post I confirmed that the fonts were in the new expected place, the {{baseUrl}}/words/fonts/available?fontsLocation=_fonts listed all CustomFonts but the conversion still failed. However, it seems this was because I was missing the fontsLocation=_fonts parameter on the call. I have retested and DOC > PDF conversion works correctly.

Thanks for your help.

To anyone having this issue, the solution is:

  • Do not follow the Docker Hub instructions to map a volume to an exclusive root folder.
  • Custom fonts should be stored under the /data folder (/data/yourCustomFolder/yourCustomFonts
  • Make sure your conversion request includes the fontsLocation parameter with a relative reference to the custom folder (fontsLocation=yourCustomFolder not fontsLocation=/yourCustomFolder). Example:

{{baseUrl}}/words/YourFile.docx?format=pdf&fontsLocation=fonts

@techteam

Thanks for your feedback. Please note the only difference between /fonts volume and custom fonts folder in /data volume is if you set /fonts folder as container volume, you don’t need to add the (fontsLocation)parameter to each request. It looks like that /fonts volume is not working as expected. We have logged a ticket WORDSCLOUD-1541 for further investigation and rectification. We will keep you updated about the issue resolution progress in this thread.

1 Like

@techteam

Please note above reported issue WORDSCLOUD-1541 is resolved. You can use the latest version of Aspose.Words Cloud Docker container for the fix.