package net.pms.image; import java.awt.color.ColorSpace; import java.awt.image.ColorModel; import net.pms.util.ParseException; import com.drew.metadata.Directory; import com.drew.metadata.Metadata; import com.drew.metadata.gif.GifControlDirectory; import com.drew.metadata.gif.GifHeaderDirectory; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @SuppressWarnings("serial") @SuppressFBWarnings("SE_NO_SERIALVERSIONID") public class GIFInfo extends ImageInfo { protected final String formatVersion; protected final boolean hasTransparency; /** * Use * {@link ImageInfo#create(int, int, ImageFormat, long, ColorModel, Metadata, boolean, boolean)} * to instantiate. */ protected GIFInfo( int width, int height, ImageFormat format, long size, ColorModel colorModel, Metadata metadata, boolean applyExifOrientation, boolean imageIOSupport ) throws ParseException { super(width, height, format, size, colorModel, metadata, applyExifOrientation, imageIOSupport); formatVersion = ((GIFParseInfo) parsedInfo).formatVersion; hasTransparency = ((GIFParseInfo) parsedInfo).hasTransparency != null ? ((GIFParseInfo) parsedInfo).hasTransparency.booleanValue() : false; } /** * Use * {@link ImageInfo#create(int, int, ImageFormat, long, int, int, ColorSpace, ColorSpaceType, Metadata, boolean, boolean)} * to instantiate. */ protected GIFInfo( int width, int height, ImageFormat format, long size, int bitDepth, int numComponents, ColorSpace colorSpace, ColorSpaceType colorSpaceType, Metadata metadata, boolean applyExifOrientation, boolean imageIOSupport ) throws ParseException { super( width, height, format, size, bitDepth, numComponents, colorSpace, colorSpaceType, metadata, applyExifOrientation, imageIOSupport ); formatVersion = ((GIFParseInfo) parsedInfo).formatVersion; hasTransparency = ((GIFParseInfo) parsedInfo).hasTransparency != null ? ((GIFParseInfo) parsedInfo).hasTransparency.booleanValue() : false; } /** * Use * {@link ImageInfo#create(int, int, Metadata, ImageFormat, long, boolean, boolean)} * to instantiate. */ protected GIFInfo( int width, int height, Metadata metadata, ImageFormat format, long size, boolean applyExifOrientation, boolean throwOnParseFailure ) throws ParseException { super(width, height, metadata, format, size, applyExifOrientation, throwOnParseFailure); formatVersion = ((GIFParseInfo) parsedInfo).formatVersion; hasTransparency = ((GIFParseInfo) parsedInfo).hasTransparency != null ? ((GIFParseInfo) parsedInfo).hasTransparency.booleanValue() : false; } /** * Copy constructor */ protected GIFInfo( int width, int height, ImageFormat format, long size, int bitDepth, int numComponents, ColorSpace colorSpace, ColorSpaceType colorSpaceType, boolean imageIOSupport, String formatVersion, boolean hasTransparency ) { super(width, height, format, size, bitDepth, numComponents, colorSpace, colorSpaceType, imageIOSupport); this.formatVersion = formatVersion; this.hasTransparency = hasTransparency; } @Override protected ParseInfo createParseInfo() { return new GIFParseInfo(); } @Override protected void parseMetadata(Metadata metadata) throws ParseException { if (metadata == null) { return; } for (Directory directory : metadata.getDirectories()) { if (directory instanceof GifHeaderDirectory) { parsedInfo.format = ImageFormat.GIF; parsedInfo.numComponents = 3; if ( ((GifHeaderDirectory) directory).containsTag(GifHeaderDirectory.TAG_IMAGE_WIDTH) && ((GifHeaderDirectory) directory).containsTag(GifHeaderDirectory.TAG_IMAGE_HEIGHT) ) { parsedInfo.width = ((GifHeaderDirectory) directory).getInteger(GifHeaderDirectory.TAG_IMAGE_WIDTH); parsedInfo.height = ((GifHeaderDirectory) directory).getInteger(GifHeaderDirectory.TAG_IMAGE_HEIGHT); } if (((GifHeaderDirectory) directory).containsTag(GifHeaderDirectory.TAG_BITS_PER_PIXEL)) { parsedInfo.colorSpaceType = ColorSpaceType.TYPE_RGB; Integer i = ((GifHeaderDirectory) directory).getInteger(GifHeaderDirectory.TAG_BITS_PER_PIXEL); if (i != null) { parsedInfo.bitDepth = i.intValue(); } } if (((GifHeaderDirectory) directory).containsTag(GifHeaderDirectory.TAG_GIF_FORMAT_VERSION)) { String s = ((GifHeaderDirectory) directory).getString(GifHeaderDirectory.TAG_GIF_FORMAT_VERSION, "US-ASCII"); if (s != null) { ((GIFParseInfo) parsedInfo).formatVersion = s; } } } else if (directory instanceof GifControlDirectory) { boolean hasTransparency = ((GifControlDirectory) directory).isTransparent(); ((GIFParseInfo) parsedInfo).hasTransparency = hasTransparency; if (hasTransparency) { if (parsedInfo.numComponents == null) { throw new ParseException( "Invalid GIF image - Graphic Control Extension block encountered before the Header block" ); } parsedInfo.numComponents = 4; } } } } @Override public GIFInfo copy() { return new GIFInfo( width, height, format, size, bitDepth, numComponents, colorSpace, colorSpaceType, imageIOSupport, formatVersion, hasTransparency ); } /** * @return The format version {@link String} from the start of the GIF * header. */ public String getFormatVersion() { return formatVersion; } /** * @return Whether the GIF has a "background" color/transparency. */ public boolean isHasTransparency() { return hasTransparency; } protected static class GIFParseInfo extends ParseInfo { String formatVersion; Boolean hasTransparency; } @Override protected void buildToString(StringBuilder sb) { if (formatVersion != null) { sb.append(", GIF Version = ").append(formatVersion); } sb.append(", Has Transparency = ").append(hasTransparency ? "True" : "False"); } }