/*
* Universal Media Server, for streaming any media to DLNA
* compatible renderers based on the http://www.ps3mediaserver.org.
* Copyright (C) 2012 UMS developers.
*
* This program is a free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2
* of the License only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package net.pms.image;
import java.util.Locale;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import com.drew.imaging.FileType;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.bmp.BmpHeaderDirectory;
import com.drew.metadata.exif.ExifDirectoryBase;
import com.drew.metadata.exif.ExifIFD0Directory;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import com.drew.metadata.gif.GifHeaderDirectory;
import com.drew.metadata.ico.IcoDirectory;
import com.drew.metadata.jfif.JfifDirectory;
import com.drew.metadata.jpeg.JpegDirectory;
import com.drew.metadata.pcx.PcxDirectory;
import com.drew.metadata.photoshop.PsdHeaderDirectory;
import com.drew.metadata.png.PngDirectory;
import com.drew.metadata.webp.WebpDirectory;
import net.pms.configuration.FormatConfiguration;
import net.pms.dlna.DLNAImageProfile;
import net.pms.image.ExifInfo.ExifCompression;
/**
* Defines the different image format supported by the ImageIO parser
* with the currently installed plugins plus the special value {@code SOURCE}.
* If more plugins are added, more entries should be added here and in
* {@link ImageIOTools#read(ImageInputStream)}.
*/
public enum ImageFormat {
ARW,
BMP,
CR2,
CRW,
CUR,
DCR,
DCX,
/** Adobe Digital Negative */
DNG,
/** Used for general "raw" formats without an explicit definition. */
RAW,
GIF,
ICNS,
ICO,
/** Interchange File Format */
IFF,
JPEG,
KDC,
NEF,
ORF,
PCX,
/** Apple PICT */
PICT,
PEF,
PNG,
PNM,
PSD,
RAF,
/** Radiance HDR/RGBE */
RGBE,
RW2,
/** Silicon Graphics SGI image format */
SGI,
/** A special code that means "whatever the source image uses" where that's relevant. */
SOURCE,
SRW,
/** Truevision Targa Graphic */
TGA,
TIFF,
WBMP,
WEBP;
public static final int TAG_DNG_VERSION = 0xC612;
public static ImageFormat toImageFormat(DLNAImageProfile imageProfile) {
if (imageProfile == null) {
return null;
}
return imageProfile.getFormat();
}
public static ImageFormat toImageFormat(FileType fileType) {
if (fileType == null) {
return null;
}
switch (fileType) {
case Arw:
return ImageFormat.ARW;
case Bmp:
return ImageFormat.BMP;
case Cr2:
return ImageFormat.CR2;
case Crw:
return ImageFormat.CRW;
case Gif:
return ImageFormat.GIF;
case Ico:
return ImageFormat.ICO;
case Jpeg:
return ImageFormat.JPEG;
case Nef:
return ImageFormat.NEF;
case Orf:
return ImageFormat.ORF;
case Pcx:
return ImageFormat.PCX;
case Png:
return ImageFormat.PNG;
case Psd:
return ImageFormat.PSD;
case Raf:
return ImageFormat.RAF;
case Rw2:
return ImageFormat.RW2;
case Tiff:
return ImageFormat.TIFF;
case Riff:
return ImageFormat.WEBP;
case Unknown:
default:
return null;
}
}
/**
* Tries to parse {@link ImageFormat} from a text representation of an image
* format.
*
* @param formatName the {@link String} containing the format code.
* @return The parsed {@link ImageFormat} or {@code null} if the parsing
* fails.
*/
public static ImageFormat toImageFormat(String formatName) {
ImageFormat result = null;
if (formatName != null) {
formatName = formatName.toUpperCase(Locale.ROOT);
if (formatName.contains("BMP")) {
result = ImageFormat.BMP;
} else if (formatName.contains("CUR")) {
result = ImageFormat.CUR;
} else if (formatName.contains("DCX")) {
result = ImageFormat.DCX;
} else if (formatName.contains("GIF")) {
result = ImageFormat.GIF;
} else if (formatName.contains("ICNS")) {
result = ImageFormat.ICNS;
} else if (formatName.contains("ICO")) {
result = ImageFormat.ICO;
} else if (formatName.equals("IFF")) {
result = ImageFormat.IFF;
} else if (formatName.contains("JPEG")) {
result = ImageFormat.JPEG;
} else if (formatName.contains("PCX")) {
result = ImageFormat.PCX;
} else if (
formatName.contains("PIC") ||
formatName.contains("PCT")
) {
result = ImageFormat.PICT;
} else if (formatName.contains("PNG")) {
result = ImageFormat.PNG;
} else if (
formatName.contains("PNM") ||
formatName.contains("PBM") ||
formatName.contains("PGM") ||
formatName.contains("PPM") ||
formatName.contains("PAM") ||
formatName.contains("PFM")
) {
result = ImageFormat.PNM;
} else if (formatName.contains("PSD")) {
result = ImageFormat.PSD;
} else if (
formatName.contains("RGBE") ||
formatName.contains("HDR") ||
formatName.contains("XYZE")
) {
result = ImageFormat.RGBE;
} else if (
formatName.contains("SGI") ||
formatName.equals("RLE")
) {
result = ImageFormat.SGI;
} else if (
formatName.contains("TGA") ||
formatName.contains("TARGA")
) {
result = ImageFormat.TGA;
} else if (formatName.contains("TIFF")) {
result = ImageFormat.TIFF;
} else if (formatName.contains("WBMP")) {
result = ImageFormat.WBMP;
}
}
return result;
}
/**
* Tries to parse {@link ImageFormat} from a {@link Metadata} instance.
*
* @param metadata the {@link Metadata} to parse.
* @return The parsed {@link ImageFormat} or {@code null} if the parsing
* fails.
*/
@SuppressWarnings("incomplete-switch")
public static ImageFormat toImageFormat(Metadata metadata) {
if (metadata == null) {
throw new NullPointerException("metadata cannot be null");
}
// Check for known directories tied to a particular format
for (Directory directory : metadata.getDirectories()) {
if (directory instanceof BmpHeaderDirectory) {
return ImageFormat.BMP;
}
if (directory instanceof GifHeaderDirectory) {
return ImageFormat.GIF;
}
if (directory instanceof IcoDirectory) {
return ImageFormat.ICO;
}
if (directory instanceof JfifDirectory || directory instanceof JpegDirectory) {
return ImageFormat.JPEG;
}
if (directory instanceof PcxDirectory) {
return ImageFormat.PCX;
}
if (directory instanceof PngDirectory) {
return ImageFormat.PNG;
}
if (directory instanceof PsdHeaderDirectory) {
return ImageFormat.PSD;
}
if (directory instanceof WebpDirectory) {
return ImageFormat.WEBP;
}
}
/*
* Check for Exif compression tag and parse known values to TIFF or
* various proprietary "raw" formats. Do not try to combine the two
* loops, Exif matching must only be attempted if the first match fails.
*/
ExifCompression exifCompression = null;
for (Directory directory : metadata.getDirectories()) {
if (directory instanceof ExifIFD0Directory || directory instanceof ExifSubIFDDirectory) {
if (((ExifDirectoryBase) directory).containsTag(ExifDirectoryBase.TAG_COMPRESSION)) {
Integer i = ((ExifDirectoryBase) directory).getInteger(ExifDirectoryBase.TAG_COMPRESSION);
if (i != null) {
exifCompression = ExifCompression.typeOf(i.intValue());
}
}
if (directory.containsTag(TAG_DNG_VERSION)) {
return ImageFormat.DNG;
}
}
}
// Nothing found by specific tags, use a generic approach based on Exif compression
if (exifCompression != null) {
switch (exifCompression) {
case ADOBE_DEFLATE:
case CCITT_1D:
case DEFLATE:
case IT8BL:
case IT8CTPAD:
case IT8LW:
case IT8MP:
case JBIG:
case JBIG2_TIFF_FX:
case JBIG_B_W:
case JBIG_COLOR:
case JPEG:
case JPEG_OLD_STYLE:
case LZW:
case PACKBITS:
case T4_GROUP_3_FAX:
case T6_GROUP_4_FAX:
case UNCOMPRESSED:
return ImageFormat.TIFF;
case DCS:
case KODAC_DCR_COMPRESSED:
return ImageFormat.DCR;
case KODAK_KDC_COMPRESSED:
return ImageFormat.KDC;
case NIKON_NEF_COMPRESSED:
return ImageFormat.NEF;
case PENTAX_PEF_COMPRESSED:
return ImageFormat.PEF;
case SAMSUNG_SRW_COMPRESSED:
case SAMSUNG_SRW_COMPRESSED_2:
return ImageFormat.SRW;
case SONY_ARW_COMPRESSED:
return ImageFormat.ARW;
}
}
// Parsing failed
return null;
}
/**
* @return whether this format is one of the proprietary camera
* image formats.
*/
public boolean isRaw() {
switch (this) {
case ARW:
case CR2:
case CRW:
case DCR:
case DNG:
case RAW:
case KDC:
case NEF:
case ORF:
case PEF:
case RAF:
case RW2:
case SRW:
return true;
default:
return false;
}
}
/**
* If new plugins for {@link ImageIO} is added, this {@code switch} must
* be updated to reflect that.
*
* @return Whether or not the format is supported by {@link ImageIO}.
*/
public boolean supportedByImageIO() {
switch (this) {
case BMP:
case CUR:
case DCX:
case GIF:
case ICNS:
case ICO:
case IFF:
case JPEG:
case PCX:
case PICT:
case PNG:
case PNM:
case PSD:
case RGBE:
case SGI:
case TGA:
case TIFF:
case WBMP:
return true;
default:
return false;
}
}
/**
* @return The {@link FormatConfiguration} value for this image format.
*/
public String toFormatConfiguration() {
switch (this) {
case ARW:
case CR2:
case CRW:
case DCR:
case DNG:
case RAW:
case KDC:
case NEF:
case ORF:
case PEF:
case RAF:
case RW2:
case SRW:
return FormatConfiguration.RAW;
case BMP:
return FormatConfiguration.BMP;
case CUR:
return FormatConfiguration.CUR;
case DCX:
return FormatConfiguration.PCX;
case GIF:
return FormatConfiguration.GIF;
case ICNS:
return FormatConfiguration.ICNS;
case ICO:
return FormatConfiguration.ICO;
case JPEG:
return FormatConfiguration.JPG;
case PCX:
return FormatConfiguration.PCX;
case PNG:
return FormatConfiguration.PNG;
case PNM:
return FormatConfiguration.PNM;
case PSD:
return FormatConfiguration.PSD;
case TIFF:
return FormatConfiguration.TIFF;
case WBMP:
return FormatConfiguration.WBMP;
case WEBP:
return FormatConfiguration.WEBP;
case SOURCE:
throw new IllegalArgumentException("SOURCE cannot be translated into an actual format");
default:
return toString().toLowerCase(Locale.ROOT);
}
}
}