001/* 002 * $RCSfile: GIFImageMetadata.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:09 $ 043 * $State: Exp $ 044 */ 045 046package com.github.jaiimageio.impl.plugins.gif; 047 048import java.io.UnsupportedEncodingException; 049import java.util.Iterator; 050import java.util.List; 051 052import javax.imageio.metadata.IIOInvalidTreeException; 053import javax.imageio.metadata.IIOMetadataFormatImpl; 054import javax.imageio.metadata.IIOMetadataNode; 055 056import org.w3c.dom.Node; 057 058/** 059 * @version 0.5 060 */ 061public class GIFImageMetadata extends GIFMetadata { 062 063 // package scope 064 static final String 065 nativeMetadataFormatName = "javax_imageio_gif_image_1.0"; 066 067 static final String[] disposalMethodNames = { 068 "none", 069 "doNotDispose", 070 "restoreToBackgroundColor", 071 "restoreToPrevious", 072 "undefinedDisposalMethod4", 073 "undefinedDisposalMethod5", 074 "undefinedDisposalMethod6", 075 "undefinedDisposalMethod7" 076 }; 077 078 // Fields from Image Descriptor 079 public int imageLeftPosition; 080 public int imageTopPosition; 081 public int imageWidth; 082 public int imageHeight; 083 public boolean interlaceFlag = false; 084 public boolean sortFlag = false; 085 public byte[] localColorTable = null; 086 087 // Fields from Graphic Control Extension 088 public int disposalMethod = 0; 089 public boolean userInputFlag = false; 090 public boolean transparentColorFlag = false; 091 public int delayTime = 0; 092 public int transparentColorIndex = 0; 093 094 // Fields from Plain Text Extension 095 public boolean hasPlainTextExtension = false; 096 public int textGridLeft; 097 public int textGridTop; 098 public int textGridWidth; 099 public int textGridHeight; 100 public int characterCellWidth; 101 public int characterCellHeight; 102 public int textForegroundColor; 103 public int textBackgroundColor; 104 public byte[] text; 105 106 // Fields from ApplicationExtension 107 // List of byte[] 108 public List applicationIDs = null; // new ArrayList(); 109 110 // List of byte[] 111 public List authenticationCodes = null; // new ArrayList(); 112 113 // List of byte[] 114 public List applicationData = null; // new ArrayList(); 115 116 // Fields from CommentExtension 117 // List of byte[] 118 public List comments = null; // new ArrayList(); 119 120 protected GIFImageMetadata(boolean standardMetadataFormatSupported, 121 String nativeMetadataFormatName, 122 String nativeMetadataFormatClassName, 123 String[] extraMetadataFormatNames, 124 String[] extraMetadataFormatClassNames) 125 { 126 super(standardMetadataFormatSupported, 127 nativeMetadataFormatName, 128 nativeMetadataFormatClassName, 129 extraMetadataFormatNames, 130 extraMetadataFormatClassNames); 131 } 132 133 public GIFImageMetadata() { 134 this(true, 135 nativeMetadataFormatName, 136 "com.github.jaiimageio.impl.plugins.gif.GIFImageMetadataFormat", 137 null, null); 138 } 139 140 public boolean isReadOnly() { 141 return true; 142 } 143 144 public Node getAsTree(String formatName) { 145 if (formatName.equals(nativeMetadataFormatName)) { 146 return getNativeTree(); 147 } else if (formatName.equals 148 (IIOMetadataFormatImpl.standardMetadataFormatName)) { 149 return getStandardTree(); 150 } else { 151 throw new IllegalArgumentException("Not a recognized format!"); 152 } 153 } 154 155 private String toISO8859(byte[] data) { 156 try { 157 return new String(data, "ISO-8859-1"); 158 } catch (UnsupportedEncodingException e) { 159 return ""; 160 } 161 } 162 163 private Node getNativeTree() { 164 IIOMetadataNode node; // scratch node 165 IIOMetadataNode root = 166 new IIOMetadataNode(nativeMetadataFormatName); 167 168 // Image descriptor 169 node = new IIOMetadataNode("ImageDescriptor"); 170 node.setAttribute("imageLeftPosition", 171 Integer.toString(imageLeftPosition)); 172 node.setAttribute("imageTopPosition", 173 Integer.toString(imageTopPosition)); 174 node.setAttribute("imageWidth", Integer.toString(imageWidth)); 175 node.setAttribute("imageHeight", Integer.toString(imageHeight)); 176 node.setAttribute("interlaceFlag", 177 interlaceFlag ? "true" : "false"); 178 root.appendChild(node); 179 180 // Local color table 181 if (localColorTable != null) { 182 node = new IIOMetadataNode("LocalColorTable"); 183 int numEntries = localColorTable.length/3; 184 node.setAttribute("sizeOfLocalColorTable", 185 Integer.toString(numEntries)); 186 node.setAttribute("sortFlag", 187 sortFlag ? "TRUE" : "FALSE"); 188 189 for (int i = 0; i < numEntries; i++) { 190 IIOMetadataNode entry = 191 new IIOMetadataNode("ColorTableEntry"); 192 entry.setAttribute("index", Integer.toString(i)); 193 int r = localColorTable[3*i] & 0xff; 194 int g = localColorTable[3*i + 1] & 0xff; 195 int b = localColorTable[3*i + 2] & 0xff; 196 entry.setAttribute("red", Integer.toString(r)); 197 entry.setAttribute("green", Integer.toString(g)); 198 entry.setAttribute("blue", Integer.toString(b)); 199 node.appendChild(entry); 200 } 201 root.appendChild(node); 202 } 203 204 // Graphic control extension 205 node = new IIOMetadataNode("GraphicControlExtension"); 206 node.setAttribute("disposalMethod", 207 disposalMethodNames[disposalMethod]); 208 node.setAttribute("userInputFlag", 209 userInputFlag ? "true" : "false"); 210 node.setAttribute("transparentColorFlag", 211 transparentColorFlag ? "true" : "false"); 212 node.setAttribute("delayTime", 213 Integer.toString(delayTime)); 214 node.setAttribute("transparentColorIndex", 215 Integer.toString(transparentColorIndex)); 216 root.appendChild(node); 217 218 if (hasPlainTextExtension) { 219 node = new IIOMetadataNode("PlainTextExtension"); 220 node.setAttribute("textGridLeft", 221 Integer.toString(textGridLeft)); 222 node.setAttribute("textGridTop", 223 Integer.toString(textGridTop)); 224 node.setAttribute("textGridWidth", 225 Integer.toString(textGridWidth)); 226 node.setAttribute("textGridHeight", 227 Integer.toString(textGridHeight)); 228 node.setAttribute("characterCellWidth", 229 Integer.toString(characterCellWidth)); 230 node.setAttribute("characterCellHeight", 231 Integer.toString(characterCellHeight)); 232 node.setAttribute("textForegroundColor", 233 Integer.toString(textForegroundColor)); 234 node.setAttribute("textBackgroundColor", 235 Integer.toString(textBackgroundColor)); 236 node.setAttribute("text", toISO8859(text)); 237 238 root.appendChild(node); 239 } 240 241 // Application extensions 242 int numAppExtensions = applicationIDs == null ? 243 0 : applicationIDs.size(); 244 if (numAppExtensions > 0) { 245 node = new IIOMetadataNode("ApplicationExtensions"); 246 for (int i = 0; i < numAppExtensions; i++) { 247 IIOMetadataNode appExtNode = 248 new IIOMetadataNode("ApplicationExtension"); 249 byte[] applicationID = (byte[])applicationIDs.get(i); 250 appExtNode.setAttribute("applicationID", 251 toISO8859(applicationID)); 252 byte[] authenticationCode = (byte[])authenticationCodes.get(i); 253 appExtNode.setAttribute("authenticationCode", 254 toISO8859(authenticationCode)); 255 byte[] appData = (byte[])applicationData.get(i); 256 appExtNode.setUserObject((byte[])appData.clone()); 257 node.appendChild(appExtNode); 258 } 259 260 root.appendChild(node); 261 } 262 263 // Comment extensions 264 int numComments = comments == null ? 0 : comments.size(); 265 if (numComments > 0) { 266 node = new IIOMetadataNode("CommentExtensions"); 267 for (int i = 0; i < numComments; i++) { 268 IIOMetadataNode commentNode = 269 new IIOMetadataNode("CommentExtension"); 270 byte[] comment = (byte[])comments.get(i); 271 commentNode.setAttribute("value", toISO8859(comment)); 272 node.appendChild(commentNode); 273 } 274 275 root.appendChild(node); 276 } 277 278 return root; 279 } 280 281 public IIOMetadataNode getStandardChromaNode() { 282 IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); 283 IIOMetadataNode node = null; // scratch node 284 285 node = new IIOMetadataNode("ColorSpaceType"); 286 node.setAttribute("name", "RGB"); 287 chroma_node.appendChild(node); 288 289 node = new IIOMetadataNode("NumChannels"); 290 node.setAttribute("value", transparentColorFlag ? "4" : "3"); 291 chroma_node.appendChild(node); 292 293 // Gamma not in format 294 295 node = new IIOMetadataNode("BlackIsZero"); 296 node.setAttribute("value", "TRUE"); 297 chroma_node.appendChild(node); 298 299 if (localColorTable != null) { 300 node = new IIOMetadataNode("Palette"); 301 int numEntries = localColorTable.length/3; 302 for (int i = 0; i < numEntries; i++) { 303 IIOMetadataNode entry = 304 new IIOMetadataNode("PaletteEntry"); 305 entry.setAttribute("index", Integer.toString(i)); 306 entry.setAttribute("red", 307 Integer.toString(localColorTable[3*i] & 0xff)); 308 entry.setAttribute("green", 309 Integer.toString(localColorTable[3*i + 1] & 0xff)); 310 entry.setAttribute("blue", 311 Integer.toString(localColorTable[3*i + 2] & 0xff)); 312 node.appendChild(entry); 313 } 314 chroma_node.appendChild(node); 315 } 316 317 // BackgroundIndex not in image 318 // BackgroundColor not in format 319 320 return chroma_node; 321 } 322 323 public IIOMetadataNode getStandardCompressionNode() { 324 IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); 325 IIOMetadataNode node = null; // scratch node 326 327 node = new IIOMetadataNode("CompressionTypeName"); 328 node.setAttribute("value", "lzw"); 329 compression_node.appendChild(node); 330 331 node = new IIOMetadataNode("Lossless"); 332 node.setAttribute("value", "TRUE"); 333 compression_node.appendChild(node); 334 335 node = new IIOMetadataNode("NumProgressiveScans"); 336 node.setAttribute("value", interlaceFlag ? "4" : "1"); 337 compression_node.appendChild(node); 338 339 // BitRate not in format 340 341 return compression_node; 342 } 343 344 public IIOMetadataNode getStandardDataNode() { 345 IIOMetadataNode data_node = new IIOMetadataNode("Data"); 346 IIOMetadataNode node = null; // scratch node 347 348 // PlanarConfiguration not in format 349 350 node = new IIOMetadataNode("SampleFormat"); 351 node.setAttribute("value", "Index"); 352 data_node.appendChild(node); 353 354 // BitsPerSample not in image 355 // SignificantBitsPerSample not in format 356 // SampleMSB not in format 357 358 return data_node; 359 } 360 361 public IIOMetadataNode getStandardDimensionNode() { 362 IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); 363 IIOMetadataNode node = null; // scratch node 364 365 // PixelAspectRatio not in image 366 367 node = new IIOMetadataNode("ImageOrientation"); 368 node.setAttribute("value", "Normal"); 369 dimension_node.appendChild(node); 370 371 // HorizontalPixelSize not in format 372 // VerticalPixelSize not in format 373 // HorizontalPhysicalPixelSpacing not in format 374 // VerticalPhysicalPixelSpacing not in format 375 // HorizontalPosition not in format 376 // VerticalPosition not in format 377 378 node = new IIOMetadataNode("HorizontalPixelOffset"); 379 node.setAttribute("value", Integer.toString(imageLeftPosition)); 380 dimension_node.appendChild(node); 381 382 node = new IIOMetadataNode("VerticalPixelOffset"); 383 node.setAttribute("value", Integer.toString(imageTopPosition)); 384 dimension_node.appendChild(node); 385 386 // HorizontalScreenSize not in image 387 // VerticalScreenSize not in image 388 389 return dimension_node; 390 } 391 392 // Document not in image 393 394 public IIOMetadataNode getStandardTextNode() { 395 if (comments == null) { 396 return null; 397 } 398 Iterator commentIter = comments.iterator(); 399 if (!commentIter.hasNext()) { 400 return null; 401 } 402 403 IIOMetadataNode text_node = new IIOMetadataNode("Text"); 404 IIOMetadataNode node = null; // scratch node 405 406 while (commentIter.hasNext()) { 407 byte[] comment = (byte[])commentIter.next(); 408 String s = null; 409 try { 410 s = new String(comment, "ISO-8859-1"); 411 } catch (UnsupportedEncodingException e) { 412 throw new RuntimeException("Encoding ISO-8859-1 unknown!"); 413 } 414 415 node = new IIOMetadataNode("TextEntry"); 416 node.setAttribute("value", s); 417 node.setAttribute("encoding", "ISO-8859-1"); 418 node.setAttribute("compression", "none"); 419 text_node.appendChild(node); 420 } 421 422 return text_node; 423 } 424 425 public IIOMetadataNode getStandardTransparencyNode() { 426 if (!transparentColorFlag) { 427 return null; 428 } 429 430 IIOMetadataNode transparency_node = 431 new IIOMetadataNode("Transparency"); 432 IIOMetadataNode node = null; // scratch node 433 434 // Alpha not in format 435 436 node = new IIOMetadataNode("TransparentIndex"); 437 node.setAttribute("value", 438 Integer.toString(transparentColorIndex)); 439 transparency_node.appendChild(node); 440 441 // TransparentColor not in format 442 // TileTransparencies not in format 443 // TileOpacities not in format 444 445 return transparency_node; 446 } 447 448 public void setFromTree(String formatName, Node root) 449 throws IIOInvalidTreeException 450 { 451 throw new IllegalStateException("Metadata is read-only!"); 452 } 453 454 protected void mergeNativeTree(Node root) throws IIOInvalidTreeException 455 { 456 throw new IllegalStateException("Metadata is read-only!"); 457 } 458 459 protected void mergeStandardTree(Node root) throws IIOInvalidTreeException 460 { 461 throw new IllegalStateException("Metadata is read-only!"); 462 } 463 464 public void reset() { 465 throw new IllegalStateException("Metadata is read-only!"); 466 } 467}