Search in sources :

Example 1 with ParseException

use of net.pms.util.ParseException 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;
}
Also used : UnknownFormatException(net.pms.util.UnknownFormatException) ParseException(net.pms.util.ParseException)

Example 2 with ParseException

use of net.pms.util.ParseException in project UniversalMediaServer by UniversalMediaServer.

the class RAW method parse.

@Override
public void parse(DLNAMediaInfo media, InputFile file, int type, RendererConfiguration renderer) {
    boolean trace = LOGGER.isTraceEnabled();
    if (media == null || file == null || file.getFile() == null) {
        // Parsing is impossible
        if (trace) {
            if (file != null && file.getFile() != null) {
                LOGGER.trace("Not parsing RAW file \"{}\" because media is null", file.getFile().getName());
            } else {
                LOGGER.error("Not parsing RAW file because file is null");
            }
        }
        return;
    }
    PmsConfiguration configuration = PMS.getConfiguration(renderer);
    try {
        // Only parse using DCRaw if it is enabled
        DCRaw dcraw = (DCRaw) PlayerFactory.getEnabledPlayer(DCRaw.class, this);
        if (dcraw != null) {
            if (trace) {
                LOGGER.trace("Parsing RAW image \"{}\" with DCRaw", file.getFile().getName());
            }
            dcraw.parse(media, file.getFile());
            media.setCodecV(FormatConfiguration.RAW);
            media.setContainer(FormatConfiguration.RAW);
            ImageInfo imageInfo = null;
            Metadata metadata = null;
            FileType fileType = null;
            try (BufferedInputStream inputStream = new BufferedInputStream(Files.newInputStream(file.getFile().toPath()))) {
                fileType = FileTypeDetector.detectFileType(inputStream);
                metadata = ImagesUtil.getMetadata(inputStream, fileType);
            } catch (IOException e) {
                metadata = new Metadata();
                LOGGER.debug("Error reading \"{}\": {}", file.getFile().getAbsolutePath(), e.getMessage());
                LOGGER.trace("", e);
            } catch (ImageProcessingException e) {
                metadata = new Metadata();
                LOGGER.debug("Error parsing {} metadata for \"{}\": {}", fileType.toString().toUpperCase(Locale.ROOT), file.getFile().getAbsolutePath(), e.getMessage());
                LOGGER.trace("", e);
            }
            if (fileType == FileType.Arw && !ImagesUtil.isARW(metadata)) {
                fileType = FileType.Tiff;
            }
            ImageFormat format = ImageFormat.toImageFormat(fileType);
            if (format == null || format == ImageFormat.TIFF) {
                format = ImageFormat.toImageFormat(metadata);
                if (format == null || format == ImageFormat.TIFF) {
                    format = ImageFormat.RAW;
                }
            }
            try {
                imageInfo = ImageInfo.create(media.getWidth(), media.getHeight(), metadata, format, file.getSize(), true, false);
                if (trace) {
                    LOGGER.trace("Parsing of RAW image \"{}\" completed: {}", file.getFile().getName(), imageInfo);
                }
            } catch (ParseException e) {
                LOGGER.warn("Unable to parse \"{}\": {}", file.getFile().getAbsolutePath(), e.getMessage());
                LOGGER.trace("", e);
            }
            media.setImageInfo(imageInfo);
            if (media.getWidth() > 0 && media.getHeight() > 0 && configuration.getImageThumbnailsEnabled()) {
                byte[] image = new DCRaw().getThumbnail(null, file.getFile().getAbsolutePath(), imageInfo);
                media.setThumb(DLNAThumbnail.toThumbnail(image, 320, 320, ScaleType.MAX, ImageFormat.JPEG, false));
            }
        } else {
            if (trace) {
                LOGGER.trace("Parsing RAW image \"{}\" as a regular image because DCRaw is disabled", file.getFile().getName());
            }
            ImagesUtil.parseImage(file.getFile(), media);
        }
        media.setSize(file.getSize());
        media.setImageCount(1);
        media.postParse(type, file);
        media.setMediaparsed(true);
    } catch (IOException e) {
        LOGGER.error("Error parsing RAW file \"{}\": {}", file.getFile().getAbsolutePath(), e.getMessage());
        LOGGER.trace("", e);
    }
}
Also used : ImageProcessingException(com.drew.imaging.ImageProcessingException) DCRaw(net.pms.encoders.DCRaw) PmsConfiguration(net.pms.configuration.PmsConfiguration) FileType(com.drew.imaging.FileType) BufferedInputStream(java.io.BufferedInputStream) Metadata(com.drew.metadata.Metadata) IOException(java.io.IOException) ParseException(net.pms.util.ParseException) ImageInfo(net.pms.image.ImageInfo) ImageFormat(net.pms.image.ImageFormat)

