Create PDF in runtime on Android and iOS

Hello,

I’ve been struggling for days and I still can’t figure it out. So here we go:

I want to create PDFs in runtime on Android and iOS. So I’ve tried many solutions (PDFSharp, iTextSharp, iText 7, etc…), some compile and produces bugs and some don’t even compile.

Now i’m testing iText 7 and I’m stuck at this point: it’s compiling, the application is running, I can create an empty PDF and save it, BUT: when I add text in it, it doesn’t want to save it anymore and I’m getting this error in Logcat (when compiled in Mono):

2022/09/22 11:14:51.597 3866 3906 Error Unity ArgumentException: The specified path is not of a legal form (empty).
2022/09/22 11:14:51.597 3866 3906 Error Unity   at System.IO.Path.InsecureGetFullPath (System.String path) [0x00025] in <c00f838d158c4f4185913cb3b6f74bb2>:0
2022/09/22 11:14:51.597 3866 3906 Error Unity   at System.IO.Path.GetFullPath (System.String path) [0x00000] in <c00f838d158c4f4185913cb3b6f74bb2>:0
2022/09/22 11:14:51.597 3866 3906 Error Unity   at System.AppDomainSetup.GetAppBase (System.String appBase) [0x00038] in <c00f838d158c4f4185913cb3b6f74bb2>:0
2022/09/22 11:14:51.597 3866 3906 Error Unity   at System.AppDomainSetup.get_ApplicationBase () [0x00000] in <c00f838d158c4f4185913cb3b6f74bb2>:0
2022/09/22 11:14:51.597 3866 3906 Error Unity   at System.AppDomain.get_BaseDirectory () [0x00006] in <c00f838d158c4f4185913cb3b6f74bb2>:0
2022/09/22 11:14:51.597 3866 3906 Error Unity   at (wrapper remoting-invoke-with-check) System.AppDomain.get_BaseDirectory()
2022/09/22 11:14:51.597 3866 3906 Error Unity   at iText.Commons.Utils.FileUtil.GetBaseDirectory () [0x00005] in <70ff0a0b3dd34b239fd922ab105d65e4>:0
2022/09/22 11:14:51.597 3866 3906 Error Unity   at iText.IO.Util.ResourceUtil.LoadITextResourceAssemblies () [0x0007e] in <c831a68b61cf41899c27077df1818d79>:0
2022/09/22 11:14:51.597 3866 3906 Error Unity   at iText.IO.Util.ResourceUtil..cctor () [0x00034] in <c831a68b61cf41899c27077df1818d79>:0

And I’m getting this error in Logcat (when compiled in IL2CPP):

2022/09/22 11:30:22.047 5138 5190 Error Unity IOException: Permission denied
2022/09/22 11:30:22.047 5138 5190 Error Unity Rethrow as UnauthorizedAccessException: Access to the path '/' is denied.
2022/09/22 11:30:22.047 5138 5190 Error Unity   at System.IO.Enumeration.FileSystemEnumerator`1[TResult].CreateDirectoryHandle (System.String path, System.Boolean ignoreNotFound) [0x00000] in <00000000000000000000000000000000>:0
2022/09/22 11:30:22.047 5138 5190 Error Unity   at System.IO.Enumeration.FileSystemEnumerator`1[TResult]..ctor (System.String directory, System.IO.EnumerationOptions options) [0x00000] in <00000000000000000000000000000000>:0
2022/09/22 11:30:22.047 5138 5190 Error Unity   at System.IO.Enumeration.FileSystemEnumerable`1+DelegateEnumerator[TResult]..ctor (System.IO.Enumeration.FileSystemEnumerable`1[TResult] enumerable) [0x00000] in <00000000000000000000000000000000>:0
2022/09/22 11:30:22.047 5138 5190 Error Unity   at System.IO.Enumeration.FileSystemEnumerable`1[TResult]..ctor (System.String directory, System.IO.Enumeration.FileSystemEnumerable`1+FindTransform[TResult] transform, System.IO.EnumerationOptions options) [0x00000] in <00000000000000000000000000000000>:0
2022/09/22 11:30:22.047 5138 5190 Error Unity   at System.IO.Enumeration.FileSystemEnumerableFactory.UserFiles (System.String directory, Sy

And here is my code:

using UnityEngine;
using iText.Kernel.Pdf;
using iText.Kernel.Geom;
using iText.Layout.Element;
using iText.Layout;
using System.IO;
using iText.IO.Image;
using UnityEngine.Android;

public class ExportPDF : MonoBehaviour
{
    [SerializeField]
    private Texture2D img;
    private string content;
    private NativeShare nativeShare;
    private string pdfpath;

    // Start is called before the first frame update
    void Start()
    {
        if (Application.platform == RuntimePlatform.Android)
        {
            if (!Permission.HasUserAuthorizedPermission(Permission.CoarseLocation))
                Permission.RequestUserPermission(Permission.CoarseLocation);
            if (!Permission.HasUserAuthorizedPermission(Permission.FineLocation))
                Permission.RequestUserPermission(Permission.FineLocation);
            if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageRead))
                Permission.RequestUserPermission(Permission.ExternalStorageRead);
            if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite))
                Permission.RequestUserPermission(Permission.ExternalStorageWrite);
            string path = Application.persistentDataPath + System.IO.Path.DirectorySeparatorChar + "pdffolder";
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);
            pdfpath = path + System.IO.Path.DirectorySeparatorChar + "test.pdf";
        }
        else
        {
            pdfpath = Application.persistentDataPath + "/test.pdf";
        }

        nativeShare = new NativeShare();
        nativeShare.SetSubject("Test");
        nativeShare.SetText("TEST");
        nativeShare.SetTitle("Share test");
    }

    public void Export()
    {
        PdfWriter wri = new PdfWriter(pdfpath);
        PdfDocument pdf = new PdfDocument(wri);

        pdf.GetCatalog().SetViewerPreferences(new PdfViewerPreferences().SetDisplayDocTitle(true));
        pdf.GetCatalog().SetLang(new PdfString("en-US"));
        PdfDocumentInfo info = pdf.GetDocumentInfo();
        info.SetTitle("TEST");

        pdf.AddNewPage();
        Document document = new Document(pdf, PageSize.A4);

        document.Add(new Image(ImageDataFactory.Create(img.EncodeToPNG())));
        Paragraph header = new Paragraph(new Text("Hello World!").SetTextAlignment(iText.Layout.Properties.TextAlignment.CENTER).SetFontSize(20));

        document.Add(header);
        document.Close();

        nativeShare.AddFile(pdfpath);
        nativeShare.Share();
    }
}

