Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javax.imageio.ImageIO file format constants

In javax.imageio.ImageIO there is a method #write(RenderedImage im, String formatName, OutputStream output) that accepts a "stringly-typed" format developer wants image to be written to.

There is an inner class called CanEncodeImageAndFormatFilter deep inside that file that checks if there is an SPI (whatever it is) that supports the aforementioned format. For example, BMPImageWriterSpi declares

    private static String[] formatNames = {"bmp", "BMP"};

But in all these SPI-classes these format names are declared either private or package-default, so I cannot access them in my application. But I'd like to expose that format parameter in API I'm working on right now, but I don't want to reinvent the wheel.

➥ Is there an enum or something I can safely use as a format name parameter for the #write method?

Yes, this is more like an opinion based question with coding-style tag. :D


UPD: What I have:
ImageIO.write(image, "jpg", outStream);

What I want:

ImageIO.write(image, ImageTypes.JPEG, outStream);
like image 729
Xobotun Avatar asked Nov 28 '19 12:11

Xobotun


1 Answers

There is no such Enum you are looking for in the default Java API.

The reason is that the Java Image I/O API uses the Service provider interface (SPI). Which allows to create extensible applications. In the scope of your question additional image reader/writer classes (which implements the respective interface) can be added to the classpath and will be discovered automatically during runtime. The application can use them without even knowing at compile time they exist. Hence such Enum not exist.

You can discover all currently known ImageWriter implementations with following snippet.

import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ImageWriterSpi;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        IIORegistry registry = IIORegistry.getDefaultInstance();
        Iterator<ImageWriterSpi> serviceProviders = registry.getServiceProviders(ImageWriterSpi.class, false);
        while(serviceProviders.hasNext()) {
            ImageWriterSpi next = serviceProviders.next();
            System.out.printf("description: %-27s   format names: %s%n",
                    next.getDescription(Locale.ENGLISH),
                    Arrays.toString(next.getFormatNames())
            );
        }
    }
}

output for Java 13

description: Standard BMP Image Writer     format names: [bmp, BMP]
description: Standard JPEG Image Writer    format names: [JPEG, jpeg, JPG, jpg]
description: Standard WBMP Image Writer    format names: [wbmp, WBMP]
description: Standard PNG image writer     format names: [png, PNG]
description: Standard GIF image writer     format names: [gif, GIF]
description: Standard TIFF image writer    format names: [tif, TIF, tiff, TIFF]

Below is a simplified example how the SPI could be used.

assume following files in the current directory

Main.class                  - the one from above source
ExampleImageWriterSpi.java  - an example implementation of the ImageWriterSpi

ExampleImageWriterSpi.java

package sub.optimal;

import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter;
import javax.imageio.spi.ImageWriterSpi;
import java.io.IOException;
import java.util.Locale;

public class ExampleImageWriterSpi extends ImageWriterSpi {

    private static final String[] formatNames = { "xyz", "XYZ"};

    public String getDescription(Locale locale) {
        return "Example XYZ image writer";
    }

    @Override
    public String[] getFormatNames() {
        return formatNames;
    }

    // following is without implementation in this example
    public boolean canEncodeImage(ImageTypeSpecifier type) {
        return false;
    }

    public ImageWriter createWriterInstance(Object extension) throws IOException {
        return null;
    }
}

compile the class

javac ExampleImageWriterSpi.java

create the provider configuration file
(the filename specifies the implemented interface, the line specifies the implementing class)

mkdir -p META-INF/services/
echo sub.optimal.ExampleImageWriterSpi > META-INF/services/javax.imageio.spi.ImageWriterSpi

create an archive for the service provider

jar cf example-image-writer.jar META-INF/ sub/

run the plain example code

java Main

output (all service providers which are part of the Java runtime)

description: Standard BMP Image Writer     format names: [bmp, BMP]
description: Standard JPEG Image Writer    format names: [JPEG, jpeg, JPG, jpg]
description: Standard WBMP Image Writer    format names: [wbmp, WBMP]
description: Standard PNG image writer     format names: [png, PNG]
description: Standard GIF image writer     format names: [gif, GIF]
description: Standard TIFF image writer    format names: [tif, TIF, tiff, TIFF]

run the example with the additional service provider

java -cp example-image-writer.jar:. Main

output

description: Example XYZ image writer      format names: [xyz, XYZ]
description: Standard JPEG Image Writer    format names: [JPEG, jpeg, JPG, jpg]
description: Standard WBMP Image Writer    format names: [wbmp, WBMP]
description: Standard PNG image writer     format names: [png, PNG]
description: Standard GIF image writer     format names: [gif, GIF]
description: Standard BMP Image Writer     format names: [bmp, BMP]
description: Standard TIFF image writer    format names: [tif, TIF, tiff, TIFF]

You might create the enum yourself. But you should check at runtime if there is a provider available for this image type. e.g. TIFF was not available in the Java runtime before Java 9.

like image 117
SubOptimal Avatar answered Sep 19 '22 01:09

SubOptimal