JAI vendorname == null

独自空忆成欢 提交于 2019-12-17 12:17:00

问题


So I finished coding my application to rotate TIFF images which required JAI to manipulate the TIFFs.

It works fine when working under Eclipse, but whenever I build a fat jar for the library and then create one implementing that (per http://fjep.sourceforge.net/fjeptutorial.html), when I do the java -jar Push.jar \path\to\dir, it runs up until it hits the part where it is compressing and saving:

TIFFImageWriterSpi tiffspi = new TIFFImageWriterSpi();
ImageWriter writer = tiffspi.createWriterInstance();
//Iterator<ImageWriter> iter =  ImageIO.getImageWritersByFormatName("TIFF");
//ImageWriter writer = iter.next();

ImageWriteParam param2 = writer.getDefaultWriteParam();
param2.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);

param2.setCompressionType("LZW");
param2.setCompressionQuality(0.0f);
File fOutputFile = workArea[i];
ImageOutputStream ios = ImageIO.createImageOutputStream(fOutputFile);
writer.setOutput(ios);

if (frontPage == 1)
{
     writer.write(null, new IIOImage(pg1, null, null), param2);
     writer.writeInsert(-1, new IIOImage(pg2, null, null), param2);
}
else if (frontPage == 2)
{
     writer.write(null, new IIOImage(pg2, null, null), param2);
     writer.writeInsert(-1, new IIOImage(pg1, null, null), param2);
}

remaining = remaining - 1;
    if (remaining > 0)
     System.out.println(remaining + " remaining.");
else
     System.out.println("Done.");

It blows up on the first line of that section with the message:

 Exception in thread "main" java.lang.IllegalArgumentException: vendorName == null!
 ....rest of stack trace.

回答1:


Since I spent a considerable amount of time debugging this problem, I thought I would share my solution here, despite the age of the question. Srikanth's second link was particularly helpful.

Reason for the error

JAI requires a vendor name for some of its deep internals, particularly the javax.imageio.spi.IIOServiceProvider which gets used by many (all?) of the image readers for their low-level IO. It's not picky what the string is, but it can't be null.

Rather than hard-code the vendor name, the ImageReaderSpi class gets the vendor name from sun.media.imageioimpl.common.PackageUtil.getVendor(). This in turn reads it from the jar's MANIFEST.MF. Normally you link against the standard jai-imageio packagage, so Sun's vendor info gets read. However, since you're making a fat jar file, you replaced Sun's MANIFEST.MF with your own which lacks the required information.

Solution

Include the following lines in your MANIFEST.MF file:

Specification-Title: Java Advanced Imaging Image I/O Tools
Specification-Version: 1.1
Specification-Vendor: Sun Microsystems, Inc.
Implementation-Title: com.sun.media.imageio
Implementation-Version: 1.1
Implementation-Vendor: Sun Microsystems, Inc.

The values for each property can be anything (I used my specific application/version/company), as long as all six are defined.

Maven

If you were using maven's assembly plugin to create your fat jar, maven can automatically include the correct version numbers and such. Update your pom.xml with the following <archive> section:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <archive>
            <manifest>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            </manifest>
            <manifestEntries>
                <Specification-Vendor>MyCompany</Specification-Vendor>
                <Implementation-Vendor>MyCompany</Implementation-Vendor>
            </manifestEntries>
        </archive>
    </configuration>
    <executions>
        <execution>
            <id>create-my-bundle</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>



回答2:


I had to use this ImageIO jar. It worked like a charm. Found it here.




回答3:


The accepted answer by Quantum7 explains the source of the problem, and in the Maven section it provides a solution when using the Maven Assembly plugin to produce a JAR including dependencies. If you are instead using the Maven Shade plugin to produce the JAR with dependencies, the configuration is slightly different. You can add something like the following to the configuration section of the Shade plugin in your pom.xml:

<configuration>
    <transformers>
        <transformer
                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <manifestEntries>
                <Main-Class>com.conveyal.r5.R5Main</Main-Class>
                <Specification-Title>Java Advanced Imaging Image I/O Tools</Specification-Title>
                <Specification-Version>1.1</Specification-Version>
                <Specification-Vendor>Sun Microsystems, Inc.</Specification-Vendor>
                <Implementation-Title>com.sun.media.imageio</Implementation-Title>
                <Implementation-Version>1.1</Implementation-Version>
                <Implementation-Vendor>Sun Microsystems, Inc.</Implementation-Vendor>
                <Extension-Name>com.sun.media.imageio</Extension-Name>
            </manifestEntries>
        </transformer>
    </transformers>
