Path: blob/master/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java
41155 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.imageio.spi;2627import java.io.IOException;28import java.lang.reflect.Constructor;29import java.lang.reflect.Method;30import java.security.AccessController;31import java.security.PrivilegedAction;32import java.util.Arrays;33import java.util.Iterator;34import javax.imageio.ImageReader;35import javax.imageio.metadata.IIOMetadata;36import javax.imageio.metadata.IIOMetadataFormat;37import javax.imageio.metadata.IIOMetadataFormatImpl;38import javax.imageio.stream.ImageInputStream;3940/**41* A superclass containing instance variables and methods common to42* {@code ImageReaderSpi} and {@code ImageWriterSpi}.43*44* @see IIORegistry45* @see ImageReaderSpi46* @see ImageWriterSpi47*48*/49public abstract class ImageReaderWriterSpi extends IIOServiceProvider {5051/**52* An array of strings to be returned from53* {@code getFormatNames}, initially {@code null}.54* Constructors should set this to a non-{@code null} value.55*/56protected String[] names = null;5758/**59* An array of strings to be returned from60* {@code getFileSuffixes}, initially {@code null}.61*/62protected String[] suffixes = null;6364/**65* An array of strings to be returned from66* {@code getMIMETypes}, initially {@code null}.67*/68protected String[] MIMETypes = null;6970/**71* A {@code String} containing the name of the associated72* plug-in class, initially {@code null}.73*/74protected String pluginClassName = null;7576/**77* A boolean indicating whether this plug-in supports the78* standard metadata format for stream metadata, initially79* {@code false}.80*/81protected boolean supportsStandardStreamMetadataFormat = false;8283/**84* A {@code String} containing the name of the native stream85* metadata format supported by this plug-in, initially86* {@code null}.87*/88protected String nativeStreamMetadataFormatName = null;8990/**91* A {@code String} containing the class name of the native92* stream metadata format supported by this plug-in, initially93* {@code null}.94*/95protected String nativeStreamMetadataFormatClassName = null;9697/**98* An array of {@code String}s containing the names of any99* additional stream metadata formats supported by this plug-in,100* initially {@code null}.101*/102protected String[] extraStreamMetadataFormatNames = null;103104/**105* An array of {@code String}s containing the class names of106* any additional stream metadata formats supported by this plug-in,107* initially {@code null}.108*/109protected String[] extraStreamMetadataFormatClassNames = null;110111/**112* A boolean indicating whether this plug-in supports the113* standard metadata format for image metadata, initially114* {@code false}.115*/116protected boolean supportsStandardImageMetadataFormat = false;117118/**119* A {@code String} containing the name of the120* native stream metadata format supported by this plug-in,121* initially {@code null}.122*/123protected String nativeImageMetadataFormatName = null;124125/**126* A {@code String} containing the class name of the127* native stream metadata format supported by this plug-in,128* initially {@code null}.129*/130protected String nativeImageMetadataFormatClassName = null;131132/**133* An array of {@code String}s containing the names of any134* additional image metadata formats supported by this plug-in,135* initially {@code null}.136*/137protected String[] extraImageMetadataFormatNames = null;138139/**140* An array of {@code String}s containing the class names of141* any additional image metadata formats supported by this142* plug-in, initially {@code null}.143*/144protected String[] extraImageMetadataFormatClassNames = null;145146/**147* Constructs an {@code ImageReaderWriterSpi} with a given148* set of values.149*150* @param vendorName the vendor name, as a non-{@code null}151* {@code String}.152* @param version a version identifier, as a non-{@code null}153* {@code String}.154* @param names a non-{@code null} array of155* {@code String}s indicating the format names. At least one156* entry must be present.157* @param suffixes an array of {@code String}s indicating the158* common file suffixes. If no suffixes are defined,159* {@code null} should be supplied. An array of length 0160* will be normalized to {@code null}.161* @param MIMETypes an array of {@code String}s indicating162* the format's MIME types. If no MIME types are defined,163* {@code null} should be supplied. An array of length 0164* will be normalized to {@code null}.165* @param pluginClassName the fully-qualified name of the166* associated {@code ImageReader} or {@code ImageWriter}167* class, as a non-{@code null String}.168* @param supportsStandardStreamMetadataFormat a169* {@code boolean} that indicates whether a stream metadata170* object can use trees described by the standard metadata format.171* @param nativeStreamMetadataFormatName a172* {@code String}, or {@code null}, to be returned from173* {@code getNativeStreamMetadataFormatName}.174* @param nativeStreamMetadataFormatClassName a175* {@code String}, or {@code null}, to be used to instantiate176* a metadata format object to be returned from177* {@code getNativeStreamMetadataFormat}.178* @param extraStreamMetadataFormatNames an array of179* {@code String}s, or {@code null}, to be returned from180* {@code getExtraStreamMetadataFormatNames}. An array of length181* 0 is normalized to {@code null}.182* @param extraStreamMetadataFormatClassNames an array of183* {@code String}s, or {@code null}, to be used to instantiate184* a metadata format object to be returned from185* {@code getStreamMetadataFormat}. An array of length186* 0 is normalized to {@code null}.187* @param supportsStandardImageMetadataFormat a188* {@code boolean} that indicates whether an image metadata189* object can use trees described by the standard metadata format.190* @param nativeImageMetadataFormatName a191* {@code String}, or {@code null}, to be returned from192* {@code getNativeImageMetadataFormatName}.193* @param nativeImageMetadataFormatClassName a194* {@code String}, or {@code null}, to be used to instantiate195* a metadata format object to be returned from196* {@code getNativeImageMetadataFormat}.197* @param extraImageMetadataFormatNames an array of198* {@code String}s to be returned from199* {@code getExtraImageMetadataFormatNames}. An array of length 0200* is normalized to {@code null}.201* @param extraImageMetadataFormatClassNames an array of202* {@code String}s, or {@code null}, to be used to instantiate203* a metadata format object to be returned from204* {@code getImageMetadataFormat}. An array of length205* 0 is normalized to {@code null}.206*207* @exception IllegalArgumentException if {@code vendorName}208* is {@code null}.209* @exception IllegalArgumentException if {@code version}210* is {@code null}.211* @exception IllegalArgumentException if {@code names}212* is {@code null} or has length 0.213* @exception IllegalArgumentException if {@code pluginClassName}214* is {@code null}.215*/216public ImageReaderWriterSpi(String vendorName,217String version,218String[] names,219String[] suffixes,220String[] MIMETypes,221String pluginClassName,222boolean supportsStandardStreamMetadataFormat,223String nativeStreamMetadataFormatName,224String nativeStreamMetadataFormatClassName,225String[] extraStreamMetadataFormatNames,226String[] extraStreamMetadataFormatClassNames,227boolean supportsStandardImageMetadataFormat,228String nativeImageMetadataFormatName,229String nativeImageMetadataFormatClassName,230String[] extraImageMetadataFormatNames,231String[] extraImageMetadataFormatClassNames) {232super(vendorName, version);233if (names == null) {234throw new IllegalArgumentException("names == null!");235}236if (names.length == 0) {237throw new IllegalArgumentException("names.length == 0!");238}239if (pluginClassName == null) {240throw new IllegalArgumentException("pluginClassName == null!");241}242243this.names = names.clone();244// If length == 0, leave it null245if (suffixes != null && suffixes.length > 0) {246this.suffixes = suffixes.clone();247}248// If length == 0, leave it null249if (MIMETypes != null && MIMETypes.length > 0) {250this.MIMETypes = MIMETypes.clone();251}252this.pluginClassName = pluginClassName;253254this.supportsStandardStreamMetadataFormat =255supportsStandardStreamMetadataFormat;256this.nativeStreamMetadataFormatName = nativeStreamMetadataFormatName;257this.nativeStreamMetadataFormatClassName =258nativeStreamMetadataFormatClassName;259// If length == 0, leave it null260if (extraStreamMetadataFormatNames != null &&261extraStreamMetadataFormatNames.length > 0) {262this.extraStreamMetadataFormatNames =263extraStreamMetadataFormatNames.clone();264}265// If length == 0, leave it null266if (extraStreamMetadataFormatClassNames != null &&267extraStreamMetadataFormatClassNames.length > 0) {268this.extraStreamMetadataFormatClassNames =269extraStreamMetadataFormatClassNames.clone();270}271this.supportsStandardImageMetadataFormat =272supportsStandardImageMetadataFormat;273this.nativeImageMetadataFormatName = nativeImageMetadataFormatName;274this.nativeImageMetadataFormatClassName =275nativeImageMetadataFormatClassName;276// If length == 0, leave it null277if (extraImageMetadataFormatNames != null &&278extraImageMetadataFormatNames.length > 0) {279this.extraImageMetadataFormatNames =280extraImageMetadataFormatNames.clone();281}282// If length == 0, leave it null283if (extraImageMetadataFormatClassNames != null &&284extraImageMetadataFormatClassNames.length > 0) {285this.extraImageMetadataFormatClassNames =286extraImageMetadataFormatClassNames.clone();287}288}289290/**291* Constructs a blank {@code ImageReaderWriterSpi}. It is up292* to the subclass to initialize instance variables and/or293* override method implementations in order to provide working294* versions of all methods.295*/296public ImageReaderWriterSpi() {297}298299/**300* Returns an array of {@code String}s containing301* human-readable names for the formats that are generally usable302* by the {@code ImageReader} or {@code ImageWriter}303* implementation associated with this service provider. For304* example, a single {@code ImageReader} might be able to305* process both PBM and PNM files.306*307* @return a non-{@code null} array of {@code String}s308* or length at least 1 containing informal format names309* associated with this reader or writer.310*/311public String[] getFormatNames() {312return names.clone();313}314315/**316* Returns an array of {@code String}s containing a list of317* file suffixes associated with the formats that are generally318* usable by the {@code ImageReader} or319* {@code ImageWriter} implementation associated with this320* service provider. For example, a single321* {@code ImageReader} might be able to process files with322* '.pbm' and '.pnm' suffixes, or both '.jpg' and '.jpeg'323* suffixes. If there are no known file suffixes,324* {@code null} will be returned.325*326* <p> Returning a particular suffix does not guarantee that files327* with that suffix can be processed; it merely indicates that it328* may be worthwhile attempting to decode or encode such files329* using this service provider.330*331* @return an array of {@code String}s or length at least 1332* containing common file suffixes associated with this reader or333* writer, or {@code null}.334*/335public String[] getFileSuffixes() {336return suffixes == null ? null : suffixes.clone();337}338339/**340* Returns an array of {@code String}s containing a list of341* MIME types associated with the formats that are generally342* usable by the {@code ImageReader} or343* {@code ImageWriter} implementation associated with this344* service provider.345*346* <p> Ideally, only a single MIME type would be required in order347* to describe a particular format. However, for several reasons348* it is necessary to associate a list of types with each service349* provider. First, many common image file formats do not have350* standard MIME types, so a list of commonly used unofficial351* names will be required, such as {@code image/x-pbm} and352* {@code image/x-portable-bitmap}. Some file formats have353* official MIME types but may sometimes be referred to using354* their previous unofficial designations, such as355* {@code image/x-png} instead of the official356* {@code image/png}. Finally, a single service provider may357* be capable of parsing multiple distinct types from the MIME358* point of view, for example {@code image/x-xbitmap} and359* {@code image/x-xpixmap}.360*361* <p> Returning a particular MIME type does not guarantee that362* files claiming to be of that type can be processed; it merely363* indicates that it may be worthwhile attempting to decode or364* encode such files using this service provider.365*366* @return an array of {@code String}s or length at least 1367* containing MIME types associated with this reader or writer, or368* {@code null}.369*/370public String[] getMIMETypes() {371return MIMETypes == null ? null : MIMETypes.clone();372}373374/**375* Returns the fully-qualified class name of the376* {@code ImageReader} or {@code ImageWriter} plug-in377* associated with this service provider.378*379* @return the class name, as a non-{@code null}380* {@code String}.381*/382public String getPluginClassName() {383return pluginClassName;384}385386/**387* Returns {@code true} if the standard metadata format is388* among the document formats recognized by the389* {@code getAsTree} and {@code setFromTree} methods on390* the stream metadata objects produced or consumed by this391* plug-in.392*393* @return {@code true} if the standard format is supported394* for stream metadata.395*/396public boolean isStandardStreamMetadataFormatSupported() {397return supportsStandardStreamMetadataFormat;398}399400/**401* Returns the name of the "native" stream metadata format for402* this plug-in, which typically allows for lossless encoding and403* transmission of the stream metadata stored in the format handled by404* this plug-in. If no such format is supported,405* {@code null} will be returned.406*407* <p> The default implementation returns the408* {@code nativeStreamMetadataFormatName} instance variable,409* which is typically set by the constructor.410*411* @return the name of the native stream metadata format, or412* {@code null}.413*414*/415public String getNativeStreamMetadataFormatName() {416return nativeStreamMetadataFormatName;417}418419/**420* Returns an array of {@code String}s containing the names421* of additional document formats, other than the native and422* standard formats, recognized by the423* {@code getAsTree} and {@code setFromTree} methods on424* the stream metadata objects produced or consumed by this425* plug-in.426*427* <p> If the plug-in does not handle metadata, null should be428* returned.429*430* <p> The set of formats may differ according to the particular431* images being read or written; this method should indicate all432* the additional formats supported by the plug-in under any433* circumstances.434*435* <p> The default implementation returns a clone of the436* {@code extraStreamMetadataFormatNames} instance variable,437* which is typically set by the constructor.438*439* @return an array of {@code String}s, or null.440*441* @see IIOMetadata#getMetadataFormatNames442* @see #getExtraImageMetadataFormatNames443* @see #getNativeStreamMetadataFormatName444*/445public String[] getExtraStreamMetadataFormatNames() {446return extraStreamMetadataFormatNames == null ?447null : extraStreamMetadataFormatNames.clone();448}449450/**451* Returns {@code true} if the standard metadata format is452* among the document formats recognized by the453* {@code getAsTree} and {@code setFromTree} methods on454* the image metadata objects produced or consumed by this455* plug-in.456*457* @return {@code true} if the standard format is supported458* for image metadata.459*/460public boolean isStandardImageMetadataFormatSupported() {461return supportsStandardImageMetadataFormat;462}463464/**465* Returns the name of the "native" image metadata format for466* this plug-in, which typically allows for lossless encoding and467* transmission of the image metadata stored in the format handled by468* this plug-in. If no such format is supported,469* {@code null} will be returned.470*471* <p> The default implementation returns the472* {@code nativeImageMetadataFormatName} instance variable,473* which is typically set by the constructor.474*475* @return the name of the native image metadata format, or476* {@code null}.477*478* @see #getExtraImageMetadataFormatNames479*/480public String getNativeImageMetadataFormatName() {481return nativeImageMetadataFormatName;482}483484/**485* Returns an array of {@code String}s containing the names486* of additional document formats, other than the native and487* standard formats, recognized by the488* {@code getAsTree} and {@code setFromTree} methods on489* the image metadata objects produced or consumed by this490* plug-in.491*492* <p> If the plug-in does not handle image metadata, null should493* be returned.494*495* <p> The set of formats may differ according to the particular496* images being read or written; this method should indicate all497* the additional formats supported by the plug-in under any circumstances.498*499* <p> The default implementation returns a clone of the500* {@code extraImageMetadataFormatNames} instance variable,501* which is typically set by the constructor.502*503* @return an array of {@code String}s, or null.504*505* @see IIOMetadata#getMetadataFormatNames506* @see #getExtraStreamMetadataFormatNames507* @see #getNativeImageMetadataFormatName508*/509public String[] getExtraImageMetadataFormatNames() {510return extraImageMetadataFormatNames == null ?511null : extraImageMetadataFormatNames.clone();512}513514/**515* Returns an {@code IIOMetadataFormat} object describing the516* given stream metadata format, or {@code null} if no517* description is available. The supplied name must be the native518* stream metadata format name, the standard metadata format name,519* or one of those returned by520* {@code getExtraStreamMetadataFormatNames}.521*522* @param formatName the desired stream metadata format.523*524* @return an {@code IIOMetadataFormat} object.525*526* @exception IllegalArgumentException if {@code formatName}527* is {@code null} or is not a supported name.528*/529public IIOMetadataFormat getStreamMetadataFormat(String formatName) {530return getMetadataFormat(formatName,531supportsStandardStreamMetadataFormat,532nativeStreamMetadataFormatName,533nativeStreamMetadataFormatClassName,534extraStreamMetadataFormatNames,535extraStreamMetadataFormatClassNames);536}537538/**539* Returns an {@code IIOMetadataFormat} object describing the540* given image metadata format, or {@code null} if no541* description is available. The supplied name must be the native542* image metadata format name, the standard metadata format name,543* or one of those returned by544* {@code getExtraImageMetadataFormatNames}.545*546* @param formatName the desired image metadata format.547*548* @return an {@code IIOMetadataFormat} object.549*550* @exception IllegalArgumentException if {@code formatName}551* is {@code null} or is not a supported name.552*/553public IIOMetadataFormat getImageMetadataFormat(String formatName) {554return getMetadataFormat(formatName,555supportsStandardImageMetadataFormat,556nativeImageMetadataFormatName,557nativeImageMetadataFormatClassName,558extraImageMetadataFormatNames,559extraImageMetadataFormatClassNames);560}561562private IIOMetadataFormat getMetadataFormat(String formatName,563boolean supportsStandard,564String nativeName,565String nativeClassName,566String [] extraNames,567String [] extraClassNames) {568if (formatName == null) {569throw new IllegalArgumentException("formatName == null!");570}571if (supportsStandard && formatName.equals572(IIOMetadataFormatImpl.standardMetadataFormatName)) {573574return IIOMetadataFormatImpl.getStandardFormatInstance();575}576String formatClassName = null;577if (formatName.equals(nativeName)) {578formatClassName = nativeClassName;579} else if (extraNames != null) {580for (int i = 0; i < extraNames.length; i++) {581if (formatName.equals(extraNames[i])) {582formatClassName = extraClassNames[i];583break; // out of for584}585}586}587if (formatClassName == null) {588throw new IllegalArgumentException("Unsupported format name");589}590try {591// Try to load from the same location as the module of the SPI592final String className = formatClassName;593PrivilegedAction<Class<?>> pa = () -> { return getMetadataFormatClass(className); };594@SuppressWarnings("removal")595Class<?> cls = AccessController.doPrivileged(pa);596Method meth = cls.getMethod("getInstance");597return (IIOMetadataFormat) meth.invoke(null);598} catch (Exception e) {599RuntimeException ex =600new IllegalStateException ("Can't obtain format");601ex.initCause(e);602throw ex;603}604}605606// If updating this method also see the same in IIOMetadata.java607private Class<?> getMetadataFormatClass(String formatClassName) {608Module thisModule = ImageReaderWriterSpi.class.getModule();609Module targetModule = this.getClass().getModule();610Class<?> c = null;611try {612ClassLoader cl = this.getClass().getClassLoader();613c = Class.forName(formatClassName, false, cl);614if (!IIOMetadataFormat.class.isAssignableFrom(c)) {615return null;616}617} catch (ClassNotFoundException e) {618}619if (thisModule.equals(targetModule) || c == null) {620return c;621}622if (targetModule.isNamed()) {623int i = formatClassName.lastIndexOf(".");624String pn = i > 0 ? formatClassName.substring(0, i) : "";625if (!targetModule.isExported(pn, thisModule)) {626throw new IllegalStateException("Class " + formatClassName +627" in named module must be exported to java.desktop module.");628}629}630return c;631}632}633634635