package uk.co.mmscomputing.imageio.bmp;
import java.awt.image.*;
import org.w3c.dom.Node;
import javax.imageio.metadata.*;
// This is imitating Sun's BMPMetadata class which is available from jvm 1.5
// according to the "BMP Metadata Format Specification"
public class BMPMetadata extends IIOMetadata implements BMPConstants{
private static final String formatName="javax_imageio_bmp_1.0";
private int width,height,bitsPerPixel,compression,imageSize;
private int xPixelsPerMeter,yPixelsPerMeter,colorsUsed,colorsImportant;
private int redMask,greenMask,blueMask;
private IndexColorModel icm;
public BMPMetadata(){
super(true,formatName,"uk.co.mmscomputing.imageio.bmp.BMPMetadata",null,null);
xPixelsPerMeter = 2953; // 75 dpi
yPixelsPerMeter = 2953; // 75 dpi
}
public void setWidth(int w){width=w;}
public void setHeight(int h){height=h;}
public void setBitsPerPixel(int v){bitsPerPixel=v;}
public void setCompression(int v){compression=v;}
public void setImageSize(int v){imageSize=v;}
public void setXPixelsPerMeter(int v){xPixelsPerMeter=v;}
public void setYPixelsPerMeter(int v){yPixelsPerMeter=v;}
// There are (1000/25.4) in/m = 39.370079 in/m, so, dpi * 39.370079 = dots/meter (PelsPerMeter).
public void setXDotsPerInch(int v){xPixelsPerMeter=(int)Math.round(((double)v)*1000.0/25.4);}
public void setYDotsPerInch(int v){yPixelsPerMeter=(int)Math.round(((double)v)*1000.0/25.4);}
public void setColorsUsed(int v){colorsUsed=v;}
public void setColorsImportant(int v){colorsImportant=v;}
public void setRedMask(int v){redMask=v;}
public void setGreenMask(int v){greenMask=v;}
public void setBlueMask(int v){blueMask=v;}
public void setIndexColorModel(IndexColorModel icm){
if(icm!=null){colorsUsed=icm.getMapSize();}
this.icm=icm;
}
public int getXPixelsPerMeter(){return xPixelsPerMeter;}
public int getYPixelsPerMeter(){return yPixelsPerMeter;}
public int getXDotsPerInch(){return (int)Math.round(((double)xPixelsPerMeter)*25.4/1000.0);}
public int getYDotsPerInch(){return (int)Math.round(((double)yPixelsPerMeter)*25.4/1000.0);}
public IndexColorModel getIndexColorModel(){return icm;}
public boolean isReadOnly(){ return false;}
public Node getAsTree(String fn){
if(fn.equals(formatName)){
return getNativeTree();
}else if(fn.equals(IIOMetadataFormatImpl.standardMetadataFormatName)){
return getStandardTree();
}
throw new IllegalArgumentException(getClass().getName()+".mergeTree:\n\tUnknown format: "+fn);
}
public void mergeTree(String formatName,Node root){
throw new IllegalStateException(getClass().getName()+".mergeTree:\n\tFunction not supported.");
}
public void reset(){
throw new IllegalStateException(getClass().getName()+".reset:\n\tFunction not supported.");
}
private Node getNativeTree(){
IIOMetadataNode root=new IIOMetadataNode(formatName);
addChildNode(root,"BMPVersion","BMP v. 3.x");
addChildNode(root,"Width",new Integer(width));
addChildNode(root,"Height",new Integer(height));
addChildNode(root,"BitsPerPixel",new Integer(bitsPerPixel));
addChildNode(root,"Compression",new Integer(compression));
addChildNode(root,"ImageSize",new Integer(imageSize));
IIOMetadataNode 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));
if(icm!=null){
node=addChildNode(root,"Palette",null);
for(int i=0;i<colorsUsed;i++){
IIOMetadataNode entry=addChildNode(node,"PaletteEntry",null);
addChildNode(entry,"Red",new Byte((byte)icm.getRed(i)));
addChildNode(entry,"Green",new Byte((byte)icm.getGreen(i)));
addChildNode(entry,"Blue",new Byte((byte)icm.getBlue(i)));
}
}
return root;
}
protected IIOMetadataNode getStandardChromaNode(){
IIOMetadataNode node=new IIOMetadataNode("Chroma");
if(icm!=null){
IIOMetadataNode subnode=new IIOMetadataNode("Palette");
node.appendChild(subnode);
for(int i=0;i<colorsUsed;i++){
IIOMetadataNode entry=new IIOMetadataNode("PaletteEntry");
subnode.appendChild(entry);
entry.setAttribute("index",""+i);
entry.setAttribute("red",""+icm.getRed(i));
entry.setAttribute("green",""+icm.getGreen(i));
entry.setAttribute("blue",""+icm.getBlue(i));
entry.setAttribute("alpha","255");
}
}
return node;
}
protected IIOMetadataNode getStandardCompressionNode(){
IIOMetadataNode node=new IIOMetadataNode("Compression");
IIOMetadataNode subnode=new IIOMetadataNode("CompressionTypeName");
subnode.setAttribute("value",compressionTypeNames[compression]);
node.appendChild(subnode);
return node;
}
private String countBits(int mask){ // masks: i.e. 0x00FF0000, 0x0000FF00, 0x000003E0, 0x0000001F
int c=0; // counter consecutive bits
while(mask>0){
if((mask&0x01)==0x01){c++;}
mask>>>=1;
}
return (c==0)?"":""+c;
}
protected IIOMetadataNode getStandardDataNode(){
IIOMetadataNode node=new IIOMetadataNode("Data");
String bits = "";
if(bitsPerPixel == 24){
bits = "8 8 8";
}else if((bitsPerPixel == 16)||(bitsPerPixel == 32)){
bits += countBits(redMask)+" "+countBits(greenMask)+" "+countBits(blueMask);
}else if(bitsPerPixel <= 8){
bits += bitsPerPixel;
}
IIOMetadataNode subnode=new IIOMetadataNode("BitsPerSample");
subnode.setAttribute("value",bits);
node.appendChild(subnode);
return node;
}
protected IIOMetadataNode getStandardDimensionNode(){
if((yPixelsPerMeter>0.0)&&(xPixelsPerMeter>0.0)){
IIOMetadataNode node=new IIOMetadataNode("Dimension");
double value=yPixelsPerMeter/xPixelsPerMeter;
IIOMetadataNode subnode=new IIOMetadataNode("PixelAspectRatio");
subnode.setAttribute("value",""+value);
node.appendChild(subnode);
value=1000.0/xPixelsPerMeter; // need pixels per millimeter
subnode=new IIOMetadataNode("HorizontalPhysicalPixelSpacing");
subnode.setAttribute("value",""+value);
node.appendChild(subnode);
value=1000.0/yPixelsPerMeter; // need pixels per millimeter
subnode=new IIOMetadataNode("VerticalPhysicalPixelSpacing");
subnode.setAttribute("value",""+value);
node.appendChild(subnode);
return node;
}
return null;
}
private String objectToString(Object obj){
return obj.toString();
}
private IIOMetadataNode addChildNode(IIOMetadataNode root,String name,Object object){
IIOMetadataNode child=new IIOMetadataNode(name);
if(object!=null){
child.setUserObject(object);
child.setNodeValue(objectToString(object));
}
root.appendChild(child);
return child;
}
}
/*
<javax_imageio_1.0>
<Compression>
<CompressionTypeName value="BI_RGB"></CompressionTypeName>
</Compression>
<Data>
<BitsPerSample value="8 8 8 "></BitsPerSample>
</Data>
<Dimension>
<PixelAspectRatio value="1.0"></PixelAspectRatio>
<HorizontalPhysicalPixelSpacing value="0"></HorizontalPhysicalPixelSpacing>
<VerticalPhysicalPixelSpacing value="0"></VerticalPhysicalPixelSpacing>
</Dimension>
</javax_imageio_1.0>
<javax_imageio_bmp_1.0>
<BMPVersion>BMP v. 3.x</BMPVersion>
<Width>1700</Width>
<Height>2338</Height>
<BitsPerPixel>24</BitsPerPixel>
<Compression>0</Compression>
<ImageSize>0</ImageSize>
<PixelsPerMeter>
<X>2834</X>
<Y>2834</Y>
</PixelsPerMeter>
<ColorsUsed>0</ColorsUsed>
<ColorsImportant>0</ColorsImportant>
</javax_imageio_bmp_1.0>
*/