My settings:

  • IL2CPP
  • .NET Framework
  • ARM64
  • Strip Engine Code: UNCHECKED
  • Managed Stripping Level: Minimal

Now multiple questions:

  • Has anyone ran into this issue before? If yes, did you find a solution? If yes, could you help me?
  • If I’m going in the wrong direction, could someone show me which PDF library is working in Unity (runtime) please?

If someone could help me that would be amazing! Thanks for reading me!

errors mention something about path,
have you tested saving into some fixed folder, like /sdcard/download/ or application.persistentDataPath ?

Thanks for the answer, yes I’ve tried and it does the same error. But the wierdest thing about this, is that if I remove line 63 which is document.Add(header); (adding text to the pdf file) then it saves the file and it works without any error! So I can save a PDF but it has to be without text lol (which is useless)…

can you check what the .Add does with files?

i’ve used this before, but it was on desktop…
http://sharppdf.sourceforge.net/

Unfortunately the functions are in DLLs, so the source code is unreachable, and even if it was I don’t think we could edit it… Or is there a way I’m unaware of?
And the only thing I can get from documentation is this:
https://api.itextpdf.com/iText7/dotnet/7.2.3/classi_text_1_1_layout_1_1_document.html#a9a3ecf11b277d951c6b72a412f3c3ee5

I’ve tried SharpPDF but I had lots of compile errors so I gave up on this.

tried asset store plugins?

No as it is not free (yes I know, it’s cheap) but I wanted to find a free alternative.

Hello. And how did your story end? I’m also in a similar situation and considering purchasing PDF Generator.

1 Like

Hello! I’ve found a free solution that works on both iOS and Android in runtime. It works with iTextSharp but you need to take the version 5 and not the 7 as the 5 is free and the 7 is under commercial license. So what you need to do is :

  • Follow this link: iTextSharp
  • Download the package
  • Extract it and copy the files that are under the “lib” folder to the “Plugins” folder of your unity project
  • Go back on the link of the first step and go to the “Dependencies” tab and download the needed dependencies, follow the same process and add the *.dll and *.xml files to the “Plugins” folder of your unity project
  • Unity is gonna give you a bunch of missing dependencies errors but don’t worry: for every missing dependency, go to nuget.org, look for the missing dependency, download it, and follow the same process as previously
  • As you fill all the required dependencies, it will display no error at a certain point
  • At this moment it’s done, you can begin scripting with the iTextSharp library

I know the process is laborious but I assure you it works as I’m still working with it, if you need help, feel free to send me a private message!

Hope that helps :wink:

I took a simpler approach =)

  • I found iTextSharp on NuGet and added it to the project.
  • All dependencies were automatically pulled into the My App/Packages/ folder.
  • I copied all new folders from My App/Packages/ to My App/Asset/Plugins/.
  • I unsubscribed and removed all the new ones from NuGet.

I encountered another problem. iTextSharp loses encodings for custom fonts, but only after the build. I needed to be able to write in different languages in the PDF file - international fonts. I added my own font and everything worked fine in runtime. But after the build, I got an error saying “1252 encoding not found”.

From various sources, I learned that I needed to add the i18n.dll and i18n.west.dll assemblies to the My App/Asset/Plugins/ folder. Apparently, iTextSharp relies on them, but Unity doesn’t include them in the final build. But that’s only half the battle. The i18n.dll and i18n.west.dll files are located in Unity directories. However, in newer versions of Unity, these dll files may not be suitable (or I didn’t search well enough). Eventually, I accidentally found the suitable libraries on a 2017 GitHub repository. I downloaded them from there and added them to my project.

In general, this is very useful information for iTextSharp users on Unity. You may want to add support for different languages or change the font style in your project =)

I will attach the link below. I hope this post will help many people. I suffered for a long time myself)

https://github.com/zouhunter/unity-pdfmaker/tree/master/Assets/Plugins

1 Like

Indeed it’as a very good approach! Well done!

Yes for the i18n.dll and i18n.west.dll, I also wanted to change the font and ran into the same issue and resolved it the same way you did, I didn’t mention it but I’m glad you did!

Good thread :smile:

Have you tried building for Universal Windows Platform? I’m having issues with it, specifically with old i18n.dll files preventing the build process.

UPD: To build UWP, you can simply exclude i18n.dll from the build. The issues described above were not found for UWP.