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.metadata.IIOInvalidTreeException; 049import javax.imageio.metadata.IIOMetadataFormatImpl; 050import javax.imageio.metadata.IIOMetadataNode; 051 052import org.w3c.dom.Node; 053 054// TODO - document elimination of globalColorTableFlag 055 056/** 057 * @version 0.5 058 */ 059public class GIFStreamMetadata extends GIFMetadata { 060 061 // package scope 062 static final String 063 nativeMetadataFormatName = "javax_imageio_gif_stream_1.0"; 064 065 public static final String[] versionStrings = { "87a", "89a" }; 066 067 public String version; // 87a or 89a 068 public int logicalScreenWidth; 069 public int logicalScreenHeight; 070 public int colorResolution; // 1 to 8 071 public int pixelAspectRatio; 072 073 public int backgroundColorIndex; // Valid if globalColorTable != null 074 public boolean sortFlag; // Valid if globalColorTable != null 075 076 public static final String[] colorTableSizes = { 077 "2", "4", "8", "16", "32", "64", "128", "256" 078 }; 079 080 // Set global color table flag in header to 0 if null, 1 otherwise 081 public byte[] globalColorTable = null; 082 083 protected GIFStreamMetadata(boolean standardMetadataFormatSupported, 084 String nativeMetadataFormatName, 085 String nativeMetadataFormatClassName, 086 String[] extraMetadataFormatNames, 087 String[] extraMetadataFormatClassNames) 088 { 089 super(standardMetadataFormatSupported, 090 nativeMetadataFormatName, 091 nativeMetadataFormatClassName, 092 extraMetadataFormatNames, 093 extraMetadataFormatClassNames); 094 } 095 096 public GIFStreamMetadata() { 097 this(true, 098 nativeMetadataFormatName, 099 "com.github.jaiimageio.impl.plugins.gif.GIFStreamMetadataFormat", 100 null, null); 101 102 } 103 104 public boolean isReadOnly() { 105 return true; 106 } 107 108 public Node getAsTree(String formatName) { 109 if (formatName.equals(nativeMetadataFormatName)) { 110 return getNativeTree(); 111 } else if (formatName.equals 112 (IIOMetadataFormatImpl.standardMetadataFormatName)) { 113 return getStandardTree(); 114 } else { 115 throw new IllegalArgumentException("Not a recognized format!"); 116 } 117 } 118 119 private Node getNativeTree() { 120 IIOMetadataNode node; // scratch node 121 IIOMetadataNode root = 122 new IIOMetadataNode(nativeMetadataFormatName); 123 124 node = new IIOMetadataNode("Version"); 125 node.setAttribute("value", version); 126 root.appendChild(node); 127 128 // Image descriptor 129 node = new IIOMetadataNode("LogicalScreenDescriptor"); 130 /* NB: At the moment we use empty strings to support undefined 131 * integer values in tree representation. 132 * We need to add better support for undefined/default values later. 133 */ 134 node.setAttribute("logicalScreenWidth", 135 logicalScreenWidth == UNDEFINED_INTEGER_VALUE ? 136 "" : Integer.toString(logicalScreenWidth)); 137 node.setAttribute("logicalScreenHeight", 138 logicalScreenHeight == UNDEFINED_INTEGER_VALUE ? 139 "" : Integer.toString(logicalScreenHeight)); 140 // Stored value plus one 141 node.setAttribute("colorResolution", 142 colorResolution == UNDEFINED_INTEGER_VALUE ? 143 "" : Integer.toString(colorResolution)); 144 node.setAttribute("pixelAspectRatio", 145 Integer.toString(pixelAspectRatio)); 146 root.appendChild(node); 147 148 if (globalColorTable != null) { 149 node = new IIOMetadataNode("GlobalColorTable"); 150 int numEntries = globalColorTable.length/3; 151 node.setAttribute("sizeOfGlobalColorTable", 152 Integer.toString(numEntries)); 153 node.setAttribute("backgroundColorIndex", 154 Integer.toString(backgroundColorIndex)); 155 node.setAttribute("sortFlag", 156 sortFlag ? "TRUE" : "FALSE"); 157 158 for (int i = 0; i < numEntries; i++) { 159 IIOMetadataNode entry = 160 new IIOMetadataNode("ColorTableEntry"); 161 entry.setAttribute("index", Integer.toString(i)); 162 int r = globalColorTable[3*i] & 0xff; 163 int g = globalColorTable[3*i + 1] & 0xff; 164 int b = globalColorTable[3*i + 2] & 0xff; 165 entry.setAttribute("red", Integer.toString(r)); 166 entry.setAttribute("green", Integer.toString(g)); 167 entry.setAttribute("blue", Integer.toString(b)); 168 node.appendChild(entry); 169 } 170 root.appendChild(node); 171 } 172 173 return root; 174 } 175 176 public IIOMetadataNode getStandardChromaNode() { 177 IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); 178 IIOMetadataNode node = null; // scratch node 179 180 node = new IIOMetadataNode("ColorSpaceType"); 181 node.setAttribute("name", "RGB"); 182 chroma_node.appendChild(node); 183 184 node = new IIOMetadataNode("BlackIsZero"); 185 node.setAttribute("value", "TRUE"); 186 chroma_node.appendChild(node); 187 188 // NumChannels not in stream 189 // Gamma not in format 190 191 if (globalColorTable != null) { 192 node = new IIOMetadataNode("Palette"); 193 int numEntries = globalColorTable.length/3; 194 for (int i = 0; i < numEntries; i++) { 195 IIOMetadataNode entry = 196 new IIOMetadataNode("PaletteEntry"); 197 entry.setAttribute("index", Integer.toString(i)); 198 entry.setAttribute("red", 199 Integer.toString(globalColorTable[3*i] & 0xff)); 200 entry.setAttribute("green", 201 Integer.toString(globalColorTable[3*i + 1] & 0xff)); 202 entry.setAttribute("blue", 203 Integer.toString(globalColorTable[3*i + 2] & 0xff)); 204 node.appendChild(entry); 205 } 206 chroma_node.appendChild(node); 207 208 // backgroundColorIndex is valid iff there is a color table 209 node = new IIOMetadataNode("BackgroundIndex"); 210 node.setAttribute("value", Integer.toString(backgroundColorIndex)); 211 chroma_node.appendChild(node); 212 } 213 214 return chroma_node; 215 } 216 217 public IIOMetadataNode getStandardCompressionNode() { 218 IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); 219 IIOMetadataNode node = null; // scratch node 220 221 node = new IIOMetadataNode("CompressionTypeName"); 222 node.setAttribute("value", "lzw"); 223 compression_node.appendChild(node); 224 225 node = new IIOMetadataNode("Lossless"); 226 node.setAttribute("value", "true"); 227 compression_node.appendChild(node); 228 229 // NumProgressiveScans not in stream 230 // BitRate not in format 231 232 return compression_node; 233 } 234 235 public IIOMetadataNode getStandardDataNode() { 236 IIOMetadataNode data_node = new IIOMetadataNode("Data"); 237 IIOMetadataNode node = null; // scratch node 238 239 // PlanarConfiguration 240 241 node = new IIOMetadataNode("SampleFormat"); 242 node.setAttribute("value", "Index"); 243 data_node.appendChild(node); 244 245 node = new IIOMetadataNode("BitsPerSample"); 246 node.setAttribute("value", 247 colorResolution == UNDEFINED_INTEGER_VALUE ? 248 "" : Integer.toString(colorResolution)); 249 data_node.appendChild(node); 250 251 // SignificantBitsPerSample 252 // SampleMSB 253 254 return data_node; 255 } 256 257 public IIOMetadataNode getStandardDimensionNode() { 258 IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); 259 IIOMetadataNode node = null; // scratch node 260 261 node = new IIOMetadataNode("PixelAspectRatio"); 262 float aspectRatio = 1.0F; 263 if (pixelAspectRatio != 0) { 264 aspectRatio = (pixelAspectRatio + 15)/64.0F; 265 } 266 node.setAttribute("value", Float.toString(aspectRatio)); 267 dimension_node.appendChild(node); 268 269 node = new IIOMetadataNode("ImageOrientation"); 270 node.setAttribute("value", "Normal"); 271 dimension_node.appendChild(node); 272 273 // HorizontalPixelSize not in format 274 // VerticalPixelSize not in format 275 // HorizontalPhysicalPixelSpacing not in format 276 // VerticalPhysicalPixelSpacing not in format 277 // HorizontalPosition not in format 278 // VerticalPosition not in format 279 // HorizontalPixelOffset not in stream 280 // VerticalPixelOffset not in stream 281 282 node = new IIOMetadataNode("HorizontalScreenSize"); 283 node.setAttribute("value", 284 logicalScreenWidth == UNDEFINED_INTEGER_VALUE ? 285 "" : Integer.toString(logicalScreenWidth)); 286 dimension_node.appendChild(node); 287 288 node = new IIOMetadataNode("VerticalScreenSize"); 289 node.setAttribute("value", 290 logicalScreenHeight == UNDEFINED_INTEGER_VALUE ? 291 "" : Integer.toString(logicalScreenHeight)); 292 dimension_node.appendChild(node); 293 294 return dimension_node; 295 } 296 297 public IIOMetadataNode getStandardDocumentNode() { 298 IIOMetadataNode document_node = new IIOMetadataNode("Document"); 299 IIOMetadataNode node = null; // scratch node 300 301 node = new IIOMetadataNode("FormatVersion"); 302 node.setAttribute("value", version); 303 document_node.appendChild(node); 304 305 // SubimageInterpretation not in format 306 // ImageCreationTime not in format 307 // ImageModificationTime not in format 308 309 return document_node; 310 } 311 312 public IIOMetadataNode getStandardTextNode() { 313 // Not in stream 314 return null; 315 } 316 317 public IIOMetadataNode getStandardTransparencyNode() { 318 // Not in stream 319 return null; 320 } 321 322 public void setFromTree(String formatName, Node root) 323 throws IIOInvalidTreeException 324 { 325 throw new IllegalStateException("Metadata is read-only!"); 326 } 327 328 protected void mergeNativeTree(Node root) throws IIOInvalidTreeException 329 { 330 throw new IllegalStateException("Metadata is read-only!"); 331 } 332 333 protected void mergeStandardTree(Node root) throws IIOInvalidTreeException 334 { 335 throw new IllegalStateException("Metadata is read-only!"); 336 } 337 338 public void reset() { 339 throw new IllegalStateException("Metadata is read-only!"); 340 } 341}