</configuration>



回答4:


These can help you to solve the problem.

How to run jai-imageio with source code

vendorName == null




回答5:


DISCLAIMER

The issue that I was having was slightly different, I was getting the "ClassNotFound" error while trying to run a compiled jar file. I happened upon this SO question while researching, so for others who followed the same trail that I did, here you go.

Possible Solution to ClassNotFound Error

To those who may find this question later on, if nothing else seems to work, You could try using the Apache Shader plugin for Maven. Here is some more information on it.

I'm not experienced enough to be able to tell you how it does it, but Apache Shader packages all the used dependencies in your project into the final jar file, so that all the dependencies are included in the META-INF folder when it's built. This increases the size of the jar file (depending on how many libraries you used in your project), but also seems to fix the jar not being able to find classes from outside libraries that are used.

To use the Shader plugin, add the following to your POM. I included it after the dependencies tag and before the properties tag.

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.4.3</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <filters>
                            <filter>
                                <artifact>*:*</artifact>
                                <excludes>
                                    <exclude>META-INF/*.SF</exclude>
                                    <exclude>META-INF/*.DSA</exclude>
                                    <exclude>META-INF/*.RSA</exclude>
                                </excludes>
                            </filter>
                        </filters>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <manifestEntries>
                                    <Main-Class>com.package.name.className</Main-Class>
                                    <Build-Number>1</Build-Number>
                                </manifestEntries>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

NOTE: Make sure you change the package and class name to reflect your project's package and class names.

Other useful links: Similar stack overflow question




回答6:


(Would have been a comment on Quantum7's answer if I had enough reputation)

I ran into the same problem. Quantum7's answer saved the day! After putting in manifestEntries Specification-Vendor and Implementation-Vendor, however, the execution of my fat jar still failed with the exception below. Note it is

version == null!

not

vendorName == null!

java.util.ServiceConfigurationError: javax.imageio.spi.ImageReaderSpi: Provider com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReaderSpi could not be instantiated
        at java.util.ServiceLoader.fail(Unknown Source)
        at java.util.ServiceLoader.access$100(Unknown Source)
        at java.util.ServiceLoader$LazyIterator.nextService(Unknown Source)
        at java.util.ServiceLoader$LazyIterator.next(Unknown Source)
        at java.util.ServiceLoader$1.next(Unknown Source)
        at javax.imageio.spi.IIORegistry.registerApplicationClasspathSpis(Unknown Source)
        at javax.imageio.spi.IIORegistry.<init>(Unknown Source)
        at javax.imageio.spi.IIORegistry.getDefaultInstance(Unknown Source)
        at javax.imageio.ImageIO.<clinit>(Unknown Source)
        at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalArgumentException: version == null!
        at javax.imageio.spi.IIOServiceProvider.<init>(Unknown Source)
        at javax.imageio.spi.ImageReaderWriterSpi.<init>(Unknown Source)
        at javax.imageio.spi.ImageReaderSpi.<init>(Unknown Source)
        at com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReaderSpi.<init>(CLibJPEGImageReaderSpi.java:80)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
        at java.lang.reflect.Constructor.newInstance(Unknown Source)
        at java.lang.Class.newInstance(Unknown Source)
        ... 14 more

Putting in manifestEntries below fixed it.

<manifestEntries>
    <Specification-Title>Java Advanced Imaging Image I/O Tools</Specification-Title>
    <Specification-Version>1.1</Specification-Version>
    <Specification-Vendor>Sun Microsystems, Inc.</Specification-Vendor>
    <Implementation-Title>com.sun.media.imageio</Implementation-Title>
    <Implementation-Version>1.1</Implementation-Version>
    <Implementation-Vendor>Sun Microsystems, Inc.</Implementation-Vendor>
</manifestEntries>

When running the fat jar, I made sure that none of the three values in the code below is null.

import com.sun.media.imageioimpl.common.PackageUtil;

public class ManifestCheck {
    public static void main(String[] args) {
        System.out.println(PackageUtil.getVendor());
        System.out.println(PackageUtil.getVersion());
        System.out.println(PackageUtil.getSpecificationTitle());
    }
}


来源:https://stackoverflow.com/questions/7051603/jai-vendorname-null

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!