| /* | |
| * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package javax.imageio.spi; | |
| import java.lang.reflect.Method; | |
| import javax.imageio.metadata.IIOMetadata; | |
| import javax.imageio.metadata.IIOMetadataFormat; | |
| import javax.imageio.metadata.IIOMetadataFormatImpl; | |
| /** | |
| * A superclass containing instance variables and methods common to | |
| * {@code ImageReaderSpi} and {@code ImageWriterSpi}. | |
| * | |
| * @see IIORegistry | |
| * @see ImageReaderSpi | |
| * @see ImageWriterSpi | |
| * | |
| */ | |
| public abstract class ImageReaderWriterSpi extends IIOServiceProvider { | |
| /** | |
| * An array of strings to be returned from | |
| * {@code getFormatNames}, initially {@code null}. | |
| * Constructors should set this to a non-{@code null} value. | |
| */ | |
| protected String[] names = null; | |
| /** | |
| * An array of strings to be returned from | |
| * {@code getFileSuffixes}, initially {@code null}. | |
| */ | |
| protected String[] suffixes = null; | |
| /** | |
| * An array of strings to be returned from | |
| * {@code getMIMETypes}, initially {@code null}. | |
| */ | |
| protected String[] MIMETypes = null; | |
| /** | |
| * A {@code String} containing the name of the associated | |
| * plug-in class, initially {@code null}. | |
| */ | |
| protected String pluginClassName = null; | |
| /** | |
| * A boolean indicating whether this plug-in supports the | |
| * standard metadata format for stream metadata, initially | |
| * {@code false}. | |
| */ | |
| protected boolean supportsStandardStreamMetadataFormat = false; | |
| /** | |
| * A {@code String} containing the name of the native stream | |
| * metadata format supported by this plug-in, initially | |
| * {@code null}. | |
| */ | |
| protected String nativeStreamMetadataFormatName = null; | |
| /** | |
| * A {@code String} containing the class name of the native | |
| * stream metadata format supported by this plug-in, initially | |
| * {@code null}. | |
| */ | |
| protected String nativeStreamMetadataFormatClassName = null; | |
| /** | |
| * An array of {@code String}s containing the names of any | |
| * additional stream metadata formats supported by this plug-in, | |
| * initially {@code null}. | |
| */ | |
| protected String[] extraStreamMetadataFormatNames = null; | |
| /** | |
| * An array of {@code String}s containing the class names of | |
| * any additional stream metadata formats supported by this plug-in, | |
| * initially {@code null}. | |
| */ | |
| protected String[] extraStreamMetadataFormatClassNames = null; | |
| /** | |
| * A boolean indicating whether this plug-in supports the | |
| * standard metadata format for image metadata, initially | |
| * {@code false}. | |
| */ | |
| protected boolean supportsStandardImageMetadataFormat = false; | |
| /** | |
| * A {@code String} containing the name of the | |
| * native stream metadata format supported by this plug-in, | |
| * initially {@code null}. | |
| */ | |
| protected String nativeImageMetadataFormatName = null; | |
| /** | |
| * A {@code String} containing the class name of the | |
| * native stream metadata format supported by this plug-in, | |
| * initially {@code null}. | |
| */ | |
| protected String nativeImageMetadataFormatClassName = null; | |
| /** | |
| * An array of {@code String}s containing the names of any | |
| * additional image metadata formats supported by this plug-in, | |
| * initially {@code null}. | |
| */ | |
| protected String[] extraImageMetadataFormatNames = null; | |
| /** | |
| * An array of {@code String}s containing the class names of | |
| * any additional image metadata formats supported by this | |
| * plug-in, initially {@code null}. | |
| */ | |
| protected String[] extraImageMetadataFormatClassNames = null; | |
| /** | |
| * Constructs an {@code ImageReaderWriterSpi} with a given | |
| * set of values. | |
| * | |
| * @param vendorName the vendor name, as a non-{@code null} | |
| * {@code String}. | |
| * @param version a version identifier, as a non-{@code null} | |
| * {@code String}. | |
| * @param names a non-{@code null} array of | |
| * {@code String}s indicating the format names. At least one | |
| * entry must be present. | |
| * @param suffixes an array of {@code String}s indicating the | |
| * common file suffixes. If no suffixes are defined, | |
| * {@code null} should be supplied. An array of length 0 | |
| * will be normalized to {@code null}. | |
| * @param MIMETypes an array of {@code String}s indicating | |
| * the format's MIME types. If no MIME types are defined, | |
| * {@code null} should be supplied. An array of length 0 | |
| * will be normalized to {@code null}. | |
| * @param pluginClassName the fully-qualified name of the | |
| * associated {@code ImageReader} or {@code ImageWriter} | |
| * class, as a non-{@code null String}. | |
| * @param supportsStandardStreamMetadataFormat a | |
| * {@code boolean} that indicates whether a stream metadata | |
| * object can use trees described by the standard metadata format. | |
| * @param nativeStreamMetadataFormatName a | |
| * {@code String}, or {@code null}, to be returned from | |
| * {@code getNativeStreamMetadataFormatName}. | |
| * @param nativeStreamMetadataFormatClassName a | |
| * {@code String}, or {@code null}, to be used to instantiate | |
| * a metadata format object to be returned from | |
| * {@code getNativeStreamMetadataFormat}. | |
| * @param extraStreamMetadataFormatNames an array of | |
| * {@code String}s, or {@code null}, to be returned from | |
| * {@code getExtraStreamMetadataFormatNames}. An array of length | |
| * 0 is normalized to {@code null}. | |
| * @param extraStreamMetadataFormatClassNames an array of | |
| * {@code String}s, or {@code null}, to be used to instantiate | |
| * a metadata format object to be returned from | |
| * {@code getStreamMetadataFormat}. An array of length | |
| * 0 is normalized to {@code null}. | |
| * @param supportsStandardImageMetadataFormat a | |
| * {@code boolean} that indicates whether an image metadata | |
| * object can use trees described by the standard metadata format. | |
| * @param nativeImageMetadataFormatName a | |
| * {@code String}, or {@code null}, to be returned from | |
| * {@code getNativeImageMetadataFormatName}. | |
| * @param nativeImageMetadataFormatClassName a | |
| * {@code String}, or {@code null}, to be used to instantiate | |
| * a metadata format object to be returned from | |
| * {@code getNativeImageMetadataFormat}. | |
| * @param extraImageMetadataFormatNames an array of | |
| * {@code String}s to be returned from | |
| * {@code getExtraImageMetadataFormatNames}. An array of length 0 | |
| * is normalized to {@code null}. | |
| * @param extraImageMetadataFormatClassNames an array of | |
| * {@code String}s, or {@code null}, to be used to instantiate | |
| * a metadata format object to be returned from | |
| * {@code getImageMetadataFormat}. An array of length | |
| * 0 is normalized to {@code null}. | |
| * | |
| * @throws IllegalArgumentException if {@code vendorName} | |
| * is {@code null}. | |
| * @throws IllegalArgumentException if {@code version} | |
| * is {@code null}. | |
| * @throws IllegalArgumentException if {@code names} | |
| * is {@code null} or has length 0. | |
| * @throws IllegalArgumentException if {@code pluginClassName} | |
| * is {@code null}. | |
| */ | |
| public ImageReaderWriterSpi(String vendorName, | |
| String version, | |
| String[] names, | |
| String[] suffixes, | |
| String[] MIMETypes, | |
| String pluginClassName, | |
| boolean supportsStandardStreamMetadataFormat, | |
| String nativeStreamMetadataFormatName, | |
| String nativeStreamMetadataFormatClassName, | |
| String[] extraStreamMetadataFormatNames, | |
| String[] extraStreamMetadataFormatClassNames, | |
| boolean supportsStandardImageMetadataFormat, | |
| String nativeImageMetadataFormatName, | |
| String nativeImageMetadataFormatClassName, | |
| String[] extraImageMetadataFormatNames, | |
| String[] extraImageMetadataFormatClassNames) { | |
| super(vendorName, version); | |
| if (names == null) { | |
| throw new IllegalArgumentException("names == null!"); | |
| } | |
| if (names.length == 0) { | |
| throw new IllegalArgumentException("names.length == 0!"); | |
| } | |
| if (pluginClassName == null) { | |
| throw new IllegalArgumentException("pluginClassName == null!"); | |
| } | |
| this.names = names.clone(); | |
| // If length == 0, leave it null | |
| if (suffixes != null && suffixes.length > 0) { | |
| this.suffixes = suffixes.clone(); | |
| } | |
| // If length == 0, leave it null | |
| if (MIMETypes != null && MIMETypes.length > 0) { | |
| this.MIMETypes = MIMETypes.clone(); | |
| } | |
| this.pluginClassName = pluginClassName; | |
| this.supportsStandardStreamMetadataFormat = | |
| supportsStandardStreamMetadataFormat; | |
| this.nativeStreamMetadataFormatName = nativeStreamMetadataFormatName; | |
| this.nativeStreamMetadataFormatClassName = | |
| nativeStreamMetadataFormatClassName; | |
| // If length == 0, leave it null | |
| if (extraStreamMetadataFormatNames != null && | |
| extraStreamMetadataFormatNames.length > 0) { | |
| this.extraStreamMetadataFormatNames = | |
| extraStreamMetadataFormatNames.clone(); | |
| } | |
| // If length == 0, leave it null | |
| if (extraStreamMetadataFormatClassNames != null && | |
| extraStreamMetadataFormatClassNames.length > 0) { | |
| this.extraStreamMetadataFormatClassNames = | |
| extraStreamMetadataFormatClassNames.clone(); | |
| } | |
| this.supportsStandardImageMetadataFormat = | |
| supportsStandardImageMetadataFormat; | |
| this.nativeImageMetadataFormatName = nativeImageMetadataFormatName; | |
| this.nativeImageMetadataFormatClassName = | |
| nativeImageMetadataFormatClassName; | |
| // If length == 0, leave it null | |
| if (extraImageMetadataFormatNames != null && | |
| extraImageMetadataFormatNames.length > 0) { | |
| this.extraImageMetadataFormatNames = | |
| extraImageMetadataFormatNames.clone(); | |
| } | |
| // If length == 0, leave it null | |
| if (extraImageMetadataFormatClassNames != null && | |
| extraImageMetadataFormatClassNames.length > 0) { | |
| this.extraImageMetadataFormatClassNames = | |
| extraImageMetadataFormatClassNames.clone(); | |
| } | |
| } | |
| /** | |
| * Constructs a blank {@code ImageReaderWriterSpi}. It is up | |
| * to the subclass to initialize instance variables and/or | |
| * override method implementations in order to provide working | |
| * versions of all methods. | |
| */ | |
| public ImageReaderWriterSpi() { | |
| } | |
| /** | |
| * Returns an array of {@code String}s containing | |
| * human-readable names for the formats that are generally usable | |
| * by the {@code ImageReader} or {@code ImageWriter} | |
| * implementation associated with this service provider. For | |
| * example, a single {@code ImageReader} might be able to | |
| * process both PBM and PNM files. | |
| * | |
| * @return a non-{@code null} array of {@code String}s | |
| * or length at least 1 containing informal format names | |
| * associated with this reader or writer. | |
| */ | |
| public String[] getFormatNames() { | |
| return names.clone(); | |
| } | |
| /** | |
| * Returns an array of {@code String}s containing a list of | |
| * file suffixes associated with the formats that are generally | |
| * usable by the {@code ImageReader} or | |
| * {@code ImageWriter} implementation associated with this | |
| * service provider. For example, a single | |
| * {@code ImageReader} might be able to process files with | |
| * '.pbm' and '.pnm' suffixes, or both '.jpg' and '.jpeg' | |
| * suffixes. If there are no known file suffixes, | |
| * {@code null} will be returned. | |
| * | |
| * <p> Returning a particular suffix does not guarantee that files | |
| * with that suffix can be processed; it merely indicates that it | |
| * may be worthwhile attempting to decode or encode such files | |
| * using this service provider. | |
| * | |
| * @return an array of {@code String}s or length at least 1 | |
| * containing common file suffixes associated with this reader or | |
| * writer, or {@code null}. | |
| */ | |
| public String[] getFileSuffixes() { | |
| return suffixes == null ? null : suffixes.clone(); | |
| } | |
| /** | |
| * Returns an array of {@code String}s containing a list of | |
| * MIME types associated with the formats that are generally | |
| * usable by the {@code ImageReader} or | |
| * {@code ImageWriter} implementation associated with this | |
| * service provider. | |
| * | |
| * <p> Ideally, only a single MIME type would be required in order | |
| * to describe a particular format. However, for several reasons | |
| * it is necessary to associate a list of types with each service | |
| * provider. First, many common image file formats do not have | |
| * standard MIME types, so a list of commonly used unofficial | |
| * names will be required, such as {@code image/x-pbm} and | |
| * {@code image/x-portable-bitmap}. Some file formats have | |
| * official MIME types but may sometimes be referred to using | |
| * their previous unofficial designations, such as | |
| * {@code image/x-png} instead of the official | |
| * {@code image/png}. Finally, a single service provider may | |
| * be capable of parsing multiple distinct types from the MIME | |
| * point of view, for example {@code image/x-xbitmap} and | |
| * {@code image/x-xpixmap}. | |
| * | |
| * <p> Returning a particular MIME type does not guarantee that | |
| * files claiming to be of that type can be processed; it merely | |
| * indicates that it may be worthwhile attempting to decode or | |
| * encode such files using this service provider. | |
| * | |
| * @return an array of {@code String}s or length at least 1 | |
| * containing MIME types associated with this reader or writer, or | |
| * {@code null}. | |
| */ | |
| public String[] getMIMETypes() { | |
| return MIMETypes == null ? null : MIMETypes.clone(); | |
| } | |
| /** | |
| * Returns the fully-qualified class name of the | |
| * {@code ImageReader} or {@code ImageWriter} plug-in | |
| * associated with this service provider. | |
| * | |
| * @return the class name, as a non-{@code null} | |
| * {@code String}. | |
| */ | |
| public String getPluginClassName() { | |
| return pluginClassName; | |
| } | |
| /** | |
| * Returns {@code true} if the standard metadata format is | |
| * among the document formats recognized by the | |
| * {@code getAsTree} and {@code setFromTree} methods on | |
| * the stream metadata objects produced or consumed by this | |
| * plug-in. | |
| * | |
| * @return {@code true} if the standard format is supported | |
| * for stream metadata. | |
| */ | |
| public boolean isStandardStreamMetadataFormatSupported() { | |
| return supportsStandardStreamMetadataFormat; | |
| } | |
| /** | |
| * Returns the name of the "native" stream metadata format for | |
| * this plug-in, which typically allows for lossless encoding and | |
| * transmission of the stream metadata stored in the format handled by | |
| * this plug-in. If no such format is supported, | |
| * {@code null} will be returned. | |
| * | |
| * <p> The default implementation returns the | |
| * {@code nativeStreamMetadataFormatName} instance variable, | |
| * which is typically set by the constructor. | |
| * | |
| * @return the name of the native stream metadata format, or | |
| * {@code null}. | |
| * | |
| */ | |
| public String getNativeStreamMetadataFormatName() { | |
| return nativeStreamMetadataFormatName; | |
| } | |
| /** | |
| * Returns an array of {@code String}s containing the names | |
| * of additional document formats, other than the native and | |
| * standard formats, recognized by the | |
| * {@code getAsTree} and {@code setFromTree} methods on | |
| * the stream metadata objects produced or consumed by this | |
| * plug-in. | |
| * | |
| * <p> If the plug-in does not handle metadata, null should be | |
| * returned. | |
| * | |
| * <p> The set of formats may differ according to the particular | |
| * images being read or written; this method should indicate all | |
| * the additional formats supported by the plug-in under any | |
| * circumstances. | |
| * | |
| * <p> The default implementation returns a clone of the | |
| * {@code extraStreamMetadataFormatNames} instance variable, | |
| * which is typically set by the constructor. | |
| * | |
| * @return an array of {@code String}s, or null. | |
| * | |
| * @see IIOMetadata#getMetadataFormatNames | |
| * @see #getExtraImageMetadataFormatNames | |
| * @see #getNativeStreamMetadataFormatName | |
| */ | |
| public String[] getExtraStreamMetadataFormatNames() { | |
| return extraStreamMetadataFormatNames == null ? | |
| null : extraStreamMetadataFormatNames.clone(); | |
| } | |
| /** | |
| * Returns {@code true} if the standard metadata format is | |
| * among the document formats recognized by the | |
| * {@code getAsTree} and {@code setFromTree} methods on | |
| * the image metadata objects produced or consumed by this | |
| * plug-in. | |
| * | |
| * @return {@code true} if the standard format is supported | |
| * for image metadata. | |
| */ | |
| public boolean isStandardImageMetadataFormatSupported() { | |
| return supportsStandardImageMetadataFormat; | |
| } | |
| /** | |
| * Returns the name of the "native" image metadata format for | |
| * this plug-in, which typically allows for lossless encoding and | |
| * transmission of the image metadata stored in the format handled by | |
| * this plug-in. If no such format is supported, | |
| * {@code null} will be returned. | |
| * | |
| * <p> The default implementation returns the | |
| * {@code nativeImageMetadataFormatName} instance variable, | |
| * which is typically set by the constructor. | |
| * | |
| * @return the name of the native image metadata format, or | |
| * {@code null}. | |
| * | |
| * @see #getExtraImageMetadataFormatNames | |
| */ | |
| public String getNativeImageMetadataFormatName() { | |
| return nativeImageMetadataFormatName; | |
| } | |
| /** | |
| * Returns an array of {@code String}s containing the names | |
| * of additional document formats, other than the native and | |
| * standard formats, recognized by the | |
| * {@code getAsTree} and {@code setFromTree} methods on | |
| * the image metadata objects produced or consumed by this | |
| * plug-in. | |
| * | |
| * <p> If the plug-in does not handle image metadata, null should | |
| * be returned. | |
| * | |
| * <p> The set of formats may differ according to the particular | |
| * images being read or written; this method should indicate all | |
| * the additional formats supported by the plug-in under any circumstances. | |
| * | |
| * <p> The default implementation returns a clone of the | |
| * {@code extraImageMetadataFormatNames} instance variable, | |
| * which is typically set by the constructor. | |
| * | |
| * @return an array of {@code String}s, or null. | |
| * | |
| * @see IIOMetadata#getMetadataFormatNames | |
| * @see #getExtraStreamMetadataFormatNames | |
| * @see #getNativeImageMetadataFormatName | |
| */ | |
| public String[] getExtraImageMetadataFormatNames() { | |
| return extraImageMetadataFormatNames == null ? | |
| null : extraImageMetadataFormatNames.clone(); | |
| } | |
| /** | |
| * Returns an {@code IIOMetadataFormat} object describing the | |
| * given stream metadata format, or {@code null} if no | |
| * description is available. The supplied name must be the native | |
| * stream metadata format name, the standard metadata format name, | |
| * or one of those returned by | |
| * {@code getExtraStreamMetadataFormatNames}. | |
| * | |
| * @param formatName the desired stream metadata format. | |
| * | |
| * @return an {@code IIOMetadataFormat} object. | |
| * | |
| * @throws IllegalArgumentException if {@code formatName} | |
| * is {@code null} or is not a supported name. | |
| */ | |
| public IIOMetadataFormat getStreamMetadataFormat(String formatName) { | |
| return getMetadataFormat(formatName, | |
| supportsStandardStreamMetadataFormat, | |
| nativeStreamMetadataFormatName, | |
| nativeStreamMetadataFormatClassName, | |
| extraStreamMetadataFormatNames, | |
| extraStreamMetadataFormatClassNames); | |
| } | |
| /** | |
| * Returns an {@code IIOMetadataFormat} object describing the | |
| * given image metadata format, or {@code null} if no | |
| * description is available. The supplied name must be the native | |
| * image metadata format name, the standard metadata format name, | |
| * or one of those returned by | |
| * {@code getExtraImageMetadataFormatNames}. | |
| * | |
| * @param formatName the desired image metadata format. | |
| * | |
| * @return an {@code IIOMetadataFormat} object. | |
| * | |
| * @throws IllegalArgumentException if {@code formatName} | |
| * is {@code null} or is not a supported name. | |
| */ | |
| public IIOMetadataFormat getImageMetadataFormat(String formatName) { | |
| return getMetadataFormat(formatName, | |
| supportsStandardImageMetadataFormat, | |
| nativeImageMetadataFormatName, | |
| nativeImageMetadataFormatClassName, | |
| extraImageMetadataFormatNames, | |
| extraImageMetadataFormatClassNames); | |
| } | |
| private IIOMetadataFormat getMetadataFormat(String formatName, | |
| boolean supportsStandard, | |
| String nativeName, | |
| String nativeClassName, | |
| String [] extraNames, | |
| String [] extraClassNames) { | |
| if (formatName == null) { | |
| throw new IllegalArgumentException("formatName == null!"); | |
| } | |
| if (supportsStandard && formatName.equals | |
| (IIOMetadataFormatImpl.standardMetadataFormatName)) { | |
| return IIOMetadataFormatImpl.getStandardFormatInstance(); | |
| } | |
| String formatClassName = null; | |
| if (formatName.equals(nativeName)) { | |
| formatClassName = nativeClassName; | |
| } else if (extraNames != null) { | |
| for (int i = 0; i < extraNames.length; i++) { | |
| if (formatName.equals(extraNames[i])) { | |
| formatClassName = extraClassNames[i]; | |
| break; // out of for | |
| } | |
| } | |
| } | |
| if (formatClassName == null) { | |
| throw new IllegalArgumentException("Unsupported format name"); | |
| } | |
| try { | |
| // Try to load from the same location as the module of the SPI | |
| Class<?> cls = getMetadataFormatClass(formatClassName); | |
| Method meth = cls.getMethod("getInstance"); | |
| return (IIOMetadataFormat) meth.invoke(null); | |
| } catch (Exception e) { | |
| throw new IllegalStateException("Can't obtain format", e); | |
| } | |
| } | |
| // If updating this method also see the same in IIOMetadata.java | |
| private Class<?> getMetadataFormatClass(String formatClassName) { | |
| Module thisModule = ImageReaderWriterSpi.class.getModule(); | |
| Module targetModule = this.getClass().getModule(); | |
| Class<?> c = null; | |
| try { | |
| ClassLoader cl = this.getClass().getClassLoader(); | |
| c = Class.forName(formatClassName, false, cl); | |
| if (!IIOMetadataFormat.class.isAssignableFrom(c)) { | |
| return null; | |
| } | |
| } catch (ClassNotFoundException e) { | |
| } | |
| if (thisModule.equals(targetModule) || c == null) { | |
| return c; | |
| } | |
| if (targetModule.isNamed()) { | |
| int i = formatClassName.lastIndexOf("."); | |
| String pn = i > 0 ? formatClassName.substring(0, i) : ""; | |
| if (!targetModule.isExported(pn, thisModule)) { | |
| throw new IllegalStateException("Class " + formatClassName + | |
| " in named module must be exported to java.desktop module."); | |
| } | |
| } | |
| return c; | |
| } | |
| } |