Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial port of RandomAccessStream/ReaderInfo #361

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Source/com/drew/imaging/FileType.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public enum FileType
Riff("RIFF", "Resource Interchange File Format", null),
Wav("WAV", "Waveform Audio File Format", "audio/vnd.wave", "wav", "wave"),
Avi("AVI", "Audio Video Interleaved", "video/vnd.avi", "avi"),
Netpbm("Netpbm", "Netpbm", "image/x-portable-graymap", "pbm", "ppm"),
WebP("WebP", "WebP", "image/webp", "webp"),
Mov("MOV", "QuickTime Movie", "video/quicktime", "mov", "qt"),
Mp4("MP4", "MPEG-4 Part 14", "video/mp4", "mp4", "m4a", "m4p", "m4b", "m4r", "m4v"),
Expand Down
26 changes: 15 additions & 11 deletions Source/com/drew/imaging/FileTypeDetector.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@

import com.drew.lang.ByteTrie;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.ReaderInfo;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.util.HashMap;

/**
* Examines the a file's first bytes and estimates the file's type.
* Examines a file's first bytes and estimates the file's type.
*/
public class FileTypeDetector
{
Expand Down Expand Up @@ -56,6 +56,13 @@ public class FileTypeDetector
_root.addPath(FileType.Gif, "GIF87a".getBytes());
_root.addPath(FileType.Gif, "GIF89a".getBytes());
_root.addPath(FileType.Ico, new byte[]{0x00, 0x00, 0x01, 0x00});
_root.addPath(FileType.Netpbm, "P1".getBytes()); // ASCII B
_root.addPath(FileType.Netpbm, "P2".getBytes()); // ASCII greysca
_root.addPath(FileType.Netpbm, "P3".getBytes()); // ASCII R
_root.addPath(FileType.Netpbm, "P4".getBytes()); // RAW B
_root.addPath(FileType.Netpbm, "P5".getBytes()); // RAW greysca
_root.addPath(FileType.Netpbm, "P6".getBytes()); // RAW R
_root.addPath(FileType.Netpbm, "P7".getBytes()); // P
_root.addPath(FileType.Pcx, new byte[]{0x0A, 0x00, 0x01}); // multiple PCX versions, explicitly listed
_root.addPath(FileType.Pcx, new byte[]{0x0A, 0x02, 0x01});
_root.addPath(FileType.Pcx, new byte[]{0x0A, 0x03, 0x01});
Expand Down Expand Up @@ -97,6 +104,8 @@ public class FileTypeDetector
_ftypMap.put("ftypM4VH", FileType.Mp4);
_ftypMap.put("ftypM4VP", FileType.Mp4);
_ftypMap.put("ftypmmp4", FileType.Mp4);
_ftypMap.put("ftyp3g2a", FileType.Mp4);
_ftypMap.put("ftyp3gp5", FileType.Mp4);
_ftypMap.put("ftypmp41", FileType.Mp4);
_ftypMap.put("ftypmp42", FileType.Mp4);
_ftypMap.put("ftypmp71", FileType.Mp4);
Expand Down Expand Up @@ -151,30 +160,25 @@ private FileTypeDetector() throws Exception
/**
* Examines the file's bytes and estimates the file's type.
* <p>
* Requires a {@link BufferedInputStream} in order to mark and reset the stream to the position
* Requires a {@link ReaderInfo} in order to mark and reset the stream to the position
* at which it was provided to this method once completed.
* <p>
* Requires the stream to contain at least eight bytes.
*
* @throws IOException if an IO error occurred or the input stream ended unexpectedly.
*/
@NotNull
public static FileType detectFileType(@NotNull final BufferedInputStream inputStream) throws IOException
public static FileType detectFileType(@NotNull final ReaderInfo rdrInfo) throws IOException
{
if (!inputStream.markSupported())
throw new IOException("Stream must support mark/reset");

int maxByteCount = Math.max(16, _root.getMaxDepth());

inputStream.mark(maxByteCount);

byte[] bytes = new byte[maxByteCount];
int bytesRead = inputStream.read(bytes);
int bytesRead = rdrInfo.read(bytes, 0, bytes.length);

if (bytesRead == -1)
throw new IOException("Stream ended before file's magic number could be determined.");

inputStream.reset();
rdrInfo.skip(-bytesRead);

FileType fileType = _root.find(bytes);

Expand Down
88 changes: 51 additions & 37 deletions Source/com/drew/imaging/ImageMetadataReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.mp3.Mp3MetadataReader;
import com.drew.imaging.mp4.Mp4MetadataReader;
import com.drew.imaging.netpbm.NetpbmMetadataReader;
import com.drew.imaging.quicktime.QuickTimeMetadataReader;
import com.drew.imaging.pcx.PcxMetadataReader;
import com.drew.imaging.png.PngMetadataReader;
Expand All @@ -37,7 +38,8 @@
import com.drew.imaging.tiff.TiffMetadataReader;
import com.drew.imaging.wav.WavMetadataReader;
import com.drew.imaging.webp.WebpMetadataReader;
import com.drew.lang.RandomAccessStreamReader;
import com.drew.lang.RandomAccessStream;
import com.drew.lang.ReaderInfo;
import com.drew.lang.StringUtil;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Directory;
Expand Down Expand Up @@ -68,6 +70,7 @@
* <li>{@link FileSystemMetadataReader} for metadata from the file system when a {@link File} is provided</li>
* <li>{@link GifMetadataReader} for GIF files</li>
* <li>{@link IcoMetadataReader} for ICO files</li>
* <li>{@link NetpbmMetadataReader} for Netpbm files (PPM, PGM, PBM, PPM)</li>
* <li>{@link JpegMetadataReader} for JPEG files</li>
* <li>{@link Mp4MetadataReader} for MPEG-4 files</li>
* <li>{@link PcxMetadataReader} for PCX files</li>
Expand Down Expand Up @@ -95,93 +98,104 @@ public class ImageMetadataReader
*
* @param inputStream a stream from which the file data may be read. The stream must be positioned at the
* beginning of the file's data.
* @param streamLength the length of the stream, if known, otherwise -1.
* @return a populated {@link Metadata} object containing directories of tags with values and any processing errors.
* @throws ImageProcessingException if the file type is unknown, or for general processing errors.
*/
@NotNull
public static Metadata readMetadata(@NotNull final InputStream inputStream) throws ImageProcessingException, IOException
public static Metadata readMetadata(@NotNull final InputStream inputStream, long streamLength) throws ImageProcessingException, IOException
{
return readMetadata(inputStream, -1);
return readMetadata(new RandomAccessStream(inputStream, streamLength));
}

/**
* Reads metadata from an {@link InputStream} of known length.
* Reads {@link Metadata} from the file at the given path
*
* @param inputStream a stream from which the file data may be read. The stream must be positioned at the
* beginning of the file's data.
* @param streamLength the length of the stream, if known, otherwise -1.
* @param filePath a file path from which the image data may be read.
* @return a populated {@link Metadata} object containing directories of tags with values and any processing errors.
* @throws ImageProcessingException for general processing errors.
*/
@NotNull
public static Metadata readMetadata(@NotNull final String filePath) throws ImageProcessingException, IOException
{
return readMetadata(new RandomAccessStream(new RandomAccessFile(filePath, "r")));
}

/**
* Reads {@link Metadata} from an {@link RandomAccessStream} of known length.
*
* @param rastream a {@link RandomAccessStream} from which the file data may be read.
* @return a populated {@link Metadata} object containing directories of tags with values and any processing errors.
* @throws ImageProcessingException if the file type is unknown, or for general processing errors.
*/
@NotNull
public static Metadata readMetadata(@NotNull final InputStream inputStream, final long streamLength) throws ImageProcessingException, IOException
public static Metadata readMetadata(@NotNull final RandomAccessStream rastream) throws ImageProcessingException, IOException
{
BufferedInputStream bufferedInputStream = inputStream instanceof BufferedInputStream
? (BufferedInputStream)inputStream
: new BufferedInputStream(inputStream);

FileType fileType = FileTypeDetector.detectFileType(bufferedInputStream);

Metadata metadata = readMetadata(bufferedInputStream, streamLength, fileType);

ReaderInfo fileTypeReader = rastream.createReader();
FileType fileType = FileTypeDetector.detectFileType(fileTypeReader);

ReaderInfo readerClone = fileTypeReader.Clone();

Metadata metadata = readMetadata(readerClone, fileType);
metadata.addDirectory(new FileTypeDirectory(fileType));

return metadata;
}

/**
* Reads metadata from an {@link InputStream} of known length and file type.
* Reads {@link Metadata} from an {@link ReaderInfo} of known length and file type.
*
* @param inputStream a stream from which the file data may be read. The stream must be positioned at the
* @param reader a {@link ReaderInfo} from which the file data may be read. The stream must be positioned at the
* beginning of the file's data.
* @param streamLength the length of the stream, if known, otherwise -1.
* @param fileType the file type of the data stream.
* @return a populated {@link Metadata} object containing directories of tags with values and any processing errors.
* @throws ImageProcessingException if the file type is unknown, or for general processing errors.
*/
@NotNull
public static Metadata readMetadata(@NotNull final InputStream inputStream, final long streamLength, final FileType fileType) throws IOException, ImageProcessingException
public static Metadata readMetadata(@NotNull final ReaderInfo reader, final FileType fileType) throws IOException, ImageProcessingException
{
switch (fileType) {
case Jpeg:
return JpegMetadataReader.readMetadata(inputStream);
return JpegMetadataReader.readMetadata(reader);
case Tiff:
case Arw:
case Cr2:
case Nef:
case Orf:
case Rw2:
return TiffMetadataReader.readMetadata(new RandomAccessStreamReader(inputStream, RandomAccessStreamReader.DEFAULT_CHUNK_LENGTH, streamLength));
return TiffMetadataReader.readMetadata(reader);
case Psd:
return PsdMetadataReader.readMetadata(inputStream);
return PsdMetadataReader.readMetadata(reader);
case Png:
return PngMetadataReader.readMetadata(inputStream);
return PngMetadataReader.readMetadata(reader);
case Bmp:
return BmpMetadataReader.readMetadata(inputStream);
return BmpMetadataReader.readMetadata(reader);
case Gif:
return GifMetadataReader.readMetadata(inputStream);
return GifMetadataReader.readMetadata(reader);
case Ico:
return IcoMetadataReader.readMetadata(inputStream);
return IcoMetadataReader.readMetadata(reader);
case Pcx:
return PcxMetadataReader.readMetadata(inputStream);
return PcxMetadataReader.readMetadata(reader);
case WebP:
return WebpMetadataReader.readMetadata(inputStream);
return WebpMetadataReader.readMetadata(reader);
case Raf:
return RafMetadataReader.readMetadata(inputStream);
return RafMetadataReader.readMetadata(reader);
case Avi:
return AviMetadataReader.readMetadata(inputStream);
return AviMetadataReader.readMetadata(reader);
case Netpbm:
return NetpbmMetadataReader.readMetadata(reader);
case Wav:
return WavMetadataReader.readMetadata(inputStream);
return WavMetadataReader.readMetadata(reader);
case Mov:
return QuickTimeMetadataReader.readMetadata(inputStream);
return QuickTimeMetadataReader.readMetadata(reader);
case Mp4:
return Mp4MetadataReader.readMetadata(inputStream);
return Mp4MetadataReader.readMetadata(reader);
case Mp3:
return Mp3MetadataReader.readMetadata(inputStream);
return Mp3MetadataReader.readMetadata(reader);
case Eps:
return EpsMetadataReader.readMetadata(inputStream);
return EpsMetadataReader.readMetadata(reader);
case Heif:
return HeifMetadataReader.readMetadata(inputStream);
return HeifMetadataReader.readMetadata(reader);
case Unknown:
throw new ImageProcessingException("File format could not be determined");
default:
Expand Down
30 changes: 22 additions & 8 deletions Source/com/drew/imaging/avi/AviMetadataReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@

import com.drew.imaging.riff.RiffProcessingException;
import com.drew.imaging.riff.RiffReader;
import com.drew.lang.StreamReader;
import com.drew.lang.RandomAccessStream;
import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.avi.AviRiffHandler;
Expand All @@ -32,6 +33,7 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;

/**
* Obtains metadata from AVI files.
Expand All @@ -43,22 +45,34 @@ public class AviMetadataReader
@NotNull
public static Metadata readMetadata(@NotNull File file) throws IOException, RiffProcessingException
{
InputStream inputStream = new FileInputStream(file);
Metadata metadata;
try {
metadata = readMetadata(inputStream);
} finally {
inputStream.close();
if(file.isFile())
{
RandomAccessFile raFile = new RandomAccessFile(file, "r");
try {
metadata = readMetadata(new RandomAccessStream(raFile).createReader());
} finally {
raFile.close();
}
}
else
{
InputStream inputStream = new FileInputStream(file);
try {
metadata = readMetadata(new RandomAccessStream(inputStream, file.length()).createReader());
} finally {
inputStream.close();
}
}
new FileSystemMetadataReader().read(file, metadata);
return metadata;
}

@NotNull
public static Metadata readMetadata(@NotNull InputStream inputStream) throws IOException, RiffProcessingException
public static Metadata readMetadata(@NotNull ReaderInfo reader) throws IOException, RiffProcessingException
{
Metadata metadata = new Metadata();
new RiffReader().processRiff(new StreamReader(inputStream), new AviRiffHandler(metadata));
new RiffReader().processRiff(reader, new AviRiffHandler(metadata));
return metadata;
}
}
9 changes: 5 additions & 4 deletions Source/com/drew/imaging/bmp/BmpMetadataReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@

package com.drew.imaging.bmp;

import com.drew.lang.StreamReader;
import com.drew.lang.RandomAccessStream;
import com.drew.lang.ReaderInfo;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.bmp.BmpReader;
Expand All @@ -42,7 +43,7 @@ public static Metadata readMetadata(@NotNull File file) throws IOException
InputStream inputStream = new FileInputStream(file);
Metadata metadata;
try {
metadata = readMetadata(inputStream);
metadata = readMetadata(new RandomAccessStream(inputStream, file.length()).createReader());
} finally {
inputStream.close();
}
Expand All @@ -51,10 +52,10 @@ public static Metadata readMetadata(@NotNull File file) throws IOException
}

@NotNull
public static Metadata readMetadata(@NotNull InputStream inputStream)
public static Metadata readMetadata(@NotNull ReaderInfo reader)
{
Metadata metadata = new Metadata();
new BmpReader().extract(new StreamReader(inputStream), metadata);
new BmpReader().extract(reader, metadata);
return metadata;
}
}
17 changes: 11 additions & 6 deletions Source/com/drew/imaging/eps/EpsMetadataReader.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.drew.imaging.eps;

import com.drew.lang.annotations.NotNull;
import com.drew.lang.RandomAccessStream;
import com.drew.lang.ReaderInfo;
import com.drew.metadata.Metadata;
import com.drew.metadata.eps.EpsReader;
import com.drew.metadata.file.FileSystemMetadataReader;
Expand All @@ -19,19 +21,22 @@ public class EpsMetadataReader {
@NotNull
public static Metadata readMetadata(@NotNull File file) throws IOException
{
Metadata metadata = new Metadata();

new EpsReader().extract(new FileInputStream(file), metadata);

InputStream inputStream = new FileInputStream(file);
Metadata metadata;
try {
metadata = readMetadata(new RandomAccessStream(inputStream, file.length()).createReader());
} finally {
inputStream.close();
}
new FileSystemMetadataReader().read(file, metadata);
return metadata;
}

@NotNull
public static Metadata readMetadata(@NotNull InputStream inputStream) throws IOException
public static Metadata readMetadata(@NotNull ReaderInfo reader) throws IOException
{
Metadata metadata = new Metadata();
new EpsReader().extract(inputStream, metadata);
new EpsReader().extract(reader, metadata);
return metadata;
}
}
Loading