phax/ph-pdf-layout

Having issues importing and using

AndroidDeveloperLB opened this issue · 40 comments

I wanted to see how to create hyperlinks, so there are these sample PDF files:

https://github.com/phax/ph-pdf-layout/tree/master/example-files/plexternallink

And also a sample code:

https://github.com/phax/ph-pdf-layout/blob/master/src/test/java/com/helger/pdflayout/element/link/PLExternalLinkTest.java

So I copied this a bit into a new Android app project, and I also tried to use this in the gradle file (kts formant):

implementation("com.helger:ph-pdf-layout4:5.2.2")}

It can't find the classes.

image

The docs say to use it this way.
Also it's mentioned here:
https://search.maven.org/artifact/com.helger/ph-pdf-layout4/5.2.2/jar?eh=

But it's weird because the latest version is also said to be 7.1.0...
Attached the problematic sample project. I can also use Java if you wish. Kotlin should be fine though, as it can handle Java easily.

I also tried to reach Jitpack as it might be able to fetch the library, but it failed:
https://jitpack.io/#phax/ph-pdf-layout

What is going on ? What should I use? Maybe the docs weren't updated?

My Application.zip

phax commented

Hi, my knowledge about building Android applications is limited.

However, I spotted an error in the badges, so now the right version number is displayed.

For historical reasons I needed to make a breaking change from v3 to v4 so that both the package name and the artifact name were altered (adding a 4 at the end as in ph-pdf-layout4). That's why your example doesn't work, because the Java package name was also modified. This verisoning scheme was kept until version 5 - see https://search.maven.org/search?q=ph-pdf-layout for the confusion.

Starting from v6 I reverted to the "original" system of using just "ph-pdf-layout", so for Java 8 please use:

implementation("com.helger:ph-pdf-layout:6.0.3")

and for Java 11 onwards use

implementation("com.helger:ph-pdf-layout:7.1.0")

Hope that makes a bit of sense :)

@phax Now I have a different issue.
It seems it relied on "java.awt.*" stuff, and this is limited on Android, sadly.
For example, there is no java.awt.Color (used for setFillColor, setBorder, for example). Instead there is android.graphics.Color, or I could just use ARGB value (Integer).
Sadly here in this library both of these aren't available.

In addition, there is BufferedImage used for PLImage. On Android, there is android.graphics.Bitmap , Or I could just provide 2-dimentional array of Integers (each is a pixel in ARGB form), or any other thing you wish.

Are there alternative to those in this library?
Can I avoid using "java.awt.*" stuff?

@phax Maybe you know of an alternative to this library, that could work even on Android?
I just want to be able to print a table with texts and links... Maybe also some images as a bonus.

phax commented

No, I am not aware of really similar libraries that I can recommend. Let me see if can operate this class away - give me some days. I am on vacation atm

That would be awesome !
But I think it's hard, no?

phax commented

No, it's not too hard. Its just a backwards incompatible change...

I hope you succeed.
Please have alternatives for each usage of "awt".

phax commented

Please see release 7.3.0 - removes java.awt.color.
Caution: don't use PDF/A - this still requires java.awt.* stuff.

@phax You succeeded?
What can I use, then, for these:

  1. Color
  2. Bitmap (PLImage)

?

phax commented

Ah yes - for color use the new class PLColor - same API as color. For PLImage there is no replacement, as the underlying PDFBox library also uses the java.awt.BufferedImage. As PLImage is a very small class, you may find a solution like PLImage2 that creates the images based on a different source???

@phax About PLColor, thank you. Seems it support RGB. Does it support alpha too? Or PDF doesn't support such a thing?
I personally don't need it (at least not for what I'm planning, which should be very small), but maybe people will find it useful.

About PLImage2 , I can't find it after changing the dependency. Sure it's there?
Also, what "different source" ?

phax commented

PDF does support alpha channel - may be later. I used Color also just in RGB mode.

Regarding PLImageXXX - this is for your to do :) Find an Android library that does the trick for you. I can't help you, as BufferedImage is the best I am aware of and I can't move away from it

@phax You mean I should extend from AbstractPLImage ?
But then I need to implement getXObject, yet PDImageXObject is marked as final , and none of its CTORs seem to offer a way to give it a simple array of pixels data. In PDImageXObject there are a lot of references to awt, too.
Another option would be to use LosslessFactory.createFromImage (which is the most suitable as it supports all kinds of bitmaps), but again, it still uses BufferedImage...

I don't see how to get away from awt when the classes are very strict...
Are you sure it's possible?

phax commented

I have no idea if it is possible or not. I don't know the Android runtime. You need to do some investigations...

@phax I didn't talk about Android being the issue.
I talked about the classes being used here.
I investigated those classes and wrote you that they are too closed to being extended, and they use awt...

I'm sure that in every framework, there is the Bitmap representation as an array of pixels, with width and/or height being input too.

I can see org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory.createFromRGBImage , for example

@phax After trying to avoid to use the image usages (maybe will try this later), the IDE claims there are duplicate classes:

Duplicate class org.apache.commons.logging.Log found in modules commons-logging-1.2 (commons-logging:commons-logging:1.2) and jcl-over-slf4j-2.0.7 (org.slf4j:jcl-over-slf4j:2.0.7)
Duplicate class org.apache.commons.logging.LogConfigurationException found in modules commons-logging-1.2 (commons-logging:commons-logging:1.2) and jcl-over-slf4j-2.0.7 (org.slf4j:jcl-over-slf4j:2.0.7)
Duplicate class org.apache.commons.logging.LogFactory found in modules commons-logging-1.2 (commons-logging:commons-logging:1.2) and jcl-over-slf4j-2.0.7 (org.slf4j:jcl-over-slf4j:2.0.7)
Duplicate class org.apache.commons.logging.impl.NoOpLog found in modules commons-logging-1.2 (commons-logging:commons-logging:1.2) and jcl-over-slf4j-2.0.7 (org.slf4j:jcl-over-slf4j:2.0.7)
Duplicate class org.apache.commons.logging.impl.SimpleLog found in modules commons-logging-1.2 (commons-logging:commons-logging:1.2) and jcl-over-slf4j-2.0.7 (org.slf4j:jcl-over-slf4j:2.0.7)

