使用中のブラウザでは JavaScript がサポートされていません。このページの機能をすべて使用するには、JavaScript のサポートが必要です。
MyFormatImageWriterSpi MyFormatImageWriterSpi
クラスは、前のセクションで説明した MyFormatImageReaderSpi
クラスと同様の役割を果たします。ただし、特定のストリームを読み込めるかどうかを判別するのではなく、メモリー内のイメージを書き込めるかどうかを判別しなければなりません。また、実際のイメージを入手する前に書き込みプラグインを選択できるようにするため、イメージそのものを調べる代わりに、ImageTypeSpecifier
を使用します。
package com.mycompany.imageio;
import java.io.IOException;
import java.util.Locale;
import javax.imageio.ImageWriter;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageInputStream;
public class MyFormatImageWriterSpi extends ImageWriterSpi {
static final String vendorName = "My Company";
static final String version = "1.0_beta33_build9467";
static final String writerClassName =
"com.mycompany.imageio.MyFormatImageWriter";
static final String[] names = { "myformat" };
static final String[] suffixes = { "myf" };
static final String[] MIMETypes = { "image/x-myformat" };
static final String[] readerSpiNames = {
"com.mycompany.imageio.MyFormatImageReaderSpi" };
static final boolean supportsStandardStreamMetadataFormat = false;
static final String nativeStreamMetadataFormatName = null;
static final String nativeStreamMetadataFormatClassName = null;
static final String[] extraStreamMetadataFormatNames = null;
static final String[] extraStreamMetadataFormatClassNames = null;
static final boolean supportsStandardImageMetadataFormat = false;
static final String nativeImageMetadataFormatName =
"com.mycompany.imageio.MyFormatMetadata_1.0";
static final String nativeImageMetadataFormatClassName =
"com.mycompany.imageio.MyFormatMetadata";
static final String[] extraImageMetadataFormatNames = null;
static final String[] extraImageMetadataFormatClassNames = null;
public MyFormatImageWriterSpi() {
super(vendorName, version,
names, suffixes, MIMETypes,
writerClassName,
STANDARD_OUTPUT_TYPE, // Write to ImageOutputStreams
readerSpiNames,
supportsStandardStreamMetadataFormat,
nativeStreamMetadataFormatName,
nativeStreamMetadataFormatClassName,
extraStreamMetadataFormatNames,
extraStreamMetadataFormatClassNames,
supportsStandardImageMetadataFormat,
nativeImageMetadataFormatName,
nativeImageMetadataFormatClassName,
extraImageMetadataFormatNames,
extraImageMetadataFormatClassNames);
}
public boolean canEncodeImage(ImageTypeSpecifier imageType) {
int bands = imageType.getNumBands();
return bands == 1 || bands == 3;
}
public String getDescription(Locale locale) {
// Localize as appropriate
return "Description goes here";
}
public ImageWriter createWriterInstance(Object extension) {
return new MyFormatImageWriter(this);
}
}
MyFormatImageWriter
package com.mycompany.imageio;
import java.awt.Rectangle;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.IIOException;
import javax.imageio.IIOImage;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageOutputStream;
public class MyFormatImageWriter extends ImageWriter {
ImageOutputStream stream = null;
public MyFormatImageWriter(ImageWriterSpi originatingProvider) {
super(originatingProvider);
}
public void setOutput(Object output) {
super.setOutput(output);
if (output != null) {
if (!(output instanceof ImageOutputStream)) {
throw new IllegalArgumentException
("output not an ImageOutputStream!");
}
this.stream = (ImageOutputStream)output;
} else {
this.stream = null;
}
}
getDefaultWriteParam
から返される ImageWriteParam
は、書き込みプラグインの機能に基づいてカスタマイズしなければなりません。この書き込みプラグインは、タイリング、プログレシブ方式のエンコーディング、および圧縮をサポートしていないため、それぞれ false
または null
という値を渡します。
// Tiling, progressive encoding, compression are disabled by default
public ImageWriteParam getDefaultWriteParam() {
return new ImageWriteParam(getLocale());
}
このファイル形式は、イメージメタデータだけを取り扱います。convertImageMetadata メソッドは、ほとんど何も実行しませんが、必要なら、ほかのプラグインによって使用されるメタデータクラスを解釈するように定義することもできます。
public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) {
return null;
}
public IIOMetadata
getDefaultImageMetadata(ImageTypeSpecifier imageType,
ImageWriteParam param) {
return new MyFormatMetadata();
}
public IIOMetadata convertStreamMetadata(IIOMetadata inData,
ImageWriteParam param) {
return null;
}
public IIOMetadata convertImageMetadata(IIOMetadata inData,
ImageTypeSpecifier imageType,
ImageWriteParam param) {
// We only understand our own metadata
if (inData instanceof MyFormatMetadata) {
return inData;
} else {
return null;
}
}
実際にイメージを書き込むには、まず、ソース領域、ソースバンド、およびサブサンプリング係数を ImageWriteParam
から適用する必要があります。ソース領域とソースバンドは、子 Raster
を作成することで処理できます。簡単にするため、ソースイメージから 1 つの Raster
を抽出します。ソースイメージがタイリングされている場合は、必要に応じて小さい Raster
を抽出することでメモリーを節約できます。
public void write(IIOMetadata streamMetadata,
IIOImage image,
ImageWriteParam param) throws IIOException {
RenderedImage im = image.getRenderedImage();
Rectangle sourceRegion =
new Rectangle(0, 0, im.getWidth(), im.getHeight());
int sourceXSubsampling = 1;
int sourceYSubsampling = 1;
int[] sourceBands = null;
if (param != null) {
sourceRegion =
sourceRegion.intersection(param.getSourceRegion());
sourceXSubsampling = param.getSourceXSubsampling();
sourceYSubsampling = param.getSourceYSubsampling();
sourceBands = param.getSourceBands();
int subsampleXOffset = param.getSubsamplingXOffset();
int subsampleYOffset = param.getSubsamplingYOffset();
sourceRegion.x += subsampleXOffset;
sourceRegion.y += subsampleYOffset;
sourceRegion.width -= subsampleXOffset;
sourceRegion.height -= subsampleYOffset;
}
// Grab a Raster containing the region of interest
int width = sourceRegion.width;
int height = sourceRegion.height;
Raster imRas = im.getData(sourceRegion);
int numBands = imRas.getNumBands();
// Check that sourceBands values are in range
if (sourceBands != null) {
for (int i = 0; i < sourceBands.length; i++) {
if (sourceBands[i] >= numBands) {
throw new IllegalArgumentException("bad band!");
}
}
}
// Translate imRas to start at (0, 0) and subset the bands
imRas = imRas.createChild(sourceRegion.x, sourceRegion.y,
width, height,
0, 0,
sourceBands);
// Reduce width and height according to subsampling factors
width = (width + sourceXSubsampling - 1)/sourceXSubsampling;
height = (height + sourceYSubsampling - 1)/sourceYSubsampling;
// Assume 1 band image is grayscale, 3 band image is RGB
int colorType;
if (numBands == 1) {
colorType = MyFormatImageReader.COLOR_TYPE_GRAY;
} else if (numBands == 3) {
colorType = MyFormatImageReader.COLOR_TYPE_RGB;
} else {
throw new IIOException("Image must have 1 or 3 bands!");
}
イメージの寸法とカラータイプを確認できたら、プラグインは、いつでもファイルヘッダーを書き込むことができます。
try {
byte[] signature = {
(byte)'m', (byte)'y', (byte)'f', (byte)'o',
(byte)'r', (byte)'m', (byte)'a', (byte)'t'
};
// Output header information
stream.write(signature);
stream.write(`\n');
stream.writeInt(width);
stream.writeInt(height);
stream.writeByte(colorType);
stream.write(`\n');
次に、write
メソッドの IIOImage
引数からイメージメタデータを抽出し、convertImageMetadata
を呼び出してメタデータを MyFormatMetadata
オブジェクトに変換してみます。その結果が null
以外であれば、メタデータからキーワードと値を抽出して、出力に書き込みます。
// Attempt to convert metadata, if present
IIOMetadata imd = image.getMetadata();
MyFormatMetadata metadata = null;
if (imd != null) {
ImageTypeSpecifier type =
ImageTypeSpecifier.createFromRenderedImage(im);
metadata =
(MyFormatMetadata)convertImageMetadata(imd,
type,
null);
}
// Output metadata if present
if (metadata != null) {
Iterator keywordIter = metadata.keywords.iterator();
Iterator valueIter = metadata.values.iterator();
while (keywordIter.hasNext()) {
String keyword = (String)keywordIter.next();
String value = (String)valueIter.next();
stream.writeUTF(keyword);
stream.write(`\n');
stream.writeUTF(value);
stream.write(`\n');
}
}
stream.writeUTF("END");
stream.write(`\n');
これで、ピクセルデータを書き込む準備ができました。イメージ Raster
を、getPixels
メソッドを使用して一度に 1 行ずつ int 配列にコピーします。その後、それらの値を水平サブサンプリング係数を使ってサブサンプリングし、その結果を byte 配列にコピーし、その配列を 1 回の write 呼び出しで出力に書き込みます。そして、ソース行を垂直サブサンプリング係数の分だけインクリメントし、ソース領域の最後まで繰り返します。最後に、出力ストリームをフラッシュします。
// Output (subsampled) pixel values
int rowLength = width*numBands;
int xSkip = sourceXSubsampling*numBands;
int[] rowPixels = imRas.getPixels(0, 0, width, 1,
(int[])null);
byte[] rowSamples = new byte[rowLength];
// Output every (sourceYSubsampling)^th row
for (int y = 0; y < height; y += sourceYSubsampling) {
imRas.getPixels(0, y, width, 1, rowPixels);
// Subsample horizontally and convert to bytes
int count = 0;
for (int x = 0; x < width; x += xSkip) {
if (colorType ==
MyFormatImageReader.COLOR_TYPE_GRAY) {
rowSamples[count++] = (byte)rowPixels[x];
} else {
rowSamples[count++] = (byte)rowPixels[x];
rowSamples[count++] =
(byte)rowPixels[x + 1];
rowSamples[count++] =
(byte)rowPixels[x + 2];
}
}
// Output a row's worth of bytes
stream.write(rowSamples, 0, width*numBands);
}
stream.flush();
} catch (IOException e) {
throw new IIOException("I/O error!", e);
}
}
}
目次 | 前へ | 次へ