use of net.pms.util.UnknownFormatException in project UniversalMediaServer by UniversalMediaServer.
the class LibMediaInfoParser method parse.
/**
* Parse media via MediaInfo.
*/
public static synchronized void parse(DLNAMediaInfo media, InputFile inputFile, int type, RendererConfiguration renderer) {
File file = inputFile.getFile();
if (!media.isMediaparsed() && file != null && MI.isValid() && MI.Open(file.getAbsolutePath()) > 0) {
StreamType general = StreamType.General;
StreamType video = StreamType.Video;
StreamType audio = StreamType.Audio;
StreamType image = StreamType.Image;
StreamType text = StreamType.Text;
DLNAMediaAudio currentAudioTrack = new DLNAMediaAudio();
DLNAMediaSubtitle currentSubTrack;
media.setSize(file.length());
String value;
// set General
getFormat(general, media, currentAudioTrack, MI.Get(general, 0, "Format"), file);
getFormat(general, media, currentAudioTrack, MI.Get(general, 0, "CodecID").trim(), file);
media.setDuration(getDuration(MI.Get(general, 0, "Duration/String1")));
media.setBitrate(getBitrate(MI.Get(general, 0, "OverallBitRate")));
media.setStereoscopy(MI.Get(general, 0, "StereoscopicLayout"));
value = MI.Get(general, 0, "Cover_Data");
if (!value.isEmpty()) {
try {
media.setThumb(DLNAThumbnail.toThumbnail(new Base64().decode(value.getBytes(StandardCharsets.US_ASCII)), 640, 480, ScaleType.MAX, ImageFormat.SOURCE, false));
} catch (EOFException e) {
LOGGER.debug("Error reading \"{}\" thumbnail from MediaInfo: Unexpected end of stream, probably corrupt or read error.", file.getName());
} catch (UnknownFormatException e) {
LOGGER.debug("Could not read \"{}\" thumbnail from MediaInfo: {}", file.getName(), e.getMessage());
} catch (IOException e) {
LOGGER.error("Error reading \"{}\" thumbnail from MediaInfo: {}", file.getName(), e.getMessage());
LOGGER.trace("", e);
}
}
value = MI.Get(general, 0, "Title");
if (!value.isEmpty()) {
media.setFileTitleFromMetadata(value);
}
// set Video
media.setVideoTrackCount(MI.Count_Get(video));
if (media.getVideoTrackCount() > 0) {
for (int i = 0; i < media.getVideoTrackCount(); i++) {
// check for DXSA and DXSB subtitles (subs in video format)
if (MI.Get(video, i, "Title").startsWith("Subtitle")) {
currentSubTrack = new DLNAMediaSubtitle();
// First attempt to detect subtitle track format
currentSubTrack.setType(SubtitleType.valueOfLibMediaInfoCodec(MI.Get(video, i, "Format")));
// Second attempt to detect subtitle track format (CodecID usually is more accurate)
currentSubTrack.setType(SubtitleType.valueOfLibMediaInfoCodec(MI.Get(video, i, "CodecID")));
currentSubTrack.setId(media.getSubtitleTracksList().size());
addSub(currentSubTrack, media);
} else {
getFormat(video, media, currentAudioTrack, MI.Get(video, i, "Format"), file);
getFormat(video, media, currentAudioTrack, MI.Get(video, i, "Format_Version"), file);
getFormat(video, media, currentAudioTrack, MI.Get(video, i, "CodecID"), file);
media.setWidth(getPixelValue(MI.Get(video, i, "Width")));
media.setHeight(getPixelValue(MI.Get(video, i, "Height")));
media.setMatrixCoefficients(MI.Get(video, i, "matrix_coefficients"));
if (!media.is3d()) {
media.setStereoscopy(MI.Get(video, i, "MultiView_Layout"));
}
media.setAspectRatioContainer(MI.Get(video, i, "DisplayAspectRatio/String"));
media.setAspectRatioVideoTrack(MI.Get(video, i, "DisplayAspectRatio_Original/String"));
media.setFrameRate(getFPSValue(MI.Get(video, i, "FrameRate")));
media.setFrameRateOriginal(MI.Get(video, i, "FrameRate_Original"));
media.setFrameRateMode(getFrameRateModeValue(MI.Get(video, i, "FrameRate_Mode")));
media.setFrameRateModeRaw(MI.Get(video, i, "FrameRate_Mode"));
media.setReferenceFrameCount(getReferenceFrameCount(MI.Get(video, i, "Format_Settings_RefFrames/String")));
media.setVideoTrackTitleFromMetadata(MI.Get(video, i, "Title"));
value = MI.Get(video, i, "Format_Settings_QPel");
if (!value.isEmpty()) {
media.putExtra(FormatConfiguration.MI_QPEL, value);
}
value = MI.Get(video, i, "Format_Settings_GMC");
if (!value.isEmpty()) {
media.putExtra(FormatConfiguration.MI_GMC, value);
}
value = MI.Get(video, i, "Format_Settings_GOP");
if (!value.isEmpty()) {
media.putExtra(FormatConfiguration.MI_GOP, value);
}
media.setMuxingMode(MI.Get(video, i, "MuxingMode"));
if (!media.isEncrypted()) {
media.setEncrypted("encrypted".equals(MI.Get(video, i, "Encryption")));
}
value = MI.Get(video, i, "BitDepth");
if (!value.isEmpty()) {
try {
media.setVideoBitDepth(Integer.parseInt(value));
} catch (NumberFormatException nfe) {
LOGGER.debug("Could not parse bits per sample \"" + value + "\"");
}
}
value = MI.Get(video, i, "Format_Profile");
if (!value.isEmpty() && media.getCodecV() != null && media.getCodecV().equals(FormatConfiguration.H264)) {
media.setAvcLevel(getAvcLevel(value));
}
}
}
}
// set Audio
int audioTracks = MI.Count_Get(audio);
if (audioTracks > 0) {
for (int i = 0; i < audioTracks; i++) {
currentAudioTrack = new DLNAMediaAudio();
getFormat(audio, media, currentAudioTrack, MI.Get(audio, i, "Format"), file);
getFormat(audio, media, currentAudioTrack, MI.Get(audio, i, "Format_Version"), file);
getFormat(audio, media, currentAudioTrack, MI.Get(audio, i, "Format_Profile"), file);
getFormat(audio, media, currentAudioTrack, MI.Get(audio, i, "CodecID"), file);
value = MI.Get(audio, i, "CodecID_Description");
if (isNotBlank(value) && value.startsWith("Windows Media Audio 10")) {
currentAudioTrack.setCodecA(FormatConfiguration.WMA10);
}
currentAudioTrack.setLang(getLang(MI.Get(audio, i, "Language/String")));
currentAudioTrack.setAudioTrackTitleFromMetadata((MI.Get(audio, i, "Title")).trim());
currentAudioTrack.getAudioProperties().setNumberOfChannels(MI.Get(audio, i, "Channel(s)"));
currentAudioTrack.setSampleFrequency(getSampleFrequency(MI.Get(audio, i, "SamplingRate")));
currentAudioTrack.setBitRate(getBitrate(MI.Get(audio, i, "BitRate")));
currentAudioTrack.setSongname(MI.Get(general, 0, "Track"));
if (renderer.isPrependTrackNumbers() && currentAudioTrack.getTrack() > 0 && currentAudioTrack.getSongname() != null && currentAudioTrack.getSongname().length() > 0) {
currentAudioTrack.setSongname(currentAudioTrack.getTrack() + ": " + currentAudioTrack.getSongname());
}
currentAudioTrack.setAlbum(MI.Get(general, 0, "Album"));
currentAudioTrack.setArtist(MI.Get(general, 0, "Performer"));
currentAudioTrack.setGenre(MI.Get(general, 0, "Genre"));
// Try to parse the year from the stored date
String recordedDate = MI.Get(general, 0, "Recorded_Date");
Matcher matcher = yearPattern.matcher(recordedDate);
if (matcher.matches()) {
try {
currentAudioTrack.setYear(Integer.parseInt(matcher.group(1)));
} catch (NumberFormatException nfe) {
LOGGER.debug("Could not parse year from recorded date \"" + recordedDate + "\"");
}
}
// Special check for OGM: MediaInfo reports specific Audio/Subs IDs (0xn) while mencoder does not
value = MI.Get(audio, i, "ID/String");
if (!value.isEmpty()) {
if (value.contains("(0x") && !FormatConfiguration.OGG.equals(media.getContainer())) {
currentAudioTrack.setId(getSpecificID(value));
} else {
currentAudioTrack.setId(media.getAudioTracksList().size());
}
}
value = MI.Get(general, i, "Track/Position");
if (!value.isEmpty()) {
try {
currentAudioTrack.setTrack(Integer.parseInt(value));
} catch (NumberFormatException nfe) {
LOGGER.debug("Could not parse track \"" + value + "\"");
}
}
value = MI.Get(audio, i, "BitDepth");
if (!value.isEmpty()) {
try {
currentAudioTrack.setBitsperSample(Integer.parseInt(value));
} catch (NumberFormatException nfe) {
LOGGER.debug("Could not parse bits per sample \"" + value + "\"");
}
}
addAudio(currentAudioTrack, media);
}
}
// set Image
media.setImageCount(MI.Count_Get(image));
if (media.getImageCount() > 0 || type == Format.IMAGE) {
boolean parseByMediainfo = false;
// For images use our own parser instead of MediaInfo which doesn't provide enough information
try {
ImagesUtil.parseImage(file, media);
// so that MI.Count_Get(image) might return 0 even if there is an image.
if (media.getImageCount() == 0) {
media.setImageCount(1);
}
} catch (IOException e) {
if (media.getImageCount() > 0) {
LOGGER.debug("Error parsing image ({}), switching to MediaInfo: {}", file.getAbsolutePath(), e.getMessage());
LOGGER.trace("", e);
parseByMediainfo = true;
} else {
LOGGER.warn("Image parsing for \"{}\" failed both with MediaInfo and internally: {}", file.getAbsolutePath(), e.getMessage());
LOGGER.trace("", e);
media.setImageCount(1);
}
}
if (parseByMediainfo) {
getFormat(image, media, currentAudioTrack, MI.Get(image, 0, "Format"), file);
media.setWidth(getPixelValue(MI.Get(image, 0, "Width")));
media.setHeight(getPixelValue(MI.Get(image, 0, "Height")));
}
}
// set Subs in text format
int subTracks = MI.Count_Get(text);
if (subTracks > 0) {
for (int i = 0; i < subTracks; i++) {
currentSubTrack = new DLNAMediaSubtitle();
currentSubTrack.setType(SubtitleType.valueOfLibMediaInfoCodec(MI.Get(text, i, "Format")));
currentSubTrack.setType(SubtitleType.valueOfLibMediaInfoCodec(MI.Get(text, i, "CodecID")));
currentSubTrack.setLang(getLang(MI.Get(text, i, "Language/String")));
currentSubTrack.setSubtitlesTrackTitleFromMetadata((MI.Get(text, i, "Title")).trim());
// Special check for OGM: MediaInfo reports specific Audio/Subs IDs (0xn) while mencoder does not
value = MI.Get(text, i, "ID/String");
if (!value.isEmpty()) {
if (value.contains("(0x") && !FormatConfiguration.OGG.equals(media.getContainer())) {
currentSubTrack.setId(getSpecificID(value));
} else {
currentSubTrack.setId(media.getSubtitleTracksList().size());
}
}
addSub(currentSubTrack, media);
}
}
/*
* Some container formats (like MP4/M4A) can represent both audio
* and video media. UMS initially recognized this as video, but this
* is corrected here it the content is only audio.
*/
if (media.isAudioOrVideoContainer() && media.isAudio()) {
media.setContainer(media.getAudioVariantFormatConfigurationString());
}
/*
* Recognize 3D layout from the filename.
*
* First we check for our custom naming convention, for which the filename
* either has to start with "3DSBSLF" or "3DSBSRF" for side-by-side layout
* or "3DOULF" or "3DOURF" for over-under layout.
* For anaglyph 3D video can be used following combination:
* 3DARCG anaglyph_red_cyan_gray
* 3DARCH anaglyph_red_cyan_half_color
* 3DARCC anaglyph_red_cyan_color
* 3DARCD anaglyph_red_cyan_dubois
* 3DAGMG anaglyph_green_magenta_gray
* 3DAGMH anaglyph_green_magenta_half_color
* 3DAGMC anaglyph_green_magenta_color
* 3DAGMD anaglyph_green_magenta_dubois
* 3DAYBG anaglyph_yellow_blue_gray
* 3DAYBH anaglyph_yellow_blue_half_color
* 3DAYBC anaglyph_yellow_blue_color
* 3DAYBD anaglyph_yellow_blue_dubois
*
* Next we check for common naming conventions.
*/
if (!media.is3d()) {
String upperCaseFileName = file.getName().toUpperCase();
if (upperCaseFileName.startsWith("3DSBS")) {
LOGGER.debug("3D format SBS detected for " + file.getName());
media.setStereoscopy(file.getName().substring(2, 7));
} else if (upperCaseFileName.startsWith("3DOU")) {
LOGGER.debug("3D format OU detected for " + file.getName());
media.setStereoscopy(file.getName().substring(2, 6));
} else if (upperCaseFileName.startsWith("3DA")) {
LOGGER.debug("3D format Anaglyph detected for " + file.getName());
media.setStereoscopy(file.getName().substring(2, 6));
} else if (upperCaseFileName.matches(".*[\\s\\.](H-|H|HALF-|HALF.)SBS[\\s\\.].*")) {
LOGGER.debug("3D format HSBS detected for " + file.getName());
media.setStereoscopy("half side by side (left eye first)");
} else if (upperCaseFileName.matches(".*[\\s\\.](H-|H|HALF-|HALF.)(OU|TB)[\\s\\.].*")) {
LOGGER.debug("3D format HOU detected for " + file.getName());
media.setStereoscopy("half top-bottom (left eye first)");
} else if (upperCaseFileName.matches(".*[\\s\\.]SBS[\\s\\.].*")) {
if (media.getWidth() > 1920) {
LOGGER.debug("3D format SBS detected for " + file.getName());
media.setStereoscopy("side by side (left eye first)");
} else {
LOGGER.debug("3D format HSBS detected based on width for " + file.getName());
media.setStereoscopy("half side by side (left eye first)");
}
} else if (upperCaseFileName.matches(".*[\\s\\.](OU|TB)[\\s\\.].*")) {
if (media.getHeight() > 1080) {
LOGGER.debug("3D format OU detected for " + file.getName());
media.setStereoscopy("top-bottom (left eye first)");
} else {
LOGGER.debug("3D format HOU detected based on height for " + file.getName());
media.setStereoscopy("half top-bottom (left eye first)");
}
}
}
media.postParse(type, inputFile);
MI.Close();
if (media.getContainer() == null) {
media.setContainer(DLNAMediaLang.UND);
}
if (media.getCodecV() == null) {
media.setCodecV(DLNAMediaLang.UND);
}
media.setMediaparsed(true);
}
}
use of net.pms.util.UnknownFormatException in project UniversalMediaServer by UniversalMediaServer.
the class ImagesUtil method getJPEGExifIFDTagOffset.
/**
* Finds the offset of the given Exif tag. Only the first IFD is searched.
*
* @param tagId the tag id to look for.
* @param reader a {@link RandomAccessReader} with a JPEG image.
* @return the offset of the given tag's value, or -1 if not found.
* @throws UnknownFormatException if the content isn't a JPEG.
* @throws IOException if any error occurs while reading.
*/
public static int getJPEGExifIFDTagOffset(int tagId, RandomAccessReader reader) throws UnknownFormatException, IOException {
reader.setMotorolaByteOrder(true);
if (reader.getUInt16(0) != 0xFFD8) {
throw new UnknownFormatException("Content isn't JPEG");
}
byte SEGMENT_IDENTIFIER = (byte) 0xFF;
byte MARKER_EOI = (byte) 0xD9;
byte APP1 = (byte) 0xE1;
final String EXIF_SEGMENT_PREAMBLE = "Exif\0\0";
byte segmentIdentifier = reader.getInt8(2);
byte segmentType = reader.getInt8(3);
int pos = 4;
while (segmentIdentifier != SEGMENT_IDENTIFIER || segmentType != APP1 && segmentType != MARKER_EOI || segmentType == APP1 && !EXIF_SEGMENT_PREAMBLE.equals(new String(reader.getBytes(pos + 2, EXIF_SEGMENT_PREAMBLE.length()), 0, EXIF_SEGMENT_PREAMBLE.length(), StandardCharsets.US_ASCII))) {
segmentIdentifier = segmentType;
segmentType = reader.getInt8(pos++);
}
if (segmentType == MARKER_EOI) {
// Reached the end of the image without finding an Exif segment
return -1;
}
int segmentLength = reader.getUInt16(pos) - 2;
pos += 2 + EXIF_SEGMENT_PREAMBLE.length();
if (segmentLength < EXIF_SEGMENT_PREAMBLE.length()) {
throw new ParseException("Exif segment is too small");
}
int exifHeaderOffset = pos;
short byteOrderIdentifier = reader.getInt16(pos);
// Skip TIFF marker
pos += 4;
if (byteOrderIdentifier == 0x4d4d) {
// "MM"
reader.setMotorolaByteOrder(true);
} else if (byteOrderIdentifier == 0x4949) {
// "II"
reader.setMotorolaByteOrder(false);
} else {
throw new ParseException("Can't determine Exif endianness from: 0x" + Integer.toHexString(byteOrderIdentifier));
}
pos = reader.getInt32(pos) + exifHeaderOffset;
int tagCount = reader.getUInt16(pos);
for (int tagNumber = 0; tagNumber < tagCount; tagNumber++) {
int tagOffset = pos + 2 + (12 * tagNumber);
int curTagId = reader.getUInt16(tagOffset);
if (curTagId == tagId) {
// tag found
return tagOffset + 8;
}
}
return -1;
}
use of net.pms.util.UnknownFormatException in project UniversalMediaServer by UniversalMediaServer.
the class ImagesUtil method transcodeImage.
/**
* Converts and scales an image in one operation. Scaling can be with or
* without padding. Preserves aspect ratio and rotates/flips the image
* according to Exif orientation. Format support is limited to that of
* {@link ImageIO}. Only one of the three input arguments may be used in any
* given call. Note that {@code outputProfile} overrides
* {@code outputFormat}.
* <p>
* <b> This method consumes and closes {@code inputStream}. </b>
*
* @param inputByteArray the source image in a supported format.
* @param inputImage the source {@link Image}.
* @param inputStream the source image in a supported format.
* @param width the new width or 0 to disable scaling.
* @param height the new height or 0 to disable scaling.
* @param scaleType the {@link ScaleType} to use when scaling.
* @param outputFormat the {@link ImageFormat} to convert to or
* {@link ImageFormat#SOURCE} to preserve source format.
* Overridden by {@code outputProfile}.
* @param outputProfile the {@link DLNAImageProfile} to convert to. This
* overrides {@code outputFormat}.
* @param dlnaCompliant whether or not the output image should be restricted
* to DLNA compliance. This also means that the output can be
* safely cast to {@link DLNAImage}.
* @param dlnaThumbnail whether or not the output image should be restricted
* to DLNA thumbnail compliance. This also means that the output
* can be safely cast to {@link DLNAThumbnail}.
* @param padToSize whether padding should be used if source aspect doesn't
* match target aspect.
* @return The scaled and/or converted image or {@code null} if the source
* is {@code null}.
* @throws IOException if the operation fails.
*/
protected static Image transcodeImage(byte[] inputByteArray, Image inputImage, InputStream inputStream, int width, int height, ScaleType scaleType, ImageFormat outputFormat, DLNAImageProfile outputProfile, boolean dlnaCompliant, boolean dlnaThumbnail, boolean padToSize) throws IOException {
if (inputByteArray == null && inputStream == null && inputImage == null) {
return null;
}
if ((inputByteArray != null & inputImage != null) || (inputByteArray != null & inputStream != null) || (inputImage != null & inputStream != null)) {
throw new IllegalArgumentException("Use either inputByteArray, inputImage or inputStream");
}
boolean trace = LOGGER.isTraceEnabled();
if (trace) {
StringBuilder sb = new StringBuilder();
if (scaleType != null) {
sb.append("ScaleType = ").append(scaleType);
}
if (width > 0 && height > 0) {
if (sb.length() > 0) {
sb.append(", ");
}
sb.append("Width = ").append(width).append(", Height = ").append(height);
}
if (sb.length() > 0) {
sb.append(", ");
}
sb.append("PadToSize = ").append(padToSize ? "True" : "False");
LOGGER.trace("Converting {} image source to {} format and type {} using the following parameters: {}", inputByteArray != null ? "byte array" : inputImage != null ? "Image" : "input stream", outputProfile != null ? outputProfile : outputFormat, dlnaThumbnail ? "DLNAThumbnail" : dlnaCompliant ? "DLNAImage" : "Image", sb);
}
ImageIO.setUseCache(false);
dlnaCompliant = dlnaCompliant || dlnaThumbnail;
if (inputImage != null) {
inputByteArray = inputImage.getBytes(false);
} else if (inputStream != null) {
inputByteArray = ImagesUtil.toByteArray(inputStream);
}
// outputProfile overrides outputFormat
if (outputProfile != null) {
if (dlnaThumbnail && outputProfile.equals(DLNAImageProfile.GIF_LRG)) {
outputProfile = DLNAImageProfile.JPEG_LRG;
}
// Default to correct ScaleType for the profile
if (scaleType == null) {
if (DLNAImageProfile.JPEG_RES_H_V.equals(outputProfile)) {
scaleType = ScaleType.EXACT;
} else {
scaleType = ScaleType.MAX;
}
}
outputFormat = ImageFormat.toImageFormat(outputProfile);
width = width > 0 ? width : outputProfile.getMaxWidth();
height = height > 0 ? height : outputProfile.getMaxHeight();
} else if (scaleType == null) {
scaleType = ScaleType.MAX;
}
ImageReaderResult inputResult;
try {
inputResult = ImageIOTools.read(new ByteArrayInputStream(inputByteArray));
} catch (IIOException e) {
throw new UnknownFormatException("Unable to read image format", e);
}
if (inputResult.bufferedImage == null || inputResult.imageFormat == null) {
// ImageIO doesn't support the image format
throw new UnknownFormatException("Failed to transform image because the source format is unknown");
}
if (outputFormat == null || outputFormat == ImageFormat.SOURCE) {
outputFormat = inputResult.imageFormat;
}
BufferedImage bufferedImage = inputResult.bufferedImage;
boolean reencode = false;
if (outputProfile == null && dlnaCompliant) {
// if the source image has alpha and JPEG if not.
switch(outputFormat) {
case GIF:
if (dlnaThumbnail) {
outputFormat = ImageFormat.JPEG;
}
break;
case JPEG:
case PNG:
break;
default:
if (bufferedImage.getColorModel().hasAlpha()) {
outputFormat = ImageFormat.PNG;
} else {
outputFormat = ImageFormat.JPEG;
}
}
}
Metadata metadata = null;
ExifOrientation orientation;
if (inputImage != null && inputImage.getImageInfo() != null) {
orientation = inputImage.getImageInfo().getExifOrientation();
} else {
try {
metadata = getMetadata(inputByteArray, inputResult.imageFormat);
} catch (IOException | ImageProcessingException e) {
LOGGER.error("Failed to read input image metadata: {}", e.getMessage());
LOGGER.trace("", e);
metadata = new Metadata();
}
if (metadata == null) {
metadata = new Metadata();
}
orientation = parseExifOrientation(metadata);
}
if (orientation != ExifOrientation.TOP_LEFT) {
// Rotate the image before doing all the other checks
BufferedImage oldBufferedImage = bufferedImage;
bufferedImage = Thumbnails.of(bufferedImage).scale(1.0d).addFilter(ExifFilterUtils.getFilterForOrientation(orientation.getThumbnailatorOrientation())).asBufferedImage();
oldBufferedImage.flush();
// Re-parse the metadata after rotation as these are newly generated.
ByteArrayOutputStream tmpOutputStream = new ByteArrayOutputStream(inputByteArray.length);
Thumbnails.of(bufferedImage).scale(1.0d).outputFormat(outputFormat.toString()).toOutputStream(tmpOutputStream);
try {
metadata = getMetadata(tmpOutputStream.toByteArray(), outputFormat);
} catch (IOException | ImageProcessingException e) {
LOGGER.debug("Failed to read rotated image metadata: {}", e.getMessage());
LOGGER.trace("", e);
metadata = new Metadata();
}
if (metadata == null) {
metadata = new Metadata();
}
reencode = true;
}
if (outputProfile == null && dlnaCompliant) {
// Set a suitable output profile.
if (width < 1 || height < 1) {
outputProfile = DLNAImageProfile.getClosestDLNAProfile(bufferedImage.getWidth(), bufferedImage.getHeight(), outputFormat, true);
width = outputProfile.getMaxWidth();
height = outputProfile.getMaxHeight();
} else {
outputProfile = DLNAImageProfile.getClosestDLNAProfile(calculateScaledResolution(bufferedImage.getWidth(), bufferedImage.getHeight(), scaleType, width, height), outputFormat, true);
width = Math.min(width, outputProfile.getMaxWidth());
height = Math.min(height, outputProfile.getMaxHeight());
}
if (DLNAImageProfile.JPEG_RES_H_V.equals(outputProfile)) {
scaleType = ScaleType.EXACT;
}
}
boolean convertColors = bufferedImage.getType() == BufferedImageType.TYPE_CUSTOM.getTypeId() || bufferedImage.getType() == BufferedImageType.TYPE_BYTE_BINARY.getTypeId() || bufferedImage.getColorModel().getColorSpace().getType() != ColorSpaceType.TYPE_RGB.getTypeId();
// Impose DLNA format restrictions
if (!reencode && outputFormat == inputResult.imageFormat && outputProfile != null) {
DLNAComplianceResult complianceResult;
switch(outputFormat) {
case GIF:
case JPEG:
case PNG:
ImageInfo imageInfo;
// metadata is only null at this stage if inputImage != null and no rotation was necessary
if (metadata == null) {
imageInfo = inputImage.getImageInfo();
}
imageInfo = ImageInfo.create(bufferedImage.getWidth(), bufferedImage.getHeight(), inputResult.imageFormat, ImageInfo.SIZE_UNKNOWN, bufferedImage.getColorModel(), metadata, false, true);
complianceResult = DLNAImageProfile.checkCompliance(imageInfo, outputProfile);
break;
default:
throw new IllegalStateException("Unexpected image format: " + outputFormat);
}
reencode = reencode || convertColors || !complianceResult.isFormatCorrect() || !complianceResult.isColorsCorrect();
;
if (!complianceResult.isResolutionCorrect()) {
width = width > 0 && complianceResult.getMaxWidth() > 0 ? Math.min(width, complianceResult.getMaxWidth()) : width > 0 ? width : complianceResult.getMaxWidth();
height = height > 0 && complianceResult.getMaxHeight() > 0 ? Math.min(height, complianceResult.getMaxHeight()) : height > 0 ? height : complianceResult.getMaxHeight();
}
if (trace) {
if (complianceResult.isAllCorrect()) {
LOGGER.trace("Image conversion DLNA compliance check: The source image is compliant");
} else {
LOGGER.trace("Image conversion DLNA compliance check for {}: " + "The source image colors are {}, format is {} and resolution ({} x {}) is {}.\nFailures:\n {}", outputProfile, complianceResult.isColorsCorrect() ? "compliant" : "non-compliant", complianceResult.isFormatCorrect() ? "compliant" : "non-compliant", bufferedImage.getWidth(), bufferedImage.getHeight(), complianceResult.isResolutionCorrect() ? "compliant" : "non-compliant", StringUtils.join(complianceResult.getFailures(), "\n "));
}
}
}
if (convertColors) {
// Preserve alpha channel if the output format supports it
BufferedImageType outputImageType;
if ((outputFormat == ImageFormat.PNG || outputFormat == ImageFormat.PSD) && bufferedImage.getColorModel().getNumComponents() == 4) {
outputImageType = bufferedImage.isAlphaPremultiplied() ? BufferedImageType.TYPE_4BYTE_ABGR_PRE : BufferedImageType.TYPE_4BYTE_ABGR;
} else {
outputImageType = BufferedImageType.TYPE_3BYTE_BGR;
}
BufferedImage convertedImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), outputImageType.getTypeId());
ColorConvertOp colorConvertOp = new ColorConvertOp(null);
colorConvertOp.filter(bufferedImage, convertedImage);
bufferedImage.flush();
bufferedImage = convertedImage;
reencode = true;
}
if (width < 1 || height < 1 || (scaleType == ScaleType.MAX && bufferedImage.getWidth() <= width && bufferedImage.getHeight() <= height) || (scaleType == ScaleType.EXACT && bufferedImage.getWidth() == width && bufferedImage.getHeight() == height)) {
// No resize, just convert
if (!reencode && inputResult.imageFormat == outputFormat) {
// Nothing to do, just return source
// metadata is only null at this stage if inputImage != null
Image result;
if (dlnaThumbnail) {
result = metadata == null ? new DLNAThumbnail(inputImage, outputProfile, false) : new DLNAThumbnail(inputByteArray, outputFormat, bufferedImage, metadata, outputProfile, false);
} else if (dlnaCompliant) {
result = metadata == null ? new DLNAImage(inputImage, outputProfile, false) : new DLNAImage(inputByteArray, outputFormat, bufferedImage, metadata, outputProfile, false);
} else {
result = metadata == null ? new Image(inputImage, false) : new Image(inputByteArray, outputFormat, bufferedImage, metadata, false);
}
bufferedImage.flush();
if (trace) {
LOGGER.trace("No conversion is needed, returning source image with width = {}, height = {} and output {}.", bufferedImage.getWidth(), bufferedImage.getHeight(), dlnaCompliant && outputProfile != null ? "profile: " + outputProfile : "format: " + outputFormat);
}
return result;
} else if (!reencode) {
// Convert format
reencode = true;
}
} else {
boolean force = DLNAImageProfile.JPEG_RES_H_V.equals(outputProfile);
BufferedImage oldBufferedImage = bufferedImage;
if (padToSize && force) {
bufferedImage = Thumbnails.of(bufferedImage).forceSize(width, height).addFilter(new Canvas(width, height, Positions.CENTER, Color.BLACK)).asBufferedImage();
} else if (padToSize) {
bufferedImage = Thumbnails.of(bufferedImage).size(width, height).addFilter(new Canvas(width, height, Positions.CENTER, Color.BLACK)).asBufferedImage();
} else if (force) {
bufferedImage = Thumbnails.of(bufferedImage).forceSize(width, height).asBufferedImage();
} else {
bufferedImage = Thumbnails.of(bufferedImage).size(width, height).asBufferedImage();
}
oldBufferedImage.flush();
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Thumbnails.of(bufferedImage).scale(1.0d).outputFormat(outputFormat.toString()).outputQuality(1.0f).toOutputStream(outputStream);
byte[] outputByteArray = outputStream.toByteArray();
Image result;
if (dlnaThumbnail) {
result = new DLNAThumbnail(outputByteArray, bufferedImage.getWidth(), bufferedImage.getHeight(), outputFormat, null, null, outputProfile, false);
} else if (dlnaCompliant) {
result = new DLNAImage(outputByteArray, bufferedImage.getWidth(), bufferedImage.getHeight(), outputFormat, null, null, outputProfile, false);
} else {
result = new Image(outputByteArray, bufferedImage.getWidth(), bufferedImage.getHeight(), outputFormat, null, null, true, false);
}
if (trace) {
StringBuilder sb = new StringBuilder();
sb.append("Convert colors = ").append(convertColors ? "True" : "False").append(", Re-encode = ").append(reencode ? "True" : "False");
LOGGER.trace("Finished converting {} {} image{}. Output image resolution: {}, {}. Flags: {}", inputResult.width + "×" + inputResult.height, inputResult.imageFormat, orientation != ExifOrientation.TOP_LEFT ? " with orientation " + orientation : "", bufferedImage.getWidth() + "×" + bufferedImage.getHeight(), dlnaCompliant && outputProfile != null ? "profile: " + outputProfile : "format: " + outputFormat, sb);
}
bufferedImage.flush();
return result;
}
use of net.pms.util.UnknownFormatException in project UniversalMediaServer by UniversalMediaServer.
the class ImageIOTools method readImageInfo.
/**
* Tries to gather the data needed to populate a {@link ImageInfo} instance
* describing the input image.
*
* <p>
* This method does not close {@code inputStream}.
*
* @param inputStream the image whose information to gather.
* @param size the size of the image in bytes or
* {@link ImageInfo#SIZE_UNKNOWN} if it can't be determined.
* @param metadata the {@link Metadata} instance to embed in the resulting
* {@link ImageInfo} instance.
* @param applyExifOrientation whether or not Exif orientation should be
* compensated for when setting width and height. This will also
* reset the Exif orientation information. <b>Changes will be
* applied to the {@code metadata} argument instance</b>.
* @return An {@link ImageInfo} instance describing the input image.
* @throws UnknownFormatException if the format could not be determined.
* @throws IOException if an IO error occurred.
*/
public static ImageInfo readImageInfo(InputStream inputStream, long size, Metadata metadata, boolean applyExifOrientation) throws IOException {
if (inputStream == null) {
throw new IllegalArgumentException("input == null!");
}
try (ImageInputStream stream = createImageInputStream(inputStream)) {
Iterator<?> iter = ImageIO.getImageReaders(stream);
if (!iter.hasNext()) {
throw new UnknownFormatException("Unable to find a suitable image reader");
}
ImageReader reader = (ImageReader) iter.next();
try {
int width = -1;
int height = -1;
ImageFormat format = ImageFormat.toImageFormat(reader.getFormatName());
if (format == null) {
throw new UnknownFormatException("Unable to determine image format");
}
ColorModel colorModel = null;
try {
reader.setInput(stream, true, true);
Iterator<ImageTypeSpecifier> iterator = reader.getImageTypes(0);
if (iterator.hasNext()) {
colorModel = iterator.next().getColorModel();
}
width = reader.getWidth(0);
height = reader.getHeight(0);
} catch (RuntimeException e) {
throw new ImageIORuntimeException("Error reading image information: " + e.getMessage(), e);
}
boolean imageIOSupport;
if (format == ImageFormat.TIFF) {
// but fails when it actually tries, so we have to test it.
try {
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceRegion(new Rectangle(1, 1));
reader.read(0, param);
imageIOSupport = true;
} catch (Exception e) {
// Catch anything here, we simply want to test if it fails.
imageIOSupport = false;
}
} else {
imageIOSupport = true;
}
ImageInfo imageInfo = ImageInfo.create(width, height, format, size, colorModel, metadata, applyExifOrientation, imageIOSupport);
return imageInfo;
} finally {
reader.dispose();
}
}
}
use of net.pms.util.UnknownFormatException in project UniversalMediaServer by UniversalMediaServer.
the class ImageIOTools method read.
/**
* A copy of {@link ImageIO#read(ImageInputStream)} that returns
* {@link ImageReaderResult} instead of {@link BufferedImage}. This lets
* information about the detected format be retained.
*
* <b>
* This method consumes and closes {@code stream}.
* </b>
*
* @param stream an {@link ImageInputStream} to read from.
*
* @see ImageIO#read(ImageInputStream)
*/
public static ImageReaderResult read(ImageInputStream stream) throws IOException {
if (stream == null) {
throw new IllegalArgumentException("stream == null!");
}
try {
Iterator<?> iter = ImageIO.getImageReaders(stream);
if (!iter.hasNext()) {
throw new UnknownFormatException("Unable to find a suitable image reader");
}
ImageFormat inputFormat = null;
BufferedImage bufferedImage = null;
ImageReader reader = (ImageReader) iter.next();
try {
// Store the parsing result
inputFormat = ImageFormat.toImageFormat(reader.getFormatName());
reader.setInput(stream, true, true);
bufferedImage = reader.read(0, reader.getDefaultReadParam());
} finally {
reader.dispose();
}
return bufferedImage != null ? new ImageReaderResult(bufferedImage, inputFormat) : null;
} catch (RuntimeException e) {
throw new ImageIORuntimeException("An error occurred while trying to read image: " + e.getMessage(), e);
} finally {
stream.close();
}
}
Aggregations