/*
* 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();
}
}