View Javadoc
1   /*
2    * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package javax.imageio.spi;
27  
28  import java.io.IOException;
29  import java.lang.reflect.Constructor;
30  import java.lang.reflect.Method;
31  import java.util.Arrays;
32  import java.util.Iterator;
33  import javax.imageio.ImageReader;
34  import javax.imageio.metadata.IIOMetadata;
35  import javax.imageio.metadata.IIOMetadataFormat;
36  import javax.imageio.metadata.IIOMetadataFormatImpl;
37  import javax.imageio.stream.ImageInputStream;
38  
39  /**
40   * A superclass containing instance variables and methods common to
41   * <code>ImageReaderSpi</code> and <code>ImageWriterSpi</code>.
42   *
43   * @see IIORegistry
44   * @see ImageReaderSpi
45   * @see ImageWriterSpi
46   *
47   */
48  public abstract class ImageReaderWriterSpi extends IIOServiceProvider {
49  
50      /**
51       * An array of strings to be returned from
52       * <code>getFormatNames</code>, initially <code>null</code>.
53       * Constructors should set this to a non-<code>null</code> value.
54       */
55      protected String[] names = null;
56  
57      /**
58       * An array of strings to be returned from
59       * <code>getFileSuffixes</code>, initially <code>null</code>.
60       */
61      protected String[] suffixes = null;
62  
63      /**
64       * An array of strings to be returned from
65       * <code>getMIMETypes</code>, initially <code>null</code>.
66       */
67      protected String[] MIMETypes = null;
68  
69      /**
70       * A <code>String</code> containing the name of the associated
71       * plug-in class, initially <code>null</code>.
72       */
73      protected String pluginClassName = null;
74  
75      /**
76       * A boolean indicating whether this plug-in supports the
77       * standard metadata format for stream metadata, initially
78       * <code>false</code>.
79       */
80      protected boolean supportsStandardStreamMetadataFormat = false;
81  
82      /**
83       * A <code>String</code> containing the name of the native stream
84       * metadata format supported by this plug-in, initially
85       * <code>null</code>.
86       */
87      protected String nativeStreamMetadataFormatName = null;
88  
89      /**
90       * A <code>String</code> containing the class name of the native
91       * stream metadata format supported by this plug-in, initially
92       * <code>null</code>.
93       */
94      protected String nativeStreamMetadataFormatClassName = null;
95  
96      /**
97       * An array of <code>String</code>s containing the names of any
98       * additional stream metadata formats supported by this plug-in,
99       * initially <code>null</code>.
100      */
101     protected String[] extraStreamMetadataFormatNames = null;
102 
103     /**
104      * An array of <code>String</code>s containing the class names of
105      * any additional stream metadata formats supported by this plug-in,
106      * initially <code>null</code>.
107      */
108     protected String[] extraStreamMetadataFormatClassNames = null;
109 
110     /**
111      * A boolean indicating whether this plug-in supports the
112      * standard metadata format for image metadata, initially
113      * <code>false</code>.
114      */
115     protected boolean supportsStandardImageMetadataFormat = false;
116 
117     /**
118      * A <code>String</code> containing the name of the
119      * native stream metadata format supported by this plug-in,
120      * initially <code>null</code>.
121      */
122     protected String nativeImageMetadataFormatName = null;
123 
124     /**
125      * A <code>String</code> containing the class name of the
126      * native stream metadata format supported by this plug-in,
127      * initially <code>null</code>.
128      */
129     protected String nativeImageMetadataFormatClassName = null;
130 
131     /**
132      * An array of <code>String</code>s containing the names of any
133      * additional image metadata formats supported by this plug-in,
134      * initially <code>null</code>.
135      */
136     protected String[] extraImageMetadataFormatNames = null;
137 
138     /**
139      * An array of <code>String</code>s containing the class names of
140      * any additional image metadata formats supported by this
141      * plug-in, initially <code>null</code>.
142      */
143     protected String[] extraImageMetadataFormatClassNames = null;
144 
145     /**
146      * Constructs an <code>ImageReaderWriterSpi</code> with a given
147      * set of values.
148      *
149      * @param vendorName the vendor name, as a non-<code>null</code>
150      * <code>String</code>.
151      * @param version a version identifier, as a non-<code>null</code>
152      * <code>String</code>.
153      * @param names a non-<code>null</code> array of
154      * <code>String</code>s indicating the format names.  At least one
155      * entry must be present.
156      * @param suffixes an array of <code>String</code>s indicating the
157      * common file suffixes.  If no suffixes are defined,
158      * <code>null</code> should be supplied.  An array of length 0
159      * will be normalized to <code>null</code>.
160      * @param MIMETypes an array of <code>String</code>s indicating
161      * the format's MIME types.  If no MIME types are defined,
162      * <code>null</code> should be supplied.  An array of length 0
163      * will be normalized to <code>null</code>.
164      * @param pluginClassName the fully-qualified name of the
165      * associated <code>ImageReader</code> or <code>ImageWriter</code>
166      * class, as a non-<code>null</code> <code>String</code>.
167      * @param supportsStandardStreamMetadataFormat a
168      * <code>boolean</code> that indicates whether a stream metadata
169      * object can use trees described by the standard metadata format.
170      * @param nativeStreamMetadataFormatName a
171      * <code>String</code>, or <code>null</code>, to be returned from
172      * <code>getNativeStreamMetadataFormatName</code>.
173      * @param nativeStreamMetadataFormatClassName a
174      * <code>String</code>, or <code>null</code>, to be used to instantiate
175      * a metadata format object to be returned from
176      * <code>getNativeStreamMetadataFormat</code>.
177      * @param extraStreamMetadataFormatNames an array of
178      * <code>String</code>s, or <code>null</code>, to be returned from
179      * <code>getExtraStreamMetadataFormatNames</code>.  An array of length
180      * 0 is normalized to <code>null</code>.
181      * @param extraStreamMetadataFormatClassNames an array of
182      * <code>String</code>s, or <code>null</code>, to be used to instantiate
183      * a metadata format object to be returned from
184      * <code>getStreamMetadataFormat</code>.  An array of length
185      * 0 is normalized to <code>null</code>.
186      * @param supportsStandardImageMetadataFormat a
187      * <code>boolean</code> that indicates whether an image metadata
188      * object can use trees described by the standard metadata format.
189      * @param nativeImageMetadataFormatName a
190      * <code>String</code>, or <code>null</code>, to be returned from
191      * <code>getNativeImageMetadataFormatName</code>.
192      * @param nativeImageMetadataFormatClassName a
193      * <code>String</code>, or <code>null</code>, to be used to instantiate
194      * a metadata format object to be returned from
195      * <code>getNativeImageMetadataFormat</code>.
196      * @param extraImageMetadataFormatNames an array of
197      * <code>String</code>s to be returned from
198      * <code>getExtraImageMetadataFormatNames</code>.  An array of length 0
199      * is normalized to <code>null</code>.
200      * @param extraImageMetadataFormatClassNames an array of
201      * <code>String</code>s, or <code>null</code>, to be used to instantiate
202      * a metadata format object to be returned from
203      * <code>getImageMetadataFormat</code>.  An array of length
204      * 0 is normalized to <code>null</code>.
205      *
206      * @exception IllegalArgumentException if <code>vendorName</code>
207      * is <code>null</code>.
208      * @exception IllegalArgumentException if <code>version</code>
209      * is <code>null</code>.
210      * @exception IllegalArgumentException if <code>names</code>
211      * is <code>null</code> or has length 0.
212      * @exception IllegalArgumentException if <code>pluginClassName</code>
213      * is <code>null</code>.
214      */
215     public ImageReaderWriterSpi(String vendorName,
216                                 String version,
217                                 String[] names,
218                                 String[] suffixes,
219                                 String[] MIMETypes,
220                                 String pluginClassName,
221                                 boolean supportsStandardStreamMetadataFormat,
222                                 String nativeStreamMetadataFormatName,
223                                 String nativeStreamMetadataFormatClassName,
224                                 String[] extraStreamMetadataFormatNames,
225                                 String[] extraStreamMetadataFormatClassNames,
226                                 boolean supportsStandardImageMetadataFormat,
227                                 String nativeImageMetadataFormatName,
228                                 String nativeImageMetadataFormatClassName,
229                                 String[] extraImageMetadataFormatNames,
230                                 String[] extraImageMetadataFormatClassNames) {
231         super(vendorName, version);
232         if (names == null) {
233             throw new IllegalArgumentException("names == null!");
234         }
235         if (names.length == 0) {
236             throw new IllegalArgumentException("names.length == 0!");
237         }
238         if (pluginClassName == null) {
239             throw new IllegalArgumentException("pluginClassName == null!");
240         }
241 
242         this.names = (String[])names.clone();
243         // If length == 0, leave it null
244         if (suffixes != null && suffixes.length > 0) {
245             this.suffixes = (String[])suffixes.clone();
246         }
247         // If length == 0, leave it null
248         if (MIMETypes != null && MIMETypes.length > 0) {
249             this.MIMETypes = (String[])MIMETypes.clone();
250         }
251         this.pluginClassName = pluginClassName;
252 
253         this.supportsStandardStreamMetadataFormat =
254             supportsStandardStreamMetadataFormat;
255         this.nativeStreamMetadataFormatName = nativeStreamMetadataFormatName;
256         this.nativeStreamMetadataFormatClassName =
257             nativeStreamMetadataFormatClassName;
258         // If length == 0, leave it null
259         if (extraStreamMetadataFormatNames != null &&
260             extraStreamMetadataFormatNames.length > 0) {
261             this.extraStreamMetadataFormatNames =
262                 (String[])extraStreamMetadataFormatNames.clone();
263         }
264         // If length == 0, leave it null
265         if (extraStreamMetadataFormatClassNames != null &&
266             extraStreamMetadataFormatClassNames.length > 0) {
267             this.extraStreamMetadataFormatClassNames =
268                 (String[])extraStreamMetadataFormatClassNames.clone();
269         }
270         this.supportsStandardImageMetadataFormat =
271             supportsStandardImageMetadataFormat;
272         this.nativeImageMetadataFormatName = nativeImageMetadataFormatName;
273         this.nativeImageMetadataFormatClassName =
274             nativeImageMetadataFormatClassName;
275         // If length == 0, leave it null
276         if (extraImageMetadataFormatNames != null &&
277             extraImageMetadataFormatNames.length > 0) {
278             this.extraImageMetadataFormatNames =
279                 (String[])extraImageMetadataFormatNames.clone();
280         }
281         // If length == 0, leave it null
282         if (extraImageMetadataFormatClassNames != null &&
283             extraImageMetadataFormatClassNames.length > 0) {
284             this.extraImageMetadataFormatClassNames =
285                 (String[])extraImageMetadataFormatClassNames.clone();
286         }
287     }
288 
289     /**
290      * Constructs a blank <code>ImageReaderWriterSpi</code>.  It is up
291      * to the subclass to initialize instance variables and/or
292      * override method implementations in order to provide working
293      * versions of all methods.
294      */
295     public ImageReaderWriterSpi() {
296     }
297 
298     /**
299      * Returns an array of <code>String</code>s containing
300      * human-readable names for the formats that are generally usable
301      * by the <code>ImageReader</code> or <code>ImageWriter</code>
302      * implementation associated with this service provider.  For
303      * example, a single <code>ImageReader</code> might be able to
304      * process both PBM and PNM files.
305      *
306      * @return a non-<code>null</code> array of <code>String</code>s
307      * or length at least 1 containing informal format names
308      * associated with this reader or writer.
309      */
310     public String[] getFormatNames() {
311         return (String[])names.clone();
312     }
313 
314     /**
315      * Returns an array of <code>String</code>s containing a list of
316      * file suffixes associated with the formats that are generally
317      * usable by the <code>ImageReader</code> or
318      * <code>ImageWriter</code> implementation associated with this
319      * service provider.  For example, a single
320      * <code>ImageReader</code> might be able to process files with
321      * '.pbm' and '.pnm' suffixes, or both '.jpg' and '.jpeg'
322      * suffixes.  If there are no known file suffixes,
323      * <code>null</code> will be returned.
324      *
325      * <p> Returning a particular suffix does not guarantee that files
326      * with that suffix can be processed; it merely indicates that it
327      * may be worthwhile attempting to decode or encode such files
328      * using this service provider.
329      *
330      * @return an array of <code>String</code>s or length at least 1
331      * containing common file suffixes associated with this reader or
332      * writer, or <code>null</code>.
333      */
334     public String[] getFileSuffixes() {
335         return suffixes == null ? null : (String[])suffixes.clone();
336     }
337 
338     /**
339      * Returns an array of <code>String</code>s containing a list of
340      * MIME types associated with the formats that are generally
341      * usable by the <code>ImageReader</code> or
342      * <code>ImageWriter</code> implementation associated with this
343      * service provider.
344      *
345      * <p> Ideally, only a single MIME type would be required in order
346      * to describe a particular format.  However, for several reasons
347      * it is necessary to associate a list of types with each service
348      * provider.  First, many common image file formats do not have
349      * standard MIME types, so a list of commonly used unofficial
350      * names will be required, such as <code>image/x-pbm</code> and
351      * <code>image/x-portable-bitmap</code>.  Some file formats have
352      * official MIME types but may sometimes be referred to using
353      * their previous unofficial designations, such as
354      * <code>image/x-png</code> instead of the official
355      * <code>image/png</code>.  Finally, a single service provider may
356      * be capable of parsing multiple distinct types from the MIME
357      * point of view, for example <code>image/x-xbitmap</code> and
358      * <code>image/x-xpixmap</code>.
359      *
360      * <p> Returning a particular MIME type does not guarantee that
361      * files claiming to be of that type can be processed; it merely
362      * indicates that it may be worthwhile attempting to decode or
363      * encode such files using this service provider.
364      *
365      * @return an array of <code>String</code>s or length at least 1
366      * containing MIME types associated with this reader or writer, or
367      * <code>null</code>.
368      */
369     public String[] getMIMETypes() {
370         return MIMETypes == null ? null : (String[])MIMETypes.clone();
371     }
372 
373     /**
374      * Returns the fully-qualified class name of the
375      * <code>ImageReader</code> or <code>ImageWriter</code> plug-in
376      * associated with this service provider.
377      *
378      * @return the class name, as a non-<code>null</code>
379      * <code>String</code>.
380      */
381     public String getPluginClassName() {
382         return pluginClassName;
383     }
384 
385     /**
386      * Returns <code>true</code> if the standard metadata format is
387      * among the document formats recognized by the
388      * <code>getAsTree</code> and <code>setFromTree</code> methods on
389      * the stream metadata objects produced or consumed by this
390      * plug-in.
391      *
392      * @return <code>true</code> if the standard format is supported
393      * for stream metadata.
394      */
395     public boolean isStandardStreamMetadataFormatSupported() {
396         return supportsStandardStreamMetadataFormat;
397     }
398 
399     /**
400      * Returns the name of the "native" stream metadata format for
401      * this plug-in, which typically allows for lossless encoding and
402      * transmission of the stream metadata stored in the format handled by
403      * this plug-in.  If no such format is supported,
404      * <code>null</code>will be returned.
405      *
406      * <p> The default implementation returns the
407      * <code>nativeStreamMetadataFormatName</code> instance variable,
408      * which is typically set by the constructor.
409      *
410      * @return the name of the native stream metadata format, or
411      * <code>null</code>.
412      *
413      */
414     public String getNativeStreamMetadataFormatName() {
415         return nativeStreamMetadataFormatName;
416     }
417 
418     /**
419      * Returns an array of <code>String</code>s containing the names
420      * of additional document formats, other than the native and
421      * standard formats, recognized by the
422      * <code>getAsTree</code> and <code>setFromTree</code> methods on
423      * the stream metadata objects produced or consumed by this
424      * plug-in.
425      *
426      * <p> If the plug-in does not handle metadata, null should be
427      * returned.
428      *
429      * <p> The set of formats may differ according to the particular
430      * images being read or written; this method should indicate all
431      * the additional formats supported by the plug-in under any
432      * circumstances.
433      *
434      * <p> The default implementation returns a clone of the
435      * <code>extraStreamMetadataFormatNames</code> instance variable,
436      * which is typically set by the constructor.
437      *
438      * @return an array of <code>String</code>s, or null.
439      *
440      * @see IIOMetadata#getMetadataFormatNames
441      * @see #getExtraImageMetadataFormatNames
442      * @see #getNativeStreamMetadataFormatName
443      */
444     public String[] getExtraStreamMetadataFormatNames() {
445         return extraStreamMetadataFormatNames == null ?
446             null : (String[])extraStreamMetadataFormatNames.clone();
447     }
448 
449     /**
450      * Returns <code>true</code> if the standard metadata format is
451      * among the document formats recognized by the
452      * <code>getAsTree</code> and <code>setFromTree</code> methods on
453      * the image metadata objects produced or consumed by this
454      * plug-in.
455      *
456      * @return <code>true</code> if the standard format is supported
457      * for image metadata.
458      */
459     public boolean isStandardImageMetadataFormatSupported() {
460         return supportsStandardImageMetadataFormat;
461     }
462 
463     /**
464      * Returns the name of the "native" image metadata format for
465      * this plug-in, which typically allows for lossless encoding and
466      * transmission of the image metadata stored in the format handled by
467      * this plug-in.  If no such format is supported,
468      * <code>null</code>will be returned.
469      *
470      * <p> The default implementation returns the
471      * <code>nativeImageMetadataFormatName</code> instance variable,
472      * which is typically set by the constructor.
473      *
474      * @return the name of the native image metadata format, or
475      * <code>null</code>.
476      *
477      * @see #getExtraImageMetadataFormatNames
478      */
479     public String getNativeImageMetadataFormatName() {
480         return nativeImageMetadataFormatName;
481     }
482 
483     /**
484      * Returns an array of <code>String</code>s containing the names
485      * of additional document formats, other than the native and
486      * standard formats, recognized by the
487      * <code>getAsTree</code> and <code>setFromTree</code> methods on
488      * the image metadata objects produced or consumed by this
489      * plug-in.
490      *
491      * <p> If the plug-in does not handle image metadata, null should
492      * be returned.
493      *
494      * <p> The set of formats may differ according to the particular
495      * images being read or written; this method should indicate all
496      * the additional formats supported by the plug-in under any circumstances.
497      *
498      * <p> The default implementation returns a clone of the
499      * <code>extraImageMetadataFormatNames</code> instance variable,
500      * which is typically set by the constructor.
501      *
502      * @return an array of <code>String</code>s, or null.
503      *
504      * @see IIOMetadata#getMetadataFormatNames
505      * @see #getExtraStreamMetadataFormatNames
506      * @see #getNativeImageMetadataFormatName
507      */
508     public String[] getExtraImageMetadataFormatNames() {
509         return extraImageMetadataFormatNames == null ?
510             null : (String[])extraImageMetadataFormatNames.clone();
511     }
512 
513     /**
514      * Returns an <code>IIOMetadataFormat</code> object describing the
515      * given stream metadata format, or <code>null</code> if no
516      * description is available.  The supplied name must be the native
517      * stream metadata format name, the standard metadata format name,
518      * or one of those returned by
519      * <code>getExtraStreamMetadataFormatNames</code>.
520      *
521      * @param formatName the desired stream metadata format.
522      *
523      * @return an <code>IIOMetadataFormat</code> object.
524      *
525      * @exception IllegalArgumentException if <code>formatName</code>
526      * is <code>null</code> or is not a supported name.
527      */
528     public IIOMetadataFormat getStreamMetadataFormat(String formatName) {
529         return getMetadataFormat(formatName,
530                                  supportsStandardStreamMetadataFormat,
531                                  nativeStreamMetadataFormatName,
532                                  nativeStreamMetadataFormatClassName,
533                                  extraStreamMetadataFormatNames,
534                                  extraStreamMetadataFormatClassNames);
535     }
536 
537     /**
538      * Returns an <code>IIOMetadataFormat</code> object describing the
539      * given image metadata format, or <code>null</code> if no
540      * description is available.  The supplied name must be the native
541      * image metadata format name, the standard metadata format name,
542      * or one of those returned by
543      * <code>getExtraImageMetadataFormatNames</code>.
544      *
545      * @param formatName the desired image metadata format.
546      *
547      * @return an <code>IIOMetadataFormat</code> object.
548      *
549      * @exception IllegalArgumentException if <code>formatName</code>
550      * is <code>null</code> or is not a supported name.
551      */
552     public IIOMetadataFormat getImageMetadataFormat(String formatName) {
553         return getMetadataFormat(formatName,
554                                  supportsStandardImageMetadataFormat,
555                                  nativeImageMetadataFormatName,
556                                  nativeImageMetadataFormatClassName,
557                                  extraImageMetadataFormatNames,
558                                  extraImageMetadataFormatClassNames);
559     }
560 
561     private IIOMetadataFormat getMetadataFormat(String formatName,
562                                                 boolean supportsStandard,
563                                                 String nativeName,
564                                                 String nativeClassName,
565                                                 String [] extraNames,
566                                                 String [] extraClassNames) {
567         if (formatName == null) {
568             throw new IllegalArgumentException("formatName == null!");
569         }
570         if (supportsStandard && formatName.equals
571                 (IIOMetadataFormatImpl.standardMetadataFormatName)) {
572 
573             return IIOMetadataFormatImpl.getStandardFormatInstance();
574         }
575         String formatClassName = null;
576         if (formatName.equals(nativeName)) {
577             formatClassName = nativeClassName;
578         } else if (extraNames != null) {
579             for (int i = 0; i < extraNames.length; i++) {
580                 if (formatName.equals(extraNames[i])) {
581                     formatClassName = extraClassNames[i];
582                     break;  // out of for
583                 }
584             }
585         }
586         if (formatClassName == null) {
587             throw new IllegalArgumentException("Unsupported format name");
588         }
589         try {
590             Class cls = Class.forName(formatClassName, true,
591                                       ClassLoader.getSystemClassLoader());
592             Method meth = cls.getMethod("getInstance");
593             return (IIOMetadataFormat) meth.invoke(null);
594         } catch (Exception e) {
595             RuntimeException ex =
596                 new IllegalStateException ("Can't obtain format");
597             ex.initCause(e);
598             throw ex;
599         }
600     }
601 }