How come?

Maybe because I use Kotlin too?

About org.apache.commons.logging.Log and org.apache.commons.logging.LogFactory, it says it's used in these:

Gradle: commons-logging:commons-logging:1.2
Gradle: org.slf4j:jcl-over-slf4j:2.0.7
org.apache.commons.logging.impl
org.jetbrains.kotlin.de.undercouch.gradle.tasks.download.org.apache.commons.logging
org.jetbrains.kotlin.de.undercouch.gradle.tasks.download.org.apache.commons.logging.impl

For org.apache.commons.logging.LogConfigurationException , it says it's used in these:

Gradle: commons-logging:commons-logging:1.2
Gradle: org.slf4j:jcl-over-slf4j:2.0.7
org.jetbrains.kotlin.de.undercouch.gradle.tasks.download.org.apache.commons.logging

And for org.apache.commons.logging.impl.SimpleLog and org.apache.commons.logging.impl.NoOpLog:

Gradle: commons-logging:commons-logging:1.2
Gradle: org.slf4j:jcl-over-slf4j:2.0.7
org.jetbrains.kotlin.de.undercouch.gradle.tasks.download.org.apache.commons.logging.impl
phax commented

Ah yes - both SLF4J and commons-logging are logging frameworks.
They both have separate artifacts for their API (slf4j-api and commons-logging-api).
But you must choose only one implementation. Either Log4J2, Logback, commons-logging, Java Util Logging etc.

I prefer using Log4J2 and org.slf4j:jcl-over-slf4j:2.0.7 as the implementation for the commons-logging-api.

Your solution depends on the Kotlin default logging - I don't know it. Most likely you need to exclude either commons-logging:commons-logging:1.2 or org.slf4j:jcl-over-slf4j:2.0.7

@phax Do you know how to do such a thing in gradle kts ?
I never did such a thing.
I tried to follow the instructions and there are so many options. I don't get which I should use:
https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html
https://docs.gradle.org/current/userguide/resolution_rules.html

How did you get it to work? Maybe I can use what you did?

phax commented

I use Maven - Maven has an explicit <exclude> element to exclude a specific dependency - no idea how this is done in Gradle.

https://docs.gradle.org/current/userguide/dependency_downgrade_and_exclude.html#sec:excluding-transitive-deps seems like what you need

@phax Can you please copy-paste what you used in maven?
Maybe from this I can try to write in gradle-kts form.

I mean your own code (maven snippets), of which ones you've excluded.

phax commented

I was looking, but couldn't find something in my dependencies - I am always very cautious with them, so usually there is no need to exclude stuff

Edit: for logging I am only including slf4j-api in all dependencies. Only the resulting applications/web application include the logging framework itself. For testing purposes (e.g. in this library) I am including slf4j-simple with scope test to only have it available for testing. slf4j-simple is like the simplest logging implementation: it writes everything to stdout only.

Odd that it works fine for you. Multiple modules with same classes and paths to them...
How does it get built...
Anyway, I will try...
Thank you

phax commented

Ah, I see what you mean, because commons-logging is referenced from pdfbox and you want to use an SLF4J binding.
Therefore I suggest:

  • Exclude commons-logging:commons-logging:1.2
  • Include commons-logging:commons-logging-api:1.1

Looks weird, but guarantees that the API requirements of PDFBox are fulfilled, but no "implementation" is present

Shouldn't it be the opposite? 1.2 is newer...

phax commented

The API is a subset and hasn't changed. Only some implementation specific parts have changed in the 1.2 implementation release. Se the different artifact IDs

OK so I tried this:

    implementation("commons-logging:commons-logging-api:1.1"){
        exclude("commons-logging:commons-logging:1.2")
    }

And got even more duplicates for some reason:

log.txt

And I tried this:

    implementation("commons-logging:commons-logging-api:1.1"){
        exclude(group = "commons-logging", module = "commons-logging")
    }

And got even more duplicates for some reason:

log.txt

I think they are identical.

:(

phax commented

I meant

    implementation("com.helger:ph-pdf-layout:7.3.0"){
        exclude("commons-logging:commons-logging:1.2")
    }
   implementation("commons-logging:commons-logging-api:1.1")

or so - whatever the right syntax is

Still duplicates:

log.txt

phax commented

There is still some commons-logging:commons-logging:1.2 left - dunno from where. Maybe some other dependency also includes it. Can you ignbore the errors in this particular case? I think it's okay in this case

It prevents from building the app (no output APK file to install and run), so I can't ignore.
If you wish, I can put here the project after these changes.

phax commented

Maybe you can post the full build file here, or send it by email

phax commented

Remove implementation("org.apache.pdfbox:pdfbox:3.0.0") and try again - that should be included automatically (transitively)

@phax It's commented (with //) , so it doesn't affect it.

phax commented

You are true.
What about the force("commons-logging:commons-logging:1.2") on top

@phax Sorry about that. This was the recent attempt to solve it and I forgot to remove/comment it.
Sadly, I still get duplicates error:

log.txt

phax commented

No idea - sorry. Check if you can list the transitive dependencies....
(Something like mvn tree:tree)