Spec-Zone .ru
спецификации, руководства, описания, API
Содержание документации
СОДЕРЖАНИЕ | ПРЕДЫДУЩИЙ | NEXT

4.4 Запись Плагинов Писателя

MyFormatImageWriterSpi MyFormatImageWriterSpi вызов играет подобную роль к MyFormatImageReaderSpi класс обсуждается в предыдущем разделе. Однако, вместо того, чтобы быть ответственным за определение, может ли данный поток быть считан, он должен deterine, может ли изображение в памяти быть записано. Вместо того, чтобы осматривать изображение непосредственно, 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;
                }
        }

ImageWriteParam возвращенный getDefaultWriteParam должен быть настроен основанный на возможностях писателя. Так как этот писатель не поддерживает мозаичное размещение, progessive кодирование, или сжатие, мы передаем в значениях 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. Для простоты мы извлекаем сингл Raster из исходного изображения. Если исходное изображение размещается рядом, мы можем сохранить память, извлекая меньший Rasters как необходимый.
        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 параметр, и попытки преобразовать это в a MyFormatMetadata объект, вызывая convertImageMetadata. Если результат не -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 метод. Затем эти значения подвыбираются, используя горизонтальный фактор подвыборки, и копируются в байтовый массив, который пишется выводу с единственным вызовом записи. Исходная строка тогда постепенно увеличивается вертикальным фактором подвыборки, пока конец исходной области не достигается, и поток вывода сбрасывается:
                        // 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);
                }
        }
}


СОДЕРЖАНИЕ | ПРЕДЫДУЩИЙ | NEXT

Oracle и/или его филиалы Авторское право © 1993, 2011, Oracle и/или его филиалы. Все права защищены.
Свяжитесь с Нами