2

I am trying to use TwelveMonkeys in my application to deal with thumbnail generation. Also, I am using maven-dependency-plugin to unpack all dependencies and create a FAT jar. Though, plugin work quite well in normal scenarios, but simply not working when used with maven-dependency-plugin. Here is my POM XML:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.prakhar</groupId>
    <artifactId>demo</artifactId>
    <name>demo</name>

    <packaging>jar</packaging>
    <version>0.0.1-SNAPSHOT</version>

    <organization>
        <!-- Used as the 'Vendor' for JNLP generation -->
        <name>Your Organisation</name>
    </organization>

    <properties>
        <slf4j.version>1.6.1</slf4j.version>
    </properties>

    <build>
        <plugins>

            <plugin>
                <!-- Get the dependencies jar files to a common place, for jar signing -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>unpack-dependencies</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>unpack-dependencies</goal>
                        </goals>
                        <configuration>
                            <!-- <includeArtifactIds>commons-net,imageio-bmp,imageio-jpeg,imageio-tiff,imageio-pnm,imageio-psd,imageio-iff,imageio-pcx,imageio-pict,imageio-sgi,imageio-tga,imageio-icns,imageio-thumbsdb,imageio-core,imageio-metadata,common-lang,common-io,common-image</includeArtifactIds> -->
                            <outputDirectory>${project.build.directory}/classes</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>


    <dependencies>

        <!-- MigLayout -->



        <!-- Apache Commons -->

        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>

        <!-- Logging  -->

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>

        <!-- Twelve Monkeys dependencies -->
        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-bmp</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-jpeg</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-tiff</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-pnm</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-psd</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-iff</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-pcx</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-pict</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-sgi</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-tga</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-icns</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.twelvemonkeys.imageio</groupId>
            <artifactId>imageio-thumbsdb</artifactId>
            <version>3.1.1</version>
        </dependency>

    </dependencies>

</project>

And, here is my function:

private static void convertToJpg(File file) {
    try {
        BufferedImage image = ImageIO.read(file);

        int width = 300, height = 200; // new width/height

        BufferedImageOp resampler = new ResampleOp(width, height, ResampleOp.FILTER_LANCZOS); // A good default filter, see class documentation for more info
        BufferedImage thumbnailImg = resampler.filter(image, null);

        FileImageOutputStream fios = new FileImageOutputStream(new File(file.getAbsolutePath() + ".png"));

        if (!ImageIO.write(thumbnailImg, "PNG", fios)) {
            System.out.println("ERROR: Unable to convert image " + file.getAbsolutePath());
        } else {
            System.out.println("SUCCESS: Image " + file.getAbsolutePath() + ".png converted successfully");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Here is the exception I am getting:

java.lang.NullPointerException: Input == null
    at com.twelvemonkeys.image.ResampleOp.filter(Unknown Source)

If anybody have any idea of how might be solved, please state.

Prakhar Mishra
  • 1,586
  • 4
  • 28
  • 52
  • 2
    What kind of file are you trying to read? The error message suggests you have no reader plugin for the file format. I don't know exactly how the fat-jar plugin works, but I know that each `imageio-xxx.jar` plugin contains images under `META-INF/services/` with the same name. *These needs to be merged somehow.* If they are overwritten, the plugins will not be registered. – Harald K Sep 18 '15 at 07:32
  • 1
    @myself: There's a typo in the comment above. ;-) It should say "*each `imageio-xxx.jar` plugin contains **resources** under `META-INF/services/` with the same name*". That is, there are multiple `META-INF/services/javax.imageio.spi.ImageReaderSpi` (and other) resources, that needs to be merged into a single resource. I'm not sure how the Maven plugin handles that. – Harald K Sep 18 '15 at 12:13
  • 1
    The Maven Shade plugin seems to provide a solution for this, see Resource transformers, especially the [ServicesResourceTransformer](https://maven.apache.org/plugins/maven-shade-plugin/examples/resource-transformers.html#ServicesResourceTransformer). – Harald K Sep 18 '15 at 12:24
  • 1
    @haraldK, Thank you very much for pointing me towards `META-INF/services/` folder. Shade plugin did hit the spot. I replaced it with legacy `maven-dependency-plugin` – Prakhar Mishra Sep 18 '15 at 12:43

1 Answers1

4

To sum it up, for future readers, the problem is that each ImageIO plugin JAR contains multiple resources under META-INF/services. These resources are needed for automatic discovery of the ImageIO plugins. They are:

META-INF/services/javax.imageio.spi.ImageReaderSpi
META-INF/services/javax.imageio.spi.ImageWriterSpi
META-INF/services/javax.imageio.spi.ImageInpuStreamSpi
META-INF/services/javax.imageio.spi.ImageOutputStreamSpi

There might be more, but these are not used by TwelveMonkeys.

For the interested you can read more about the Service Provider Interface mechanism and the ServiceRegistry class in particular.

When you unpack all the JAR files into a single folder, these will be overwritten for each JAR. Instead, the resources with the same name needs to be merged into a new, single resource.

The Maven Shade plugin provides a solution for this, see Resource transformers, especially the ServicesResourceTransformer.

Harald K
  • 26,314
  • 7
  • 65
  • 111
  • My quick and temporary solution was to add this line `com.twelvemonkeys.imageio.plugins.pnm.PNMImageReaderSpi` to `/META-INF/services/javax.imageio.spi.ImageReaderSpi` since I only needed to read PNM/PGM files. It worked well for submitting my assignment! – Will Hardwick-Smith Aug 18 '16 at 03:15