blob: d6119b0789ab320e0522ef1d49bd7237cd276b16 [file] [log] [blame]
/*
* 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.
*/
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
* instanties 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 Signals that an I/O exception has occurred
* during writting.
*/
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 Signals that an I/O exception has occurred
* during writting.
*/
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();
}
/**
* Returnes 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 Signals that 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 Signals that 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 Signals that 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 Signals that an I/O exception has occurred.
*/
public void endInsertEmpty() throws IOException {
unsupportedOperation();
}
/**
* Ends the repalce pixels operation.
*
* @throws IOException Signals that an I/O exception has occurred.
*/
public void endReplacePixels() throws IOException {
unsupportedOperation();
}
/**
* Ends an empty write operation.
*
* @throws IOException Signals that an I/O exception has occurred.
*/
public void endWriteEmpty() throws IOException {
unsupportedOperation();
}
/**
* Ends the sequence of write operations.
*
* @throws IOException Signals that 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 suported 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 Signals that 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 Signals that 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 Signals that 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 Signals that 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 Signals that 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 Signals that 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 Signals that 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 Signals that 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 Signals that 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 Signals that 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 Signals that an I/O exception has occurred
* during writting.
*/
public void writeToSequence(IIOImage image, ImageWriteParam param) throws IOException {
unsupportedOperation();
}
}