/*
Java Media APIs: Cross-Platform Imaging, Media and Visualization
Alejandro Terrazas
Sams, Published November 2002,
ISBN 0672320940
*/
import
java.awt.Rectangle;
import
java.awt.image.Raster;
import
java.io.IOException;
import
javax.imageio.IIOImage;
import
javax.imageio.ImageTypeSpecifier;
import
javax.imageio.ImageWriteParam;
import
javax.imageio.ImageWriter;
import
javax.imageio.metadata.IIOMetadata;
import
javax.imageio.metadata.IIOMetadataFormat;
import
javax.imageio.metadata.IIOMetadataNode;
import
javax.imageio.spi.ImageWriterSpi;
import
javax.imageio.stream.ImageOutputStream;
import
org.w3c.dom.Node;
/**
* ch5ImageWriter.java -- this class provides the functionality to write an
* image of format ch5.
*/
public class
ch5ImageWriter
extends
ImageWriter
{
public
ch5ImageWriter
(
ImageWriterSpi originatingProvider
) {
super
(
originatingProvider
)
;
streamMetadataWritten =
false
;
}
/**
* this method is used to convert an ImageReader's image metadata which is
* in a particular format into image metadata that can be used for this
* ImageWriter. Primarily this is used for transcoding (format conversion).
* This ImageWriter does not support such conversions
*/
public
IIOMetadata convertImageMetadata
(
IIOMetadata metadata,
ImageTypeSpecifier specifier, ImageWriteParam param
) {
return null
;
}
/**
* this method is used to convert an ImageReader's stream metadata which is
* in a particular format into stream metadata that can be used for this
* ImageWriter. Primarily this is used for transcoding (format conversion).
* This ImageWriter does not support such conversions
*/
public
IIOMetadata convertStreamMetadata
(
IIOMetadata metadata,
ImageWriteParam param
) {
return null
;
}
/**
* provide default values for the image metadata
*/
public
IIOMetadata getDefaultImageMetadata
(
ImageTypeSpecifier specifier,
ImageWriteParam param
) {
ch5ImageMetadata imagemd =
new
ch5ImageMetadata
()
;
int
width = raster.getWidth
()
;
int
height = raster.getHeight
()
;
imagemd.initialize
(
width, height
)
;
// default image size
return
imagemd;
}
/**
* provide default values for the stream metadata
*/
public
IIOMetadata getDefaultStreamMetadata
(
ImageWriteParam param
) {
ch5StreamMetadata streammd =
new
ch5StreamMetadata
()
;
streammd.initialize
(
1
)
;
// default number of images
return
streammd;
}
/**
* write out the output image specified by index imageIndex using the
* parameters specified by the ImageWriteParam object param
*/
public
void
write
(
IIOMetadata metadata, IIOImage iioimage,
ImageWriteParam param
) {
Node root =
null
;
Node dimensionsElementNode =
null
;
if
(
iioimage.getRenderedImage
()
!=
null
)
raster = iioimage.getRenderedImage
()
.getData
()
;
else
raster = iioimage.getRaster
()
;
/*
* since this format allows you to write multiple images, the
* streamMetadataWritten variable makes sure the stream metadata is
* written only once
*/
if
(
streamMetadataWritten ==
false
) {
if
(
metadata ==
null
)
metadata = getDefaultStreamMetadata
(
param
)
;
root = metadata.getAsTree
(
"ch5.imageio.ch5stream_1.00"
)
;
dimensionsElementNode = root.getFirstChild
()
;
Node numberImagesAttributeNode = dimensionsElementNode
.getAttributes
()
.getNamedItem
(
"numberImages"
)
;
String numberImages = numberImagesAttributeNode.getNodeValue
()
;
try
{
ios.writeBytes
(
"5\n"
)
;
ios.writeBytes
(
numberImages
)
;
ios.flush
()
;
}
catch
(
IOException ioe
) {
System.err.println
(
"IOException "
+ ioe.getMessage
())
;
}
streamMetadataWritten =
true
;
}
String widthString;
String heightString;
IIOMetadata imageMetadata =
(
ch5ImageMetadata
)
iioimage.getMetadata
()
;
/*
* don't really need image metadata object here since raster knows
* necessary information
*/
if
(
imageMetadata ==
null
)
imageMetadata = getDefaultImageMetadata
(
null, param
)
;
root = imageMetadata.getAsTree
(
"ch5.imageio.ch5image_1.00"
)
;
dimensionsElementNode = root.getFirstChild
()
;
Node widthAttributeNode = dimensionsElementNode.getAttributes
()
.getNamedItem
(
"imageWidth"
)
;
widthString = widthAttributeNode.getNodeValue
()
;
Node heightAttributeNode = dimensionsElementNode.getAttributes
()
.getNamedItem
(
"imageHeight"
)
;
heightString = heightAttributeNode.getNodeValue
()
;
int
sourceWidth = Integer.parseInt
(
widthString
)
;
int
sourceHeight = Integer.parseInt
(
heightString
)
;
int
destinationWidth = -
1
;
int
destinationHeight = -
1
;
int
sourceRegionWidth = -
1
;
int
sourceRegionHeight = -
1
;
int
sourceRegionXOffset = -
1
;
int
sourceRegionYOffset = -
1
;
int
xSubsamplingFactor = -
1
;
int
ySubsamplingFactor = -
1
;
if
(
param ==
null
)
param = getDefaultWriteParam
()
;
/*
* get Rectangle object which will be used to clip the source image's
* dimensions.
*/
Rectangle sourceRegion = param.getSourceRegion
()
;
if
(
sourceRegion !=
null
) {
sourceRegionWidth =
(
int
)
sourceRegion.getWidth
()
;
sourceRegionHeight =
(
int
)
sourceRegion.getHeight
()
;
sourceRegionXOffset =
(
int
)
sourceRegion.getX
()
;
sourceRegionYOffset =
(
int
)
sourceRegion.getY
()
;
/*
* correct for overextended source regions
*/
if
(
sourceRegionXOffset + sourceRegionWidth > sourceWidth
)
destinationWidth = sourceWidth - sourceRegionXOffset;
else
destinationWidth = sourceRegionWidth;
if
(
sourceRegionYOffset + sourceRegionHeight > sourceHeight
)
destinationHeight = sourceHeight - sourceRegionYOffset;
else
destinationHeight = sourceRegionHeight;
}
else
{
destinationWidth = sourceWidth;
destinationHeight = sourceHeight;
sourceRegionXOffset = sourceRegionYOffset =
0
;
}
/*
* get subsampling factors
*/
xSubsamplingFactor = param.getSourceXSubsampling
()
;
ySubsamplingFactor = param.getSourceYSubsampling
()
;
destinationWidth =
(
destinationWidth -
1
)
/ xSubsamplingFactor +
1
;
destinationHeight =
(
destinationHeight -
1
)
/ ySubsamplingFactor +
1
;
byte
[]
sourceBuffer;
byte
[]
destinationBuffer =
new
byte
[
destinationWidth
]
;
try
{
ios.writeBytes
(
new
String
(
"\n"
))
;
ios.writeBytes
(
new
String
(
destinationWidth +
"\n"
))
;
ios.writeBytes
(
new
String
(
destinationHeight +
"\n"
))
;
int
jj;
int
index;
for
(
int
j =
0
; j < sourceWidth; j++
) {
sourceBuffer =
(
byte
[])
raster.getDataElements
(
0
, j,
sourceWidth,
1
,
null
)
;
jj = j - sourceRegionYOffset;
if
(
jj % ySubsamplingFactor ==
0
) {
jj /= ySubsamplingFactor;
if
((
jj >=
0
)
&&
(
jj < destinationHeight
)) {
for
(
int
i =
0
; i < destinationWidth; i++
) {
index = sourceRegionXOffset + i
* xSubsamplingFactor;
destinationBuffer
[
i
]
= sourceBuffer
[
index
]
;
}
ios.write
(
destinationBuffer,
0
, destinationWidth
)
;
ios.flush
()
;
}
}
}
}
catch
(
IOException e
) {
System.err.println
(
"IOException: "
+ e.getMessage
())
;
}
}
public
void
setOutput
(
Object output
) {
super
.setOutput
(
output
)
;
if
(
output ==
null
)
throw new
IllegalArgumentException
(
"output is null"
)
;
if
(
!
(
output
instanceof
ImageOutputStream
))
throw new
IllegalArgumentException
(
"output not an ImageOutputStream"
)
;
ios =
(
ImageOutputStream
)
output;
streamMetadataWritten =
false
;
}
private
ImageOutputStream ios;
private
boolean
streamMetadataWritten;
private
Raster raster;
}
/**
* ch5StreamMetadata.java -- holds stream metadata for the ch5 format. The
* internal tree for holding this metadata is read only
*/
class
ch5StreamMetadata
extends
IIOMetadata
{
static final
String nativeMetadataFormatName =
"ch5.imageio.ch5stream_1.00"
;
static final
String nativeMetadataFormatClassName =
"ch5.imageio.ch5stream"
;
static final
String
[]
extraMetadataFormatNames =
null
;
static final
String
[]
extraMetadataFormatClassNames =
null
;
static final
boolean
standardMetadataFormatSupported =
false
;
public
int
numberImages;
public
ch5StreamMetadata
() {
super
(
standardMetadataFormatSupported, nativeMetadataFormatName,
nativeMetadataFormatClassName, extraMetadataFormatNames,
extraMetadataFormatClassNames
)
;
numberImages = -
1
;
}
public
boolean
isReadOnly
() {
return true
;
}
/**
* IIOMetadataFormat objects are meant to describe the structure of metadata
* returned from the getAsTree method. In this case, no such description is
* available
*/
public
IIOMetadataFormat getMetadataFormat
(
String formatName
) {
if
(
formatName.equals
(
nativeMetadataFormatName
)) {
return null
;
}
else
{
throw new
IllegalArgumentException
(
"Unrecognized format!"
)
;
}
}
/**
* returns the stream metadata in a tree corresponding to the provided
* formatName
*/
public
Node getAsTree
(
String formatName
) {
if
(
formatName.equals
(
nativeMetadataFormatName
)) {
return
getNativeTree
()
;
}
else
{
throw new
IllegalArgumentException
(
"Unrecognized format!"
)
;
}
}
/**
* returns the stream metadata in a tree using the following format
*
<!ELEMENT ch5.imageio.ch5stream_1.00 (imageDimensions)>
<!ATTLIST
* imageDimensions numberImages CDATA #REQUIRED
*/
private
Node getNativeTree
() {
IIOMetadataNode node;
// scratch node
IIOMetadataNode root =
new
IIOMetadataNode
(
nativeMetadataFormatName
)
;
// Image descriptor
node =
new
IIOMetadataNode
(
"imageDimensions"
)
;
node.setAttribute
(
"numberImages"
, Integer.toString
(
numberImages
))
;
root.appendChild
(
node
)
;
return
root;
}
public
void
setFromTree
(
String formatName, Node root
) {
throw new
IllegalStateException
(
"Metadata is read-only!"
)
;
}
public
void
mergeTree
(
String formatName, Node root
) {
throw new
IllegalStateException
(
"Metadata is read-only!"
)
;
}
public
void
reset
() {
throw new
IllegalStateException
(
"Metadata is read-only!"
)
;
}
/**
* initialize the stream metadata element numberImages
*/
public
void
initialize
(
int
numberImages
) {
this
.numberImages = numberImages;
}
}
/**
* ch5ImageMetadata.java -- holds image metadata for the ch5 format.
* The internal tree for holding this metadata is read only
*/
class
ch5ImageMetadata
extends
IIOMetadata
{
static final
String
nativeMetadataFormatName =
"ch5.imageio.ch5image_1.00"
;
static final
String
nativeMetadataFormatClassName =
"ch5.imageio.ch5image"
;
static final
String
[]
extraMetadataFormatNames =
null
;
static final
String
[]
extraMetadataFormatClassNames =
null
;
static final
boolean
standardMetadataFormatSupported =
false
;
public
int
imageWidth;
public
int
imageHeight;
public
ch5ImageMetadata
() {
super
(
standardMetadataFormatSupported,
nativeMetadataFormatName,
nativeMetadataFormatClassName,
extraMetadataFormatNames,
extraMetadataFormatClassNames
)
;
imageWidth = -
1
;
imageHeight = -
1
;
}
public
boolean
isReadOnly
() {
return true
;
}
/**
* IIOMetadataFormat objects are meant to describe the structure of
* metadata returned from the getAsTree method. In this case,
* no such description is available
*/
public
IIOMetadataFormat getMetadataFormat
(
String formatName
) {
if
(
formatName.equals
(
nativeMetadataFormatName
)) {
return null
;
}
else
{
throw new
IllegalArgumentException
(
"Unrecognized format!"
)
;
}
}
/**
* returns the image metadata in a tree corresponding to the
* provided formatName
*/
public
Node getAsTree
(
String formatName
) {
if
(
formatName.equals
(
nativeMetadataFormatName
)) {
return
getNativeTree
()
;
}
else
{
throw new
IllegalArgumentException
(
"Unrecognized format!"
)
;
}
}
/**
* returns the image metadata in a tree using the following format
*
<!ELEMENT ch5.imageio.ch5image_1.00 (imageDimensions)>
* <!ATTLIST imageDimensions
* imageWidth CDATA #REQUIRED
* imageHeight CDATA #REQUIRED
*/
private
Node getNativeTree
() {
IIOMetadataNode root =
new
IIOMetadataNode
(
nativeMetadataFormatName
)
;
IIOMetadataNode node =
new
IIOMetadataNode
(
"imageDimensions"
)
;
node.setAttribute
(
"imageWidth"
, Integer.toString
(
imageWidth
))
;
node.setAttribute
(
"imageHeight"
, Integer.toString
(
imageHeight
))
;
root.appendChild
(
node
)
;
return
root;
}
public
void
setFromTree
(
String formatName, Node root
) {
throw new
IllegalStateException
(
"Metadata is read-only!"
)
;
}
public
void
mergeTree
(
String formatName, Node root
) {
throw new
IllegalStateException
(
"Metadata is read-only!"
)
;
}
public
void
reset
() {
throw new
IllegalStateException
(
"Metadata is read-only!"
)
;
}
/**
* initialize the image metadata elements width and height
*/
public
void
initialize
(
int
width,
int
height
) {
imageWidth = width;
imageHeight = height;
}
}
|