Example 3 with ParseException

use of net.pms.util.ParseException in project UniversalMediaServer by UniversalMediaServer.

the class ImagesUtil method parseImage.

/**
 * Parses an image file and stores the results in the given
 * {@link DLNAMediaInfo}. Parsing is performed using both
 * <a href=https://github.com/drewnoakes/metadata-extractor>Metadata Extractor</a>
 * and {@link ImageIO}. While Metadata Extractor offers more detailed
 * information, {@link ImageIO} offers information that is convenient for
 * image transformation with {@link ImageIO}. Parsing will be performed if
 * just one of the two methods produces results, but some details will be
 * missing if either one failed.
 * <p><b>
 * This method consumes and closes {@code inputStream}.
 * </b>
 * @param file the {@link File} to parse.
 * @param media the {@link DLNAMediaInfo} instance to store the parsing
 *              results to.
 * @throws IOException if an IO error occurs or no information can be parsed.
 */
public static void parseImage(File file, DLNAMediaInfo media) throws IOException {
    // 1 MB
    final int MAX_BUFFER = 1048576;
    if (file == null) {
        throw new IllegalArgumentException("parseImage: file cannot be null");
    }
    if (media == null) {
        throw new IllegalArgumentException("parseImage: media cannot be null");
    }
    boolean trace = LOGGER.isTraceEnabled();
    if (trace) {
        LOGGER.trace("Parsing image file \"{}\"", file.getAbsolutePath());
    }
    long size = file.length();
    ResettableInputStream inputStream = new ResettableInputStream(Files.newInputStream(file.toPath()), MAX_BUFFER);
    try {
        Metadata metadata = null;
        FileType fileType = null;
        try {
            fileType = FileTypeDetector.detectFileType(inputStream);
            metadata = getMetadata(inputStream, fileType);
        } catch (IOException e) {
            metadata = new Metadata();
            LOGGER.debug("Error reading \"{}\": {}", file.getAbsolutePath(), e.getMessage());
            LOGGER.trace("", e);
        } catch (ImageProcessingException e) {
            metadata = new Metadata();
            LOGGER.debug("Error parsing {} metadata for \"{}\": {}", fileType.toString().toUpperCase(Locale.ROOT), file.getAbsolutePath(), e.getMessage());
            LOGGER.trace("", e);
        }
        ImageFormat format = ImageFormat.toImageFormat(fileType);
        if (format == null || format == ImageFormat.TIFF) {
            ImageFormat tmpformat = ImageFormat.toImageFormat(metadata);
            if (tmpformat != null) {
                format = tmpformat;
            }
        }
        if (inputStream.isFullResetAvailable()) {
            inputStream.fullReset();
        } else {
            // If we can't reset it, close it and create a new
            inputStream.close();
            inputStream = new ResettableInputStream(Files.newInputStream(file.toPath()), MAX_BUFFER);
        }
        ImageInfo imageInfo = null;
        try {
            imageInfo = ImageIOTools.readImageInfo(inputStream, size, metadata, false);
        } catch (UnknownFormatException | IIOException | ParseException e) {
            if (format == null) {
                throw new UnknownFormatException("Unable to recognize image format for \"" + file.getAbsolutePath() + "\" - parsing failed", e);
            }
            LOGGER.debug("Unable to parse \"{}\" with ImageIO because the format is unsupported, image information will be limited", file.getAbsolutePath());
            LOGGER.trace("ImageIO parse failure reason: {}", e.getMessage());
            // Gather basic information from the data we have
            if (metadata != null) {
                try {
                    imageInfo = ImageInfo.create(metadata, format, size, true, true);
                } catch (ParseException pe) {
                    LOGGER.debug("Unable to parse metadata for \"{}\": {}", file.getAbsolutePath(), pe.getMessage());
                    LOGGER.trace("", pe);
                }
            }
        }
        if (imageInfo == null && format == null) {
            throw new ParseException("Parsing of \"" + file.getAbsolutePath() + "\" failed");
        }
        if (format == null) {
            format = imageInfo.getFormat();
        } else if (imageInfo != null && imageInfo.getFormat() != null && format != imageInfo.getFormat()) {
            if (imageInfo.getFormat() == ImageFormat.TIFF && format.isRaw()) {
                if (format == ImageFormat.ARW && !isARW(metadata)) {
                    // XXX Remove this if https://github.com/drewnoakes/metadata-extractor/issues/217 is fixed
                    // Metadata extractor misidentifies some Photoshop created TIFFs for ARW, correct it
                    format = ImageFormat.toImageFormat(metadata);
                    if (format == null) {
                        format = ImageFormat.TIFF;
                    }
                    LOGGER.trace("Correcting misidentified image format ARW to {} for \"{}\"", format, file.getAbsolutePath());
                } else {
                    /*
						 * ImageIO recognizes many RAW formats as TIFF because
						 * of their close relationship let's treat them as what
						 * they really are.
						 */
                    imageInfo = ImageInfo.create(imageInfo.getWidth(), imageInfo.getHeight(), format, size, imageInfo.getBitDepth(), imageInfo.getNumComponents(), imageInfo.getColorSpace(), imageInfo.getColorSpaceType(), metadata, false, imageInfo.isImageIOSupported());
                    LOGGER.trace("Correcting misidentified image format TIFF to {} for \"{}\"", format.toString(), file.getAbsolutePath());
                }
            } else {
                LOGGER.debug("Image parsing for \"{}\" was inconclusive, metadata parsing " + "detected {} format while ImageIO detected {}. Choosing {}.", file.getAbsolutePath(), format, imageInfo.getFormat(), imageInfo.getFormat());
                format = imageInfo.getFormat();
            }
        }
        media.setImageInfo(imageInfo);
        if (format != null) {
            media.setCodecV(format.toFormatConfiguration());
            media.setContainer(format.toFormatConfiguration());
        }
        if (trace) {
            LOGGER.trace("Parsing of image \"{}\" completed", file.getName());
        }
    } finally {
        inputStream.close();
    }
}
Also used : ImageProcessingException(com.drew.imaging.ImageProcessingException) Metadata(com.drew.metadata.Metadata) IIOException(javax.imageio.IIOException) IIOException(javax.imageio.IIOException) FileType(com.drew.imaging.FileType) UnknownFormatException(net.pms.util.UnknownFormatException) ParseException(net.pms.util.ParseException) ResettableInputStream(net.pms.util.ResettableInputStream)

