ch5ImageWriter.java Source code

Java tutorial

Introduction

Here is the source code for ch5ImageWriter.java

Source

/*
    
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;
    }
}