Darren Christopher
Darren Christopher

Reputation: 4779

Xamarin Android print PDF file

I am trying to print a PDF file I created using PrintManager. I have already written my code to generate PDF File using ITextSharp in my activity. Below is my generate PDF method:

    private byte[] generatePdf()
    {
        using (var baos = new MemoryStream())
        {
            using (var ps = new StreamWriter(baos))
            {
                Document doc = new Document(PageSize.A4, 72, 72, 72, 72);
                PdfWriter writer = PdfWriter.GetInstance(doc, ps.BaseStream);
                if (!doc.IsOpen())
                    doc.Open();

                doc.AddTitle("Sales Order " + GlobalVars.selectedSales.DocumentNo);
                var TitleFont = new Font(Font.FontFamily.TIMES_ROMAN, 24, Font.BOLD);
                var SubTitleFont = new Font(Font.FontFamily.TIMES_ROMAN, 20);
                var HeadingFont = new Font(Font.FontFamily.TIMES_ROMAN, 18, Font.BOLD);
                var BoldNormalFont = new Font(Font.FontFamily.TIMES_ROMAN, 14, Font.BOLD);
                var NormalFont = new Font(Font.FontFamily.TIMES_ROMAN, 14);

                doc.Add(new Paragraph("SALES ORDER", TitleFont));
                ... //other data
                doc.Close();
                writer.Close();
            }
            var bytes = baos.ToArray();
            return bytes;
        }
    }

In short, the code above will return byte array containing the PDF file generated because I do not want to save the PDF anywhere in the Android device.

After generating this PDF, I am lost to use PrintManager, which takes only PrintDocumentAdapter argument to generate the file and not using my generated PDF. I am trying to generate CustomPrintAdapter which inherits from PrintDocumentAdapter, but have no idea how could I reuse the PDF that I created above from my activity because it uses PrintedPdfDocument data type.

Could you guys point me into the right direction here? Or is there any other easier approach to achieve printing custom PDF file?

UPDATE 1

Turns out Xamarin Android does not support System.Drawing.dll based on this article. I think ITextSharp library uses System.Drawing library because when I tried to build it, it raise an exception:

Exception while loading assemblies: System.IO.FileNotFoundException: Could not load assembly 'System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. 
Perhaps it doesn't exist in the Mono for Android profile?

And when I removed it, the build is success and no exception raised. Note that I have tried closing solution, delete all contents from Packages folder, reopen solution, and build; it did not work in this case.

Therefore, I will try generate the PDF using Android.Graphics.Canvas as seen on the Android Developer site.

Upvotes: 1

Views: 3411

Answers (1)

Darren Christopher
Darren Christopher

Reputation: 4779

UPDATE 2

I got no success generating PDF with Android.Graphics.Canvas like the way Android developer site does. The reason is I have no idea how to calculate the page and change the page as the content is dynamic. There was also a method like getPrintItemCount() in the site, which I have no idea what is that as the site does not include the explanation there.

Therefore, the workaround that I could think of now is printing WebView which is handled by my web service endpoint. I am creating a HTML layout for the page that I would like to print, then the WebView will open my web service endpoint. Luckily, printing with this approach can be done well. And of course, this approach has limitation which is the web service should be reachable to do printing.

To do this, first, I need to create a custom class that extends WebViewClient to get the event when page is finished loading using OnPageFinished method. I, then use the print method from my activity, which I pass it using the constructor. To make it clearer, I will attach my codes.

public class CustomWebViewClient : WebViewClient
{
    private SalesDetailView myActivity;
    public bool shouldOverrideUrlLoading(WebView view, string url)
    {
        return false;
    }
    public override void OnPageFinished(WebView view, string url)
    {
        Log.Debug("PRINT", "page finished loading " + url);
        myActivity.doWebViewPrint(url);
        base.OnPageFinished(view, url);
    }
    public CustomWebViewClient(SalesDetailView activity)
    {
        myActivity = activity;
    }
}

Here is the doWebPrint method from my activity

public async void doWebViewPrint(string URL)
    {
        if (await vm.printCheck())
        {
            PrintDocumentAdapter adapter;
            if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Lollipop)
                adapter = webView.CreatePrintDocumentAdapter("test");
            else
                adapter = webView.CreatePrintDocumentAdapter();
            var printMgr = (PrintManager)GetSystemService(PrintService);
            printMgr.Print("printTest", adapter, null);
        }
    }

I then create the WebView, load the website whenever the user clicks print button.

Button btnPrintSO = FindViewById<Button>(Resource.Id.btnPrintSO);
btnPrintSO.Click += delegate
{
    string URL = ServerDatabaseApi.printSOEndpoint + GlobalVars.selectedSales.DocumentNo;
    webView = new WebView(this);
    CustomWebViewClient client = new CustomWebViewClient(this);
    webView.SetWebViewClient(client);
    webView.Settings.JavaScriptEnabled = true;
    webView.LoadUrl(URL);
    webView.Settings.UseWideViewPort = true;
    webView.Settings.LoadWithOverviewMode = true;
};

Hope these updates could help anyone in the future.

Upvotes: 1

Related Questions