The "ImageWrite" operation uses the
Java
Image I/O Framework to write images to an output destination. Which
formats may be written depends on which ImageWriter
plug-ins are registered with the Image I/O Framework when the operation is
invoked.

The output destination will usually be an
ImageOutputStream, but may be a
File, RandomAccessFile,
OutputStream, Socket,
WritableByteChannel, file path represented as a
String or some other type compatible with a writer plug-in. The
ImageIO class should be used to specify the location
and enable the use of cache files via its setCacheDirectory()
and setUseCache() methods, respectively. Note that this cache
pertains to image stream caching and is unrelated to the JAI
TileCache. If an ImageOutputStream
is created internally by the operation, for example from a
File-valued Output parameter,
then it will be flushed automatically if and only if the operation is not
in collection mode and pixel replacement is
not occurring.

The "ImageWrite" operation supports rendered,
renderable, and
collection modes and requires a single
source. The operation is "immediate" for all modes as specified by
OperationDescriptor.isImmediate() so that
isImmediate() returns true. The operation will
therefore be rendered when created via either JAI.create[NS]()
or JAI.createCollection[NS]().
A RenderingHints object supplied when the
operation is created will have no effect except with respect to the
mapping of JAI.KEY_INTERPOLATION and then only in renderable
mode.

Image properties are used to pass metadata and other information to the
writer plug-in and to make available metadata as actually written to the
output destination. Property handling is mode-specific.

Similarly to the case of any ImageReadParam or ImageReader supplied to the
"ImageRead" operation, any ImageWriteParam or ImageWriter supplied to the
"ImageWrite" operation is subject to modification within the operation
classes. A policy similar to the
"ImageRead"
synchronization policy therefore applies as well for "ImageWrite".

In the Sun Microsystems implementation of this operation these potential
conflicts have been mitigated to a certain extent:

If the param is cloneable then it is cloned and the clone used internally.
Otherwise if the param is an instance of ImageWriteParam itself rather than
of a subclass thereof, i.e., getClass().getName() invoked on the param
returns "javax.imageio.ImageWriteParam", then a new ImageWriteParam is
constructed and the settings of the original param copied to it. If the
param is not cloneable and is an instance of a proper subclass of
ImageWriteParam then it is used directly.

The only ImageWriter methods invoked after rendering are
prepareReplacePixels(int,Rectangle), replacePixels(Raster,ImageWriteParam),
and endReplacePixels() and these are invoked within a method synchronized
on the ImageWriter object.

The following algorithm is used to determine the tile size of the
image written to the output destination:

if ImageWriter cannot write tiles
output is untiled
else
if TileSize parameter is non-null
set tile size to TileSize
else
if WriteParam is null
set tile size to source tile size
else
if tilingMode is ImageWriteParam.MODE_EXPLICIT
if tile dimension is set in WriteParam
set tile size to tile dimension from WriteParam
else
if preferred tile dimension is set in WriteParam
set tile size to average of first two preferred dimensions
else
set tile size to source tile size
else // tilingMode is not ImageWriteParam.MODE_EXPLICIT
the plug-in decides the tile size

If AllowPixelReplacement is TRUE, the ImageWriter can replace pixels, and
the source is a PlanarImage, then the rendering of the operation
will respond to RenderingChangeEvents and Shape-valued PropertyChangeEvents
named "InvalidRegion". The rendering will be automatically registered as
a sink of the rendering of the operation node's source. As the source
rendering does not usually generate events, the calling code must also
explicitly register the "ImageWrite" rendering as a sink of the source
node. By whatever means the event is generated, when the rendering
receives such an event, it will determine the indices of all tiles which
overlap the invalid region and will replace the pixels of all these tiles
in the output.

Note that this behavior differs from what would happen if the RenderedOp
created by the operation received a RenderingChangeEvent: in this case a
new rendering of the node would be created using the ParameterBlock and
RenderingHints currently in effect. This would cause the entire image to be
rewritten at the current position of the output. This will also happen
when AllowPixelReplacement is FALSE. In effect in both of these cases the
behavior in response to a RenderingChangeEvent is unspecified and the result
will likely be unexpected.

To avoid any inadvertent overwriting of the destination as a result of
events received by the RenderedOp, the following usage is recommended when
the objective is automatic pixel replacement:

At this point a reference to imageWriteRendering must be held as long as the
data of the source of the operation may change. Then provided the events are
correctly propagated to imageWriteRendering, the data in the output file
will be automatically updated to match the source data.

If pixel replacement is not the objective and inadvertent overwriting is
to be avoided then the safest approach would be the following:

Image properties are used for metadata, thumbnails, and writer-related
information. The following properties may be set on the RenderedOp created
for the "ImageWrite" operation in rendered mode:

Rendered Mode Image Properties

Property Name

Type

Comment

JAI.ImageWriteParam

ImageWriteParam

Set to ImageWriteParam actually used which may differ from the one passed in.

JAI.ImageWriter

ImageWriter

Set to ImageWriter actually used.

JAI.ImageMetadata

IIOMetadata

Set if and only if image metadata are available; may be transcoded.

JAI.StreamMetadata

IIOMetadata

Set if and only if stream metadata are available; may be transcoded.

JAI.Thumbnails

BufferedImage[]

Set if and only thumbnails are provided and the writer supportes writing them.

If a given property is not set, this implies of course that the names of
absent properties will not appear in the array returned by getPropertyNames()
and getProperty() invoked to obtain absent properties will return
java.awt.Image.UndefinedProperty as usual.

