📄 extending.fm4.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html><head><title>Java Image I/O API Guide: 4 - Writing Image I/O Plug-ins</title></head><body bgcolor="#ffffff"> <table summary="layout" width="100%"><tr><td><!-- Bug in Communicator w/font: NavBar text disappears for Times 14pt pref. --><!-- font size="-1" --> <a href="imageio_guideTOC.fm.html" tppabs="http://java.sun.com/j2se/1.4.2/docs/guide/imageio/spec/imageio_guideTOC.fm.html">CONTENTS</a> | <a href="extending.fm3.html" tppabs="http://java.sun.com/j2se/1.4.2/docs/guide/imageio/spec/extending.fm3.html">PREV</a> | <a href="extending.fm5.html" tppabs="http://java.sun.com/j2se/1.4.2/docs/guide/imageio/spec/extending.fm5.html">NEXT</a> <!-- | <a href="copyright.fm.html">INDEX</a> --><!-- /font --></td><td align=right><i>Java<sup><font size="-1">TM</font></sup></font> Image I/O API Guide</i></td></tr></table><br> <p><hr size="8" width="35%" align="left" noshade><h2><a name="999064"><i>4.4 </i> Writing Writer Plug-ins</a></h2><blockquote><a name="999425"><!-- --></a><i><b> MyFormatImageWriterSpi</b></i></blockquote><blockquote><a name="999426"><!-- --></a>The <code>MyFormatImageWriterSpi</code> call plays a similar role to the <code>MyFormatImageReaderSpi</code> class discussed in the previous section. However, instead of being responsible for determining whether a given stream can be read, it must deterine whether an image in memory can be written. Rather than inspecting the image itself, an <code>ImageTypeSpecifier</code> is used so that writers may be selected before an actual image is available.<p></blockquote><blockquote><pre>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); }}</pre></blockquote><blockquote><a name="1000429"><!-- --></a><i><b> MyFormatImageWriter</b></i></blockquote><blockquote><a name="999511"><!-- --></a><p></blockquote><blockquote><pre>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; } }</pre></blockquote><blockquote><a name="1000510"><!-- --></a>The <code>ImageWriteParam</code> returned by <code>getDefaultWriteParam</code> must be customized based on the writer's capabilities. Since this writer does not support tiling, progessive encoding, or compression, we pass in values of <code>false</code> or <code>null</code> as appropriate:<p></blockquote><blockquote><pre> // Tiling, progressive encoding, compression are disabled by default public ImageWriteParam getDefaultWriteParam() { return new ImageWriteParam(getLocale()); }</pre></blockquote><blockquote><a name="1000534"><!-- --></a>The format only handles image metadata. The convertImageMetadata method does very little; it could be defined to interpret the metadata classes used by other plug-ins.<p><a name="1000956"><!-- --></a><p></blockquote><blockquote><pre> 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; } }</pre></blockquote><blockquote><a name="1000544"><!-- --></a>The actual writing of the image requires first applying the source region, source bands, and subsampling factors from the <code>ImageWriteParam</code>. The source region and source bands may be handled by creating a child <code>Raster</code>. For simplicity, we extract a single <code>Raster</code> from the source image. If the source image is tiled, we can save memory by extracting smaller <code>Raster</code>s as needed.<p></blockquote><blockquote><pre> 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!"); }</pre></blockquote><blockquote><a name="1000564"><!-- --></a>Once the image dimensions and color type of the image have been ascertained, the plug-in is ready to write the file header:<p></blockquote><blockquote><pre> 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'); </pre></blockquote><blockquote><a name="1000568"><!-- --></a>Next, the plug-in extracts the image metadata from the <code>write</code> method's <code>IIOImage</code> argument, and attempts to convert it into a <code>MyFormatMetadata</code> object by calling <code>convertImageMetadata</code>. If the result is non-<code>null</code>, the keywords and values are extracted from the metadata and written to the output:<p></blockquote><blockquote><pre> // 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');</pre></blockquote><blockquote><a name="1000582"><!-- --></a>Finally, the plug-in is ready to begin writing the pixel data. The image <code>Raster</code> is copied into an int array, one row at a time using the <code>getPixels</code> method. Then these values are subsampled using the horizontal subsampling factor, and copied into a byte array, which is written to the output with a single write call. The source row is then incremented by the vertical subsampling factor until the end of the source region is reached, and the output stream is flushed:<p></blockquote><blockquote><pre> // 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); } }}</pre></blockquote><br><hr><!-- Bug in Communicator w/font: NavBar text disappears for Times 14pt pref. --><!-- font size="-1" --> <a href="imageio_guideTOC.fm.html" tppabs="http://java.sun.com/j2se/1.4.2/docs/guide/imageio/spec/imageio_guideTOC.fm.html">CONTENTS</a> | <a href="extending.fm3.html" tppabs="http://java.sun.com/j2se/1.4.2/docs/guide/imageio/spec/extending.fm3.html">PREV</a> | <a href="extending.fm5.html" tppabs="http://java.sun.com/j2se/1.4.2/docs/guide/imageio/spec/extending.fm5.html">NEXT</a> <!-- | <a href="copyright.fm.html">INDEX</a> --><!-- /font --><hr><font size="-1"><i><A HREF="copyright.fm.html" tppabs="http://java.sun.com/j2se/1.4.2/docs/guide/imageio/spec/copyright.fm.html">Copyright</a> © 2001 Sun Microsystems, Inc. All Rights Reserved.</i></font><!-- This HTML file was created with Quadralay WebWorks Publisher 3.5.0 --><!-- by Suzette Pelouch --><!-- Last updated: Fri Apr 27 11:23:03 2001 --> </body><script language="JavaScript" src="s_code_remote.js" tppabs="http://java.sun.com/js/omi/jsc/s_code_remote.js"></script></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -