1. /*
  2. * @(#)BMPMetadata.java 1.3 04/03/19 12:28:41
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.imageio.plugins.bmp;
  8. import java.io.UnsupportedEncodingException;
  9. import java.util.ArrayList;
  10. import java.util.Iterator;
  11. import java.util.List;
  12. import javax.imageio.ImageTypeSpecifier;
  13. import javax.imageio.metadata.IIOMetadata;
  14. import javax.imageio.metadata.IIOMetadataNode;
  15. import javax.imageio.metadata.IIOMetadataFormat;
  16. import javax.imageio.metadata.IIOMetadataFormatImpl;
  17. import org.w3c.dom.Node;
  18. import com.sun.imageio.plugins.common.I18N;
  19. import com.sun.imageio.plugins.common.ImageUtil;
  20. public class BMPMetadata extends IIOMetadata implements BMPConstants {
  21. public static final String nativeMetadataFormatName =
  22. "javax_imageio_bmp_1.0";
  23. // Fields for Image Descriptor
  24. public String bmpVersion;
  25. public int width ;
  26. public int height;
  27. public short bitsPerPixel;
  28. public int compression;
  29. public int imageSize;
  30. // Fields for PixelsPerMeter
  31. public int xPixelsPerMeter;
  32. public int yPixelsPerMeter;
  33. public int colorsUsed;
  34. public int colorsImportant;
  35. // Fields for BI_BITFIELDS compression(Mask)
  36. public int redMask;
  37. public int greenMask;
  38. public int blueMask;
  39. public int alphaMask;
  40. public int colorSpace;
  41. // Fields for CIE XYZ for the LCS_CALIBRATED_RGB color space
  42. public double redX;
  43. public double redY;
  44. public double redZ;
  45. public double greenX;
  46. public double greenY;
  47. public double greenZ;
  48. public double blueX;
  49. public double blueY;
  50. public double blueZ;
  51. // Fields for Gamma values for the LCS_CALIBRATED_RGB color space
  52. public int gammaRed;
  53. public int gammaGreen;
  54. public int gammaBlue;
  55. public int intent;
  56. // Fields for the Palette and Entries
  57. public byte[] palette = null;
  58. public int paletteSize;
  59. public int red;
  60. public int green;
  61. public int blue;
  62. // Fields from CommentExtension
  63. // List of byte[]
  64. public List comments = null; // new ArrayList();
  65. public BMPMetadata() {
  66. super(true,
  67. nativeMetadataFormatName,
  68. "com.sun.imageio.plugins.bmp.BMPMetadataFormat",
  69. null, null);
  70. }
  71. public boolean isReadOnly() {
  72. return true;
  73. }
  74. public Node getAsTree(String formatName) {
  75. if (formatName.equals(nativeMetadataFormatName)) {
  76. return getNativeTree();
  77. } else if (formatName.equals
  78. (IIOMetadataFormatImpl.standardMetadataFormatName)) {
  79. return getStandardTree();
  80. } else {
  81. throw new IllegalArgumentException(I18N.getString("BMPMetadata0"));
  82. }
  83. }
  84. private String toISO8859(byte[] data) {
  85. try {
  86. return new String(data, "ISO-8859-1");
  87. } catch (UnsupportedEncodingException e) {
  88. return "";
  89. }
  90. }
  91. private Node getNativeTree() {
  92. IIOMetadataNode root =
  93. new IIOMetadataNode(nativeMetadataFormatName);
  94. addChildNode(root, "BMPVersion", bmpVersion);
  95. addChildNode(root, "Width", new Integer(width));
  96. addChildNode(root, "Height", new Integer(height));
  97. addChildNode(root, "BitsPerPixel", new Short(bitsPerPixel));
  98. addChildNode(root, "Compression", new Integer(compression));
  99. addChildNode(root, "ImageSize", new Integer(imageSize));
  100. IIOMetadataNode node = addChildNode(root, "PixelsPerMeter", null);
  101. addChildNode(node, "X", new Integer(xPixelsPerMeter));
  102. addChildNode(node, "Y", new Integer(yPixelsPerMeter));
  103. addChildNode(root, "ColorsUsed", new Integer(colorsUsed));
  104. addChildNode(root, "ColorsImportant", new Integer(colorsImportant));
  105. int version = 0;
  106. for (int i = 0; i < bmpVersion.length(); i++)
  107. if (Character.isDigit(bmpVersion.charAt(i)))
  108. version = bmpVersion.charAt(i) -'0';
  109. if (version >= 4) {
  110. node = addChildNode(root, "Mask", null);
  111. addChildNode(node, "Red", new Integer(redMask));
  112. addChildNode(node, "Green", new Integer(greenMask));
  113. addChildNode(node, "Blue", new Integer(blueMask));
  114. addChildNode(node, "Alpha", new Integer(alphaMask));
  115. addChildNode(root, "ColorSpaceType", new Integer(colorSpace));
  116. node = addChildNode(root, "CIEXYZEndPoints", null);
  117. addXYZPoints(node, "Red", redX, redY, redZ);
  118. addXYZPoints(node, "Green", greenX, greenY, greenZ);
  119. addXYZPoints(node, "Blue", blueX, blueY, blueZ);
  120. node = addChildNode(root, "Intent", new Integer(intent));
  121. }
  122. // Palette
  123. if ((palette != null) && (paletteSize > 0)) {
  124. node = addChildNode(root, "Palette", null);
  125. int numComps = palette.length / paletteSize;
  126. for (int i = 0, j = 0; i < paletteSize; i++) {
  127. IIOMetadataNode entry =
  128. addChildNode(node, "PaletteEntry", null);
  129. red = palette[j++] & 0xff;
  130. green = palette[j++] & 0xff;
  131. blue = palette[j++] & 0xff;
  132. addChildNode(entry, "Red", new Byte((byte)red));
  133. addChildNode(entry, "Green", new Byte((byte)green));
  134. addChildNode(entry, "Blue", new Byte((byte)blue));
  135. if (numComps == 4)
  136. addChildNode(entry, "Alpha",
  137. new Byte((byte)(palette[j++] & 0xff)));
  138. }
  139. }
  140. return root;
  141. }
  142. // Standard tree node methods
  143. protected IIOMetadataNode getStandardChromaNode() {
  144. if ((palette != null) && (paletteSize > 0)) {
  145. IIOMetadataNode node = new IIOMetadataNode("Chroma");
  146. IIOMetadataNode subNode = new IIOMetadataNode("Palette");
  147. int numComps = palette.length / paletteSize;
  148. subNode.setAttribute("value", "" + numComps);
  149. for (int i = 0, j = 0; i < paletteSize; i++) {
  150. IIOMetadataNode subNode1 = new IIOMetadataNode("PaletteEntry");
  151. subNode1.setAttribute("index", ""+i);
  152. subNode1.setAttribute("red", "" + palette[j++]);
  153. subNode1.setAttribute("green", "" + palette[j++]);
  154. subNode1.setAttribute("blue", "" + palette[j++]);
  155. if (numComps == 4 && palette[j] != 0)
  156. subNode1.setAttribute("alpha", "" + palette[j++]);
  157. subNode.appendChild(subNode1);
  158. }
  159. node.appendChild(subNode);
  160. return node;
  161. }
  162. return null;
  163. }
  164. protected IIOMetadataNode getStandardCompressionNode() {
  165. IIOMetadataNode node = new IIOMetadataNode("Compression");
  166. // CompressionTypeName
  167. IIOMetadataNode subNode = new IIOMetadataNode("CompressionTypeName");
  168. subNode.setAttribute("value", compressionTypeNames[compression]);
  169. node.appendChild(subNode);
  170. return node;
  171. }
  172. protected IIOMetadataNode getStandardDataNode() {
  173. IIOMetadataNode node = new IIOMetadataNode("Data");
  174. String bits = "";
  175. if (bitsPerPixel == 24)
  176. bits = "8 8 8 ";
  177. else if (bitsPerPixel == 16 || bitsPerPixel == 32) {
  178. bits = "" + countBits(redMask) + " " + countBits(greenMask) +
  179. countBits(blueMask) + "" + countBits(alphaMask);
  180. }
  181. IIOMetadataNode subNode = new IIOMetadataNode("BitsPerSample");
  182. subNode.setAttribute("value", bits);
  183. node.appendChild(subNode);
  184. return node;
  185. }
  186. protected IIOMetadataNode getStandardDimensionNode() {
  187. if (yPixelsPerMeter > 0.0F && xPixelsPerMeter > 0.0F) {
  188. IIOMetadataNode node = new IIOMetadataNode("Dimension");
  189. float ratio = yPixelsPerMeter / xPixelsPerMeter;
  190. IIOMetadataNode subNode = new IIOMetadataNode("PixelAspectRatio");
  191. subNode.setAttribute("value", "" + ratio);
  192. node.appendChild(subNode);
  193. subNode = new IIOMetadataNode("HorizontalPhysicalPixelSpacing");
  194. subNode.setAttribute("value", "" + (1 / xPixelsPerMeter * 1000));
  195. node.appendChild(subNode);
  196. subNode = new IIOMetadataNode("VerticalPhysicalPixelSpacing");
  197. subNode.setAttribute("value", "" + (1 / yPixelsPerMeter * 1000));
  198. node.appendChild(subNode);
  199. return node;
  200. }
  201. return null;
  202. }
  203. public void setFromTree(String formatName, Node root) {
  204. throw new IllegalStateException(I18N.getString("BMPMetadata1"));
  205. }
  206. public void mergeTree(String formatName, Node root) {
  207. throw new IllegalStateException(I18N.getString("BMPMetadata1"));
  208. }
  209. public void reset() {
  210. throw new IllegalStateException(I18N.getString("BMPMetadata1"));
  211. }
  212. private String countBits(int num) {
  213. int count = 0;
  214. while(num > 0) {
  215. if ((num & 1) == 1)
  216. count++;
  217. num >>>= 1;
  218. }
  219. return count == 0 ? "" : "" + count;
  220. }
  221. private void addXYZPoints(IIOMetadataNode root, String name, double x, double y, double z) {
  222. IIOMetadataNode node = addChildNode(root, name, null);
  223. addChildNode(node, "X", new Double(x));
  224. addChildNode(node, "Y", new Double(y));
  225. addChildNode(node, "Z", new Double(z));
  226. }
  227. private IIOMetadataNode addChildNode(IIOMetadataNode root,
  228. String name,
  229. Object object) {
  230. IIOMetadataNode child = new IIOMetadataNode(name);
  231. if (object != null) {
  232. child.setUserObject(object);
  233. child.setNodeValue(ImageUtil.convertObjectToString(object));
  234. }
  235. root.appendChild(child);
  236. return child;
  237. }
  238. }