All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.jaiimageio.impl.plugins.bmp.BMPMetadata Maven / Gradle / Ivy

Go to download

Java Advanced Imaging Image I/O Tools API core, but without the classes involved with javax.media.jai dependencies, JPEG2000 or codecLibJIIO, meaning that this library can be distributed under the modified BSD license and should be GPL compatible.

The newest version!
/*
 * $RCSfile: BMPMetadata.java,v $
 *
 * 
 * Copyright (c) 2005 Sun Microsystems, Inc. All  Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met: 
 * 
 * - Redistribution of source code must retain the above copyright 
 *   notice, this  list of conditions and the following disclaimer.
 * 
 * - Redistribution in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in 
 *   the documentation and/or other materials provided with the
 *   distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of 
 * contributors may be used to endorse or promote products derived 
 * from this software without specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any 
 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 
 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
 * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 
 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 
 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 
 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES. 
 * 
 * You acknowledge that this software is not designed or intended for 
 * use in the design, construction, operation or maintenance of any 
 * nuclear facility. 
 *
 * $Revision: 1.2 $
 * $Date: 2006/04/21 23:14:37 $
 * $State: Exp $
 */
package com.github.jaiimageio.impl.plugins.bmp;

import java.awt.image.ColorModel;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.SampleModel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import javax.imageio.ImageWriteParam;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataFormatImpl;
import javax.imageio.metadata.IIOMetadataNode;

import org.w3c.dom.Node;

import com.github.jaiimageio.impl.common.ImageUtil;

public class BMPMetadata extends IIOMetadata
    implements Cloneable, BMPConstants {

    public static final String nativeMetadataFormatName =
        "com_sun_media_imageio_plugins_bmp_image_1.0";

    // Fields for Image Descriptor
    public String bmpVersion;
    public int width ;
    public int height;
    public short bitsPerPixel;
    public int compression;
    public int imageSize;

    // Fields for PixelsPerMeter
    public int xPixelsPerMeter;
    public int yPixelsPerMeter;

    public int colorsUsed;
    public int colorsImportant;

    // Fields for BI_BITFIELDS compression(Mask)
    public int redMask;
    public int greenMask;
    public int blueMask;
    public int alphaMask;

    public int colorSpace;

    // Fields for CIE XYZ for the LCS_CALIBRATED_RGB color space
    public double redX;
    public double redY;
    public double redZ;
    public double greenX;
    public double greenY;
    public double greenZ;
    public double blueX;
    public double blueY;
    public double blueZ;

    // Fields for Gamma values for the LCS_CALIBRATED_RGB color space
    public int gammaRed;
    public int gammaGreen;
    public int gammaBlue;

    public int intent;

    // Fields for the Palette and Entries
    public byte[] palette = null;
    public int paletteSize;
    public int red;
    public int green;
    public int blue;

    // Fields from CommentExtension
    // List of String
    public List comments = null; // new ArrayList();

    public BMPMetadata() {
        super(true,
              nativeMetadataFormatName,
              "com.github.jaiimageio.impl.bmp.BMPMetadataFormat",
              null, null);
    }

    public BMPMetadata(IIOMetadata metadata)
        throws IIOInvalidTreeException {

        this();

        if(metadata != null) {
            List formats = Arrays.asList(metadata.getMetadataFormatNames());

            if(formats.contains(nativeMetadataFormatName)) {
                // Initialize from native image metadata format.
                setFromTree(nativeMetadataFormatName,
                            metadata.getAsTree(nativeMetadataFormatName));
            } else if(metadata.isStandardMetadataFormatSupported()) {
                // Initialize from standard metadata form of the input tree.
                String format =
                    IIOMetadataFormatImpl.standardMetadataFormatName;
                setFromTree(format, metadata.getAsTree(format));
            }
        }
    }

    public boolean isReadOnly() {
        return false;
    }

    public Object clone() {
        BMPMetadata metadata;
        try {
            metadata = (BMPMetadata)super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
        
        return metadata;
    }

    public Node getAsTree(String formatName) {
        if (formatName.equals(nativeMetadataFormatName)) {
            return getNativeTree();
        } else if (formatName.equals
                   (IIOMetadataFormatImpl.standardMetadataFormatName)) {
            return getStandardTree();
        } else {
            throw new IllegalArgumentException(I18N.getString("BMPMetadata0"));
        }
    }

    private Node getNativeTree() {
        IIOMetadataNode root =
            new IIOMetadataNode(nativeMetadataFormatName);

        addChildNode(root, "BMPVersion", bmpVersion);
        addChildNode(root, "Width", new Integer(width));
        addChildNode(root, "Height", new Integer(height));
        addChildNode(root, "BitsPerPixel", new Short(bitsPerPixel));
        addChildNode(root, "Compression", new Integer(compression));
        addChildNode(root, "ImageSize", new Integer(imageSize));

        IIOMetadataNode node;
        if(xPixelsPerMeter > 0 && yPixelsPerMeter > 0) {
            node = addChildNode(root, "PixelsPerMeter", null);
            addChildNode(node, "X", new Integer(xPixelsPerMeter));
            addChildNode(node, "Y", new Integer(yPixelsPerMeter));
        }

        addChildNode(root, "ColorsUsed", new Integer(colorsUsed));
        addChildNode(root, "ColorsImportant", new Integer(colorsImportant));

        int version = 0;
        for (int i = 0; i < bmpVersion.length(); i++)
            if (Character.isDigit(bmpVersion.charAt(i)))
                version = bmpVersion.charAt(i) -'0';

        if (version >= 4) {
            node = addChildNode(root, "Mask", null);
            addChildNode(node, "Red", new Integer(redMask));
            addChildNode(node, "Green", new Integer(greenMask));
            addChildNode(node, "Blue", new Integer(blueMask));
            addChildNode(node, "Alpha", new Integer(alphaMask));

            addChildNode(root, "ColorSpaceType", new Integer(colorSpace));

            node = addChildNode(root, "CIEXYZEndpoints", null);
            addXYZPoints(node, "Red", redX, redY, redZ);
            addXYZPoints(node, "Green", greenX, greenY, greenZ);
            addXYZPoints(node, "Blue", blueX, blueY, blueZ);

            node = addChildNode(root, "Gamma", null);
            addChildNode(node, "Red", new Integer(gammaRed));
            addChildNode(node, "Green", new Integer(gammaGreen));
            addChildNode(node, "Blue", new Integer(gammaBlue));

            node = addChildNode(root, "Intent", new Integer(intent));
        }

        // Palette
        if ((palette != null) && (paletteSize > 0)) {
            node = addChildNode(root, "Palette", null);
            boolean isVersion2 =
                bmpVersion != null && bmpVersion.equals(VERSION_2);

            for (int i = 0, j = 0; i < paletteSize; i++) {
                IIOMetadataNode entry =
                    addChildNode(node, "PaletteEntry", null);
                blue = palette[j++] & 0xff;
                green = palette[j++] & 0xff;
                red = palette[j++] & 0xff;
                addChildNode(entry, "Red", new Integer(red));
                addChildNode(entry, "Green", new Integer(green));
                addChildNode(entry, "Blue", new Integer(blue));
                if(!isVersion2) j++; // skip reserved entry
            }
        }

        return root;
    }

    // Standard tree node methods
    protected IIOMetadataNode getStandardChromaNode() {

        IIOMetadataNode node = new IIOMetadataNode("Chroma");

        IIOMetadataNode subNode = new IIOMetadataNode("ColorSpaceType");
        String colorSpaceType;
        if (((palette != null) && (paletteSize > 0)) ||
            (redMask != 0 || greenMask != 0 || blueMask != 0) ||
            bitsPerPixel > 8) {
            colorSpaceType = "RGB";
        } else {
            colorSpaceType = "GRAY";
        }
        subNode.setAttribute("name", colorSpaceType);
        node.appendChild(subNode);

        subNode = new IIOMetadataNode("NumChannels");
        String numChannels;
        if (((palette != null) && (paletteSize > 0)) ||
            (redMask != 0 || greenMask != 0 || blueMask != 0) ||
            bitsPerPixel > 8) {
            if(alphaMask != 0) {
                numChannels = "4";
            } else {
                numChannels = "3";
            }
        } else {
            numChannels = "1";
        }
        subNode.setAttribute("value", numChannels);
        node.appendChild(subNode);

        if(gammaRed != 0 && gammaGreen != 0 && gammaBlue != 0) {
            subNode = new IIOMetadataNode("Gamma");
            Double gamma = new Double((gammaRed+gammaGreen+gammaBlue)/3.0);
            subNode.setAttribute("value", gamma.toString());
            node.appendChild(subNode);
        }

        if(numChannels.equals("1") &&
           (palette == null || paletteSize == 0)) {
            subNode = new IIOMetadataNode("BlackIsZero");
            subNode.setAttribute("value", "TRUE");
            node.appendChild(subNode);
        }

        if ((palette != null) && (paletteSize > 0)) {
            subNode = new IIOMetadataNode("Palette");
            boolean isVersion2 =
                bmpVersion != null && bmpVersion.equals(VERSION_2);

            for (int i = 0, j = 0; i < paletteSize; i++) {
                IIOMetadataNode subNode1 =
                    new IIOMetadataNode("PaletteEntry");
                subNode1.setAttribute("index", ""+i);
                subNode1.setAttribute("blue", "" + (palette[j++]&0xff));
                subNode1.setAttribute("green", "" + (palette[j++]&0xff));
                subNode1.setAttribute("red", "" + (palette[j++]&0xff));
                if(!isVersion2) j++; // skip reserved entry
                subNode.appendChild(subNode1);
            }
            node.appendChild(subNode);
        }

        return node;
    }

    protected IIOMetadataNode getStandardCompressionNode() {
        IIOMetadataNode node = new IIOMetadataNode("Compression");

        // CompressionTypeName
        IIOMetadataNode subNode = new IIOMetadataNode("CompressionTypeName");
        subNode.setAttribute("value", compressionTypeNames[compression]);
        node.appendChild(subNode);

        subNode = new IIOMetadataNode("Lossless");
        subNode.setAttribute("value",
                             compression == BI_JPEG ? "FALSE" : "TRUE");
        node.appendChild(subNode);

        return node;
    }

    protected IIOMetadataNode getStandardDataNode() {
        IIOMetadataNode node = new IIOMetadataNode("Data");

        String sampleFormat = (palette != null) && (paletteSize > 0) ?
            "Index" : "UnsignedIntegral";
        IIOMetadataNode subNode = new IIOMetadataNode("SampleFormat");
        subNode.setAttribute("value", sampleFormat);
        node.appendChild(subNode);

        String bits = "";
        if(redMask != 0 || greenMask != 0 || blueMask != 0) {
            bits =
                countBits(redMask) + " " +
                countBits(greenMask) + " " +
                countBits(blueMask);
            if(alphaMask != 0) {
                bits += " " + countBits(alphaMask);
            }
        } else if(palette != null && paletteSize > 0) {
            for(int i = 1; i <= 3; i++) {
                bits += bitsPerPixel;
                if(i != 3) {
                    bits += " ";
                }
            }
        } else {
            if (bitsPerPixel == 1) {
                bits = "1";
            } else if (bitsPerPixel == 4) {
                bits = "4";
            } else if (bitsPerPixel == 8) {
                bits = "8";
            } else if (bitsPerPixel == 16) {
                bits = "5 6 5";
            } else if (bitsPerPixel == 24) {
                bits = "8 8 8";
            } else if ( bitsPerPixel == 32) {
                bits = "8 8 8 8";
            }
        }

        if(!bits.equals("")) {
            subNode = new IIOMetadataNode("BitsPerSample");
            subNode.setAttribute("value", bits);
            node.appendChild(subNode);
        }

        return node;
    }

    protected IIOMetadataNode getStandardDimensionNode() {
	if (yPixelsPerMeter > 0 && xPixelsPerMeter > 0) {
	    IIOMetadataNode node = new IIOMetadataNode("Dimension");
	    float ratio = (float)yPixelsPerMeter / (float)xPixelsPerMeter;
	    IIOMetadataNode subNode = new IIOMetadataNode("PixelAspectRatio");
	    subNode.setAttribute("value", "" + ratio);
	    node.appendChild(subNode);

	    subNode = new IIOMetadataNode("HorizontalPixelSize");
	    subNode.setAttribute("value", "" + (1000.0F / xPixelsPerMeter));
	    node.appendChild(subNode);

	    subNode = new IIOMetadataNode("VerticalPixelSize");
	    subNode.setAttribute("value", "" + (1000.0F / yPixelsPerMeter));
	    node.appendChild(subNode);

            // Emit HorizontalPhysicalPixelSpacing and
            // VerticalPhysicalPixelSpacing for historical reasonse:
            // HorizontalPixelSize and VerticalPixelSize should have
            // been used in the first place.
	    subNode = new IIOMetadataNode("HorizontalPhysicalPixelSpacing");
	    subNode.setAttribute("value", "" + (1000.0F / xPixelsPerMeter));
	    node.appendChild(subNode);

	    subNode = new IIOMetadataNode("VerticalPhysicalPixelSpacing");
	    subNode.setAttribute("value", "" + (1000.0F / yPixelsPerMeter));
	    node.appendChild(subNode);

	    return node;
	}
	return null;
    }

    protected IIOMetadataNode getStandardDocumentNode() {
        if(bmpVersion != null) {
	    IIOMetadataNode node = new IIOMetadataNode("Document");
	    IIOMetadataNode subNode = new IIOMetadataNode("FormatVersion");
	    subNode.setAttribute("value", bmpVersion);
	    node.appendChild(subNode);
            return node;
        }
	return null;
    }

    protected IIOMetadataNode getStandardTextNode() {
        if(comments != null) {
	    IIOMetadataNode node = new IIOMetadataNode("Text");
            Iterator iter = comments.iterator();
            while(iter.hasNext()) {
                String comment = (String)iter.next();
                IIOMetadataNode subNode = new IIOMetadataNode("TextEntry");
                subNode.setAttribute("keyword", "comment");
                subNode.setAttribute("value", comment);
                node.appendChild(subNode);
            }
            return node;
        }
	return null;
    }

    protected IIOMetadataNode getStandardTransparencyNode() {
        IIOMetadataNode node = new IIOMetadataNode("Transparency");
        IIOMetadataNode subNode = new IIOMetadataNode("Alpha");
        String alpha;
        if(alphaMask != 0) {
            alpha = "nonpremultiplied";
        } else {
            alpha = "none";
        }

        subNode.setAttribute("value", alpha);
        node.appendChild(subNode);
        return node;
    }

    // Shorthand for throwing an IIOInvalidTreeException
    private void fatal(Node node, String reason)
        throws IIOInvalidTreeException {
        throw new IIOInvalidTreeException(reason, node);
    }

    // Get an integer-valued attribute
    private int getIntAttribute(Node node, String name,
                                int defaultValue, boolean required)
        throws IIOInvalidTreeException {
        String value = getAttribute(node, name, null, required);
        if (value == null) {
            return defaultValue;
        }
        return Integer.parseInt(value);
    }

    // Get a double-valued attribute
    private double getDoubleAttribute(Node node, String name,
                                      double defaultValue, boolean required)
        throws IIOInvalidTreeException {
        String value = getAttribute(node, name, null, required);
        if (value == null) {
            return defaultValue;
        }
        return Double.parseDouble(value);
    }

    // Get a required integer-valued attribute
    private int getIntAttribute(Node node, String name)
        throws IIOInvalidTreeException {
        return getIntAttribute(node, name, -1, true);
    }

    // Get a required double-valued attribute
    private double getDoubleAttribute(Node node, String name)
        throws IIOInvalidTreeException {
        return getDoubleAttribute(node, name, -1.0F, true);
    }

    // Get a String-valued attribute
    private String getAttribute(Node node, String name,
                                String defaultValue, boolean required)
        throws IIOInvalidTreeException {
        Node attr = node.getAttributes().getNamedItem(name);
        if (attr == null) {
            if (!required) {
                return defaultValue;
            } else {
                fatal(node, "Required attribute " + name + " not present!");
            }
        }
        return attr.getNodeValue();
    }

    // Get a required String-valued attribute
    private String getAttribute(Node node, String name)
        throws IIOInvalidTreeException {
        return getAttribute(node, name, null, true);
    }

    void initialize(ColorModel cm, SampleModel sm, ImageWriteParam param) {
        // bmpVersion and compression.
        if(param != null) {
            bmpVersion = BMPConstants.VERSION_3;

            if(param.getCompressionMode() == ImageWriteParam.MODE_EXPLICIT) {
                String compressionType = param.getCompressionType();
                compression =
                    BMPImageWriter.getCompressionType(compressionType);
            }
        } else {
            bmpVersion = BMPConstants.VERSION_3;
            compression = BMPImageWriter.getPreferredCompressionType(cm, sm);
        }

        // width and height
        width = sm.getWidth();
        height = sm.getHeight();

        // bitsPerPixel
        bitsPerPixel = (short)cm.getPixelSize();

        // mask
        if(cm instanceof DirectColorModel) {
            DirectColorModel dcm = (DirectColorModel)cm;
            redMask = dcm.getRedMask();
            greenMask = dcm.getGreenMask();
            blueMask = dcm.getBlueMask();
            alphaMask = dcm.getAlphaMask();
        }

        // palette and paletteSize
        if(cm instanceof IndexColorModel) {
	    IndexColorModel icm = (IndexColorModel)cm;
	    paletteSize = icm.getMapSize();

	    byte[] r = new byte[paletteSize];
	    byte[] g = new byte[paletteSize];
	    byte[] b = new byte[paletteSize];

	    icm.getReds(r);
	    icm.getGreens(g);
	    icm.getBlues(b);

            boolean isVersion2 =
                bmpVersion != null && bmpVersion.equals(VERSION_2);

            palette = new byte[(isVersion2 ? 3 : 4)*paletteSize];
            for(int i = 0, j = 0; i < paletteSize; i++) {
                palette[j++] = b[i];
                palette[j++] = g[i];
                palette[j++] = r[i];
                if(!isVersion2) j++; // skip reserved entry
            }
        }
    }

    public void mergeTree(String formatName, Node root)
        throws IIOInvalidTreeException {
        if (formatName.equals(nativeMetadataFormatName)) {
            if (root == null) {
                throw new IllegalArgumentException("root == null!");
            }
            mergeNativeTree(root);
        } else if (formatName.equals
                   (IIOMetadataFormatImpl.standardMetadataFormatName)) {
            if (root == null) {
                throw new IllegalArgumentException("root == null!");
            }
            mergeStandardTree(root);
        } else {
            throw new IllegalArgumentException("Not a recognized format!");
        }
    }

    private void mergeNativeTree(Node root)
        throws IIOInvalidTreeException {
        Node node = root;
        if (!node.getNodeName().equals(nativeMetadataFormatName)) {
            fatal(node, "Root must be " + nativeMetadataFormatName);
        }
        
        byte[] r = null, g = null, b = null;
        int maxIndex = -1;

        node = node.getFirstChild();
        while (node != null) {
            String name = node.getNodeName();

            if (name.equals("BMPVersion")) {
                String value = getStringValue(node);
                if(value != null) bmpVersion = value;
            } else if (name.equals("Width")) {
                Integer value = getIntegerValue(node);
                if(value != null) width = value.intValue();
            } else if (name.equals("Height")) {
                Integer value = getIntegerValue(node);
                if(value != null) height = value.intValue();
            } else if (name.equals("BitsPerPixel")) {
                Short value = getShortValue(node);
                if(value != null) bitsPerPixel = value.shortValue();
            } else if (name.equals("Compression")) {
                Integer value = getIntegerValue(node);
                if(value != null) compression = value.intValue();
            } else if (name.equals("ImageSize")) {
                Integer value = getIntegerValue(node);
                if(value != null) imageSize = value.intValue();
            } else if (name.equals("PixelsPerMeter")) {
                Node subNode = node.getFirstChild();
                while (subNode != null) {
                    String subName = subNode.getNodeName();
                    if(subName.equals("X")) {
                        Integer value = getIntegerValue(subNode);
                        if(value != null)
                            xPixelsPerMeter = value.intValue();
                    } else if(subName.equals("Y")) {
                        Integer value = getIntegerValue(subNode);
                        if(value != null)
                            yPixelsPerMeter = value.intValue();
                    }
                    subNode = subNode.getNextSibling();
                }
            } else if (name.equals("ColorsUsed")) {
                Integer value = getIntegerValue(node);
                if(value != null) colorsUsed = value.intValue();
            } else if (name.equals("ColorsImportant")) {
                Integer value = getIntegerValue(node);
                if(value != null) colorsImportant = value.intValue();
            } else if (name.equals("Mask")) {
                Node subNode = node.getFirstChild();
                while (subNode != null) {
                    String subName = subNode.getNodeName();
                    if(subName.equals("Red")) {
                        Integer value = getIntegerValue(subNode);
                        if(value != null)
                            redMask = value.intValue();
                    } else if(subName.equals("Green")) {
                        Integer value = getIntegerValue(subNode);
                        if(value != null)
                            greenMask = value.intValue();
                    } else if(subName.equals("Blue")) {
                        Integer value = getIntegerValue(subNode);
                        if(value != null)
                            blueMask = value.intValue();
                    } else if(subName.equals("Alpha")) {
                        Integer value = getIntegerValue(subNode);
                        if(value != null)
                            alphaMask = value.intValue();
                    }
                    subNode = subNode.getNextSibling();
                }
            } else if (name.equals("ColorSpace")) {
                Integer value = getIntegerValue(node);
                if(value != null) colorSpace = value.intValue();
            } else if (name.equals("CIEXYZEndpoints")) {
                Node subNode = node.getFirstChild();
                while (subNode != null) {
                    String subName = subNode.getNodeName();
                    if(subName.equals("Red")) {
                        Node subNode1 = subNode.getFirstChild();
                        while (subNode1 != null) {
                            String subName1 = subNode1.getNodeName();
                            if(subName1.equals("X")) {
                                Double value = getDoubleValue(subNode1);
                                if(value != null)
                                    redX = value.doubleValue();
                            } else if(subName1.equals("Y")) {
                                Double value = getDoubleValue(subNode1);
                                if(value != null)
                                    redY = value.doubleValue();
                            } else if(subName1.equals("Z")) {
                                Double value = getDoubleValue(subNode1);
                                if(value != null)
                                    redZ = value.doubleValue();
                            }
                            subNode1 = subNode1.getNextSibling();
                        }
                    } else if(subName.equals("Green")) {
                        Node subNode1 = subNode.getFirstChild();
                        while (subNode1 != null) {
                            String subName1 = subNode1.getNodeName();
                            if(subName1.equals("X")) {
                                Double value = getDoubleValue(subNode1);
                                if(value != null)
                                    greenX = value.doubleValue();
                            } else if(subName1.equals("Y")) {
                                Double value = getDoubleValue(subNode1);
                                if(value != null)
                                    greenY = value.doubleValue();
                            } else if(subName1.equals("Z")) {
                                Double value = getDoubleValue(subNode1);
                                if(value != null)
                                    greenZ = value.doubleValue();
                            }
                            subNode1 = subNode1.getNextSibling();
                        }
                    } else if(subName.equals("Blue")) {
                        Node subNode1 = subNode.getFirstChild();
                        while (subNode1 != null) {
                            String subName1 = subNode1.getNodeName();
                            if(subName1.equals("X")) {
                                Double value = getDoubleValue(subNode1);
                                if(value != null)
                                    blueX = value.doubleValue();
                            } else if(subName1.equals("Y")) {
                                Double value = getDoubleValue(subNode1);
                                if(value != null)
                                    blueY = value.doubleValue();
                            } else if(subName1.equals("Z")) {
                                Double value = getDoubleValue(subNode1);
                                if(value != null)
                                    blueZ = value.doubleValue();
                            }
                            subNode1 = subNode1.getNextSibling();
                        }
                    }
                    subNode = subNode.getNextSibling();
                }
            } else if (name.equals("Gamma")) {
                Node subNode = node.getFirstChild();
                while (subNode != null) {
                    String subName = subNode.getNodeName();
                    if(subName.equals("Red")) {
                        Integer value = getIntegerValue(subNode);
                        if(value != null)
                            gammaRed = value.intValue();
                    } else if(subName.equals("Green")) {
                        Integer value = getIntegerValue(subNode);
                        if(value != null)
                            gammaGreen = value.intValue();
                    } else if(subName.equals("Blue")) {
                        Integer value = getIntegerValue(subNode);
                        if(value != null)
                            gammaBlue = value.intValue();
                    }
                    subNode = subNode.getNextSibling();
                }
            } else if (name.equals("Intent")) {
                Integer value = getIntegerValue(node);
                if(value != null) intent = value.intValue();
            } else if (name.equals("Palette")) {
                paletteSize = getIntAttribute(node, "sizeOfPalette");

                r = new byte[paletteSize];
                g = new byte[paletteSize];
                b = new byte[paletteSize];
                maxIndex = -1;
                
                Node paletteEntry = node.getFirstChild();
                if (paletteEntry == null) {
                    fatal(node, "Palette has no entries!");
                }

                int numPaletteEntries = 0;
                while (paletteEntry != null) {
                    if (!paletteEntry.getNodeName().equals("PaletteEntry")) {
                        fatal(node,
                              "Only a PaletteEntry may be a child of a Palette!");
                    }

                    int index = -1;
                    Node subNode = paletteEntry.getFirstChild();
                    while (subNode != null) {
                        String subName = subNode.getNodeName();
                        if(subName.equals("Index")) {
                            Integer value = getIntegerValue(subNode);
                            if(value != null)
                                index = value.intValue();
                            if (index < 0 || index > paletteSize - 1) {
                                fatal(node,
                                      "Bad value for PaletteEntry attribute index!");
                            }
                        } else if(subName.equals("Red")) {
                            Integer value = getIntegerValue(subNode);
                            if(value != null)
                                red = value.intValue();
                        } else if(subName.equals("Green")) {
                            Integer value = getIntegerValue(subNode);
                            if(value != null)
                                green = value.intValue();
                        } else if(subName.equals("Blue")) {
                            Integer value = getIntegerValue(subNode);
                            if(value != null)
                                blue = value.intValue();
                        }
                        subNode = subNode.getNextSibling();
                    }

                    if(index == -1) {
                        index = numPaletteEntries;
                    }
                    if (index > maxIndex) {
                        maxIndex = index;
                    }

                    r[index] = (byte)red;
                    g[index] = (byte)green;
                    b[index] = (byte)blue;

                    numPaletteEntries++;
                    paletteEntry = paletteEntry.getNextSibling();
                }
            } else if (name.equals("CommentExtensions")) {
                // CommentExtension
                Node commentExtension = node.getFirstChild();
                if (commentExtension == null) {
                    fatal(node, "CommentExtensions has no entries!");
                }

                if(comments == null) {
                    comments = new ArrayList();
                }

                while (commentExtension != null) {
                    if (!commentExtension.getNodeName().equals("CommentExtension")) {
                        fatal(node,
                              "Only a CommentExtension may be a child of a CommentExtensions!");
                    }

                    comments.add(getAttribute(commentExtension, "value"));

                    commentExtension = commentExtension.getNextSibling();
                }
            } else {
                fatal(node, "Unknown child of root node!");
            }
            
            node = node.getNextSibling();
        }

        if(r != null && g != null && b != null) {
            boolean isVersion2 =
                bmpVersion != null && bmpVersion.equals(VERSION_2);

            int numEntries = maxIndex + 1;
            palette = new byte[(isVersion2 ? 3 : 4)*numEntries];
            for(int i = 0, j = 0; i < numEntries; i++) {
                palette[j++] = b[i];
                palette[j++] = g[i];
                palette[j++] = r[i];
                if(!isVersion2) j++; // skip reserved entry
            }
        }
    }

    private void mergeStandardTree(Node root)
        throws IIOInvalidTreeException {
        Node node = root;
        if (!node.getNodeName()
            .equals(IIOMetadataFormatImpl.standardMetadataFormatName)) {
            fatal(node, "Root must be " +
                  IIOMetadataFormatImpl.standardMetadataFormatName);
        }

        String colorSpaceType = null;
        int numChannels = 0;
        int[] bitsPerSample = null;
        boolean hasAlpha = false;
        
        byte[] r = null, g = null, b = null;
        int maxIndex = -1;

        node = node.getFirstChild();
        while(node != null) {
            String name = node.getNodeName();

            if (name.equals("Chroma")) {
                Node child = node.getFirstChild();
                while (child != null) {
                    String childName = child.getNodeName();
                    if (childName.equals("ColorSpaceType")) {
                        colorSpaceType = getAttribute(child, "name");
                    } else if (childName.equals("NumChannels")) {
                        numChannels = getIntAttribute(child, "value");
                    } else if (childName.equals("Gamma")) {
                        gammaRed = gammaGreen = gammaBlue =
                            (int)(getDoubleAttribute(child, "value") + 0.5);
                    } else if (childName.equals("Palette")) {
                        r = new byte[256];
                        g  = new byte[256];
                        b = new byte[256];
                        maxIndex = -1;
                
                        Node paletteEntry = child.getFirstChild();
                        if (paletteEntry == null) {
                            fatal(node, "Palette has no entries!");
                        }

                        while (paletteEntry != null) {
                            if (!paletteEntry.getNodeName().equals("PaletteEntry")) {
                                fatal(node,
                                      "Only a PaletteEntry may be a child of a Palette!");
                            }
                    
                            int index = getIntAttribute(paletteEntry, "index");
                            if (index < 0 || index > 255) {
                                fatal(node,
                                      "Bad value for PaletteEntry attribute index!");
                            }
                            if (index > maxIndex) {
                                maxIndex = index;
                            }
                            r[index] =
                                (byte)getIntAttribute(paletteEntry, "red");
                            g[index] =
                                (byte)getIntAttribute(paletteEntry, "green");
                            b[index] =
                                (byte)getIntAttribute(paletteEntry, "blue");
                        
                            paletteEntry = paletteEntry.getNextSibling();
                        }
                    }

                    child = child.getNextSibling();
                }
            } else if (name.equals("Compression")) {
                Node child = node.getFirstChild();
                while(child != null) {
                    String childName = child.getNodeName();
                    if (childName.equals("CompressionTypeName")) {
                        String compressionName = getAttribute(child, "value");
                        compression =
                            BMPImageWriter.getCompressionType(compressionName);
                    }
                    child = child.getNextSibling();
                }
            } else if (name.equals("Data")) {
                Node child = node.getFirstChild();
                while(child != null) {
                    String childName = child.getNodeName();
                    if (childName.equals("BitsPerSample")) {
                        List bps = new ArrayList(4);
                        String s = getAttribute(child, "value");
                        StringTokenizer t = new StringTokenizer(s);
                        while(t.hasMoreTokens()) {
                            bps.add(Integer.valueOf(t.nextToken()));
                        }
                        bitsPerSample = new int[bps.size()];
                        for(int i = 0; i < bitsPerSample.length; i++) {
                            bitsPerSample[i] =
                                ((Integer)bps.get(i)).intValue();
                        }
                        break;
                    }
                    child = child.getNextSibling();
                }
            } else if (name.equals("Dimension")) {
                boolean gotWidth = false;
                boolean gotHeight = false;
                boolean gotAspectRatio = false;
                boolean gotSpaceX = false;
                boolean gotSpaceY = false;

                double width = -1.0F;
                double height = -1.0F;
                double aspectRatio = -1.0F;
                double spaceX = -1.0F;
                double spaceY = -1.0F;
                
                Node child = node.getFirstChild();
                while (child != null) {
                    String childName = child.getNodeName();
                    if (childName.equals("PixelAspectRatio")) {
                        aspectRatio = getDoubleAttribute(child, "value");
                        gotAspectRatio = true;
                    } else if (childName.equals("HorizontalPixelSize")) {
                        width = getDoubleAttribute(child, "value");
                        gotWidth = true;
                    } else if (childName.equals("VerticalPixelSize")) {
                        height = getDoubleAttribute(child, "value");
                        gotHeight = true;
                    } else if (childName.equals("HorizontalPhysicalPixelSpacing")) {
                        spaceX = getDoubleAttribute(child, "value");
                        gotSpaceX = true;
                    } else if (childName.equals("VerticalPhysicalPixelSpacing")) {
                        spaceY = getDoubleAttribute(child, "value");
                        gotSpaceY = true;
                        // } else if (childName.equals("ImageOrientation")) {
                        // } else if (childName.equals("HorizontalPosition")) {
                        // } else if (childName.equals("VerticalPosition")) {
                        // } else if (childName.equals("HorizontalPixelOffset")) {
                        // } else if (childName.equals("VerticalPixelOffset")) {
                    }
                    child = child.getNextSibling();
                }

                // Use PhysicalPixelSpacing if PixelSize not available.
                if(!(gotWidth || gotHeight) && (gotSpaceX || gotSpaceY)) {
                    width = spaceX;
                    gotWidth = gotSpaceX;
                    height = spaceY;
                    gotHeight = gotSpaceY;
                }

                // Round floating point values to obtain int resolution.
                if (gotWidth && gotHeight) {
                    xPixelsPerMeter = (int)(1000.0/width + 0.5);
                    yPixelsPerMeter = (int)(1000.0/height + 0.5);
                } else if (gotAspectRatio && aspectRatio != 0.0) {
                    if(gotWidth) {
                        xPixelsPerMeter = (int)(1000.0/width + 0.5);
                        yPixelsPerMeter =
                            (int)(aspectRatio*(1000.0/width) + 0.5);
                    } else if(gotHeight) {
                        xPixelsPerMeter =
                            (int)(1000.0/height/aspectRatio + 0.5);
                        yPixelsPerMeter = (int)(1000.0/height + 0.5);
                    }
                }
            } else if (name.equals("Document")) {
                Node child = node.getFirstChild();
                while(child != null) {
                    String childName = child.getNodeName();
                    if (childName.equals("FormatVersion")) {
                        bmpVersion = getAttribute(child, "value");
                        break;
                    }
                    child = child.getNextSibling();
                }
            } else if (name.equals("Text")) {
                Node child = node.getFirstChild();
                while(child != null) {
                    String childName = child.getNodeName();
                    if (childName.equals("TextEntry")) {
                        if(comments == null) {
                            comments = new ArrayList();
                        }
                        comments.add(getAttribute(child, "value"));
                    }
                    child = child.getNextSibling();
                }
            } else if (name.equals("Transparency")) {
                Node child = node.getFirstChild();
                while(child != null) {
                    String childName = child.getNodeName();
                    if (childName.equals("Alpha")) {
                        hasAlpha =
                            !getAttribute(child, "value").equals("none");
                        break;
                    }
                    child = child.getNextSibling();
                }
            } else {
                // XXX Ignore it.
            }
            
            node = node.getNextSibling();
        }

        // Set bitsPerPixel.
        if(bitsPerSample != null) {
            if(palette != null && paletteSize > 0) {
                bitsPerPixel = (short)bitsPerSample[0];
            } else {
                bitsPerPixel = 0;
                for(int i = 0; i < bitsPerSample.length; i++) {
                    bitsPerPixel += bitsPerSample[i];
                }
            }
        } else if(palette != null) {
            bitsPerPixel = 8;
        } else if(numChannels == 1) {
            bitsPerPixel = 8;
        } else if(numChannels == 3) {
            bitsPerPixel = 24;
        } else if(numChannels == 4) {
            bitsPerPixel = 32;
        } else if(colorSpaceType.equals("GRAY")) {
            bitsPerPixel = 8;
        } else if(colorSpaceType.equals("RGB")) {
            bitsPerPixel = (short)(hasAlpha ? 32 : 24);
        }

        // Set RGB masks.
        if((bitsPerSample != null && bitsPerSample.length == 4) ||
           bitsPerPixel >= 24) {
            redMask   = 0x00ff0000;
            greenMask = 0x0000ff00;
            blueMask  = 0x000000ff;
        }

        // Set alpha mask.
        if((bitsPerSample != null && bitsPerSample.length == 4) ||
           bitsPerPixel > 24) {
            alphaMask = 0xff000000;
        }

        // Set palette
        if(r != null && g != null && b != null) {
            boolean isVersion2 =
                bmpVersion != null && bmpVersion.equals(VERSION_2);

            paletteSize = maxIndex + 1;
            palette = new byte[(isVersion2 ? 3 : 4)*paletteSize];
            for(int i = 0, j = 0; i < paletteSize; i++) {
                palette[j++] = b[i];
                palette[j++] = g[i];
                palette[j++] = r[i];
                if(!isVersion2) j++; // skip reserved entry
            }
        }
    }

    public void reset() {
        // Fields for Image Descriptor
        bmpVersion = null;
        width = 0;
        height = 0;
        bitsPerPixel = 0;
        compression = 0;
        imageSize = 0;

        // Fields for PixelsPerMeter
        xPixelsPerMeter = 0;
        yPixelsPerMeter = 0;

        colorsUsed = 0;
        colorsImportant = 0;

        // Fields for BI_BITFIELDS compression(Mask)
        redMask = 0;
        greenMask = 0;
        blueMask = 0;
        alphaMask = 0;

        colorSpace = 0;

        // Fields for CIE XYZ for the LCS_CALIBRATED_RGB color space
        redX = 0;
        redY = 0;
        redZ = 0;
        greenX = 0;
        greenY = 0;
        greenZ = 0;
        blueX = 0;
        blueY = 0;
        blueZ = 0;

        // Fields for Gamma values for the LCS_CALIBRATED_RGB color space
        gammaRed = 0;
        gammaGreen = 0;
        gammaBlue = 0;

        intent = 0;

        // Fields for the Palette and Entries
        palette = null;
        paletteSize = 0;
        red = 0;
        green = 0;
        blue = 0;

        // Fields from CommentExtension
        comments = null;
    }

    private String countBits(int num) {
        int count = 0;
        while(num != 0) {
            if ((num & 1) == 1)
                count++;
            num >>>= 1;
        }

        return count == 0 ? "0" : "" + count;
    }

    private void addXYZPoints(IIOMetadataNode root, String name, double x, double y, double z) {
        IIOMetadataNode node = addChildNode(root, name, null);
        addChildNode(node, "X", new Double(x));
        addChildNode(node, "Y", new Double(y));
        addChildNode(node, "Z", new Double(z));
    }

    private IIOMetadataNode addChildNode(IIOMetadataNode root,
                                         String name,
                                         Object object) {
        IIOMetadataNode child = new IIOMetadataNode(name);
        if (object != null) {
            child.setUserObject(object);
	    child.setNodeValue(ImageUtil.convertObjectToString(object));
	}
        root.appendChild(child);
        return child;
    }

    private Object getObjectValue(Node node) {
        Object tmp = node.getNodeValue();

        if(tmp == null && node instanceof IIOMetadataNode) {
            tmp = ((IIOMetadataNode)node).getUserObject();
        }

        return tmp;
    }

    private String getStringValue(Node node) {
        Object tmp = getObjectValue(node);
        return tmp instanceof String ? (String)tmp : null;
    }

    private Byte getByteValue(Node node) {
        Object tmp = getObjectValue(node);
        Byte value = null;
        if(tmp instanceof String) {
            value = Byte.valueOf((String)tmp);
        } else if(tmp instanceof Byte) {
            value = (Byte)tmp;
        }
        return value;
    }

    private Short getShortValue(Node node) {
        Object tmp = getObjectValue(node);
        Short value = null;
        if(tmp instanceof String) {
            value = Short.valueOf((String)tmp);
        } else if(tmp instanceof Short) {
            value = (Short)tmp;
        }
        return value;
    }

    private Integer getIntegerValue(Node node) {
        Object tmp = getObjectValue(node);
        Integer value = null;
        if(tmp instanceof String) {
            value = Integer.valueOf((String)tmp);
        } else if(tmp instanceof Integer) {
            value = (Integer)tmp;
        } else if(tmp instanceof Byte) {
            value = new Integer(((Byte)tmp).byteValue() & 0xff);
        }
        return value;
    }

    private Double getDoubleValue(Node node) {
        Object tmp = getObjectValue(node);
        Double value = null;
        if(tmp instanceof String) {
            value = Double.valueOf((String)tmp);
        } else if(tmp instanceof Double) {
            value = (Double)tmp;
        }
        return value;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy