asciidoctor-maven-plugin and images.

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

asciidoctor-maven-plugin and images.

Jeremie Bresson
I would like to understand how images are handled using the asciidoctor-maven-plugin used to generate html

In the pom file, I can read this:

---
Embed stylesheets but link images (default)::
  - don't set embedAssets option
  - don't set linkcss attribute
  - set imagesdir attribute to path relative to AsciiDoc source file

  <attributes>
      <imagesdir>./images</imagesdir>
  </attributes>

IMPORTANT: When you enable image embedding, you must qualify the path the the imagesdir, as shown above.

---

Well... I am not sure to understand what this means, and how to use it.

== 1/ first use-case: renaming

Rename
`asciidoctor-maven-examples/asciidoc-to-html-example/src/docs/asciidoc/images`
to
`asciidoctor-maven-examples/asciidoc-to-html-example/src/docs/asciidoc/imgs`

Because `<imagesdir>` is defined in the pom.xml, it is the leading declaration.
It needs to be changed from
`<imagesdir>./images</imagesdir>`
to
`<imagesdir>./imgs</imagesdir>`.

I think it is a good practice to also modify the imagesdir declaration on top of the `example-manual.adoc`:
`ifndef::imagesdir[:imagesdir: imgs]`
This way if you have a preview program to watch how the document will look like.

== 2/ second use-case: location of the image folder.

I have tried to move the images folder somewhere else:
`asciidoctor-maven-examples/asciidoc-to-html-example/src/imgs`
In the document the imagesdir declaration becomes:
`ifndef::imagesdir[:imagesdir: ../../imgs]`

This works well with a preview program. But the maven plugin is not capable of handling this.
The maven plugin copy the content (without the asciidoctor files) of sourceDirectory (`src/docs/asciidoc`) to the `target/generated-docs`.

If you set the imagesdir property in the pom file to: `<imagesdir>./images</imagesdir>` [imagesdir2]. The path in the `src` attribute of the `img` tag doesn't point to the image.

My expectations would be that the images from
`asciidoctor-maven-examples/asciidoc-to-html-example/src/imgs` [imagesdir1]
should be copied to
`asciidoctor-maven-examples/asciidoc-to-html-example/target/generated-docs/images` [imagesdir2].
During this operation, it would be nice to copy only the images (from imagesdir1 to imagesdir2) that are used in the produced html file.

Such program is really not complicated to write (few lines of java code if you combine jsoup and google guava).
I have no idea if it is easy to plug such a program into the maven chain (in order to run it after the generation of the html using asciidoctorj).
Instead of jsoup, if acsiidoctorj is capable to produce the list of used images, this can also be used as input.

---

Maybe I do not understand it well.
Feel to explain me the philosophy behind image handling.

Another approach for asciidoctorj (or asciidoctor-maven-plugin) could be:

* with imagesdir you specify where the images are (this how it seems to work anywhere else)
* with an additional parameter imagesdir_out you specify where the images should be. The default value is iamgesdir, but if you specify something else you can.

I have noticed the gradle plugin has a special note about handling additional files.

Also related to this topic, the issue in asciidoctor-pdf about images: Images are not being correctly inserted

Reply | Threaded
Open this post in threaded view
|

Re: asciidoctor-maven-plugin and images.

abelsromero
First of all, thanks for such a thoroughly explanation, I'd try to answer point by point.
As a briefing, the main thing to understand is that  there're two separate processes:
1. Generating the images url in the final document: here imagesDir parameter (and other parameters) is used to generate the final path, which is not checked.
2. Copying resources to target folder: this is done by the plugin based on some configuration, and not by asciidoctorj or ascidoctor (ruby core).
You see, the trick is getting the correct configuration so that the final target path matches the one being generated.

= 1/ first use-case: renaming
You got it right.

== 2/ second use-case: location of the image folder
imageDir is just used to generate the images url in the final document. If you are using an HTML backend, this parameter is prepended to the image filename. In other words, nor the maven plugin, nor asciidoctorj or asciidoctor (the ruby final engine) validates if the path is correct, it just generates the path.
It is expected that imageDir is a relative to basePath, which by default is the same as sourceDirectory. Also keep in mind that if relativeBaseDir is set to true, all resources will be looked for in a relative location  to its AsciiDoc file...this is tricky.

Regarding the final target folder, the plugin kinda 'assumes' images and other resources are in a path relative to the AsciiDoc documents and I think this is an issue that we should fix. Currently only resources under the 'sourceDirectory' parameter are copied, and 'basePath' resources should be copied too.
Adding this behaviour you should be able to achieve what I think you want to do using this configuration:

<basePath>../../imgs<basePath>
<images>images</images> // this would work as long as image files are in ../../imgs/images. If you set the image files directly under  ../../imgs, images will be copied to 'target/generated-docs/' and the value should be <images></images>

However, this struck me as a weird and hard to maintain configuration. Anyway, please, feel free to open an issue on GitHub regarding baseDir resources not being copied.

About copying only used images, currently asciidoctorj (nor asciidoctor) does not provide information on things like that, it's something that has been discussed sometime and is on the work, but don't expect it soon, sorry :%

==  gradle plugin has a special note
The gradle feature is a copy-from-to function with no relation to the asciidoctor conversion process (afaik). This is easy to integrate in gradle and of course we could include something similar, but this is harder in maven and it can already be done using other plugins like http://maven.apache.org/plugins/maven-resources-plugin/. Just attach it to process-resources (assuming you use generate-resources for asciidoctor) and you'll be fine.

==  asciidoctor-pdf issue
Indeed, that's a serious issue. You have to understant that every backend is a made with a different implementation and some undesired different behauvour between some of them may arise :%

