diff --git a/Source/com/drew/imaging/png/PngMetadataReader.java b/Source/com/drew/imaging/png/PngMetadataReader.java index c276e9bfa..1a0447451 100644 --- a/Source/com/drew/imaging/png/PngMetadataReader.java +++ b/Source/com/drew/imaging/png/PngMetadataReader.java @@ -330,7 +330,7 @@ private static void processChunk(@NotNull Metadata metadata, @NotNull PngChunk c metadata.addDirectory(directory); } else if (chunkType.equals(PngChunkType.eXIf)) { try { - ExifTiffHandler handler = new ExifTiffHandler(metadata, null); + ExifTiffHandler handler = new ExifTiffHandler(metadata, null, 0); new TiffReader().processTiff(new ByteArrayReader(bytes), handler, 0); } catch (TiffProcessingException ex) { PngDirectory directory = new PngDirectory(PngChunkType.eXIf); diff --git a/Source/com/drew/imaging/tiff/TiffMetadataReader.java b/Source/com/drew/imaging/tiff/TiffMetadataReader.java index 7137a0384..5db7883d4 100644 --- a/Source/com/drew/imaging/tiff/TiffMetadataReader.java +++ b/Source/com/drew/imaging/tiff/TiffMetadataReader.java @@ -67,7 +67,7 @@ public static Metadata readMetadata(@NotNull InputStream inputStream) throws IOE public static Metadata readMetadata(@NotNull RandomAccessReader reader) throws IOException, TiffProcessingException { Metadata metadata = new Metadata(); - ExifTiffHandler handler = new ExifTiffHandler(metadata, null); + ExifTiffHandler handler = new ExifTiffHandler(metadata, null, 0); new TiffReader().processTiff(reader, handler, 0); return metadata; } diff --git a/Source/com/drew/metadata/exif/ExifReader.java b/Source/com/drew/metadata/exif/ExifReader.java index ff2e9a954..d343597f1 100644 --- a/Source/com/drew/metadata/exif/ExifReader.java +++ b/Source/com/drew/metadata/exif/ExifReader.java @@ -87,7 +87,7 @@ public void extract(@NotNull final RandomAccessReader reader, @NotNull final Met /** Reads TIFF formatted Exif data at a specified offset within a {@link RandomAccessReader}. */ public void extract(@NotNull final RandomAccessReader reader, @NotNull final Metadata metadata, int readerOffset, @Nullable Directory parentDirectory) { - ExifTiffHandler exifTiffHandler = new ExifTiffHandler(metadata, parentDirectory); + ExifTiffHandler exifTiffHandler = new ExifTiffHandler(metadata, parentDirectory, readerOffset); try { // Read the TIFF-formatted Exif data diff --git a/Source/com/drew/metadata/exif/ExifThumbnailDescriptor.java b/Source/com/drew/metadata/exif/ExifThumbnailDescriptor.java index 430491772..15525e87f 100644 --- a/Source/com/drew/metadata/exif/ExifThumbnailDescriptor.java +++ b/Source/com/drew/metadata/exif/ExifThumbnailDescriptor.java @@ -63,7 +63,8 @@ public String getThumbnailLengthDescription() @Nullable public String getThumbnailOffsetDescription() { - String value = _directory.getString(TAG_THUMBNAIL_OFFSET); - return value == null ? null : value + " bytes"; + Integer offset = _directory.getAdjustedThumbnailOffset(); + + return offset == null ? null : offset.intValue() + " bytes"; } } diff --git a/Source/com/drew/metadata/exif/ExifThumbnailDirectory.java b/Source/com/drew/metadata/exif/ExifThumbnailDirectory.java index 85b106f7e..572a0505f 100644 --- a/Source/com/drew/metadata/exif/ExifThumbnailDirectory.java +++ b/Source/com/drew/metadata/exif/ExifThumbnailDirectory.java @@ -34,7 +34,11 @@ public class ExifThumbnailDirectory extends ExifDirectoryBase { /** - * The offset to thumbnail image bytes. + * The offset to thumbnail image bytes, relative to the start of the IFD. + * + * To obtain the offset relative to the start of the TIFF data stream, use + * getAdjustedThumbnailOffset, which includes the value of + * getExifStartOffset. */ public static final int TAG_THUMBNAIL_OFFSET = 0x0201; /** @@ -59,8 +63,11 @@ public class ExifThumbnailDirectory extends ExifDirectoryBase _tagNameMap.put(TAG_THUMBNAIL_LENGTH, "Thumbnail Length"); } - public ExifThumbnailDirectory() + private final int _exifStartOffset; + + public ExifThumbnailDirectory(int exifStartOffset) { + _exifStartOffset = exifStartOffset; this.setDescriptor(new ExifThumbnailDescriptor(this)); } @@ -77,4 +84,35 @@ protected HashMap getTagNameMap() { return _tagNameMap; } + + /** + * Gets the offset at which the Exif data stream commenced within any containing stream. + */ + public int getExifStartOffset() + { + return _exifStartOffset; + } + + /** + * Returns the offset to thumbnail data within the outermost data stream. + * + * The value for TagThumbnailOffset is relative to the Exif data stream. + * Generally, consumers of thumbnail data need this value relative to the outermost stream, + * so that the thumbnail data may be extracted from that stream. + * + * This property adds the value of ExifStartOffset to this tag's value in order + * to produce that value. + * + * Returns null when the tag is not defined in this directory. + */ + public Integer getAdjustedThumbnailOffset() + { + Integer offset = this.getInteger(TAG_THUMBNAIL_OFFSET); + + if (offset == null) { + return null; + } + + return offset.intValue() + _exifStartOffset; + } } diff --git a/Source/com/drew/metadata/exif/ExifTiffHandler.java b/Source/com/drew/metadata/exif/ExifTiffHandler.java index 2acf88294..39857b440 100644 --- a/Source/com/drew/metadata/exif/ExifTiffHandler.java +++ b/Source/com/drew/metadata/exif/ExifTiffHandler.java @@ -57,9 +57,12 @@ */ public class ExifTiffHandler extends DirectoryTiffHandler { - public ExifTiffHandler(@NotNull Metadata metadata, @Nullable Directory parentDirectory) + private final int _exifStartOffset; + + public ExifTiffHandler(@NotNull Metadata metadata, @Nullable Directory parentDirectory, int exifStartOffset) { super(metadata, parentDirectory); + _exifStartOffset = exifStartOffset; } public void setTiffMarker(int marker) throws TiffProcessingException @@ -149,7 +152,7 @@ public boolean hasFollowerIfd() if (_currentDirectory.containsTag(ExifDirectoryBase.TAG_PAGE_NUMBER)) pushDirectory(ExifImageDirectory.class); else - pushDirectory(ExifThumbnailDirectory.class); + pushDirectory(new ExifThumbnailDirectory(_exifStartOffset)); return true; } diff --git a/Source/com/drew/metadata/photoshop/PhotoshopTiffHandler.java b/Source/com/drew/metadata/photoshop/PhotoshopTiffHandler.java index b5de35ea8..a90e52827 100644 --- a/Source/com/drew/metadata/photoshop/PhotoshopTiffHandler.java +++ b/Source/com/drew/metadata/photoshop/PhotoshopTiffHandler.java @@ -33,7 +33,7 @@ public class PhotoshopTiffHandler extends ExifTiffHandler public PhotoshopTiffHandler(Metadata metadata, Directory parentDirectory) { - super(metadata, parentDirectory); + super(metadata, parentDirectory, 0); } public boolean customProcessTag(final int tagOffset, diff --git a/Source/com/drew/metadata/tiff/DirectoryTiffHandler.java b/Source/com/drew/metadata/tiff/DirectoryTiffHandler.java index a327bd808..21ed52917 100644 --- a/Source/com/drew/metadata/tiff/DirectoryTiffHandler.java +++ b/Source/com/drew/metadata/tiff/DirectoryTiffHandler.java @@ -67,21 +67,26 @@ protected void pushDirectory(@NotNull Class directoryClass) throw new RuntimeException(e); } + pushDirectory(newDirectory); + } + + protected void pushDirectory(@NotNull Directory directory) + { // If this is the first directory, don't add to the stack if (_currentDirectory == null) { // Apply any pending root parent to this new directory if (_rootParentDirectory != null) { - newDirectory.setParent(_rootParentDirectory); + directory.setParent(_rootParentDirectory); _rootParentDirectory = null; } } else { // The current directory is pushed onto the stack, and set as the new directory's parent _directoryStack.push(_currentDirectory); - newDirectory.setParent(_currentDirectory); + directory.setParent(_currentDirectory); } - _currentDirectory = newDirectory; + _currentDirectory = directory; _metadata.addDirectory(_currentDirectory); } diff --git a/Tests/com/drew/metadata/MetadataTest.java b/Tests/com/drew/metadata/MetadataTest.java index 7a10e52a2..05b5239cb 100644 --- a/Tests/com/drew/metadata/MetadataTest.java +++ b/Tests/com/drew/metadata/MetadataTest.java @@ -96,7 +96,7 @@ public void testOrderOfDifferentTypes() { Metadata metadata = new Metadata(); Directory directory1 = new ExifSubIFDDirectory(); - Directory directory2 = new ExifThumbnailDirectory(); + Directory directory2 = new ExifThumbnailDirectory(0); Directory directory3 = new ExifIFD0Directory(); metadata.addDirectory(directory1); diff --git a/Tests/com/drew/metadata/exif/ExifDirectoryTest.java b/Tests/com/drew/metadata/exif/ExifDirectoryTest.java index d818dcbac..d96822b23 100644 --- a/Tests/com/drew/metadata/exif/ExifDirectoryTest.java +++ b/Tests/com/drew/metadata/exif/ExifDirectoryTest.java @@ -46,7 +46,7 @@ public void testGetDirectoryName() throws Exception { Directory subIFDDirectory = new ExifSubIFDDirectory(); Directory ifd0Directory = new ExifIFD0Directory(); - Directory thumbDirectory = new ExifThumbnailDirectory(); + Directory thumbDirectory = new ExifThumbnailDirectory(0); Directory gpsDirectory = new GpsDirectory(); assertFalse(subIFDDirectory.hasErrors()); diff --git a/Tests/com/drew/metadata/exif/ExifThumbnailDescriptorTest.java b/Tests/com/drew/metadata/exif/ExifThumbnailDescriptorTest.java index a223eab42..1c3bc304f 100644 --- a/Tests/com/drew/metadata/exif/ExifThumbnailDescriptorTest.java +++ b/Tests/com/drew/metadata/exif/ExifThumbnailDescriptorTest.java @@ -36,7 +36,7 @@ public class ExifThumbnailDescriptorTest @Test public void testGetYCbCrSubsamplingDescription() throws Exception { - ExifThumbnailDirectory directory = new ExifThumbnailDirectory(); + ExifThumbnailDirectory directory = new ExifThumbnailDirectory(0); directory.setIntArray(TAG_YCBCR_SUBSAMPLING, new int[]{2, 1}); ExifThumbnailDescriptor descriptor = new ExifThumbnailDescriptor(directory);