Example 4 with ParseException

use of net.pms.util.ParseException in project UniversalMediaServer by UniversalMediaServer.

the class PNGInfo method parseMetadata.

@Override
protected void parseMetadata(Metadata metadata) throws ParseException {
    if (metadata == null) {
        return;
    }
    for (Directory directory : metadata.getDirectories()) {
        if (directory instanceof PngDirectory && PngChunkType.IHDR.equals(((PngDirectory) directory).getPngChunkType())) {
            parsedInfo.format = ImageFormat.PNG;
            if (((PngDirectory) directory).containsTag(PngDirectory.TAG_IMAGE_WIDTH) && ((PngDirectory) directory).containsTag(PngDirectory.TAG_IMAGE_HEIGHT)) {
                parsedInfo.width = ((PngDirectory) directory).getInteger(PngDirectory.TAG_IMAGE_WIDTH);
                parsedInfo.height = ((PngDirectory) directory).getInteger(PngDirectory.TAG_IMAGE_HEIGHT);
            }
            if (((PngDirectory) directory).containsTag(PngDirectory.TAG_BITS_PER_SAMPLE)) {
                parsedInfo.bitDepth = ((PngDirectory) directory).getInteger(PngDirectory.TAG_BITS_PER_SAMPLE);
            }
            if (((PngDirectory) directory).containsTag(PngDirectory.TAG_INTERLACE_METHOD)) {
                Integer i = ((PngDirectory) directory).getInteger(PngDirectory.TAG_INTERLACE_METHOD);
                if (i != null) {
                    ((PNGParseInfo) parsedInfo).interlaceMethod = InterlaceMethod.typeOf(i);
                }
            }
            if (((PngDirectory) directory).containsTag(PngDirectory.TAG_COLOR_TYPE)) {
                Integer i = ((PngDirectory) directory).getInteger(PngDirectory.TAG_COLOR_TYPE);
                if (i != null) {
                    ((PNGParseInfo) parsedInfo).colorType = PngColorType.fromNumericValue(i);
                    switch(((PNGParseInfo) parsedInfo).colorType) {
                        case // Grayscale without alpha
                        Greyscale:
                            parsedInfo.numComponents = 1;
                            parsedInfo.colorSpaceType = ColorSpaceType.TYPE_GRAY;
                            break;
                        case // RGB without alpha
                        TrueColor:
                            parsedInfo.numComponents = 3;
                            parsedInfo.colorSpaceType = ColorSpaceType.TYPE_RGB;
                            break;
                        case // Palette index
                        IndexedColor:
                            parsedInfo.numComponents = 3;
                            parsedInfo.colorSpaceType = ColorSpaceType.TYPE_RGB;
                            break;
                        case // Grayscale with alpha
                        GreyscaleWithAlpha:
                            parsedInfo.numComponents = 2;
                            parsedInfo.colorSpaceType = ColorSpaceType.TYPE_GRAY;
                            break;
                        case // RGB with alpha
                        TrueColorWithAlpha:
                            parsedInfo.numComponents = 4;
                            parsedInfo.colorSpaceType = ColorSpaceType.TYPE_RGB;
                            break;
                        default:
                    }
                }
            }
        }
        if (directory instanceof PngDirectory && PngChunkType.tRNS.equals(((PngDirectory) directory).getPngChunkType())) {
            ((PNGParseInfo) parsedInfo).hasTransparencyChunk = true;
            if (((PNGParseInfo) parsedInfo).colorType == null || ((PNGParseInfo) parsedInfo).numComponents == null) {
                throw new ParseException("PNG parsing failed with ancillary chunk tRNS appearing before critical chunk IHDR");
            }
            if (((PNGParseInfo) parsedInfo).colorType == PngColorType.GreyscaleWithAlpha || ((PNGParseInfo) parsedInfo).colorType == PngColorType.TrueColorWithAlpha) {
                throw new ParseException(String.format("PNG parsing failed with illegal combination of %s color type and tRNS transparancy chunk", ((PNGParseInfo) parsedInfo).colorType));
            }
            parsedInfo.numComponents++;
        }
        if (directory instanceof PngDirectory && PngChunkType.sBIT.equals(((PngDirectory) directory).getPngChunkType())) {
            ((PNGParseInfo) parsedInfo).isModifiedBitDepth = true;
        }
    }
}
Also used : PngDirectory(com.drew.metadata.png.PngDirectory) ParseException(net.pms.util.ParseException) Directory(com.drew.metadata.Directory) PngDirectory(com.drew.metadata.png.PngDirectory)