The ImageWriter and ImageWriteParam may be used for subsequent invocations
of the operation or for informational purposes. Care should be taken in using
these property values with respect to the synchronization issues previously
discussed.

Metadata properties will be set to those actually written to the output. They
may be derived either from input parameters or source properties depending on
the values of the StreamMetadata, ImageMetadata, and UseProperties parameters.
They will be transcoded data if Transcode is TRUE and the ImageWriter supports
transcoding.

In renderable mode the "ImageWrite" operation requires a
RenderableImage source and writes a
RenderedImage to the specified output destination.
As the "immediate" designation specified by isImmediate()
has no effect in renderable mode, no image will be written without further
action by the calling code. To write an image, createRendering(),
createScaledRendering(), or createDefaultRendering()
must be invoked. Each of these will create a RenderedImage by forwarding the
createRendering() or equivalent call to the source image. The resulting
RenderedImage will be written to the output according to the
rendered mode operation of "ImageWrite".
If a mapping of JAI.KEY_INTERPOLATION is supplied via a
RenderingHints passed to the operation, then the interpolation
type it specifies will be used to create the rendering if interpolation is
required.

Pixel Replacement in Renderable Mode

Pixel replacement pertains only to RenderedImages generated by rendering the
RenderableOp. It may occur if the same conditions apply as described for
pixel replacement in rendered mode. Due to the unspecified nature of the
underlying rendered sources of any rendering, this is not a recommended
procedure.

Image Properties in Renderable Mode

The RenderableOp node itself does not have any ImageWrite-related
properties. Any RenderedImages created by rendering the RenderableOp
(thereby writing an image to the output as described), may have
rendered mode properties set.

In collection mode the "ImageWrite" operation requires a
Collection source and writes its contents to the
specified output destination.

The Collection is treated as a sequence of images which will be
extracted from the Collection in the order returned by a new Iterator.
Elements in the Collection which are not RenderedImages will be ignored.
The derived sequence of images will then be written to the output.

If there is only one RenderedImage in the source Collection, this image
will be written as done in rendered mode operation. If there is more than
one RenderedImage, the sequence of RenderedImages will be written as an
image sequence. In the latter case the ImageWriter must be able to write
sequences.

If the source is not a CollectionOp then the number of RenderedImages in
the source is counted. If it is not at least one then an exception is
thrown when the operation is created. If it is greater than one, then
the ImageWriter is checked to determine whether it can write sequences.
If it cannot then an exception is thrown when the operation is created.

The first index of the thumbnails array corresponds to the ordinal position
of the image in the collection and the second index to the thumbnails of
that image.

The change to the ImageMetadata and Thumbnails parameters is that there can
now be a distinct image metadata object and thumbnail array for each image
in the Collection. The components of these respective arrays will be indexed
using the sequence of RenderedImages extracted from the source Collection by
the Iterator. It is the responsibility of the caller to ensure that this
sequencing is correct. In this context it is advisable to use a source
Collection which maintains the order of its elements such as a List.

Pixel Replacement in Collection Mode

If the value of the AllowPixelReplacement parameter is TRUE, then the
rendered Collection will contain RenderedImages which are registered as
listeners of their respective sources. Each image in the rendered Collection
will however be a rendering as opposed to a RenderedOp. This obviates the
need to unhook such a RenderedOp from its source as suggested. Two actions
on the part of the application are however necessary in this case: 1) the
sequence must be manually ended, and 2) the Collection node must be removed
as a sink of its source Collection. The first action is necessary as
pixels may be replaced at various times in various images in the sequence
and it is not possible to terminate the sequence at rendering time, and there
is no reliable mechanism to detect programmatically when this may later be
effected. The second action is necessary because a CollectionChangeEvent
received by the Collection node would cause the node to be re-rendered, i.e.,
the collection data to be rewritten using the current state of all parameters.
This will in fact also happen when AllowPixelReplacement is FALSE. In effect
in both of these cases the behavior in response to a CollectionChangeEvent
is unspecified and the result will likely be unexpected.

To ensure proper termination of the image sequence and avoid any inadvertent
overwriting of the destination as a result of events received by the
CollectionOp, the following usage is recommended when the objective is
automatic pixel replacement:

Using the foregoing construct, all pixels in all images written to the output
sequence will remain current with the in-memory data of their respective
source provided all events are propagated as expected. Note that it is not
necessary to end the sequence manually if pixel replacement is not allowed or
is not supported. Also the sequence must be manually ended if and only if the
writer is capable of writing sequences. This permits pixel replacement to
work in the case where the source collection contains only a single image
and the writer supports pixel replacement but cannot write sequences.

If pixel replacement is not the objective, i.e., AllowPixelReplacement is
FALSE, and inadvertent overwriting is to be avoided then the safest approach
would be the following:

The image is written by the first statement and no reference to the
rendering need be retained.

Image Properties in Collection Mode

Contingent on parameter settings and the presence of the appropriate
metadata, the rendered Collection may have the "JAI.StreamMetadata",
"JAI.ImageReadParam", and "JAI.ImageReader" properties set. Each
RenderedImage in the Collection may contain
rendered mode properties
contingent on parameter settings and data availability. Metadata
properties may be transcoded.

If the superclass method finds that the arguments are invalid, or if
this method determines that any of the foregoing conditions is true,
an error message will be appended to msg and
false will be returned; otherwise true will
be returned.