Skip to content

Commit

Permalink
Fix Exif thumbnail offset
Browse files Browse the repository at this point in the history
Fixes #578

The offset is currently reported relative to the start of the Exif data. However, most users will need the value relative to the start of the outermost data stream. This change attempts to provide that value.

Should work for JPEG and RAW files. Won't work for Exif data embedded within other formats such as PNG, QuickTime, WebP or HEIF. Such support could be added in future.
  • Loading branch information
drewnoakes committed May 8, 2023
1 parent 8e26c65 commit b4a2422
Show file tree
Hide file tree
Showing 11 changed files with 63 additions and 16 deletions.
2 changes: 1 addition & 1 deletion Source/com/drew/imaging/png/PngMetadataReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion Source/com/drew/imaging/tiff/TiffMetadataReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion Source/com/drew/metadata/exif/ExifReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions Source/com/drew/metadata/exif/ExifThumbnailDescriptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
}
42 changes: 40 additions & 2 deletions Source/com/drew/metadata/exif/ExifThumbnailDirectory.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
* <code>getAdjustedThumbnailOffset</code>, which includes the value of
* <code>getExifStartOffset</code>.
*/
public static final int TAG_THUMBNAIL_OFFSET = 0x0201;
/**
Expand All @@ -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));
}

Expand All @@ -77,4 +84,35 @@ protected HashMap<Integer, String> 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 <code>TagThumbnailOffset</code> 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 <code>ExifStartOffset</code> to this tag's value in order
* to produce that value.
*
* Returns <code>null</code> 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;
}
}
7 changes: 5 additions & 2 deletions Source/com/drew/metadata/exif/ExifTiffHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
11 changes: 8 additions & 3 deletions Source/com/drew/metadata/tiff/DirectoryTiffHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,26 @@ protected void pushDirectory(@NotNull Class<? extends Directory> 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);
}

Expand Down
2 changes: 1 addition & 1 deletion Tests/com/drew/metadata/MetadataTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion Tests/com/drew/metadata/exif/ExifDirectoryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit b4a2422

Please sign in to comment.