Example 5 with ParseException

use of net.pms.util.ParseException in project UniversalMediaServer by UniversalMediaServer.

the class GIFInfo method parseMetadata.

@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;
            }
        }
    }
}
Also used : GifControlDirectory(com.drew.metadata.gif.GifControlDirectory) ParseException(net.pms.util.ParseException) GifHeaderDirectory(com.drew.metadata.gif.GifHeaderDirectory) Directory(com.drew.metadata.Directory) GifControlDirectory(com.drew.metadata.gif.GifControlDirectory) GifHeaderDirectory(com.drew.metadata.gif.GifHeaderDirectory)

Aggregations

ParseException (net.pms.util.ParseException)5 FileType (com.drew.imaging.FileType)2 ImageProcessingException (com.drew.imaging.ImageProcessingException)2 Directory (com.drew.metadata.Directory)2 Metadata (com.drew.metadata.Metadata)2 UnknownFormatException (net.pms.util.UnknownFormatException)2 GifControlDirectory (com.drew.metadata.gif.GifControlDirectory)1 GifHeaderDirectory (com.drew.metadata.gif.GifHeaderDirectory)1 PngDirectory (com.drew.metadata.png.PngDirectory)1 BufferedInputStream (java.io.BufferedInputStream)1 IOException (java.io.IOException)1 IIOException (javax.imageio.IIOException)1 PmsConfiguration (net.pms.configuration.PmsConfiguration)1 DCRaw (net.pms.encoders.DCRaw)1 ImageFormat (net.pms.image.ImageFormat)1 ImageInfo (net.pms.image.ImageInfo)1 ResettableInputStream (net.pms.util.ResettableInputStream)1