info: show EXIF in PNG/HEIF (WIP)
This commit is contained in:
parent
59c19966e4
commit
27880bf7a3
3 changed files with 268 additions and 232 deletions
|
@ -22,21 +22,14 @@ import com.adobe.internal.xmp.properties.XMPProperty;
|
|||
import com.adobe.internal.xmp.properties.XMPPropertyInfo;
|
||||
import com.drew.imaging.ImageMetadataReader;
|
||||
import com.drew.imaging.ImageProcessingException;
|
||||
import com.drew.imaging.jpeg.JpegMetadataReader;
|
||||
import com.drew.imaging.jpeg.JpegSegmentMetadataReader;
|
||||
import com.drew.imaging.jpeg.JpegSegmentType;
|
||||
import com.drew.lang.GeoLocation;
|
||||
import com.drew.lang.Rational;
|
||||
import com.drew.lang.annotations.NotNull;
|
||||
import com.drew.metadata.Directory;
|
||||
import com.drew.metadata.Metadata;
|
||||
import com.drew.metadata.MetadataException;
|
||||
import com.drew.metadata.Tag;
|
||||
import com.drew.metadata.exif.ExifDirectoryBase;
|
||||
import com.drew.metadata.exif.ExifIFD0Directory;
|
||||
import com.drew.metadata.exif.ExifReader;
|
||||
import com.drew.metadata.exif.ExifSubIFDDirectory;
|
||||
import com.drew.metadata.exif.ExifThumbnailDirectory;
|
||||
import com.drew.metadata.exif.GpsDirectory;
|
||||
import com.drew.metadata.file.FileTypeDirectory;
|
||||
import com.drew.metadata.gif.GifAnimationDirectory;
|
||||
|
@ -129,49 +122,6 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
|
|||
// "+51.3328-000.7053+113.474/" (Apple)
|
||||
private static final Pattern VIDEO_LOCATION_PATTERN = Pattern.compile("([+-][.0-9]+)([+-][.0-9]+).*");
|
||||
|
||||
private static int TAG_THUMBNAIL_DATA = 0x10000;
|
||||
|
||||
// modify metadata-extractor readers to store EXIF thumbnail data
|
||||
// cf https://github.com/drewnoakes/metadata-extractor/issues/276#issuecomment-677767368
|
||||
static {
|
||||
List<JpegSegmentMetadataReader> allReaders = (List<JpegSegmentMetadataReader>) JpegMetadataReader.ALL_READERS;
|
||||
for (int n = 0, cnt = allReaders.size(); n < cnt; n++) {
|
||||
if (allReaders.get(n).getClass() != ExifReader.class) {
|
||||
continue;
|
||||
}
|
||||
|
||||
allReaders.set(n, new ExifReader() {
|
||||
@Override
|
||||
public void readJpegSegments(@NotNull final Iterable<byte[]> segments, @NotNull final Metadata metadata, @NotNull final JpegSegmentType segmentType) {
|
||||
super.readJpegSegments(segments, metadata, segmentType);
|
||||
|
||||
for (byte[] segmentBytes : segments) {
|
||||
// Filter any segments containing unexpected preambles
|
||||
if (!startsWithJpegExifPreamble(segmentBytes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extract the thumbnail
|
||||
try {
|
||||
ExifThumbnailDirectory tnDirectory = metadata.getFirstDirectoryOfType(ExifThumbnailDirectory.class);
|
||||
if (tnDirectory != null && tnDirectory.containsTag(ExifThumbnailDirectory.TAG_THUMBNAIL_OFFSET)) {
|
||||
int offset = tnDirectory.getInt(ExifThumbnailDirectory.TAG_THUMBNAIL_OFFSET);
|
||||
int length = tnDirectory.getInt(ExifThumbnailDirectory.TAG_THUMBNAIL_LENGTH);
|
||||
|
||||
byte[] tnData = new byte[length];
|
||||
System.arraycopy(segmentBytes, JPEG_SEGMENT_PREAMBLE.length() + offset, tnData, 0, length);
|
||||
tnDirectory.setObject(TAG_THUMBNAIL_DATA, tnData);
|
||||
}
|
||||
} catch (MetadataException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private Context context;
|
||||
|
||||
public MetadataHandler(Context context) {
|
||||
|
@ -226,7 +176,7 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
|
|||
try (InputStream is = StorageUtils.openInputStream(context, uri)) {
|
||||
Metadata metadata = ImageMetadataReader.readMetadata(is);
|
||||
for (Directory dir : metadata.getDirectories()) {
|
||||
if (dir.getTagCount() > 0) {
|
||||
if (dir.getTagCount() > 0 && !(dir instanceof FileTypeDirectory)) {
|
||||
foundExif |= dir instanceof ExifDirectoryBase;
|
||||
|
||||
// directory name
|
||||
|
@ -603,16 +553,14 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
|
|||
Uri uri = Uri.parse(call.argument("uri"));
|
||||
List<byte[]> thumbnails = new ArrayList<>();
|
||||
try (InputStream is = StorageUtils.openInputStream(context, uri)) {
|
||||
Metadata metadata = ImageMetadataReader.readMetadata(is);
|
||||
for (ExifThumbnailDirectory dir : metadata.getDirectoriesOfType(ExifThumbnailDirectory.class)) {
|
||||
byte[] data = (byte[]) dir.getObject(TAG_THUMBNAIL_DATA);
|
||||
if (data != null) {
|
||||
thumbnails.add(data);
|
||||
ExifInterface exif = new ExifInterface(is);
|
||||
if (exif.hasThumbnail()) {
|
||||
thumbnails.add(exif.getThumbnailBytes());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.w(LOG_TAG, "failed to extract exif thumbnail with ExifInterface for uri=" + uri, e);
|
||||
}
|
||||
} catch (IOException | ImageProcessingException | NoClassDefFoundError e) {
|
||||
Log.w(LOG_TAG, "failed to extract exif thumbnail", e);
|
||||
}
|
||||
|
||||
result.success(thumbnails);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
package deckers.thibault.aves.utils
|
||||
|
||||
import android.util.Log
|
||||
import androidx.exifinterface.media.ExifInterface
|
||||
import com.drew.lang.Rational
|
||||
import com.drew.metadata.Directory
|
||||
import com.drew.metadata.exif.ExifDirectoryBase
|
||||
import com.drew.metadata.exif.ExifThumbnailDirectory
|
||||
import com.drew.metadata.exif.GpsDirectory
|
||||
import com.drew.metadata.exif.PanasonicRawIFD0Directory
|
||||
import com.drew.metadata.exif.*
|
||||
import com.drew.metadata.exif.makernotes.OlympusCameraSettingsMakernoteDirectory
|
||||
import com.drew.metadata.exif.makernotes.OlympusImageProcessingMakernoteDirectory
|
||||
import com.drew.metadata.exif.makernotes.OlympusMakernoteDirectory
|
||||
import java.util.*
|
||||
import kotlin.math.floor
|
||||
import kotlin.math.roundToLong
|
||||
|
||||
object ExifInterfaceHelper {
|
||||
private val LOG_TAG = Utils.createLogTag(ExifInterfaceHelper::class.java)
|
||||
|
||||
private val exifIFD0Dir = ExifIFD0Directory()
|
||||
private val exifThumbnailDirectory = ExifThumbnailDirectory()
|
||||
private val gpsDir = GpsDirectory()
|
||||
private val olympusImageProcessingMakernoteDirectory = OlympusImageProcessingMakernoteDirectory()
|
||||
|
@ -19,181 +23,190 @@ object ExifInterfaceHelper {
|
|||
private val olympusMakernoteDirectory = OlympusMakernoteDirectory()
|
||||
private val panasonicRawIFD0Directory = PanasonicRawIFD0Directory()
|
||||
|
||||
private val baseTags: Map<String, Pair<Int, Directory>?> = hashMapOf(
|
||||
ExifInterface.TAG_APERTURE_VALUE to Pair(ExifDirectoryBase.TAG_APERTURE, gpsDir),
|
||||
ExifInterface.TAG_ARTIST to Pair(ExifDirectoryBase.TAG_ARTIST, gpsDir),
|
||||
ExifInterface.TAG_BITS_PER_SAMPLE to Pair(ExifDirectoryBase.TAG_BITS_PER_SAMPLE, gpsDir),
|
||||
ExifInterface.TAG_BODY_SERIAL_NUMBER to Pair(ExifDirectoryBase.TAG_BODY_SERIAL_NUMBER, gpsDir),
|
||||
ExifInterface.TAG_BRIGHTNESS_VALUE to Pair(ExifDirectoryBase.TAG_BRIGHTNESS_VALUE, gpsDir),
|
||||
ExifInterface.TAG_CAMERA_OWNER_NAME to Pair(ExifDirectoryBase.TAG_CAMERA_OWNER_NAME, gpsDir),
|
||||
ExifInterface.TAG_CFA_PATTERN to Pair(ExifDirectoryBase.TAG_CFA_PATTERN, gpsDir),
|
||||
ExifInterface.TAG_COLOR_SPACE to Pair(ExifDirectoryBase.TAG_COLOR_SPACE, gpsDir),
|
||||
ExifInterface.TAG_COMPONENTS_CONFIGURATION to Pair(ExifDirectoryBase.TAG_COMPONENTS_CONFIGURATION, gpsDir),
|
||||
ExifInterface.TAG_COMPRESSED_BITS_PER_PIXEL to Pair(ExifDirectoryBase.TAG_COMPRESSED_AVERAGE_BITS_PER_PIXEL, gpsDir),
|
||||
ExifInterface.TAG_COMPRESSION to Pair(ExifDirectoryBase.TAG_COMPRESSION, gpsDir),
|
||||
ExifInterface.TAG_CONTRAST to Pair(ExifDirectoryBase.TAG_CONTRAST, gpsDir),
|
||||
ExifInterface.TAG_COPYRIGHT to Pair(ExifDirectoryBase.TAG_COPYRIGHT, gpsDir),
|
||||
ExifInterface.TAG_CUSTOM_RENDERED to Pair(ExifDirectoryBase.TAG_CUSTOM_RENDERED, gpsDir),
|
||||
ExifInterface.TAG_DATETIME to Pair(ExifDirectoryBase.TAG_DATETIME, gpsDir),
|
||||
ExifInterface.TAG_DATETIME_DIGITIZED to Pair(ExifDirectoryBase.TAG_DATETIME_DIGITIZED, gpsDir),
|
||||
ExifInterface.TAG_DATETIME_ORIGINAL to Pair(ExifDirectoryBase.TAG_DATETIME_ORIGINAL, gpsDir),
|
||||
ExifInterface.TAG_DEVICE_SETTING_DESCRIPTION to Pair(ExifDirectoryBase.TAG_DEVICE_SETTING_DESCRIPTION, gpsDir),
|
||||
ExifInterface.TAG_DIGITAL_ZOOM_RATIO to Pair(ExifDirectoryBase.TAG_DIGITAL_ZOOM_RATIO, gpsDir),
|
||||
ExifInterface.TAG_EXIF_VERSION to Pair(ExifDirectoryBase.TAG_EXIF_VERSION, gpsDir),
|
||||
ExifInterface.TAG_EXPOSURE_BIAS_VALUE to Pair(ExifDirectoryBase.TAG_EXPOSURE_BIAS, gpsDir),
|
||||
ExifInterface.TAG_EXPOSURE_INDEX to Pair(ExifDirectoryBase.TAG_EXPOSURE_INDEX, gpsDir),
|
||||
ExifInterface.TAG_EXPOSURE_MODE to Pair(ExifDirectoryBase.TAG_EXPOSURE_MODE, gpsDir),
|
||||
ExifInterface.TAG_EXPOSURE_PROGRAM to Pair(ExifDirectoryBase.TAG_EXPOSURE_PROGRAM, gpsDir),
|
||||
ExifInterface.TAG_EXPOSURE_TIME to Pair(ExifDirectoryBase.TAG_EXPOSURE_TIME, gpsDir),
|
||||
ExifInterface.TAG_FILE_SOURCE to Pair(ExifDirectoryBase.TAG_FILE_SOURCE, gpsDir),
|
||||
ExifInterface.TAG_FLASH to Pair(ExifDirectoryBase.TAG_FLASH, gpsDir),
|
||||
ExifInterface.TAG_FLASHPIX_VERSION to Pair(ExifDirectoryBase.TAG_FLASHPIX_VERSION, gpsDir),
|
||||
ExifInterface.TAG_FLASH_ENERGY to Pair(ExifDirectoryBase.TAG_FLASH_ENERGY, gpsDir),
|
||||
ExifInterface.TAG_FOCAL_LENGTH to Pair(ExifDirectoryBase.TAG_FOCAL_LENGTH, gpsDir),
|
||||
ExifInterface.TAG_FOCAL_LENGTH_IN_35MM_FILM to Pair(ExifDirectoryBase.TAG_35MM_FILM_EQUIV_FOCAL_LENGTH, gpsDir),
|
||||
ExifInterface.TAG_FOCAL_PLANE_RESOLUTION_UNIT to Pair(ExifDirectoryBase.TAG_FOCAL_PLANE_RESOLUTION_UNIT, gpsDir),
|
||||
ExifInterface.TAG_FOCAL_PLANE_X_RESOLUTION to Pair(ExifDirectoryBase.TAG_FOCAL_PLANE_X_RESOLUTION, gpsDir),
|
||||
ExifInterface.TAG_FOCAL_PLANE_Y_RESOLUTION to Pair(ExifDirectoryBase.TAG_FOCAL_PLANE_Y_RESOLUTION, gpsDir),
|
||||
ExifInterface.TAG_F_NUMBER to Pair(ExifDirectoryBase.TAG_FNUMBER, gpsDir),
|
||||
ExifInterface.TAG_GAIN_CONTROL to Pair(ExifDirectoryBase.TAG_GAIN_CONTROL, gpsDir),
|
||||
ExifInterface.TAG_GAMMA to Pair(ExifDirectoryBase.TAG_GAMMA, gpsDir),
|
||||
ExifInterface.TAG_IMAGE_DESCRIPTION to Pair(ExifDirectoryBase.TAG_IMAGE_DESCRIPTION, gpsDir),
|
||||
ExifInterface.TAG_IMAGE_LENGTH to Pair(ExifDirectoryBase.TAG_IMAGE_HEIGHT, gpsDir),
|
||||
ExifInterface.TAG_IMAGE_UNIQUE_ID to Pair(ExifDirectoryBase.TAG_IMAGE_UNIQUE_ID, gpsDir),
|
||||
ExifInterface.TAG_IMAGE_WIDTH to Pair(ExifDirectoryBase.TAG_IMAGE_WIDTH, gpsDir),
|
||||
ExifInterface.TAG_INTEROPERABILITY_INDEX to Pair(ExifDirectoryBase.TAG_INTEROP_INDEX, gpsDir),
|
||||
ExifInterface.TAG_ISO_SPEED to Pair(ExifDirectoryBase.TAG_ISO_SPEED, gpsDir),
|
||||
ExifInterface.TAG_ISO_SPEED_LATITUDE_YYY to Pair(ExifDirectoryBase.TAG_ISO_SPEED_LATITUDE_YYY, gpsDir),
|
||||
ExifInterface.TAG_ISO_SPEED_LATITUDE_ZZZ to Pair(ExifDirectoryBase.TAG_ISO_SPEED_LATITUDE_ZZZ, gpsDir),
|
||||
ExifInterface.TAG_LENS_MAKE to Pair(ExifDirectoryBase.TAG_LENS_MAKE, gpsDir),
|
||||
ExifInterface.TAG_LENS_MODEL to Pair(ExifDirectoryBase.TAG_LENS_MODEL, gpsDir),
|
||||
ExifInterface.TAG_LENS_SERIAL_NUMBER to Pair(ExifDirectoryBase.TAG_LENS_SERIAL_NUMBER, gpsDir),
|
||||
ExifInterface.TAG_LENS_SPECIFICATION to Pair(ExifDirectoryBase.TAG_LENS_SPECIFICATION, gpsDir),
|
||||
ExifInterface.TAG_LIGHT_SOURCE to Pair(ExifDirectoryBase.TAG_WHITE_BALANCE, gpsDir),
|
||||
ExifInterface.TAG_MAKE to Pair(ExifDirectoryBase.TAG_MAKE, gpsDir),
|
||||
ExifInterface.TAG_MAKER_NOTE to Pair(ExifDirectoryBase.TAG_MAKERNOTE, gpsDir),
|
||||
ExifInterface.TAG_MAX_APERTURE_VALUE to Pair(ExifDirectoryBase.TAG_MAX_APERTURE, gpsDir),
|
||||
ExifInterface.TAG_METERING_MODE to Pair(ExifDirectoryBase.TAG_METERING_MODE, gpsDir),
|
||||
ExifInterface.TAG_MODEL to Pair(ExifDirectoryBase.TAG_MODEL, gpsDir),
|
||||
ExifInterface.TAG_NEW_SUBFILE_TYPE to Pair(ExifDirectoryBase.TAG_NEW_SUBFILE_TYPE, gpsDir),
|
||||
ExifInterface.TAG_OECF to Pair(ExifDirectoryBase.TAG_OPTO_ELECTRIC_CONVERSION_FUNCTION, gpsDir),
|
||||
ExifInterface.TAG_OFFSET_TIME to Pair(ExifDirectoryBase.TAG_TIME_ZONE, gpsDir),
|
||||
ExifInterface.TAG_OFFSET_TIME_DIGITIZED to Pair(ExifDirectoryBase.TAG_TIME_ZONE_DIGITIZED, gpsDir),
|
||||
ExifInterface.TAG_OFFSET_TIME_ORIGINAL to Pair(ExifDirectoryBase.TAG_TIME_ZONE_ORIGINAL, gpsDir),
|
||||
ExifInterface.TAG_ORIENTATION to Pair(ExifDirectoryBase.TAG_ORIENTATION, gpsDir),
|
||||
ExifInterface.TAG_PHOTOGRAPHIC_SENSITIVITY to Pair(ExifDirectoryBase.TAG_ISO_EQUIVALENT, gpsDir),
|
||||
ExifInterface.TAG_PHOTOMETRIC_INTERPRETATION to Pair(ExifDirectoryBase.TAG_PHOTOMETRIC_INTERPRETATION, gpsDir),
|
||||
ExifInterface.TAG_PIXEL_X_DIMENSION to Pair(ExifDirectoryBase.TAG_EXIF_IMAGE_WIDTH, gpsDir),
|
||||
ExifInterface.TAG_PIXEL_Y_DIMENSION to Pair(ExifDirectoryBase.TAG_EXIF_IMAGE_HEIGHT, gpsDir),
|
||||
ExifInterface.TAG_PLANAR_CONFIGURATION to Pair(ExifDirectoryBase.TAG_PLANAR_CONFIGURATION, gpsDir),
|
||||
ExifInterface.TAG_PRIMARY_CHROMATICITIES to Pair(ExifDirectoryBase.TAG_PRIMARY_CHROMATICITIES, gpsDir),
|
||||
ExifInterface.TAG_RECOMMENDED_EXPOSURE_INDEX to Pair(ExifDirectoryBase.TAG_RECOMMENDED_EXPOSURE_INDEX, gpsDir),
|
||||
ExifInterface.TAG_REFERENCE_BLACK_WHITE to Pair(ExifDirectoryBase.TAG_REFERENCE_BLACK_WHITE, gpsDir),
|
||||
ExifInterface.TAG_RELATED_SOUND_FILE to Pair(ExifDirectoryBase.TAG_RELATED_SOUND_FILE, gpsDir),
|
||||
ExifInterface.TAG_RESOLUTION_UNIT to Pair(ExifDirectoryBase.TAG_RESOLUTION_UNIT, gpsDir),
|
||||
ExifInterface.TAG_ROWS_PER_STRIP to Pair(ExifDirectoryBase.TAG_ROWS_PER_STRIP, gpsDir),
|
||||
ExifInterface.TAG_SAMPLES_PER_PIXEL to Pair(ExifDirectoryBase.TAG_SAMPLES_PER_PIXEL, gpsDir),
|
||||
ExifInterface.TAG_SATURATION to Pair(ExifDirectoryBase.TAG_SATURATION, gpsDir),
|
||||
ExifInterface.TAG_SCENE_CAPTURE_TYPE to Pair(ExifDirectoryBase.TAG_SCENE_CAPTURE_TYPE, gpsDir),
|
||||
ExifInterface.TAG_SCENE_TYPE to Pair(ExifDirectoryBase.TAG_SCENE_TYPE, gpsDir),
|
||||
ExifInterface.TAG_SENSING_METHOD to Pair(ExifDirectoryBase.TAG_SENSING_METHOD, gpsDir),
|
||||
ExifInterface.TAG_SENSITIVITY_TYPE to Pair(ExifDirectoryBase.TAG_SENSITIVITY_TYPE, gpsDir),
|
||||
ExifInterface.TAG_SHARPNESS to Pair(ExifDirectoryBase.TAG_SHARPNESS, gpsDir),
|
||||
ExifInterface.TAG_SHUTTER_SPEED_VALUE to Pair(ExifDirectoryBase.TAG_SHUTTER_SPEED, gpsDir),
|
||||
ExifInterface.TAG_SOFTWARE to Pair(ExifDirectoryBase.TAG_SOFTWARE, gpsDir),
|
||||
ExifInterface.TAG_SPATIAL_FREQUENCY_RESPONSE to Pair(ExifDirectoryBase.TAG_SPATIAL_FREQ_RESPONSE, gpsDir),
|
||||
ExifInterface.TAG_SPECTRAL_SENSITIVITY to Pair(ExifDirectoryBase.TAG_SPECTRAL_SENSITIVITY, gpsDir),
|
||||
ExifInterface.TAG_STANDARD_OUTPUT_SENSITIVITY to Pair(ExifDirectoryBase.TAG_STANDARD_OUTPUT_SENSITIVITY, gpsDir),
|
||||
ExifInterface.TAG_STRIP_BYTE_COUNTS to Pair(ExifDirectoryBase.TAG_STRIP_BYTE_COUNTS, gpsDir),
|
||||
ExifInterface.TAG_STRIP_OFFSETS to Pair(ExifDirectoryBase.TAG_STRIP_OFFSETS, gpsDir),
|
||||
ExifInterface.TAG_SUBFILE_TYPE to Pair(ExifDirectoryBase.TAG_SUBFILE_TYPE, gpsDir),
|
||||
ExifInterface.TAG_SUBJECT_AREA to Pair(ExifDirectoryBase.TAG_SUBJECT_LOCATION_TIFF_EP, gpsDir),
|
||||
ExifInterface.TAG_SUBJECT_DISTANCE to Pair(ExifDirectoryBase.TAG_SUBJECT_DISTANCE, gpsDir),
|
||||
ExifInterface.TAG_SUBJECT_DISTANCE_RANGE to Pair(ExifDirectoryBase.TAG_SUBJECT_DISTANCE_RANGE, gpsDir),
|
||||
ExifInterface.TAG_SUBJECT_LOCATION to Pair(ExifDirectoryBase.TAG_SUBJECT_LOCATION, gpsDir),
|
||||
ExifInterface.TAG_SUBSEC_TIME to Pair(ExifDirectoryBase.TAG_SUBSECOND_TIME, gpsDir),
|
||||
ExifInterface.TAG_SUBSEC_TIME_DIGITIZED to Pair(ExifDirectoryBase.TAG_SUBSECOND_TIME_DIGITIZED, gpsDir),
|
||||
ExifInterface.TAG_SUBSEC_TIME_ORIGINAL to Pair(ExifDirectoryBase.TAG_SUBSECOND_TIME_ORIGINAL, gpsDir),
|
||||
ExifInterface.TAG_THUMBNAIL_IMAGE_LENGTH to Pair(ExifDirectoryBase.TAG_IMAGE_HEIGHT, gpsDir), // IFD_THUMBNAIL_TAGS 0x0101
|
||||
ExifInterface.TAG_THUMBNAIL_IMAGE_WIDTH to Pair(ExifDirectoryBase.TAG_IMAGE_WIDTH, gpsDir), // IFD_THUMBNAIL_TAGS 0x0100
|
||||
ExifInterface.TAG_TRANSFER_FUNCTION to Pair(ExifDirectoryBase.TAG_TRANSFER_FUNCTION, gpsDir),
|
||||
ExifInterface.TAG_USER_COMMENT to Pair(ExifDirectoryBase.TAG_USER_COMMENT, gpsDir),
|
||||
ExifInterface.TAG_WHITE_BALANCE to Pair(ExifDirectoryBase.TAG_WHITE_BALANCE, gpsDir),
|
||||
ExifInterface.TAG_WHITE_POINT to Pair(ExifDirectoryBase.TAG_WHITE_POINT, gpsDir),
|
||||
ExifInterface.TAG_X_RESOLUTION to Pair(ExifDirectoryBase.TAG_X_RESOLUTION, gpsDir),
|
||||
ExifInterface.TAG_Y_CB_CR_COEFFICIENTS to Pair(ExifDirectoryBase.TAG_YCBCR_COEFFICIENTS, gpsDir),
|
||||
ExifInterface.TAG_Y_CB_CR_POSITIONING to Pair(ExifDirectoryBase.TAG_YCBCR_POSITIONING, gpsDir),
|
||||
ExifInterface.TAG_Y_CB_CR_SUB_SAMPLING to Pair(ExifDirectoryBase.TAG_YCBCR_SUBSAMPLING, gpsDir),
|
||||
ExifInterface.TAG_Y_RESOLUTION to Pair(ExifDirectoryBase.TAG_Y_RESOLUTION, gpsDir),
|
||||
// ExifInterface always states it has the following attributes
|
||||
// and returns "0" instead of "null" when they are actually missing
|
||||
private val neverNullTags = listOf(
|
||||
ExifInterface.TAG_IMAGE_LENGTH,
|
||||
ExifInterface.TAG_IMAGE_WIDTH,
|
||||
ExifInterface.TAG_LIGHT_SOURCE,
|
||||
ExifInterface.TAG_ORIENTATION,
|
||||
)
|
||||
|
||||
private val thumbnailTags: Map<String, Pair<Int, Directory>?> = hashMapOf(
|
||||
ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT to Pair(ExifThumbnailDirectory.TAG_THUMBNAIL_OFFSET, exifThumbnailDirectory), // IFD_TIFF_TAGS or IFD_THUMBNAIL_TAGS 0x0201
|
||||
ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH to Pair(ExifThumbnailDirectory.TAG_THUMBNAIL_LENGTH, exifThumbnailDirectory), // IFD_TIFF_TAGS or IFD_THUMBNAIL_TAGS 0x0202
|
||||
private val baseTags: Map<String, TagMapper?> = hashMapOf(
|
||||
ExifInterface.TAG_APERTURE_VALUE to TagMapper(ExifDirectoryBase.TAG_APERTURE, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_ARTIST to TagMapper(ExifDirectoryBase.TAG_ARTIST, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_BITS_PER_SAMPLE to TagMapper(ExifDirectoryBase.TAG_BITS_PER_SAMPLE, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_BODY_SERIAL_NUMBER to TagMapper(ExifDirectoryBase.TAG_BODY_SERIAL_NUMBER, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_BRIGHTNESS_VALUE to TagMapper(ExifDirectoryBase.TAG_BRIGHTNESS_VALUE, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_CAMERA_OWNER_NAME to TagMapper(ExifDirectoryBase.TAG_CAMERA_OWNER_NAME, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_CFA_PATTERN to TagMapper(ExifDirectoryBase.TAG_CFA_PATTERN, exifIFD0Dir, TagFormat.UNDEFINED),
|
||||
ExifInterface.TAG_COLOR_SPACE to TagMapper(ExifDirectoryBase.TAG_COLOR_SPACE, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_COMPONENTS_CONFIGURATION to TagMapper(ExifDirectoryBase.TAG_COMPONENTS_CONFIGURATION, exifIFD0Dir, TagFormat.UNDEFINED),
|
||||
ExifInterface.TAG_COMPRESSED_BITS_PER_PIXEL to TagMapper(ExifDirectoryBase.TAG_COMPRESSED_AVERAGE_BITS_PER_PIXEL, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_COMPRESSION to TagMapper(ExifDirectoryBase.TAG_COMPRESSION, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_CONTRAST to TagMapper(ExifDirectoryBase.TAG_CONTRAST, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_COPYRIGHT to TagMapper(ExifDirectoryBase.TAG_COPYRIGHT, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_CUSTOM_RENDERED to TagMapper(ExifDirectoryBase.TAG_CUSTOM_RENDERED, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_DATETIME to TagMapper(ExifDirectoryBase.TAG_DATETIME, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_DATETIME_DIGITIZED to TagMapper(ExifDirectoryBase.TAG_DATETIME_DIGITIZED, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_DATETIME_ORIGINAL to TagMapper(ExifDirectoryBase.TAG_DATETIME_ORIGINAL, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_DEVICE_SETTING_DESCRIPTION to TagMapper(ExifDirectoryBase.TAG_DEVICE_SETTING_DESCRIPTION, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_DIGITAL_ZOOM_RATIO to TagMapper(ExifDirectoryBase.TAG_DIGITAL_ZOOM_RATIO, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_EXIF_VERSION to TagMapper(ExifDirectoryBase.TAG_EXIF_VERSION, exifIFD0Dir, TagFormat.UNDEFINED),
|
||||
ExifInterface.TAG_EXPOSURE_BIAS_VALUE to TagMapper(ExifDirectoryBase.TAG_EXPOSURE_BIAS, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_EXPOSURE_INDEX to TagMapper(ExifDirectoryBase.TAG_EXPOSURE_INDEX, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_EXPOSURE_MODE to TagMapper(ExifDirectoryBase.TAG_EXPOSURE_MODE, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_EXPOSURE_PROGRAM to TagMapper(ExifDirectoryBase.TAG_EXPOSURE_PROGRAM, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_EXPOSURE_TIME to TagMapper(ExifDirectoryBase.TAG_EXPOSURE_TIME, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_FILE_SOURCE to TagMapper(ExifDirectoryBase.TAG_FILE_SOURCE, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_FLASH to TagMapper(ExifDirectoryBase.TAG_FLASH, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_FLASHPIX_VERSION to TagMapper(ExifDirectoryBase.TAG_FLASHPIX_VERSION, exifIFD0Dir, TagFormat.UNDEFINED),
|
||||
ExifInterface.TAG_FLASH_ENERGY to TagMapper(ExifDirectoryBase.TAG_FLASH_ENERGY, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_FOCAL_LENGTH to TagMapper(ExifDirectoryBase.TAG_FOCAL_LENGTH, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_FOCAL_LENGTH_IN_35MM_FILM to TagMapper(ExifDirectoryBase.TAG_35MM_FILM_EQUIV_FOCAL_LENGTH, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_FOCAL_PLANE_RESOLUTION_UNIT to TagMapper(ExifDirectoryBase.TAG_FOCAL_PLANE_RESOLUTION_UNIT, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_FOCAL_PLANE_X_RESOLUTION to TagMapper(ExifDirectoryBase.TAG_FOCAL_PLANE_X_RESOLUTION, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_FOCAL_PLANE_Y_RESOLUTION to TagMapper(ExifDirectoryBase.TAG_FOCAL_PLANE_Y_RESOLUTION, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_F_NUMBER to TagMapper(ExifDirectoryBase.TAG_FNUMBER, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_GAIN_CONTROL to TagMapper(ExifDirectoryBase.TAG_GAIN_CONTROL, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_GAMMA to TagMapper(ExifDirectoryBase.TAG_GAMMA, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_IMAGE_DESCRIPTION to TagMapper(ExifDirectoryBase.TAG_IMAGE_DESCRIPTION, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_IMAGE_LENGTH to TagMapper(ExifDirectoryBase.TAG_IMAGE_HEIGHT, exifIFD0Dir, TagFormat.LONG),
|
||||
ExifInterface.TAG_IMAGE_UNIQUE_ID to TagMapper(ExifDirectoryBase.TAG_IMAGE_UNIQUE_ID, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_IMAGE_WIDTH to TagMapper(ExifDirectoryBase.TAG_IMAGE_WIDTH, exifIFD0Dir, TagFormat.LONG),
|
||||
ExifInterface.TAG_INTEROPERABILITY_INDEX to TagMapper(ExifDirectoryBase.TAG_INTEROP_INDEX, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_ISO_SPEED to TagMapper(ExifDirectoryBase.TAG_ISO_SPEED, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_ISO_SPEED_LATITUDE_YYY to TagMapper(ExifDirectoryBase.TAG_ISO_SPEED_LATITUDE_YYY, exifIFD0Dir, TagFormat.LONG),
|
||||
ExifInterface.TAG_ISO_SPEED_LATITUDE_ZZZ to TagMapper(ExifDirectoryBase.TAG_ISO_SPEED_LATITUDE_ZZZ, exifIFD0Dir, TagFormat.LONG),
|
||||
ExifInterface.TAG_LENS_MAKE to TagMapper(ExifDirectoryBase.TAG_LENS_MAKE, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_LENS_MODEL to TagMapper(ExifDirectoryBase.TAG_LENS_MODEL, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_LENS_SERIAL_NUMBER to TagMapper(ExifDirectoryBase.TAG_LENS_SERIAL_NUMBER, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_LENS_SPECIFICATION to TagMapper(ExifDirectoryBase.TAG_LENS_SPECIFICATION, exifIFD0Dir, TagFormat.RATIONAL_ARRAY),
|
||||
ExifInterface.TAG_LIGHT_SOURCE to TagMapper(ExifDirectoryBase.TAG_WHITE_BALANCE, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_MAKE to TagMapper(ExifDirectoryBase.TAG_MAKE, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_MAKER_NOTE to TagMapper(ExifDirectoryBase.TAG_MAKERNOTE, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_MAX_APERTURE_VALUE to TagMapper(ExifDirectoryBase.TAG_MAX_APERTURE, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_METERING_MODE to TagMapper(ExifDirectoryBase.TAG_METERING_MODE, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_MODEL to TagMapper(ExifDirectoryBase.TAG_MODEL, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_NEW_SUBFILE_TYPE to TagMapper(ExifDirectoryBase.TAG_NEW_SUBFILE_TYPE, exifIFD0Dir, TagFormat.LONG),
|
||||
ExifInterface.TAG_OECF to TagMapper(ExifDirectoryBase.TAG_OPTO_ELECTRIC_CONVERSION_FUNCTION, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_OFFSET_TIME to TagMapper(ExifDirectoryBase.TAG_TIME_ZONE, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_OFFSET_TIME_DIGITIZED to TagMapper(ExifDirectoryBase.TAG_TIME_ZONE_DIGITIZED, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_OFFSET_TIME_ORIGINAL to TagMapper(ExifDirectoryBase.TAG_TIME_ZONE_ORIGINAL, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_ORIENTATION to TagMapper(ExifDirectoryBase.TAG_ORIENTATION, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_PHOTOGRAPHIC_SENSITIVITY to TagMapper(ExifDirectoryBase.TAG_ISO_EQUIVALENT, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_PHOTOMETRIC_INTERPRETATION to TagMapper(ExifDirectoryBase.TAG_PHOTOMETRIC_INTERPRETATION, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_PIXEL_X_DIMENSION to TagMapper(ExifDirectoryBase.TAG_EXIF_IMAGE_WIDTH, exifIFD0Dir, TagFormat.LONG),
|
||||
ExifInterface.TAG_PIXEL_Y_DIMENSION to TagMapper(ExifDirectoryBase.TAG_EXIF_IMAGE_HEIGHT, exifIFD0Dir, TagFormat.LONG),
|
||||
ExifInterface.TAG_PLANAR_CONFIGURATION to TagMapper(ExifDirectoryBase.TAG_PLANAR_CONFIGURATION, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_PRIMARY_CHROMATICITIES to TagMapper(ExifDirectoryBase.TAG_PRIMARY_CHROMATICITIES, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_RECOMMENDED_EXPOSURE_INDEX to TagMapper(ExifDirectoryBase.TAG_RECOMMENDED_EXPOSURE_INDEX, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_REFERENCE_BLACK_WHITE to TagMapper(ExifDirectoryBase.TAG_REFERENCE_BLACK_WHITE, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_RELATED_SOUND_FILE to TagMapper(ExifDirectoryBase.TAG_RELATED_SOUND_FILE, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_RESOLUTION_UNIT to TagMapper(ExifDirectoryBase.TAG_RESOLUTION_UNIT, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_ROWS_PER_STRIP to TagMapper(ExifDirectoryBase.TAG_ROWS_PER_STRIP, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_SAMPLES_PER_PIXEL to TagMapper(ExifDirectoryBase.TAG_SAMPLES_PER_PIXEL, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_SATURATION to TagMapper(ExifDirectoryBase.TAG_SATURATION, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_SCENE_CAPTURE_TYPE to TagMapper(ExifDirectoryBase.TAG_SCENE_CAPTURE_TYPE, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_SCENE_TYPE to TagMapper(ExifDirectoryBase.TAG_SCENE_TYPE, exifIFD0Dir, TagFormat.UNDEFINED),
|
||||
ExifInterface.TAG_SENSING_METHOD to TagMapper(ExifDirectoryBase.TAG_SENSING_METHOD, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_SENSITIVITY_TYPE to TagMapper(ExifDirectoryBase.TAG_SENSITIVITY_TYPE, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_SHARPNESS to TagMapper(ExifDirectoryBase.TAG_SHARPNESS, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_SHUTTER_SPEED_VALUE to TagMapper(ExifDirectoryBase.TAG_SHUTTER_SPEED, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_SOFTWARE to TagMapper(ExifDirectoryBase.TAG_SOFTWARE, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_SPATIAL_FREQUENCY_RESPONSE to TagMapper(ExifDirectoryBase.TAG_SPATIAL_FREQ_RESPONSE, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_SPECTRAL_SENSITIVITY to TagMapper(ExifDirectoryBase.TAG_SPECTRAL_SENSITIVITY, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_STANDARD_OUTPUT_SENSITIVITY to TagMapper(ExifDirectoryBase.TAG_STANDARD_OUTPUT_SENSITIVITY, exifIFD0Dir, null),
|
||||
ExifInterface.TAG_STRIP_BYTE_COUNTS to TagMapper(ExifDirectoryBase.TAG_STRIP_BYTE_COUNTS, exifIFD0Dir, TagFormat.LONG),
|
||||
ExifInterface.TAG_STRIP_OFFSETS to TagMapper(ExifDirectoryBase.TAG_STRIP_OFFSETS, exifIFD0Dir, TagFormat.LONG),
|
||||
ExifInterface.TAG_SUBFILE_TYPE to TagMapper(ExifDirectoryBase.TAG_SUBFILE_TYPE, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_SUBJECT_AREA to TagMapper(ExifDirectoryBase.TAG_SUBJECT_LOCATION_TIFF_EP, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_SUBJECT_DISTANCE to TagMapper(ExifDirectoryBase.TAG_SUBJECT_DISTANCE, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_SUBJECT_DISTANCE_RANGE to TagMapper(ExifDirectoryBase.TAG_SUBJECT_DISTANCE_RANGE, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_SUBJECT_LOCATION to TagMapper(ExifDirectoryBase.TAG_SUBJECT_LOCATION, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_SUBSEC_TIME to TagMapper(ExifDirectoryBase.TAG_SUBSECOND_TIME, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_SUBSEC_TIME_DIGITIZED to TagMapper(ExifDirectoryBase.TAG_SUBSECOND_TIME_DIGITIZED, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_SUBSEC_TIME_ORIGINAL to TagMapper(ExifDirectoryBase.TAG_SUBSECOND_TIME_ORIGINAL, exifIFD0Dir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_THUMBNAIL_IMAGE_LENGTH to TagMapper(ExifDirectoryBase.TAG_IMAGE_HEIGHT, exifIFD0Dir, TagFormat.LONG), // IFD_THUMBNAIL_TAGS 0x0101
|
||||
ExifInterface.TAG_THUMBNAIL_IMAGE_WIDTH to TagMapper(ExifDirectoryBase.TAG_IMAGE_WIDTH, exifIFD0Dir, TagFormat.LONG), // IFD_THUMBNAIL_TAGS 0x0100
|
||||
ExifInterface.TAG_TRANSFER_FUNCTION to TagMapper(ExifDirectoryBase.TAG_TRANSFER_FUNCTION, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_USER_COMMENT to TagMapper(ExifDirectoryBase.TAG_USER_COMMENT, exifIFD0Dir, TagFormat.COMMENT),
|
||||
ExifInterface.TAG_WHITE_BALANCE to TagMapper(ExifDirectoryBase.TAG_WHITE_BALANCE, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_WHITE_POINT to TagMapper(ExifDirectoryBase.TAG_WHITE_POINT, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_X_RESOLUTION to TagMapper(ExifDirectoryBase.TAG_X_RESOLUTION, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_Y_CB_CR_COEFFICIENTS to TagMapper(ExifDirectoryBase.TAG_YCBCR_COEFFICIENTS, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_Y_CB_CR_POSITIONING to TagMapper(ExifDirectoryBase.TAG_YCBCR_POSITIONING, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_Y_CB_CR_SUB_SAMPLING to TagMapper(ExifDirectoryBase.TAG_YCBCR_SUBSAMPLING, exifIFD0Dir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_Y_RESOLUTION to TagMapper(ExifDirectoryBase.TAG_Y_RESOLUTION, exifIFD0Dir, TagFormat.RATIONAL),
|
||||
)
|
||||
|
||||
private val gpsTags: Map<String, Pair<Int, Directory>?> = hashMapOf(
|
||||
private val thumbnailTags: Map<String, TagMapper?> = hashMapOf(
|
||||
ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT to TagMapper(ExifThumbnailDirectory.TAG_THUMBNAIL_OFFSET, exifThumbnailDirectory, TagFormat.LONG), // IFD_TIFF_TAGS or IFD_THUMBNAIL_TAGS 0x0201
|
||||
ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH to TagMapper(ExifThumbnailDirectory.TAG_THUMBNAIL_LENGTH, exifThumbnailDirectory, TagFormat.LONG), // IFD_TIFF_TAGS or IFD_THUMBNAIL_TAGS 0x0202
|
||||
)
|
||||
|
||||
private val gpsTags: Map<String, TagMapper?> = hashMapOf(
|
||||
// GPS
|
||||
ExifInterface.TAG_GPS_ALTITUDE to Pair(GpsDirectory.TAG_ALTITUDE, gpsDir),
|
||||
ExifInterface.TAG_GPS_ALTITUDE_REF to Pair(GpsDirectory.TAG_ALTITUDE_REF, gpsDir),
|
||||
ExifInterface.TAG_GPS_AREA_INFORMATION to Pair(GpsDirectory.TAG_AREA_INFORMATION, gpsDir),
|
||||
ExifInterface.TAG_GPS_DATESTAMP to Pair(GpsDirectory.TAG_DATE_STAMP, gpsDir),
|
||||
ExifInterface.TAG_GPS_DEST_BEARING to Pair(GpsDirectory.TAG_DEST_BEARING, gpsDir),
|
||||
ExifInterface.TAG_GPS_DEST_BEARING_REF to Pair(GpsDirectory.TAG_DEST_BEARING_REF, gpsDir),
|
||||
ExifInterface.TAG_GPS_DEST_DISTANCE to Pair(GpsDirectory.TAG_DEST_DISTANCE, gpsDir),
|
||||
ExifInterface.TAG_GPS_DEST_DISTANCE_REF to Pair(GpsDirectory.TAG_DEST_DISTANCE_REF, gpsDir),
|
||||
ExifInterface.TAG_GPS_DEST_LATITUDE to Pair(GpsDirectory.TAG_DEST_LATITUDE, gpsDir),
|
||||
ExifInterface.TAG_GPS_DEST_LATITUDE_REF to Pair(GpsDirectory.TAG_DEST_LATITUDE_REF, gpsDir),
|
||||
ExifInterface.TAG_GPS_DEST_LONGITUDE to Pair(GpsDirectory.TAG_DEST_LONGITUDE, gpsDir),
|
||||
ExifInterface.TAG_GPS_DEST_LONGITUDE_REF to Pair(GpsDirectory.TAG_DEST_LONGITUDE_REF, gpsDir),
|
||||
ExifInterface.TAG_GPS_DIFFERENTIAL to Pair(GpsDirectory.TAG_DIFFERENTIAL, gpsDir),
|
||||
ExifInterface.TAG_GPS_DOP to Pair(GpsDirectory.TAG_DOP, gpsDir),
|
||||
ExifInterface.TAG_GPS_H_POSITIONING_ERROR to Pair(GpsDirectory.TAG_H_POSITIONING_ERROR, gpsDir),
|
||||
ExifInterface.TAG_GPS_IMG_DIRECTION to Pair(GpsDirectory.TAG_IMG_DIRECTION, gpsDir),
|
||||
ExifInterface.TAG_GPS_IMG_DIRECTION_REF to Pair(GpsDirectory.TAG_IMG_DIRECTION_REF, gpsDir),
|
||||
ExifInterface.TAG_GPS_LATITUDE to Pair(GpsDirectory.TAG_LATITUDE, gpsDir),
|
||||
ExifInterface.TAG_GPS_LATITUDE_REF to Pair(GpsDirectory.TAG_LATITUDE_REF, gpsDir),
|
||||
ExifInterface.TAG_GPS_LONGITUDE to Pair(GpsDirectory.TAG_LONGITUDE, gpsDir),
|
||||
ExifInterface.TAG_GPS_LONGITUDE_REF to Pair(GpsDirectory.TAG_LONGITUDE_REF, gpsDir),
|
||||
ExifInterface.TAG_GPS_MAP_DATUM to Pair(GpsDirectory.TAG_MAP_DATUM, gpsDir),
|
||||
ExifInterface.TAG_GPS_MEASURE_MODE to Pair(GpsDirectory.TAG_MEASURE_MODE, gpsDir),
|
||||
ExifInterface.TAG_GPS_PROCESSING_METHOD to Pair(GpsDirectory.TAG_PROCESSING_METHOD, gpsDir),
|
||||
ExifInterface.TAG_GPS_SATELLITES to Pair(GpsDirectory.TAG_SATELLITES, gpsDir),
|
||||
ExifInterface.TAG_GPS_SPEED to Pair(GpsDirectory.TAG_SPEED, gpsDir),
|
||||
ExifInterface.TAG_GPS_SPEED_REF to Pair(GpsDirectory.TAG_SPEED_REF, gpsDir),
|
||||
ExifInterface.TAG_GPS_STATUS to Pair(GpsDirectory.TAG_STATUS, gpsDir),
|
||||
ExifInterface.TAG_GPS_TIMESTAMP to Pair(GpsDirectory.TAG_TIME_STAMP, gpsDir),
|
||||
ExifInterface.TAG_GPS_TRACK to Pair(GpsDirectory.TAG_TRACK, gpsDir),
|
||||
ExifInterface.TAG_GPS_TRACK_REF to Pair(GpsDirectory.TAG_TRACK_REF, gpsDir),
|
||||
ExifInterface.TAG_GPS_VERSION_ID to Pair(GpsDirectory.TAG_VERSION_ID, gpsDir),
|
||||
ExifInterface.TAG_GPS_ALTITUDE to TagMapper(GpsDirectory.TAG_ALTITUDE, gpsDir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_GPS_ALTITUDE_REF to TagMapper(GpsDirectory.TAG_ALTITUDE_REF, gpsDir, TagFormat.BYTE),
|
||||
ExifInterface.TAG_GPS_AREA_INFORMATION to TagMapper(GpsDirectory.TAG_AREA_INFORMATION, gpsDir, TagFormat.COMMENT),
|
||||
ExifInterface.TAG_GPS_DATESTAMP to TagMapper(GpsDirectory.TAG_DATE_STAMP, gpsDir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_GPS_DEST_BEARING to TagMapper(GpsDirectory.TAG_DEST_BEARING, gpsDir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_GPS_DEST_BEARING_REF to TagMapper(GpsDirectory.TAG_DEST_BEARING_REF, gpsDir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_GPS_DEST_DISTANCE to TagMapper(GpsDirectory.TAG_DEST_DISTANCE, gpsDir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_GPS_DEST_DISTANCE_REF to TagMapper(GpsDirectory.TAG_DEST_DISTANCE_REF, gpsDir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_GPS_DEST_LATITUDE to TagMapper(GpsDirectory.TAG_DEST_LATITUDE, gpsDir, TagFormat.RATIONAL_ARRAY),
|
||||
ExifInterface.TAG_GPS_DEST_LATITUDE_REF to TagMapper(GpsDirectory.TAG_DEST_LATITUDE_REF, gpsDir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_GPS_DEST_LONGITUDE to TagMapper(GpsDirectory.TAG_DEST_LONGITUDE, gpsDir, TagFormat.RATIONAL_ARRAY),
|
||||
ExifInterface.TAG_GPS_DEST_LONGITUDE_REF to TagMapper(GpsDirectory.TAG_DEST_LONGITUDE_REF, gpsDir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_GPS_DIFFERENTIAL to TagMapper(GpsDirectory.TAG_DIFFERENTIAL, gpsDir, TagFormat.SHORT),
|
||||
ExifInterface.TAG_GPS_DOP to TagMapper(GpsDirectory.TAG_DOP, gpsDir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_GPS_H_POSITIONING_ERROR to TagMapper(GpsDirectory.TAG_H_POSITIONING_ERROR, gpsDir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_GPS_IMG_DIRECTION to TagMapper(GpsDirectory.TAG_IMG_DIRECTION, gpsDir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_GPS_IMG_DIRECTION_REF to TagMapper(GpsDirectory.TAG_IMG_DIRECTION_REF, gpsDir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_GPS_LATITUDE to TagMapper(GpsDirectory.TAG_LATITUDE, gpsDir, TagFormat.RATIONAL_ARRAY),
|
||||
ExifInterface.TAG_GPS_LATITUDE_REF to TagMapper(GpsDirectory.TAG_LATITUDE_REF, gpsDir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_GPS_LONGITUDE to TagMapper(GpsDirectory.TAG_LONGITUDE, gpsDir, TagFormat.RATIONAL_ARRAY),
|
||||
ExifInterface.TAG_GPS_LONGITUDE_REF to TagMapper(GpsDirectory.TAG_LONGITUDE_REF, gpsDir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_GPS_MAP_DATUM to TagMapper(GpsDirectory.TAG_MAP_DATUM, gpsDir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_GPS_MEASURE_MODE to TagMapper(GpsDirectory.TAG_MEASURE_MODE, gpsDir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_GPS_PROCESSING_METHOD to TagMapper(GpsDirectory.TAG_PROCESSING_METHOD, gpsDir, TagFormat.COMMENT),
|
||||
ExifInterface.TAG_GPS_SATELLITES to TagMapper(GpsDirectory.TAG_SATELLITES, gpsDir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_GPS_SPEED to TagMapper(GpsDirectory.TAG_SPEED, gpsDir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_GPS_SPEED_REF to TagMapper(GpsDirectory.TAG_SPEED_REF, gpsDir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_GPS_STATUS to TagMapper(GpsDirectory.TAG_STATUS, gpsDir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_GPS_TIMESTAMP to TagMapper(GpsDirectory.TAG_TIME_STAMP, gpsDir, TagFormat.RATIONAL_ARRAY),
|
||||
ExifInterface.TAG_GPS_TRACK to TagMapper(GpsDirectory.TAG_TRACK, gpsDir, TagFormat.RATIONAL),
|
||||
ExifInterface.TAG_GPS_TRACK_REF to TagMapper(GpsDirectory.TAG_TRACK_REF, gpsDir, TagFormat.ASCII),
|
||||
ExifInterface.TAG_GPS_VERSION_ID to TagMapper(GpsDirectory.TAG_VERSION_ID, gpsDir, TagFormat.BYTE),
|
||||
)
|
||||
|
||||
private val xmpTags: Map<String, Pair<Int, Directory>?> = hashMapOf(
|
||||
private val xmpTags: Map<String, TagMapper?> = hashMapOf(
|
||||
ExifInterface.TAG_XMP to null, // IFD_TIFF_TAGS 0x02BC
|
||||
)
|
||||
|
||||
private val rawTags: Map<String, Pair<Int, Directory>?> = hashMapOf(
|
||||
private val rawTags: Map<String, TagMapper?> = hashMapOf(
|
||||
// DNG
|
||||
ExifInterface.TAG_DEFAULT_CROP_SIZE to null, // IFD_EXIF_TAGS 0xC620
|
||||
ExifInterface.TAG_DNG_VERSION to null, // IFD_EXIF_TAGS 0xC612
|
||||
// ORF
|
||||
ExifInterface.TAG_ORF_ASPECT_FRAME to Pair(OlympusImageProcessingMakernoteDirectory.TagAspectFrame, olympusImageProcessingMakernoteDirectory), // ORF_IMAGE_PROCESSING_TAGS 0x1113
|
||||
ExifInterface.TAG_ORF_PREVIEW_IMAGE_LENGTH to Pair(OlympusCameraSettingsMakernoteDirectory.TagPreviewImageLength, olympusCameraSettingsMakernoteDirectory), // ORF_CAMERA_SETTINGS_TAGS 0x0102
|
||||
ExifInterface.TAG_ORF_PREVIEW_IMAGE_START to Pair(OlympusCameraSettingsMakernoteDirectory.TagPreviewImageStart, olympusCameraSettingsMakernoteDirectory), // ORF_CAMERA_SETTINGS_TAGS 0x0101
|
||||
ExifInterface.TAG_ORF_THUMBNAIL_IMAGE to Pair(OlympusMakernoteDirectory.TAG_THUMBNAIL_IMAGE, olympusMakernoteDirectory), // ORF_MAKER_NOTE_TAGS 0x0100
|
||||
ExifInterface.TAG_ORF_ASPECT_FRAME to TagMapper(OlympusImageProcessingMakernoteDirectory.TagAspectFrame, olympusImageProcessingMakernoteDirectory, null), // ORF_IMAGE_PROCESSING_TAGS 0x1113
|
||||
ExifInterface.TAG_ORF_PREVIEW_IMAGE_LENGTH to TagMapper(OlympusCameraSettingsMakernoteDirectory.TagPreviewImageLength, olympusCameraSettingsMakernoteDirectory, null), // ORF_CAMERA_SETTINGS_TAGS 0x0102
|
||||
ExifInterface.TAG_ORF_PREVIEW_IMAGE_START to TagMapper(OlympusCameraSettingsMakernoteDirectory.TagPreviewImageStart, olympusCameraSettingsMakernoteDirectory, null), // ORF_CAMERA_SETTINGS_TAGS 0x0101
|
||||
ExifInterface.TAG_ORF_THUMBNAIL_IMAGE to TagMapper(OlympusMakernoteDirectory.TAG_THUMBNAIL_IMAGE, olympusMakernoteDirectory, null), // ORF_MAKER_NOTE_TAGS 0x0100
|
||||
// RW2
|
||||
ExifInterface.TAG_RW2_ISO to Pair(PanasonicRawIFD0Directory.TagIso, panasonicRawIFD0Directory), // IFD_TIFF_TAGS 0x0017
|
||||
ExifInterface.TAG_RW2_JPG_FROM_RAW to Pair(PanasonicRawIFD0Directory.TagJpgFromRaw, panasonicRawIFD0Directory), // IFD_TIFF_TAGS 0x002E
|
||||
ExifInterface.TAG_RW2_SENSOR_BOTTOM_BORDER to Pair(PanasonicRawIFD0Directory.TagSensorBottomBorder, panasonicRawIFD0Directory), // IFD_TIFF_TAGS 0x0006
|
||||
ExifInterface.TAG_RW2_SENSOR_LEFT_BORDER to Pair(PanasonicRawIFD0Directory.TagSensorLeftBorder, panasonicRawIFD0Directory), // IFD_TIFF_TAGS 0x0005
|
||||
ExifInterface.TAG_RW2_SENSOR_RIGHT_BORDER to Pair(PanasonicRawIFD0Directory.TagSensorRightBorder, panasonicRawIFD0Directory), // IFD_TIFF_TAGS 0x0007
|
||||
ExifInterface.TAG_RW2_SENSOR_TOP_BORDER to Pair(PanasonicRawIFD0Directory.TagSensorTopBorder, panasonicRawIFD0Directory), // IFD_TIFF_TAGS 0x0004
|
||||
ExifInterface.TAG_RW2_ISO to TagMapper(PanasonicRawIFD0Directory.TagIso, panasonicRawIFD0Directory, null), // IFD_TIFF_TAGS 0x0017
|
||||
ExifInterface.TAG_RW2_JPG_FROM_RAW to TagMapper(PanasonicRawIFD0Directory.TagJpgFromRaw, panasonicRawIFD0Directory, null), // IFD_TIFF_TAGS 0x002E
|
||||
ExifInterface.TAG_RW2_SENSOR_BOTTOM_BORDER to TagMapper(PanasonicRawIFD0Directory.TagSensorBottomBorder, panasonicRawIFD0Directory, null), // IFD_TIFF_TAGS 0x0006
|
||||
ExifInterface.TAG_RW2_SENSOR_LEFT_BORDER to TagMapper(PanasonicRawIFD0Directory.TagSensorLeftBorder, panasonicRawIFD0Directory, null), // IFD_TIFF_TAGS 0x0005
|
||||
ExifInterface.TAG_RW2_SENSOR_RIGHT_BORDER to TagMapper(PanasonicRawIFD0Directory.TagSensorRightBorder, panasonicRawIFD0Directory, null), // IFD_TIFF_TAGS 0x0007
|
||||
ExifInterface.TAG_RW2_SENSOR_TOP_BORDER to TagMapper(PanasonicRawIFD0Directory.TagSensorTopBorder, panasonicRawIFD0Directory, null), // IFD_TIFF_TAGS 0x0004
|
||||
)
|
||||
|
||||
// list of known ExifInterface tags (as of androidx.exifinterface:exifinterface:1.3.0)
|
||||
// mapped to metadata-extractor tags (as of v2.14.0)
|
||||
@JvmField
|
||||
val allTags: Map<String, Pair<Int, Directory>?> = hashMapOf<String, Pair<Int, Directory>?>(
|
||||
val allTags: Map<String, TagMapper?> = hashMapOf<String, TagMapper?>(
|
||||
).apply {
|
||||
putAll(baseTags)
|
||||
putAll(thumbnailTags)
|
||||
|
@ -213,25 +226,101 @@ object ExifInterfaceHelper {
|
|||
}.filterValues { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
private fun describeDir(exif: ExifInterface, tags: Map<String, Pair<Int, Directory>?>): Map<String, String> {
|
||||
private fun describeDir(exif: ExifInterface, tags: Map<String, TagMapper?>): Map<String, String> {
|
||||
val dirMap = HashMap<String, String>()
|
||||
|
||||
fillMetadataExtractorDir(exif, tags)
|
||||
|
||||
for (kv in tags) {
|
||||
val exifInterfaceTag: String = kv.key
|
||||
if (exif.hasAttribute(exifInterfaceTag)) {
|
||||
val value: String? = exif.getAttribute(exifInterfaceTag)
|
||||
if (value != null && (value != "0" || !neverNullTags.contains(exifInterfaceTag))) {
|
||||
val mapper = kv.value
|
||||
val tagName = if (mapper != null) {
|
||||
val extractorTagType = mapper.first
|
||||
val extractorDir = mapper.second
|
||||
extractorDir.getTagName(extractorTagType)
|
||||
if (mapper != null) {
|
||||
val dir = mapper.dir
|
||||
val type = mapper.type
|
||||
val tagName = dir.getTagName(type)
|
||||
|
||||
val description: String? = dir.getDescription(type)
|
||||
if (description != null) {
|
||||
dirMap[tagName] = description
|
||||
} else {
|
||||
exifInterfaceTag
|
||||
Log.w(LOG_TAG, "failed to get description for tag=$exifInterfaceTag value=$value")
|
||||
dirMap[tagName] = value
|
||||
}
|
||||
} else {
|
||||
dirMap[exifInterfaceTag] = value
|
||||
}
|
||||
val tagValue: String? = exif.getAttribute(exifInterfaceTag)
|
||||
if (tagValue != null) {
|
||||
dirMap[tagName] = tagValue
|
||||
}
|
||||
}
|
||||
}
|
||||
return dirMap
|
||||
}
|
||||
|
||||
private fun fillMetadataExtractorDir(exif: ExifInterface, tags: Map<String, TagMapper?>) {
|
||||
for (kv in tags) {
|
||||
val exifInterfaceTag: String = kv.key
|
||||
if (exif.hasAttribute(exifInterfaceTag)) {
|
||||
val value: String? = exif.getAttribute(exifInterfaceTag)
|
||||
if (value != null && (value != "0" || !neverNullTags.contains(exifInterfaceTag))) {
|
||||
val mapper = kv.value
|
||||
if (mapper != null) {
|
||||
val obj: Any? = when (mapper.format) {
|
||||
TagFormat.ASCII, TagFormat.COMMENT, TagFormat.UNDEFINED -> value
|
||||
TagFormat.BYTE -> null // TODO TLAD convert ExifInterface string to byte
|
||||
TagFormat.SHORT -> value.toShortOrNull()
|
||||
TagFormat.LONG -> value.toLongOrNull()
|
||||
TagFormat.RATIONAL -> toRational(value)
|
||||
TagFormat.RATIONAL_ARRAY -> toRationalArray(value)
|
||||
null -> null
|
||||
}
|
||||
if (obj != null) {
|
||||
mapper.dir.setObject(mapper.type, obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun toRational(s: String?): Rational? {
|
||||
s ?: return null
|
||||
|
||||
// convert "12345/100"
|
||||
val parts = s.split("/")
|
||||
if (parts.size == 2) {
|
||||
val numerator = parts[0].toLongOrNull() ?: return null
|
||||
val denominator = parts[1].toLongOrNull() ?: return null
|
||||
return Rational(numerator, denominator)
|
||||
}
|
||||
|
||||
// convert "123.45"
|
||||
var d = s.toDoubleOrNull() ?: return null
|
||||
if (d == 0.0) return Rational(0, 1)
|
||||
var denominator: Long = 1
|
||||
while (d != floor(d)) {
|
||||
denominator *= 10
|
||||
d *= 10
|
||||
if (denominator > 10000000000) {
|
||||
// let's not get irrational
|
||||
return null
|
||||
}
|
||||
}
|
||||
val numerator: Long = d.roundToLong()
|
||||
return Rational(numerator, denominator)
|
||||
}
|
||||
|
||||
private fun toRationalArray(s: String?): Array<Rational>? {
|
||||
s ?: return null
|
||||
val list = s.split(",").mapNotNull { toRational(it) }
|
||||
if (list.isEmpty()) return null
|
||||
return list.toTypedArray()
|
||||
}
|
||||
}
|
||||
|
||||
enum class TagFormat {
|
||||
ASCII, COMMENT, BYTE, SHORT, LONG, RATIONAL, RATIONAL_ARRAY, UNDEFINED
|
||||
}
|
||||
|
||||
data class TagMapper(val type: Int, val dir: Directory, val format: TagFormat?)
|
||||
|
|
|
@ -4,7 +4,6 @@ import 'package:aves/model/settings/settings.dart';
|
|||
import 'package:aves/services/android_file_service.dart';
|
||||
import 'package:flutter_driver/driver_extension.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:pedantic/pedantic.dart';
|
||||
|
||||
import 'constants.dart';
|
||||
|
||||
|
@ -14,7 +13,7 @@ void main() {
|
|||
// scan files copied from test assets
|
||||
// we do it via the app instead of broadcasting via ADB
|
||||
// because `MEDIA_SCANNER_SCAN_FILE` intent got deprecated in API 29
|
||||
unawaited(AndroidFileService.scanFile(path.join(targetPicturesDir, 'ipse.jpg'), 'image/jpeg'));
|
||||
AndroidFileService.scanFile(path.join(targetPicturesDir, 'ipse.jpg'), 'image/jpeg');
|
||||
|
||||
configureAndLaunch();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue