1 /*
2 * Copyright 2000-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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 * iamge 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 }