1 /*
   2  * Copyright (c) 1999, 2014, 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.awt.image.RenderedImage;
  29 import java.io.IOException;
  30 import javax.imageio.ImageTypeSpecifier;
  31 import javax.imageio.ImageWriter;
  32 import javax.imageio.stream.ImageOutputStream;
  33 
  34 /**
  35  * The service provider interface (SPI) for <code>ImageWriter</code>s.
  36  * For more information on service provider classes, see the class comment
  37  * for the <code>IIORegistry</code> class.
  38  *
  39  * <p> Each <code>ImageWriterSpi</code> provides several types of information
  40  * about the <code>ImageWriter</code> class with which it is associated.
  41  *
  42  * <p> The name of the vendor who defined the SPI class and a
  43  * brief description of the class are available via the
  44  * <code>getVendorName</code>, <code>getDescription</code>,
  45  * and <code>getVersion</code> methods.
  46  * These methods may be internationalized to provide locale-specific
  47  * output.  These methods are intended mainly to provide short,
  48  * human-writable information that might be used to organize a pop-up
  49  * menu or other list.
  50  *
  51  * <p> Lists of format names, file suffixes, and MIME types associated
  52  * with the service may be obtained by means of the
  53  * <code>getFormatNames</code>, <code>getFileSuffixes</code>, and
  54  * <code>getMIMEType</code> methods.  These methods may be used to
  55  * identify candidate <code>ImageWriter</code>s for writing a
  56  * particular file or stream based on manual format selection, file
  57  * naming, or MIME associations.
  58  *
  59  * <p> A more reliable way to determine which <code>ImageWriter</code>s
  60  * are likely to be able to parse a particular data stream is provided
  61  * by the <code>canEncodeImage</code> method.  This methods allows the
  62  * service provider to inspect the actual image contents.
  63  *
  64  * <p> Finally, an instance of the <code>ImageWriter</code> class
  65  * associated with this service provider may be obtained by calling
  66  * the <code>createWriterInstance</code> method.  Any heavyweight
  67  * initialization, such as the loading of native libraries or creation
  68  * of large tables, should be deferred at least until the first
  69  * invocation of this method.
  70  *
  71  * @see IIORegistry
  72  * @see javax.imageio.ImageTypeSpecifier
  73  * @see javax.imageio.ImageWriter
  74  *
  75  */
  76 public abstract class ImageWriterSpi extends ImageReaderWriterSpi {
  77 
  78     /**
  79      * A single-element array, initially containing
  80      * <code>ImageOutputStream.class</code>, to be returned from
  81      * <code>getOutputTypes</code>.
  82      * @deprecated Instead of using this field, directly create
  83      * the equivalent array <code>{ ImageOutputStream.class }</code>.
  84      */
  85     @Deprecated
  86     public static final Class[] STANDARD_OUTPUT_TYPE =
  87         { ImageOutputStream.class };
  88 
  89     /**
  90      * An array of <code>Class</code> objects to be returned from
  91      * <code>getOutputTypes</code>, initially <code>null</code>.
  92      */
  93     protected Class[] outputTypes = null;
  94 
  95     /**
  96      * An array of strings to be returned from
  97      * <code>getImageReaderSpiNames</code>, initially
  98      * <code>null</code>.
  99      */
 100     protected String[] readerSpiNames = null;
 101 
 102     /**
 103      * The <code>Class</code> of the writer, initially
 104      * <code>null</code>.
 105      */
 106     private Class writerClass = null;
 107 
 108     /**
 109      * Constructs a blank <code>ImageWriterSpi</code>.  It is up to
 110      * the subclass to initialize instance variables and/or override
 111      * method implementations in order to provide working versions of
 112      * all methods.
 113      */
 114     protected ImageWriterSpi() {
 115     }
 116 
 117     /**
 118      * Constructs an <code>ImageWriterSpi</code> with a given
 119      * set of values.
 120      *
 121      * @param vendorName the vendor name, as a non-<code>null</code>
 122      * <code>String</code>.
 123      * @param version a version identifier, as a non-<code>null</code>
 124      * <code>String</code>.
 125      * @param names a non-<code>null</code> array of
 126      * <code>String</code>s indicating the format names.  At least one
 127      * entry must be present.
 128      * @param suffixes an array of <code>String</code>s indicating the
 129      * common file suffixes.  If no suffixes are defined,
 130      * <code>null</code> should be supplied.  An array of length 0
 131      * will be normalized to <code>null</code>.
 132      * @param MIMETypes an array of <code>String</code>s indicating
 133      * the format's MIME types.  If no suffixes are defined,
 134      * <code>null</code> should be supplied.  An array of length 0
 135      * will be normalized to <code>null</code>.
 136      * @param writerClassName the fully-qualified name of the
 137      * associated <code>ImageWriterSpi</code> class, as a
 138      * non-<code>null</code> <code>String</code>.
 139      * @param outputTypes an array of <code>Class</code> objects of
 140      * length at least 1 indicating the legal output types.
 141      * @param readerSpiNames an array <code>String</code>s of length
 142      * at least 1 naming the classes of all associated
 143      * <code>ImageReader</code>s, or <code>null</code>.  An array of
 144      * length 0 is normalized to <code>null</code>.
 145      * @param supportsStandardStreamMetadataFormat a
 146      * <code>boolean</code> that indicates whether a stream metadata
 147      * object can use trees described by the standard metadata format.
 148      * @param nativeStreamMetadataFormatName a
 149      * <code>String</code>, or <code>null</code>, to be returned from
 150      * <code>getNativeStreamMetadataFormatName</code>.
 151      * @param nativeStreamMetadataFormatClassName a
 152      * <code>String</code>, or <code>null</code>, to be used to instantiate
 153      * a metadata format object to be returned from
 154      * <code>getNativeStreamMetadataFormat</code>.
 155      * @param extraStreamMetadataFormatNames an array of
 156      * <code>String</code>s, or <code>null</code>, to be returned from
 157      * <code>getExtraStreamMetadataFormatNames</code>.  An array of length
 158      * 0 is normalized to <code>null</code>.
 159      * @param extraStreamMetadataFormatClassNames an array of
 160      * <code>String</code>s, or <code>null</code>, to be used to instantiate
 161      * a metadata format object to be returned from
 162      * <code>getStreamMetadataFormat</code>.  An array of length
 163      * 0 is normalized to <code>null</code>.
 164      * @param supportsStandardImageMetadataFormat a
 165      * <code>boolean</code> that indicates whether an image metadata
 166      * object can use trees described by the standard metadata format.
 167      * @param nativeImageMetadataFormatName a
 168      * <code>String</code>, or <code>null</code>, to be returned from
 169      * <code>getNativeImageMetadataFormatName</code>.
 170      * @param nativeImageMetadataFormatClassName a
 171      * <code>String</code>, or <code>null</code>, to be used to instantiate
 172      * a metadata format object to be returned from
 173      * <code>getNativeImageMetadataFormat</code>.
 174      * @param extraImageMetadataFormatNames an array of
 175      * <code>String</code>s to be returned from
 176      * <code>getExtraImageMetadataFormatNames</code>.  An array of length 0
 177      * is normalized to <code>null</code>.
 178      * @param extraImageMetadataFormatClassNames an array of
 179      * <code>String</code>s, or <code>null</code>, to be used to instantiate
 180      * a metadata format object to be returned from
 181      * <code>getImageMetadataFormat</code>.  An array of length
 182      * 0 is normalized to <code>null</code>.
 183      *
 184      * @exception IllegalArgumentException if <code>vendorName</code>
 185      * is <code>null</code>.
 186      * @exception IllegalArgumentException if <code>version</code>
 187      * is <code>null</code>.
 188      * @exception IllegalArgumentException if <code>names</code>
 189      * is <code>null</code> or has length 0.
 190      * @exception IllegalArgumentException if <code>writerClassName</code>
 191      * is <code>null</code>.
 192      * @exception IllegalArgumentException if <code>outputTypes</code>
 193      * is <code>null</code> or has length 0.
 194      */
 195     public ImageWriterSpi(String vendorName,
 196                           String version,
 197                           String[] names,
 198                           String[] suffixes,
 199                           String[] MIMETypes,
 200                           String writerClassName,
 201                           Class[] outputTypes,
 202                           String[] readerSpiNames,
 203                           boolean supportsStandardStreamMetadataFormat,
 204                           String nativeStreamMetadataFormatName,
 205                           String nativeStreamMetadataFormatClassName,
 206                           String[] extraStreamMetadataFormatNames,
 207                           String[] extraStreamMetadataFormatClassNames,
 208                           boolean supportsStandardImageMetadataFormat,
 209                           String nativeImageMetadataFormatName,
 210                           String nativeImageMetadataFormatClassName,
 211                           String[] extraImageMetadataFormatNames,
 212                           String[] extraImageMetadataFormatClassNames) {
 213         super(vendorName, version,
 214               names, suffixes, MIMETypes, writerClassName,
 215               supportsStandardStreamMetadataFormat,
 216               nativeStreamMetadataFormatName,
 217               nativeStreamMetadataFormatClassName,
 218               extraStreamMetadataFormatNames,
 219               extraStreamMetadataFormatClassNames,
 220               supportsStandardImageMetadataFormat,
 221               nativeImageMetadataFormatName,
 222               nativeImageMetadataFormatClassName,
 223               extraImageMetadataFormatNames,
 224               extraImageMetadataFormatClassNames);
 225 
 226         if (outputTypes == null) {
 227             throw new IllegalArgumentException
 228                 ("outputTypes == null!");
 229         }
 230         if (outputTypes.length == 0) {
 231             throw new IllegalArgumentException
 232                 ("outputTypes.length == 0!");
 233         }
 234 
 235         this.outputTypes = (outputTypes == STANDARD_OUTPUT_TYPE) ?
 236             new Class<?>[] { ImageOutputStream.class } :
 237             outputTypes.clone();
 238 
 239         // If length == 0, leave it null
 240         if (readerSpiNames != null && readerSpiNames.length > 0) {
 241             this.readerSpiNames = readerSpiNames.clone();
 242         }
 243     }
 244 
 245     /**
 246      * Returns <code>true</code> if the format that this writer
 247      * outputs preserves pixel data bit-accurately.  The default
 248      * implementation returns <code>true</code>.
 249      *
 250      * @return <code>true</code> if the format preserves full pixel
 251      * accuracy.
 252      */
 253     public boolean isFormatLossless() {
 254         return true;
 255     }
 256 
 257     /**
 258      * Returns an array of <code>Class</code> objects indicating what
 259      * types of objects may be used as arguments to the writer's
 260      * <code>setOutput</code> method.
 261      *
 262      * <p> For most writers, which only output to an
 263      * <code>ImageOutputStream</code>, a single-element array
 264      * containing <code>ImageOutputStream.class</code> should be
 265      * returned.
 266      *
 267      * @return a non-<code>null</code> array of
 268      * <code>Class</code>objects of length at least 1.
 269      */
 270     public Class[] getOutputTypes() {
 271         return outputTypes.clone();
 272     }
 273 
 274     /**
 275      * Returns <code>true</code> if the <code>ImageWriter</code>
 276      * implementation associated with this service provider is able to
 277      * encode an image with the given layout.  The layout
 278      * (<i>i.e.</i>, the image's <code>SampleModel</code> and
 279      * <code>ColorModel</code>) is described by an
 280      * <code>ImageTypeSpecifier</code> object.
 281      *
 282      * <p> A return value of <code>true</code> is not an absolute
 283      * guarantee of successful encoding; the encoding process may still
 284      * produce errors due to factors such as I/O errors, inconsistent
 285      * or malformed data structures, etc.  The intent is that a
 286      * reasonable inspection of the basic structure of the image be
 287      * performed in order to determine if it is within the scope of
 288      * the encoding format.  For example, a service provider for a
 289      * format that can only encode greyscale would return
 290      * <code>false</code> if handed an RGB <code>BufferedImage</code>.
 291      * Similarly, a service provider for a format that can encode
 292      * 8-bit RGB imagery might refuse to encode an image with an
 293      * associated alpha channel.
 294      *
 295      * <p> Different <code>ImageWriter</code>s, and thus service
 296      * providers, may choose to be more or less strict.  For example,
 297      * they might accept an image with premultiplied alpha even though
 298      * it will have to be divided out of each pixel, at some loss of
 299      * precision, in order to be stored.
 300      *
 301      * @param type an <code>ImageTypeSpecifier</code> specifying the
 302      * layout of the image to be written.
 303      *
 304      * @return <code>true</code> if this writer is likely to be able
 305      * to encode images with the given layout.
 306      *
 307      * @exception IllegalArgumentException if <code>type</code>
 308      * is <code>null</code>.
 309      */
 310     public abstract boolean canEncodeImage(ImageTypeSpecifier type);
 311 
 312     /**
 313      * Returns <code>true</code> if the <code>ImageWriter</code>
 314      * implementation associated with this service provider is able to
 315      * encode the given <code>RenderedImage</code> instance.  Note
 316      * that this includes instances of
 317      * <code>java.awt.image.BufferedImage</code>.
 318      *
 319      * <p> See the discussion for
 320      * <code>canEncodeImage(ImageTypeSpecifier)</code> for information
 321      * on the semantics of this method.
 322      *
 323      * @param im an instance of <code>RenderedImage</code> to be encoded.
 324      *
 325      * @return <code>true</code> if this writer is likely to be able
 326      * to encode this image.
 327      *
 328      * @exception IllegalArgumentException if <code>im</code>
 329      * is <code>null</code>.
 330      */
 331     public boolean canEncodeImage(RenderedImage im) {
 332         return canEncodeImage(ImageTypeSpecifier.createFromRenderedImage(im));
 333     }
 334 
 335     /**
 336      * Returns an instance of the <code>ImageWriter</code>
 337      * implementation associated with this service provider.
 338      * The returned object will initially be in an initial state as if
 339      * its <code>reset</code> method had been called.
 340      *
 341      * <p> The default implementation simply returns
 342      * <code>createWriterInstance(null)</code>.
 343      *
 344      * @return an <code>ImageWriter</code> instance.
 345      *
 346      * @exception IOException if an error occurs during loading,
 347      * or initialization of the writer class, or during instantiation
 348      * or initialization of the writer object.
 349      */
 350     public ImageWriter createWriterInstance() throws IOException {
 351         return createWriterInstance(null);
 352     }
 353 
 354     /**
 355      * Returns an instance of the <code>ImageWriter</code>
 356      * implementation associated with this service provider.
 357      * The returned object will initially be in an initial state
 358      * as if its <code>reset</code> method had been called.
 359      *
 360      * <p> An <code>Object</code> may be supplied to the plug-in at
 361      * construction time.  The nature of the object is entirely
 362      * plug-in specific.
 363      *
 364      * <p> Typically, a plug-in will implement this method using code
 365      * such as <code>return new MyImageWriter(this)</code>.
 366      *
 367      * @param extension a plug-in specific extension object, which may
 368      * be <code>null</code>.
 369      *
 370      * @return an <code>ImageWriter</code> instance.
 371      *
 372      * @exception IOException if the attempt to instantiate
 373      * the writer fails.
 374      * @exception IllegalArgumentException if the
 375      * <code>ImageWriter</code>'s constructor throws an
 376      * <code>IllegalArgumentException</code> to indicate that the
 377      * extension object is unsuitable.
 378      */
 379     public abstract ImageWriter createWriterInstance(Object extension)
 380         throws IOException;
 381 
 382     /**
 383      * Returns <code>true</code> if the <code>ImageWriter</code> object
 384      * passed in is an instance of the <code>ImageWriter</code>
 385      * associated with this service provider.
 386      *
 387      * @param writer an <code>ImageWriter</code> instance.
 388      *
 389      * @return <code>true</code> if <code>writer</code> is recognized
 390      *
 391      * @exception IllegalArgumentException if <code>writer</code> is
 392      * <code>null</code>.
 393      */
 394     public boolean isOwnWriter(ImageWriter writer) {
 395         if (writer == null) {
 396             throw new IllegalArgumentException("writer == null!");
 397         }
 398         String name = writer.getClass().getName();
 399         return name.equals(pluginClassName);
 400     }
 401 
 402     /**
 403      * Returns an array of <code>String</code>s containing all the
 404      * fully qualified names of all the <code>ImageReaderSpi</code>
 405      * classes that can understand the internal metadata
 406      * representation used by the <code>ImageWriter</code> associated
 407      * with this service provider, or <code>null</code> if there are
 408      * no such <code>ImageReaders</code> specified.  If a
 409      * non-<code>null</code> value is returned, it must have non-zero
 410      * length.
 411      *
 412      * <p> The first item in the array must be the name of the service
 413      * provider for the "preferred" reader, as it will be used to
 414      * instantiate the <code>ImageReader</code> returned by
 415      * <code>ImageIO.getImageReader(ImageWriter)</code>.
 416      *
 417      * <p> This mechanism may be used to obtain
 418      * <code>ImageReaders</code> that will generated non-pixel
 419      * meta-data (see <code>IIOExtraDataInfo</code>) in a structure
 420      * understood by an <code>ImageWriter</code>.  By reading the
 421      * image and obtaining this data from one of the
 422      * <code>ImageReaders</code> obtained with this method and passing
 423      * it on to the <code>ImageWriter</code>, a client program can
 424      * read an image, modify it in some way, and write it back out
 425      * preserving all meta-data, without having to understand anything
 426      * about the internal structure of the meta-data, or even about
 427      * the image format.
 428      *
 429      * @return an array of <code>String</code>s of length at least 1
 430      * containing names of <code>ImageReaderSpi</code>s, or
 431      * <code>null</code>.
 432      *
 433      * @see javax.imageio.ImageIO#getImageReader(ImageWriter)
 434      * @see ImageReaderSpi#getImageWriterSpiNames()
 435      */
 436     public String[] getImageReaderSpiNames() {
 437         return readerSpiNames == null ?
 438             null : readerSpiNames.clone();
 439     }
 440 }