sungaila / PDFtoImage

A .NET library to render PDF files into images.
https://www.sungaila.de/PDFtoImage/
MIT License
152 stars 15 forks source link

QUESTION: Is it possible to use the PDFtoImage library in a Xamarin Android project? #9

Closed Auto72 closed 2 years ago

Auto72 commented 2 years ago

Is it possible to use the PDFtoImage library in a Xamarin Android project? I just need to get the bitmap of the page, even skbitmap. Thanks.

sungaila commented 2 years ago

Hi @Auto72,

does your Android project target .NET 6 or newer?

Right now, Android is not supported by PDFtoImage. But I might add net6.0-android and net6.0-ios as targets if that helps.

Auto72 commented 2 years ago

Hi sungaila Actually, I don't know if my Android project target .NET 6. It targets Android 12 and for sure C# 9.0. Would be a great idea if you could add net6.0-android and net6.0-ios targets to the PDFtoImage library, then I will give it a try. Thanks.

sungaila commented 2 years ago

@Auto72 You can try to use this test release I've built just now: https://github.com/sungaila/PDFtoImage/releases/tag/v2.0.0-preview6

Your project must use .NET 6 or newer and the Android API level must be 28 (Android 9 Pie) or higher.

Let me know if that worked for you and I will merge this into master.

Auto72 commented 2 years ago

Thank you sungaila for your work. Unfortunately it seems the NuGet Package doesn't install. May be monoandroid12.0 is not .NET 6.0 :-(

PM> Install-Package C:\dotNET\NuGet_Packages_OFF_Line\PDFtoImage.2.0.0-preview6.nupkg The 'Source' parameter is not respected for the transitive package management based project(s) TestPDF.csproj. The enabled sources in your NuGet configuration will be used. Restoring packages for C:\Users\Auto72\Documents\GitHub\TestPDF\TestPDF.csproj... Install-Package : NU1202: Package PDFtoImage 2.0.0-preview6 is not compatible with monoandroid12.0 (MonoAndroid,Version=v12.0). Package PDFtoImage 2.0.0-preview6 supports:

Install-Package : Package restore failed. Rolling back package changes for 'TestPDF'. At line:1 char:1

Time Elapsed: 00:00:00.5421120 PM>

sungaila commented 2 years ago

@Auto72 Give this one a try: https://github.com/sungaila/PDFtoImage/releases/tag/v2.0.0-preview7

I've added monoandroid9.0 as a target framework.

Auto72 commented 2 years ago

Thanks sungaila the last NuGet package (preview 7) has now been successfully imported into the Xamarin Android project . I will try to find some C# example code to load PDF ad render a page to bitmap. Thanks again.

sungaila commented 2 years ago

Great, please let me know if your test succeeds.

Auto72 commented 2 years ago

I tried the following:

System.IO.Stream assetStream = Application.Context.Assets.Open("MyDoc.pdf"); int numPages = Conversion.GetPageCount(assetStream); Console.WriteLine($"numPages: {numPages}");

But in the second line above I get the following exception error:

System.NotSupportedException: 'The input stream must support seek to load a PDF document.'

So, I used a byte array to avoid the stream and the following code worked :-)

        Stream assetStream = Application.Context.Assets.Open("MyDoc.pdf");
        using var ms = new MemoryStream();
        assetStream.CopyTo(ms);
        byte[] byteArrayPdf = ms.ToArray();

        int numPages = Conversion.GetPageCount(byteArrayPdf);
        Console.WriteLine($"numPages: {numPages}");

Next week I will try to get a bitmap of some page of the PDF.

Thanks.

sungaila commented 2 years ago

Yes, I've stumbled over this problem as well. This is because Android.Runtime.InputStreamInvoker does not support seeking.

In your workaround you can use the memory stream directly:

using var assetStream = Application.Context.Assets.Open("MyDoc.pdf");
using var ms = new MemoryStream();
assetStream.CopyTo(ms);

int numPages = Conversion.GetPageCount(ms);
Console.WriteLine($"numPages: {numPages}");
Auto72 commented 2 years ago

Yes, the code above works, anyway when I do the conversion (Conversion.SaveJpeg), the same error appears, so I used the byte array workaround. May be even the MemoryStream in Android is not seekable after the first use. I don't know.

        using var assetStream = Application.Context.Assets.Open("MyDoc.pdf");
        using var ms = new MemoryStream();
        assetStream.CopyTo(ms);
        byte[] byteArrayPdf = ms.ToArray();

        int numPages = Conversion.GetPageCount(byteArrayPdf);
        Console.WriteLine($"numPages: {numPages}");

        using var outStream = new MemoryStream();

        // The below line generates the following error --> System.NotSupportedException: 'The input stream must support seek to load a PDF document.'
        //Conversion.SaveJpeg(outStream, ms, page: 0, dpi: 300, withAnnotations: true, withFormFill: true);

        Conversion.SaveJpeg(outStream, byteArrayPdf, page: 0, dpi: 300, withAnnotations: false, withFormFill: false);

        Bitmap bitmap = BitmapFactory.DecodeStream(outStream);
        _imageView1.SetImageBitmap(bitmap);

There is still a problem in the following line:

Bitmap bitmap = BitmapFactory.DecodeStream(outStream);

The following message appears in the Output window: [skia] --- Failed to create image decoder with message 'unimplemented'

Do you have any idea to solve the issue?

Thanks

sungaila commented 2 years ago

On which API level did you test this? I ran your code on an Android API 31 emulator just fine.

Maybe older API levels do not have a JPEG decoder available. Might want to try SavePng or SaveWebp instead.

Auto72 commented 2 years ago

I use API 31. Actually I run on a device with Android 12. I also tried SavePng and SaveWebp, but with same result. If you ran the code on an Android API 31 emulator just fine, the library it is fine 🙂👍

I have some problem with Android Device Manager, I can't create or use an emulator since few days after some updates. 1

Thanks for your help.

sungaila commented 2 years ago

@Auto72 Please reopen this issue, if this unimplemented problem doesn't resolve on its own.

Other than that: Glad this worked out! 👍