/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ package javax.imageio; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; import javax.imageio.event.IIOWriteProgressListener; import javax.imageio.event.IIOWriteWarningListener; import javax.imageio.metadata.IIOMetadata; import javax.imageio.spi.ImageWriterSpi; /** * The ImageWriter class is an abstract class for encoding images. ImageWriter * objects are instantiated by the service provider interface, ImageWriterSpi * class, for the specific format. ImageWriterSpi class should be registered * with the IIORegistry, which uses them for format recognition and presentation * of available format readers and writers. * * @since Android 1.0 */ public abstract class ImageWriter implements ImageTranscoder { /** * The available locales. */ protected Locale[] availableLocales; /** * The locale. */ protected Locale locale; /** * The originating provider. */ protected ImageWriterSpi originatingProvider; /** * The output. */ protected Object output; /** * The progress listeners. */ protected List<IIOWriteProgressListener> progressListeners; /** * The warning listeners. */ protected List<IIOWriteWarningListener> warningListeners; /** * The warning locales. */ protected List<Locale> warningLocales; // Indicates that abort operation is requested // Abort mechanism should be thread-safe /** The aborted. */ private boolean aborted; /** * Instantiates a new ImageWriter. * * @param originatingProvider * the ImageWriterSpi which instantiates this ImageWriter. */ protected ImageWriter(ImageWriterSpi originatingProvider) { this.originatingProvider = originatingProvider; } public abstract IIOMetadata convertStreamMetadata(IIOMetadata iioMetadata, ImageWriteParam imageWriteParam); public abstract IIOMetadata convertImageMetadata(IIOMetadata iioMetadata, ImageTypeSpecifier imageTypeSpecifier, ImageWriteParam imageWriteParam); /** * Gets the ImageWriterSpi which instantiated this ImageWriter. * * @return the ImageWriterSpi. */ public ImageWriterSpi getOriginatingProvider() { return originatingProvider; } /** * Processes the start of an image read by calling their imageStarted method * of registered IIOWriteProgressListeners. * * @param imageIndex * the image index. */ protected void processImageStarted(int imageIndex) { if (null != progressListeners) { for (IIOWriteProgressListener listener : progressListeners) { listener.imageStarted(this, imageIndex); } } } /** * Processes the current percentage of image completion by calling * imageProgress method of registered IIOWriteProgressListener. * * @param percentageDone * the percentage done. */ protected void processImageProgress(float percentageDone) { if (null != progressListeners) { for (IIOWriteProgressListener listener : progressListeners) { listener.imageProgress(this, percentageDone); } } } /** * Processes image completion by calling imageComplete method of registered * IIOWriteProgressListeners. */ protected void processImageComplete() { if (null != progressListeners) { for (IIOWriteProgressListener listener : progressListeners) { listener.imageComplete(this); } } } /** * Processes a warning message by calling warningOccurred method of * registered IIOWriteWarningListeners. * * @param imageIndex * the image index. * @param warning * the warning. */ protected void processWarningOccurred(int imageIndex, String warning) { if (null == warning) { throw new NullPointerException("warning message should not be NULL"); } if (null != warningListeners) { for (IIOWriteWarningListener listener : warningListeners) { listener.warningOccurred(this, imageIndex, warning); } } } /** * Processes a warning message by calling warningOccurred method of * registered IIOWriteWarningListeners with string from ResourceBundle. * * @param imageIndex * the image index. * @param bundle * the name of ResourceBundle. * @param key * the keyword. */ protected void processWarningOccurred(int imageIndex, String bundle, String key) { if (warningListeners != null) { // Don't check the parameters return; } if (bundle == null) { throw new IllegalArgumentException("baseName == null!"); } if (key == null) { throw new IllegalArgumentException("keyword == null!"); } // Get the context class loader and try to locate the bundle with it // first ClassLoader contextClassloader = AccessController .doPrivileged(new PrivilegedAction<ClassLoader>() { public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); } }); // Iterate through both listeners and locales int n = warningListeners.size(); for (int i = 0; i < n; i++) { IIOWriteWarningListener listener = warningListeners.get(i); Locale locale = warningLocales.get(i); // Now try to get the resource bundle ResourceBundle rb; try { rb = ResourceBundle.getBundle(bundle, locale, contextClassloader); } catch (MissingResourceException e) { try { rb = ResourceBundle.getBundle(bundle, locale); } catch (MissingResourceException e1) { throw new IllegalArgumentException("Bundle not found!"); } } try { String warning = rb.getString(key); listener.warningOccurred(this, imageIndex, warning); } catch (MissingResourceException e) { throw new IllegalArgumentException("Resource is missing!"); } catch (ClassCastException e) { throw new IllegalArgumentException("Resource is not a String!"); } } } /** * Sets the specified Object to the output of this ImageWriter. * * @param output * the Object which represents destination, it can be * ImageOutputStream or other objects. */ public void setOutput(Object output) { if (output != null) { ImageWriterSpi spi = getOriginatingProvider(); if (null != spi) { Class[] outTypes = spi.getOutputTypes(); boolean supported = false; for (Class<?> element : outTypes) { if (element.isInstance(output)) { supported = true; break; } } if (!supported) { throw new IllegalArgumentException("output " + output + " is not supported"); } } } this.output = output; } /** * Writes a completed image stream that contains the specified image, * default metadata, and thumbnails to the output. * * @param image * the specified image to be written. * @throws IOException * if an I/O exception has occurred during writing. */ public void write(IIOImage image) throws IOException { write(null, image, null); } /** * Writes a completed image stream that contains the specified rendered * image, default metadata, and thumbnails to the output. * * @param image * the specified RenderedImage to be written. * @throws IOException * if an I/O exception has occurred during writing. */ public void write(RenderedImage image) throws IOException { write(null, new IIOImage(image, null, null), null); } /** * Writes a completed image stream that contains the specified image, * metadata and thumbnails to the output. * * @param streamMetadata * the stream metadata, or null. * @param image * the specified image to be written, if canWriteRaster() method * returns false, then Image must contain only RenderedImage. * @param param * the ImageWriteParam, or null. * @throws IOException * if an error occurs during writing. */ public abstract void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException; /** * Disposes of any resources. */ public void dispose() { // def impl. does nothing according to the spec. } /** * Requests an abort operation for current writing operation. */ public synchronized void abort() { aborted = true; } /** * Checks whether or not a request to abort the current write operation has * been made successfully. * * @return true, if the request to abort the current write operation has * been made successfully, false otherwise. */ protected synchronized boolean abortRequested() { return aborted; } /** * Clears all previous abort request, and abortRequested returns false after * calling this method. */ protected synchronized void clearAbortRequest() { aborted = false; } /** * Adds the IIOWriteProgressListener listener. * * @param listener * the IIOWriteProgressListener listener. */ public void addIIOWriteProgressListener(IIOWriteProgressListener listener) { if (listener == null) { return; } if (progressListeners == null) { progressListeners = new ArrayList<IIOWriteProgressListener>(); } progressListeners.add(listener); } /** * Adds the IIOWriteWarningListener. * * @param listener * the IIOWriteWarningListener listener. */ public void addIIOWriteWarningListener(IIOWriteWarningListener listener) { if (listener == null) { return; } if (warningListeners == null) { warningListeners = new ArrayList<IIOWriteWarningListener>(); warningLocales = new ArrayList<Locale>(); } warningListeners.add(listener); warningLocales.add(getLocale()); } /** * Gets the output object that was set by setOutput method. * * @return the output object such as ImageOutputStream, or null if it is not * set. */ public Object getOutput() { return output; } /** * Check output return false. * * @return true, if successful. */ private final boolean checkOutputReturnFalse() { if (getOutput() == null) { throw new IllegalStateException("getOutput() == null!"); } return false; } /** * Unsupported operation. */ private final void unsupportedOperation() { if (getOutput() == null) { throw new IllegalStateException("getOutput() == null!"); } throw new UnsupportedOperationException("Unsupported write variant!"); } /** * Returns true if a new empty image can be inserted at the specified index. * * @param imageIndex * the specified index of image. * @return true if a new empty image can be inserted at the specified index, * false otherwise. * @throws IOException * Signals that an I/O exception has occurred. */ public boolean canInsertEmpty(int imageIndex) throws IOException { return checkOutputReturnFalse(); } /** * Returns true if a new image can be inserted at the specified index. * * @param imageIndex * the specified index of image. * @return true if a new image can be inserted at the specified index, false * otherwise. * @throws IOException * Signals that an I/O exception has occurred. */ public boolean canInsertImage(int imageIndex) throws IOException { return checkOutputReturnFalse(); } /** * Returns true if the image with the specified index can be removed. * * @param imageIndex * the specified index of image. * @return true if the image with the specified index can be removed, false * otherwise. * @throws IOException * Signals that an I/O exception has occurred. */ public boolean canRemoveImage(int imageIndex) throws IOException { return checkOutputReturnFalse(); } /** * Returns true if metadata of the image with the specified index can be * replaced. * * @param imageIndex * the specified image index. * @return true if metadata of the image with the specified index can be * replaced, false otherwise. * @throws IOException * if an I/O exception has occurred. */ public boolean canReplaceImageMetadata(int imageIndex) throws IOException { return checkOutputReturnFalse(); } /** * Returns true if pixels of the image with the specified index can be * replaced by the replacePixels methods. * * @param imageIndex * the image's index. * @return true if pixels of the image with the specified index can be * replaced by the replacePixels methods, false otherwise. * @throws IOException * Signals that an I/O exception has occurred. */ public boolean canReplacePixels(int imageIndex) throws IOException { return checkOutputReturnFalse(); } /** * Returns true if the stream metadata presented in the output can be * removed. * * @return true if the stream metadata presented in the output can be * removed, false otherwise. * @throws IOException * if an I/O exception has occurred. */ public boolean canReplaceStreamMetadata() throws IOException { return checkOutputReturnFalse(); } /** * Returns true if the writing of a complete image stream which contains a * single image is supported with undefined pixel values and associated * metadata and thumbnails to the output. * * @return true if the writing of a complete image stream which contains a * single image is supported, false otherwise. * @throws IOException * if an I/O exception has occurred. */ public boolean canWriteEmpty() throws IOException { return checkOutputReturnFalse(); } /** * Returns true if the methods which taken an IIOImageParameter can deal * with a Raster source image. * * @return true if the methods which taken an IIOImageParameter can deal * with a Raster source image, false otherwise. */ public boolean canWriteRasters() { return false; } /** * Returns true if the writer can add an image to stream that already * contains header information. * * @return if the writer can add an image to stream that already contains * header information, false otherwise. */ public boolean canWriteSequence() { return false; } /** * Ends the insertion of a new image. * * @throws IOException * if an I/O exception has occurred. */ public void endInsertEmpty() throws IOException { unsupportedOperation(); } /** * Ends the replace pixels operation. * * @throws IOException * if an I/O exception has occurred. */ public void endReplacePixels() throws IOException { unsupportedOperation(); } /** * Ends an empty write operation. * * @throws IOException * if an I/O exception has occurred. */ public void endWriteEmpty() throws IOException { unsupportedOperation(); } /** * Ends the sequence of write operations. * * @throws IOException * if an I/O exception has occurred. */ public void endWriteSequence() throws IOException { unsupportedOperation(); } /** * Gets an array of available locales. * * @return an of array available locales. */ public Locale[] getAvailableLocales() { if (availableLocales == null) { return null; } return availableLocales.clone(); } /** * Gets an IIOMetadata object that contains default values for encoding an * image with the specified type. * * @param imageType * the ImageTypeSpecifier. * @param param * the ImageWriteParam. * @return the IIOMetadata object. */ public abstract IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param); /** * Gets an IIOMetadata object that contains default values for encoding a * stream of images. * * @param param * the ImageWriteParam. * @return the IIOMetadata object. */ public abstract IIOMetadata getDefaultStreamMetadata(ImageWriteParam param); /** * Gets the current locale of this ImageWriter. * * @return the current locale of this ImageWriter. */ public Locale getLocale() { return locale; } /** * Gets the default write param. Gets a new ImageWriteParam object for this * ImageWriter with the current Locale. * * @return a new ImageWriteParam object for this ImageWriter. */ public ImageWriteParam getDefaultWriteParam() { return new ImageWriteParam(getLocale()); } /** * Gets the number of thumbnails supported by the format being written with * supported image type, image write parameters, stream, and image metadata * objects. * * @param imageType * the ImageTypeSpecifier. * @param param * the image's parameters. * @param streamMetadata * the stream metadata. * @param imageMetadata * the image metadata. * @return the number of thumbnails supported. */ public int getNumThumbnailsSupported(ImageTypeSpecifier imageType, ImageWriteParam param, IIOMetadata streamMetadata, IIOMetadata imageMetadata) { return 0; } /** * Gets the preferred thumbnail sizes. Gets an array of Dimensions with the * sizes for thumbnail images as they are encoded in the output file or * stream. * * @param imageType * the ImageTypeSpecifier. * @param param * the ImageWriteParam. * @param streamMetadata * the stream metadata. * @param imageMetadata * the image metadata. * @return the preferred thumbnail sizes. */ public Dimension[] getPreferredThumbnailSizes(ImageTypeSpecifier imageType, ImageWriteParam param, IIOMetadata streamMetadata, IIOMetadata imageMetadata) { return null; } /** * Prepares insertion of an empty image by requesting the insertion of a new * image into an existing image stream. * * @param imageIndex * the image index. * @param imageType * the image type. * @param width * the width of the image. * @param height * the height of the image. * @param imageMetadata * the image metadata, or null. * @param thumbnails * the array thumbnails for this image, or null. * @param param * the ImageWriteParam, or null. * @throws IOException * if an I/O exception has occurred. */ public void prepareInsertEmpty(int imageIndex, ImageTypeSpecifier imageType, int width, int height, IIOMetadata imageMetadata, List<? extends BufferedImage> thumbnails, ImageWriteParam param) throws IOException { unsupportedOperation(); } /** * Prepares the writer to call the replacePixels method for the specified * region. * * @param imageIndex * the image's index. * @param region * the specified region. * @throws IOException * if an I/O exception has occurred. */ public void prepareReplacePixels(int imageIndex, Rectangle region) throws IOException { unsupportedOperation(); } /** * Prepares the writer for writing an empty image by beginning the process * of writing a complete image stream that contains a single image with * undefined pixel values, metadata and thumbnails, to the output. * * @param streamMetadata * the stream metadata. * @param imageType * the image type. * @param width * the width of the image. * @param height * the height of the image. * @param imageMetadata * the image's metadata, or null. * @param thumbnails * the image's thumbnails, or null. * @param param * the image's parameters, or null. * @throws IOException * if an I/O exception has occurred. */ public void prepareWriteEmpty(IIOMetadata streamMetadata, ImageTypeSpecifier imageType, int width, int height, IIOMetadata imageMetadata, List<? extends BufferedImage> thumbnails, ImageWriteParam param) throws IOException { unsupportedOperation(); } /** * Prepares a stream to accept calls of writeToSequence method using the * metadata object. * * @param streamMetadata * the stream metadata. * @throws IOException * if an I/O exception has occurred. */ public void prepareWriteSequence(IIOMetadata streamMetadata) throws IOException { unsupportedOperation(); } /** * Processes the completion of a thumbnail read by calling their * thumbnailComplete method of registered IIOWriteProgressListeners. */ protected void processThumbnailComplete() { if (progressListeners != null) { for (IIOWriteProgressListener listener : progressListeners) { listener.thumbnailComplete(this); } } } /** * Processes the current percentage of thumbnail completion by calling their * thumbnailProgress method of registered IIOWriteProgressListeners. * * @param percentageDone * the percentage done. */ protected void processThumbnailProgress(float percentageDone) { if (progressListeners != null) { for (IIOWriteProgressListener listener : progressListeners) { listener.thumbnailProgress(this, percentageDone); } } } /** * Processes the start of a thumbnail read by calling thumbnailStarted * method of registered IIOWriteProgressListeners. * * @param imageIndex * the image index. * @param thumbnailIndex * the thumbnail index. */ protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) { if (progressListeners != null) { for (IIOWriteProgressListener listener : progressListeners) { listener.thumbnailStarted(this, imageIndex, thumbnailIndex); } } } /** * Processes that the writing has been aborted by calling writeAborted * method of registered IIOWriteProgressListeners. */ protected void processWriteAborted() { if (progressListeners != null) { for (IIOWriteProgressListener listener : progressListeners) { listener.writeAborted(this); } } } /** * Removes the all IIOWriteProgressListener listeners. */ public void removeAllIIOWriteProgressListeners() { progressListeners = null; } /** * Removes the all IIOWriteWarningListener listeners. */ public void removeAllIIOWriteWarningListeners() { warningListeners = null; warningLocales = null; } /** * Removes the specified IIOWriteProgressListener listener. * * @param listener * the registered IIOWriteProgressListener to be removed. */ public void removeIIOWriteProgressListener(IIOWriteProgressListener listener) { if (progressListeners != null && listener != null) { if (progressListeners.remove(listener) && progressListeners.isEmpty()) { progressListeners = null; } } } /** * Removes the specified IIOWriteWarningListener listener. * * @param listener * the registered IIOWriteWarningListener listener to be removed. */ public void removeIIOWriteWarningListener(IIOWriteWarningListener listener) { if (warningListeners == null || listener == null) { return; } int idx = warningListeners.indexOf(listener); if (idx > -1) { warningListeners.remove(idx); warningLocales.remove(idx); if (warningListeners.isEmpty()) { warningListeners = null; warningLocales = null; } } } /** * Removes the image with the specified index from the stream. * * @param imageIndex * the image's index. * @throws IOException * if an I/O exception has occurred. */ public void removeImage(int imageIndex) throws IOException { unsupportedOperation(); } /** * Replaces image metadata of the image with specified index. * * @param imageIndex * the image's index. * @param imageMetadata * the image metadata. * @throws IOException * if an I/O exception has occurred. */ public void replaceImageMetadata(int imageIndex, IIOMetadata imageMetadata) throws IOException { unsupportedOperation(); } /** * Replaces a part of an image presented in the output with the specified * RenderedImage. * * @param image * the RenderedImage. * @param param * the ImageWriteParam. * @throws IOException * if an I/O exception has occurred. */ public void replacePixels(RenderedImage image, ImageWriteParam param) throws IOException { unsupportedOperation(); } /** * Replaces a part of an image presented in the output with the specified * Raster. * * @param raster * the Raster. * @param param * the ImageWriteParam. * @throws IOException * if an I/O exception has occurred. */ public void replacePixels(Raster raster, ImageWriteParam param) throws IOException { unsupportedOperation(); } /** * Replaces the stream metadata of the output with new IIOMetadata. * * @param streamMetadata * the new stream metadata. * @throws IOException * if an I/O exception has occurred. */ public void replaceStreamMetadata(IIOMetadata streamMetadata) throws IOException { unsupportedOperation(); } /** * Sets the locale of this ImageWriter. * * @param locale * the new locale. */ public void setLocale(Locale locale) { if (locale == null) { this.locale = null; return; } Locale[] locales = getAvailableLocales(); boolean validLocale = false; if (locales != null) { for (int i = 0; i < locales.length; i++) { if (locale.equals(locales[i])) { validLocale = true; break; } } } if (validLocale) { this.locale = locale; } else { throw new IllegalArgumentException("Invalid locale!"); } } /** * Resets this ImageWriter. */ public void reset() { setOutput(null); setLocale(null); removeAllIIOWriteWarningListeners(); removeAllIIOWriteProgressListeners(); clearAbortRequest(); } /** * Inserts image into existing output stream. * * @param imageIndex * the image index where an image will be written. * @param image * the specified image to be written. * @param param * the ImageWriteParam, or null. * @throws IOException * if an I/O exception has occurred. */ public void writeInsert(int imageIndex, IIOImage image, ImageWriteParam param) throws IOException { unsupportedOperation(); } /** * Writes the specified image to the sequence. * * @param image * the image to be written. * @param param * the ImageWriteParam, or null. * @throws IOException * if an I/O exception has occurred during writing. */ public void writeToSequence(IIOImage image, ImageWriteParam param) throws IOException { unsupportedOperation(); } }