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