additional parameter imagesdir_out
I can see the option to set some conversion pattern useful sometimes, but I said before, it seems to me like something hard to maintain. Hard, not from the plugin but for consumers, what I mean, is that having to match different sources folders to different target folder can be complicated to deal with in a collaborative environment.

Finally, if you really want to get into the philosophy and understand what's under the hood, I recommend you to have a look at asciidoctor manual http://asciidoctor.org/docs/user-manual/ and play a bit with the command tool.

And thanks again for such analysis,  this really helps to see other points of view to improve the tools.
Reply | Threaded
Open this post in threaded view
|

Re: asciidoctor-maven-plugin and images.

Jeremie Bresson
Thank you for your feedback.

Because you told that you are interested to my setup, I can share how I plan to organize our repository:

    repository
    +---build
    |   |
    |   +---howto_install
    |   |   |   pom.xml
    |   |   |
    |   |   \---src
    |   |           howto_install.adoc
    |   |
    |   \---tutorial_helloworld
    |       |   pom.xml
    |       |
    |       \---src
    |               tutorial_helloworld.adoc
    |
    +---code
    |   +---aNewProject
    |   |       (Some *.java files)
    |   |
    |   \---helloworldJava
    |           HelloWorld.java
    |
    +---images
    |       helloworld_swing.png
    |       helloworld_swt.png
    |
    \---modules
            module1.adoc
            module2.adoc

* modules: short asciidoctor files (modules) that can be reused in several documents. They often correspond to one section of text (without any title).
* images: images for the modules and the documents.
* code: java code that can be compiled. Used in the modules.
* build: contains the documents that are build. Because maven is standard in our project and company (ci-server already provides it) it would be the preferred way for us.

----

From what you told me, for the HTML backend I think that I will go with the option of setting imagesdir in the maven pom to a not existing directory (where the images should be at the end). For example:
<imagesdir>./img</imagesdir>

This way the produced HTML will contain:
<img src="./img/helloworld_swing.png" alt="Hello World">

Then I need to copy the image form the real destination (the common images folder) to the one defined in the html document. I can do this with something similar to this method (I already have from some other experiments):
    public static void copyImages(Document doc, File inFolder, File outFolder) throws IOException {
      Elements elements = doc.getElementsByTag("img");
      for (Element element : elements) {
        String src = element.attr("src");
        if (src != null) {
          File inFile = new File(inFolder, src);
          File outFile = new File(outFolder, src);
          if (inFile.exists() && inFile.isFile()) {
            Files.createParentDirs(outFile);
            Files.copy(inFile, outFile);
          }
          else if (outFile.exists() && outFile.isFile()) {
            //the in file was not found and not copied, but the outFile already exists. Nothing to do, no warning.
          }
          else {
            System.err.println("Image file '" + inFile.getAbsolutePath() + "' is missing");
          }
        }
      }
    }

Where the doc variable is initialized like this: Document doc = Jsoup.parse(html);

I think I will be fine with this pattern. If you have some inputs, do not hesitate to share them with me (I need to do the have possible setup. Changes later on are painful).
Reply | Threaded
Open this post in threaded view
|

Re: asciidoctor-maven-plugin and images.

abelsromero
With your example I see what's the problem now, this also reminds me of another issue we have and which has been in my head some days.

Currently there's no way to deal with those complex scenarios other than manually copying files from folder to folder. In which case I'd recommend (if possible) to change your built to gradle. It is much easier to customized the build with gradle's copy tasks. Also in gradle, it would be possible to add your image copy code in the build script itself.
Another option, more risky and not available in maven now (see https://github.com/asciidoctor/asciidoctor-maven-plugin/issues/146), you could write an extension to do the copying while processing, that way you avoid parsing the HTML, and only used images are copied. This implies using the build in gradle or waiting till the issue is solved, I hope I can do something this week, but I cannot say when this will be released.
pros:
+You can make the conversion fail if an image is not found
cons:
-You create a new macro which converts means you'r not using standard AsciiDoc

Btw, I think a good approach could be an inline macro, check http://asciidoctor.org/docs/asciidoctorj/


A bit off-topic, but I think that it would be great if asciidoctor was able to get resources from the classpath, which currently can't. That way it would be possible to pack common resources in distributable jars like your 'modules' and 'images' folders.
I'm asking this to the rest of the team, could this be done in Asciidoctorj? Maybe creating a temp folder where all resources are unpacked?
Reply | Threaded
Open this post in threaded view
|

Re: asciidoctor-maven-plugin and images.

ixchelruiz
abelsromero wrote
A bit off-topic, but I think that it would be great if asciidoctor was able to get resources from the classpath, which currently can't. That way it would be possible to pack common resources in distributable jars like your 'modules' and 'images' folders.
I'm asking this to the rest of the team, could this be done in Asciidoctorj? Maybe creating a temp folder where all resources are unpacked?
I'm looking at exactly this use case. I would like to include custom images and/or icons from a springboot + asciidoctorj app.  

I have the resources (images) as a compile dependency (jar) but setting the image dir from the classpath it's impossible.

Is there any proposal? solution? work around? that you could point me towards? Please!!
Reply | Threaded
Open this post in threaded view
|

Re: asciidoctor-maven-plugin and images.

abelsromero
Not officially, and being honest, due other compromises my time is very limited lately :%

All options require to unpack the jar in a temp dir, and I think this should be managed by the building tool (maven or gradle). Some attempt to standardize this for maven was done here https://discuss.asciidoctor.org/About-Asciidoctor-Maven-integration-A-custom-lifecycle-td7063.html.
Maybe we can push this effort to close a proposal.