001/* 002 * $RCSfile: GIFStreamMetadata.java,v $ 003 * 004 * 005 * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without 008 * modification, are permitted provided that the following conditions 009 * are met: 010 * 011 * - Redistribution of source code must retain the above copyright 012 * notice, this list of conditions and the following disclaimer. 013 * 014 * - Redistribution in binary form must reproduce the above copyright 015 * notice, this list of conditions and the following disclaimer in 016 * the documentation and/or other materials provided with the 017 * distribution. 018 * 019 * Neither the name of Sun Microsystems, Inc. or the names of 020 * contributors may be used to endorse or promote products derived 021 * from this software without specific prior written permission. 022 * 023 * This software is provided "AS IS," without a warranty of any 024 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 025 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 026 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY 027 * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 028 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 029 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS 030 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 031 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, 032 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND 033 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR 034 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE 035 * POSSIBILITY OF SUCH DAMAGES. 036 * 037 * You acknowledge that this software is not designed or intended for 038 * use in the design, construction, operation or maintenance of any 039 * nuclear facility. 040 * 041 * $Revision: 1.1 $ 042 * $Date: 2006/03/24 22:30:10 $ 043 * $State: Exp $ 044 */ 045 046package com.github.jaiimageio.impl.plugins.gif; 047 048import javax.imageio.ImageTypeSpecifier; 049import javax.imageio.metadata.IIOInvalidTreeException; 050import javax.imageio.metadata.IIOMetadata; 051import javax.imageio.metadata.IIOMetadataNode; 052import javax.imageio.metadata.IIOMetadataFormat; 053import javax.imageio.metadata.IIOMetadataFormatImpl; 054import org.w3c.dom.Node; 055 056// TODO - document elimination of globalColorTableFlag 057 058/** 059 * @version 0.5 060 */ 061public class GIFStreamMetadata extends GIFMetadata { 062 063 // package scope 064 static final String 065 nativeMetadataFormatName = "javax_imageio_gif_stream_1.0"; 066 067 public static final String[] versionStrings = { "87a", "89a" }; 068 069 public String version; // 87a or 89a 070 public int logicalScreenWidth; 071 public int logicalScreenHeight; 072 public int colorResolution; // 1 to 8 073 public int pixelAspectRatio; 074 075 public int backgroundColorIndex; // Valid if globalColorTable != null 076 public boolean sortFlag; // Valid if globalColorTable != null 077 078 public static final String[] colorTableSizes = { 079 "2", "4", "8", "16", "32", "64", "128", "256" 080 }; 081 082 // Set global color table flag in header to 0 if null, 1 otherwise 083 public byte[] globalColorTable = null; 084 085 protected GIFStreamMetadata(boolean standardMetadataFormatSupported, 086 String nativeMetadataFormatName, 087 String nativeMetadataFormatClassName, 088 String[] extraMetadataFormatNames, 089 String[] extraMetadataFormatClassNames) 090 { 091 super(standardMetadataFormatSupported, 092 nativeMetadataFormatName, 093 nativeMetadataFormatClassName, 094 extraMetadataFormatNames, 095 extraMetadataFormatClassNames); 096 } 097 098 public GIFStreamMetadata() { 099 this(true, 100 nativeMetadataFormatName, 101 "com.github.jaiimageio.impl.plugins.gif.GIFStreamMetadataFormat", 102 null, null); 103 104 } 105 106 public boolean isReadOnly() { 107 return true; 108 } 109 110 public Node getAsTree(String formatName) { 111 if (formatName.equals(nativeMetadataFormatName)) { 112 return getNativeTree(); 113 } else if (formatName.equals 114 (IIOMetadataFormatImpl.standardMetadataFormatName)) { 115 return getStandardTree(); 116 } else { 117 throw new IllegalArgumentException("Not a recognized format!"); 118 } 119 } 120 121 private Node getNativeTree() { 122 IIOMetadataNode node; // scratch node 123 IIOMetadataNode root = 124 new IIOMetadataNode(nativeMetadataFormatName); 125 126 node = new IIOMetadataNode("Version"); 127 node.setAttribute("value", version); 128 root.appendChild(node); 129 130 // Image descriptor 131 node = new IIOMetadataNode("LogicalScreenDescriptor"); 132 /* NB: At the moment we use empty strings to support undefined 133 * integer values in tree representation. 134 * We need to add better support for undefined/default values later. 135 */ 136 node.setAttribute("logicalScreenWidth", 137 logicalScreenWidth == UNDEFINED_INTEGER_VALUE ? 138 "" : Integer.toString(logicalScreenWidth)); 139 node.setAttribute("logicalScreenHeight", 140 logicalScreenHeight == UNDEFINED_INTEGER_VALUE ? 141 "" : Integer.toString(logicalScreenHeight)); 142 // Stored value plus one 143 node.setAttribute("colorResolution", 144 colorResolution == UNDEFINED_INTEGER_VALUE ? 145 "" : Integer.toString(colorResolution)); 146 node.setAttribute("pixelAspectRatio", 147 Integer.toString(pixelAspectRatio)); 148 root.appendChild(node); 149 150 if (globalColorTable != null) { 151 node = new IIOMetadataNode("GlobalColorTable"); 152 int numEntries = globalColorTable.length/3; 153 node.setAttribute("sizeOfGlobalColorTable", 154 Integer.toString(numEntries)); 155 node.setAttribute("backgroundColorIndex", 156 Integer.toString(backgroundColorIndex)); 157 node.setAttribute("sortFlag", 158 sortFlag ? "TRUE" : "FALSE"); 159 160 for (int i = 0; i < numEntries; i++) { 161 IIOMetadataNode entry = 162 new IIOMetadataNode("ColorTableEntry"); 163 entry.setAttribute("index", Integer.toString(i)); 164 int r = globalColorTable[3*i] & 0xff; 165 int g = globalColorTable[3*i + 1] & 0xff; 166 int b = globalColorTable[3*i + 2] & 0xff; 167 entry.setAttribute("red", Integer.toString(r)); 168 entry.setAttribute("green", Integer.toString(g)); 169 entry.setAttribute("blue", Integer.toString(b)); 170 node.appendChild(entry); 171 } 172 root.appendChild(node); 173 } 174 175 return root; 176 } 177 178 public IIOMetadataNode getStandardChromaNode() { 179 IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); 180 IIOMetadataNode node = null; // scratch node 181 182 node = new IIOMetadataNode("ColorSpaceType"); 183 node.setAttribute("name", "RGB"); 184 chroma_node.appendChild(node); 185 186 node = new IIOMetadataNode("BlackIsZero"); 187 node.setAttribute("value", "TRUE"); 188 chroma_node.appendChild(node); 189 190 // NumChannels not in stream 191 // Gamma not in format 192 193 if (globalColorTable != null) { 194 node = new IIOMetadataNode("Palette"); 195 int numEntries = globalColorTable.length/3; 196 for (int i = 0; i < numEntries; i++) { 197 IIOMetadataNode entry = 198 new IIOMetadataNode("PaletteEntry"); 199 entry.setAttribute("index", Integer.toString(i)); 200 entry.setAttribute("red", 201 Integer.toString(globalColorTable[3*i] & 0xff)); 202 entry.setAttribute("green", 203 Integer.toString(globalColorTable[3*i + 1] & 0xff)); 204 entry.setAttribute("blue", 205 Integer.toString(globalColorTable[3*i + 2] & 0xff)); 206 node.appendChild(entry); 207 } 208 chroma_node.appendChild(node); 209 210 // backgroundColorIndex is valid iff there is a color table 211 node = new IIOMetadataNode("BackgroundIndex"); 212 node.setAttribute("value", Integer.toString(backgroundColorIndex)); 213 chroma_node.appendChild(node); 214 } 215 216 return chroma_node; 217 } 218 219 public IIOMetadataNode getStandardCompressionNode() { 220 IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); 221 IIOMetadataNode node = null; // scratch node 222 223 node = new IIOMetadataNode("CompressionTypeName"); 224 node.setAttribute("value", "lzw"); 225 compression_node.appendChild(node); 226 227 node = new IIOMetadataNode("Lossless"); 228 node.setAttribute("value", "true"); 229 compression_node.appendChild(node); 230 231 // NumProgressiveScans not in stream 232 // BitRate not in format 233 234 return compression_node; 235 } 236 237 public IIOMetadataNode getStandardDataNode() { 238 IIOMetadataNode data_node = new IIOMetadataNode("Data"); 239 IIOMetadataNode node = null; // scratch node 240 241 // PlanarConfiguration 242 243 node = new IIOMetadataNode("SampleFormat"); 244 node.setAttribute("value", "Index"); 245 data_node.appendChild(node); 246 247 node = new IIOMetadataNode("BitsPerSample"); 248 node.setAttribute("value", 249 colorResolution == UNDEFINED_INTEGER_VALUE ? 250 "" : Integer.toString(colorResolution)); 251 data_node.appendChild(node); 252 253 // SignificantBitsPerSample 254 // SampleMSB 255 256 return data_node; 257 } 258 259 public IIOMetadataNode getStandardDimensionNode() { 260 IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); 261 IIOMetadataNode node = null; // scratch node 262 263 node = new IIOMetadataNode("PixelAspectRatio"); 264 float aspectRatio = 1.0F; 265 if (pixelAspectRatio != 0) { 266 aspectRatio = (pixelAspectRatio + 15)/64.0F; 267 } 268 node.setAttribute("value", Float.toString(aspectRatio)); 269 dimension_node.appendChild(node); 270 271 node = new IIOMetadataNode("ImageOrientation"); 272 node.setAttribute("value", "Normal"); 273 dimension_node.appendChild(node); 274 275 // HorizontalPixelSize not in format 276 // VerticalPixelSize not in format 277 // HorizontalPhysicalPixelSpacing not in format 278 // VerticalPhysicalPixelSpacing not in format 279 // HorizontalPosition not in format 280 // VerticalPosition not in format 281 // HorizontalPixelOffset not in stream 282 // VerticalPixelOffset not in stream 283 284 node = new IIOMetadataNode("HorizontalScreenSize"); 285 node.setAttribute("value", 286 logicalScreenWidth == UNDEFINED_INTEGER_VALUE ? 287 "" : Integer.toString(logicalScreenWidth)); 288 dimension_node.appendChild(node); 289 290 node = new IIOMetadataNode("VerticalScreenSize"); 291 node.setAttribute("value", 292 logicalScreenHeight == UNDEFINED_INTEGER_VALUE ? 293 "" : Integer.toString(logicalScreenHeight)); 294 dimension_node.appendChild(node); 295 296 return dimension_node; 297 } 298 299 public IIOMetadataNode getStandardDocumentNode() { 300 IIOMetadataNode document_node = new IIOMetadataNode("Document"); 301 IIOMetadataNode node = null; // scratch node 302 303 node = new IIOMetadataNode("FormatVersion"); 304 node.setAttribute("value", version); 305 document_node.appendChild(node); 306 307 // SubimageInterpretation not in format 308 // ImageCreationTime not in format 309 // ImageModificationTime not in format 310 311 return document_node; 312 } 313 314 public IIOMetadataNode getStandardTextNode() { 315 // Not in stream 316 return null; 317 } 318 319 public IIOMetadataNode getStandardTransparencyNode() { 320 // Not in stream 321 return null; 322 } 323 324 public void setFromTree(String formatName, Node root) 325 throws IIOInvalidTreeException 326 { 327 throw new IllegalStateException("Metadata is read-only!"); 328 } 329 330 protected void mergeNativeTree(Node root) throws IIOInvalidTreeException 331 { 332 throw new IllegalStateException("Metadata is read-only!"); 333 } 334 335 protected void mergeStandardTree(Node root) throws IIOInvalidTreeException 336 { 337 throw new IllegalStateException("Metadata is read-only!"); 338 } 339 340 public void reset() { 341 throw new IllegalStateException("Metadata is read-only!"); 342 } 343}