/*
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.BufferedImage;
import?
java.awt.image.DataBuffer;
import?
java.awt.image.WritableRaster;
import?
java.io.IOException;
import?
java.util.Iterator;
import?
javax.imageio.IIOException;
import?
javax.imageio.ImageReadParam;
import?
javax.imageio.ImageReader;
import?
javax.imageio.ImageTypeSpecifier;
import?
javax.imageio.metadata.IIOMetadata;
import?
javax.imageio.metadata.IIOMetadataFormat;
import?
javax.imageio.metadata.IIOMetadataNode;
import?
javax.imageio.spi.ImageReaderSpi;
import?
javax.imageio.stream.ImageInputStream;
import?
org.w3c.dom.Node;
/**
?
*?ch5ImageReader.java?--?this?class?provides?the?functionality?to?read?an?image
?
*?of?format?ch5.
?
*/
public?class?
ch5ImageReader?
extends?
ImageReader?
{
??
private?
ImageInputStream?iis;
??
private?
ch5ImageMetadata
[]?
imagemd;
??
private?
ch5StreamMetadata?streammd;
??
public?
ch5ImageReader
(
ImageReaderSpi?originatingProvider
)?{
????
super
(
originatingProvider
)
;
??
}
??
/**
???
*?return?the?ch5StreamMetadata?object?instantiated?in?the?setStreamMetadata
???
*?method
???
*/
??
public?
IIOMetadata?getStreamMetadata
()?{
????
return?
streammd;
??
}
??
/**
???
*?return?the?ch5ImageMetadata?object?instantiated?in?the?setImageMetadata
???
*?method
???
*/
??
public?
IIOMetadata?getImageMetadata
(
int?
imageIndex
)?{
????
return?
imagemd
[
imageIndex
]
;
??
}
??
/**
???
*?this?method?sets?the?input?for?this?ImageReader?and?also?calls?the
???
*?setStreamMetadata?method?so?that?the?numberImages?field?is?available
???
*/
??
public?
void?
setInput
(
Object?object,?
boolean?
seekForwardOnly
)?{
????
super
.setInput
(
object,?seekForwardOnly
)
;
????
if?
(
object?==?
null
)
??????
throw?new?
IllegalArgumentException
(
"input?is?null"
)
;
????
if?
(
!
(
object?
instanceof?
ImageInputStream
))?{
??????
String?argString?=?
"input?not?an?ImageInputStream"
;
??????
throw?new?
IllegalArgumentException
(
argString
)
;
????
}
????
iis?=?
(
ImageInputStream
)?
object;
????
setStreamMetadata
(
iis
)
;
??
}
??
/**
???
*?this?method?provides?suggestions?for?possible?image?types?that?will?be
???
*?used?to?decode?the?image?specified?by?index?imageIndex.?By?default,?the
???
*?first?image?type?returned?by?this?method?will?be?the?image?type?of?the
???
*?BufferedImage?returned?by?the?ImageReader's?getDestination?method.?In
???
*?this?case,?we?are?suggesting?using?an?8?bit?grayscale?image?with?no?alpha
???
*?component.
???
*/
??
public?
Iterator?getImageTypes
(
int?
imageIndex
)?{
????
java.util.List?l?=?
new?
java.util.ArrayList
()
;
????
;
????
int?
bits?=?
8
;
????
/*
?????
*?can?convert?ch5?format?into?8?bit?grayscale?image?with?no?alpha
?????
*/
????
l.add
(
ImageTypeSpecifier.createGrayscale
(
bits,?DataBuffer.TYPE_BYTE,
????????
false
))
;
????
return?
l.iterator
()
;
??
}
??
/**
???
*?read?in?the?input?image?specified?by?index?imageIndex?using?the
???
*?parameters?specified?by?the?ImageReadParam?object?param
???
*/
??
public?
BufferedImage?read
(
int?
imageIndex,?ImageReadParam?param
)?{
????
checkIndex
(
imageIndex
)
;
????
if?
(
isSeekForwardOnly
())
??????
minIndex?=?imageIndex;
????
else
??????
minIndex?=?
0
;
????
BufferedImage?bimage?=?
null
;
????
WritableRaster?raster?=?
null
;
????
/*
?????
*?this?method?sets?the?image?metadata?so?that?we?can?use?the?getWidth
?????
*?and?getHeight?methods
?????
*/
????
setImageMetadata
(
iis,?imageIndex
)
;
????
int?
srcWidth?=?getWidth
(
imageIndex
)
;
????
int?
srcHeight?=?getHeight
(
imageIndex
)
;
????
//?initialize?values?to?-1
????
int?
dstWidth?=?-
1
;
????
int?
dstHeight?=?-
1
;
????
int?
srcRegionWidth?=?-
1
;
????
int?
srcRegionHeight?=?-
1
;
????
int?
srcRegionXOffset?=?-
1
;
????
int?
srcRegionYOffset?=?-
1
;
????
int?
xSubsamplingFactor?=?-
1
;
????
int?
ySubsamplingFactor?=?-
1
;
????
if?
(
param?==?
null
)
??????
param?=?getDefaultReadParam
()
;
????
Iterator?imageTypes?=?getImageTypes
(
imageIndex
)
;
????
try?
{
??????
/*
???????
*?get?the?destination?BufferedImage?which?will?be?filled?using?the
???????
*?input?image's?pixel?data
???????
*/
??????
bimage?=?getDestination
(
param,?imageTypes,?srcWidth,?srcHeight
)
;
??????
/*
???????
*?get?Rectangle?object?which?will?be?used?to?clip?the?source
???????
*?image's?dimensions.
???????
*/
??????
Rectangle?srcRegion?=?param.getSourceRegion
()
;
??????
if?
(
srcRegion?!=?
null
)?{
????????
srcRegionWidth?=?
(
int
)?
srcRegion.getWidth
()
;
????????
srcRegionHeight?=?
(
int
)?
srcRegion.getHeight
()
;
????????
srcRegionXOffset?=?
(
int
)?
srcRegion.getX
()
;
????????
srcRegionYOffset?=?
(
int
)?
srcRegion.getY
()
;
????????
/*
?????????
*?correct?for?overextended?source?regions
?????????
*/
????????
if?
(
srcRegionXOffset?+?srcRegionWidth?>?srcWidth
)
??????????
dstWidth?=?srcWidth?-?srcRegionXOffset;
????????
else
??????????
dstWidth?=?srcRegionWidth;
????????
if?
(
srcRegionYOffset?+?srcRegionHeight?>?srcHeight
)
??????????
dstHeight?=?srcHeight?-?srcRegionYOffset;
????????
else
??????????
dstHeight?=?srcRegionHeight;
??????
}?
else?
{
????????
dstWidth?=?srcWidth;
????????
dstHeight?=?srcHeight;
????????
srcRegionXOffset?=?srcRegionYOffset?=?
0
;
??????
}
??????
/*
???????
*?get?subsampling?factors
???????
*/
??????
xSubsamplingFactor?=?param.getSourceXSubsampling
()
;
??????
ySubsamplingFactor?=?param.getSourceYSubsampling
()
;
??????
/**
???????
*?dstWidth?and?dstHeight?should?be?equal?to?bimage.getWidth()?and
???????
*?bimage.getHeight()?after?these?next?two?instructions
???????
*/
??????
dstWidth?=?
(
dstWidth?-?
1
)?
/?xSubsamplingFactor?+?
1
;
??????
dstHeight?=?
(
dstHeight?-?
1
)?
/?ySubsamplingFactor?+?
1
;
????
}?
catch?
(
IIOException?e
)?{
??????
System.err.println
(
"Can't?create?destination?BufferedImage"
)
;
????
}
????
raster?=?bimage.getWritableTile
(
0
,?
0
)
;
????
/*
?????
*?using?the?parameters?specified?by?the?ImageReadParam?object,?read?the
?????
*?image?image?data?into?the?destination?BufferedImage
?????
*/
????
byte
[]?
srcBuffer?=?
new?
byte
[
srcWidth
]
;
????
byte
[]?
dstBuffer?=?
new?
byte
[
dstWidth
]
;
????
int?
jj;
????
int?
index;
????
try?
{
??????
for?
(
int?
j?=?
0
;?j?<?srcHeight;?j++
)?{
????????
iis.readFully
(
srcBuffer,?
0
,?srcWidth
)
;
????????
jj?=?j?-?srcRegionYOffset;
????????
if?
(
jj?%?ySubsamplingFactor?==?
0
)?{
??????????
jj?/=?ySubsamplingFactor;
??????????
if?
((
jj?>=?
0
)?
&&?
(
jj?<?dstHeight
))?{
????????????
for?
(
int?
i?=?
0
;?i?<?dstWidth;?i++
)?{
??????????????
index?=?srcRegionXOffset?+?i?*?xSubsamplingFactor;
??????????????
dstBuffer
[
i
]?
=?srcBuffer
[
index
]
;
????????????
}
????????????
raster.setDataElements
(
0
,?jj,?dstWidth,?
1
,?dstBuffer
)
;
??????????
}
????????
}
??????
}
????
}?
catch?
(
IOException?e
)?{
??????
bimage?=?
null
;
????
}
????
return?
bimage;
??
}
??
/**
???
*?this?method?sets?the?image?metadata?for?the?image?indexed?by?index
???
*?imageIndex.?This?method?is?specific?for?the?ch5?format?and?thus?only?sets
???
*?the?image?width?and?image?height
???
*/
??
private?
void?
setImageMetadata
(
ImageInputStream?iis,?
int?
imageIndex
)?{
????
imagemd
[
imageIndex
]?
=?
new?
ch5ImageMetadata
()
;
????
try?
{
??????
String?s;
??????
s?=?iis.readLine
()
;
??????
while?
(
s.length
()?
==?
0
)
????????
s?=?iis.readLine
()
;
??????
imagemd
[
imageIndex
]
.imageWidth?=?Integer.parseInt
(
s.trim
())
;
??????
s?=?iis.readLine
()
;
??????
imagemd
[
imageIndex
]
.imageHeight?=?Integer.parseInt
(
s.trim
())
;
????
}?
catch?
(
IOException?exception
)?{
????
}
??
}
??
/**
???
*?this?method?sets?the?stream?metadata?for?the?images?represented?by?the
???
*?ImageInputStream?iis.?This?method?is?specific?for?the?ch5?format?and?thus
???
*?only?sets?the?numberImages?field.
???
*/
??
private?
void?
setStreamMetadata
(
ImageInputStream?iis
)?{
????
streammd?=?
new?
ch5StreamMetadata
()
;
????
try?
{
??????
String?magicNumber?=?iis.readLine
()
;
??????
int?
numImages?=?Integer.parseInt
(
iis.readLine
()
.trim
())
;
??????
streammd.numberImages?=?numImages;
??????
imagemd?=?
new?
ch5ImageMetadata
[
streammd.numberImages
]
;
????
}?
catch?
(
IOException?exception
)?{
????
}
??
}
??
/**
???
*?This?method?can?only?be?used?after?the?stream?metadata?has?been?set
???
*?(which?occurs?in?the?setInput?method).?Else?it?will?return?a?-1
???
*/
??
public?
int?
getNumImages
(
boolean?
allowSearch
)?{
????
return?
streammd.numberImages;
??
}
??
/**
???
*?This?method?can?only?be?used?after?the?stream?metadata?has?been?set
???
*?(which?occurs?in?the?setInput?method).?Else?it?will?return?a?-1
???
*/
??
public?
int?
getHeight
(
int?
imageIndex
)?{
????
if?
(
imagemd?==?
null
)
??????
return?
-
1
;
????
checkIndex
(
imageIndex
)
;
????
return?
imagemd
[
imageIndex
]
.imageHeight;
??
}
??
/**
???
*?This?method?can?only?be?used?after?the?stream?metadata?has?been?set
???
*?(which?occurs?in?the?setInput?method).?Else?it?will?return?a?-1
???
*/
??
public?
int?
getWidth
(
int?
imageIndex
)?{
????
if?
(
imagemd?==?
null
)
??????
return?
-
1
;
????
checkIndex
(
imageIndex
)
;
????
return?
imagemd
[
imageIndex
]
.imageWidth;
??
}
??
private?
void?
checkIndex
(
int?
imageIndex
)?{
????
if?
(
imageIndex?>=?streammd.numberImages
)?{
??????
String?argString?=?
"imageIndex?>=?number?of?images"
;
??????
throw?new?
IndexOutOfBoundsException
(
argString
)
;
????
}
????
if?
(
imageIndex?<?minIndex
)?{
??????
String?argString?=?
"imageIndex?<?minIndex"
;
??????
throw?new?
IndexOutOfBoundsException
(
argString
)
;
????
}
??
}
}
/**
?
*?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;
??
}
}
|