From c1f83e1706b66b19535347b42c2255a799db21fa Mon Sep 17 00:00:00 2001 From: tateisu Date: Tue, 8 Oct 2019 06:19:45 +0900 Subject: [PATCH] refactor --- .idea/dictionaries/tateisu.xml | 1 + .../main/java/jp/juggler/util/BitmapUtils.kt | 6 +- .../android/library/exif2/ExifData.kt | 30 +- .../android/library/exif2/ExifInterface.kt | 444 ++++++++---------- .../android/library/exif2/ExifTag.kt | 4 +- .../sephiroth/android/library/exif2/Test1.kt | 52 +- 6 files changed, 240 insertions(+), 297 deletions(-) diff --git a/.idea/dictionaries/tateisu.xml b/.idea/dictionaries/tateisu.xml index d171d3b2..f93c029b 100644 --- a/.idea/dictionaries/tateisu.xml +++ b/.idea/dictionaries/tateisu.xml @@ -57,6 +57,7 @@ kddi kenglxn kotlinx + lparams magick mailto mimumedon diff --git a/app/src/main/java/jp/juggler/util/BitmapUtils.kt b/app/src/main/java/jp/juggler/util/BitmapUtils.kt index 2e49f121..bc86316f 100644 --- a/app/src/main/java/jp/juggler/util/BitmapUtils.kt +++ b/app/src/main/java/jp/juggler/util/BitmapUtils.kt @@ -13,14 +13,14 @@ private val log = LogCategory("BitmapUtils") val InputStream.imageOrientation : Int? get() = try { - ExifInterface().apply { - readExif( + ExifInterface() + .readExif( this@imageOrientation, ExifInterface.Options.OPTION_IFD_0 or ExifInterface.Options.OPTION_IFD_1 or ExifInterface.Options.OPTION_IFD_EXIF ) - }.getTagIntValue(ExifInterface.TAG_ORIENTATION) + .getTagIntValue(ExifInterface.TAG_ORIENTATION) } catch(ex : Throwable) { log.w(ex, "imageOrientation: exif parse failed.") null diff --git a/exif/src/main/java/it/sephiroth/android/library/exif2/ExifData.kt b/exif/src/main/java/it/sephiroth/android/library/exif2/ExifData.kt index 76ff143d..54cdf5d2 100644 --- a/exif/src/main/java/it/sephiroth/android/library/exif2/ExifData.kt +++ b/exif/src/main/java/it/sephiroth/android/library/exif2/ExifData.kt @@ -16,6 +16,8 @@ package it.sephiroth.android.library.exif2 +import android.graphics.Bitmap +import android.graphics.BitmapFactory import android.util.Log import it.sephiroth.android.library.exif2.utils.notEmpty @@ -102,12 +104,28 @@ internal class ExifData( val stripList : List? get() = mStripBytes.filterNotNull().notEmpty() - /** - * Returns true it this header contains a compressed thumbnail. - */ - fun hasCompressedThumbnail() : Boolean { - return compressedThumbnail != null - } + val thumbnailBytes : ByteArray? + get() = when { + compressedThumbnail != null -> compressedThumbnail + hasUncompressedStrip() -> null // TODO: implement this + else -> null + } + + val thumbnailBitmap : Bitmap? + get() { + val compressedThumbnail = this.compressedThumbnail + if(compressedThumbnail != null) { + return BitmapFactory + .decodeByteArray(compressedThumbnail, 0, compressedThumbnail.size) + } + val stripList = this.stripList + if(stripList != null) { + // TODO: decoding uncompressed thumbnail is not implemented. + return null + } + + return null + } /** * Adds an uncompressed strip. diff --git a/exif/src/main/java/it/sephiroth/android/library/exif2/ExifInterface.kt b/exif/src/main/java/it/sephiroth/android/library/exif2/ExifInterface.kt index 3e73fe06..b31ed9d9 100644 --- a/exif/src/main/java/it/sephiroth/android/library/exif2/ExifInterface.kt +++ b/exif/src/main/java/it/sephiroth/android/library/exif2/ExifInterface.kt @@ -17,7 +17,6 @@ package it.sephiroth.android.library.exif2 import android.graphics.Bitmap -import android.graphics.BitmapFactory import android.util.Log import android.util.SparseIntArray import org.apache.commons.io.IOUtils @@ -46,12 +45,18 @@ import kotlin.math.ln * * @see ExifTag */ -@Suppress("unused", "unused") +@Suppress("unused") class ExifInterface { - private var mData = ExifData() + private val mGPSTimeStampCalendar : Calendar by lazy { + Calendar.getInstance(TimeZone.getTimeZone("UTC")) + } - private val mGPSTimeStampCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")) + val tagInfo : SparseIntArray by lazy { + SparseIntArray().initTagInfo() + } + + private var mData = ExifData() /** * Get the exif tags in this ExifInterface object or null if none exist. @@ -61,28 +66,14 @@ class ExifInterface { val allTags : List get() = mData.allTags - val tagInfo : SparseIntArray by lazy { SparseIntArray().also { it.initTagInfo() } } - /** - * Returns the thumbnail from IFD1 as a bitmap, or null if none exists. + * Returns the JPEG quality used to generate the image + * or 0 if not found * - * @return the thumbnail as a bitmap. + * @return qualityGuess */ - val thumbnailBitmap : Bitmap? - get() { - val compressedThumbnail = mData.compressedThumbnail - if(compressedThumbnail != null) { - return BitmapFactory - .decodeByteArray(compressedThumbnail, 0, compressedThumbnail.size) - } - val stripList = mData.stripList - if(stripList != null) { - // TODO: decoding uncompressed thumbnail is not implemented. - return null - } - - return null - } + val qualityGuess : Int + get() = mData.qualityGuess /** * Returns the thumbnail from IFD1 as a byte array, or null if none exists. @@ -92,28 +83,15 @@ class ExifInterface { * @return the thumbnail as a byte array. */ val thumbnailBytes : ByteArray? - get() = when { - mData.hasCompressedThumbnail() -> mData.compressedThumbnail - mData.hasUncompressedStrip() -> null // TODO: implement this - else -> null - } + get() = mData.thumbnailBytes /** - * Returns the thumbnail if it is jpeg compressed, or null if none exists. + * Returns the thumbnail from IFD1 as a bitmap, or null if none exists. * - * @return the thumbnail as a byte array. + * @return the thumbnail as a bitmap. */ - val thumbnail : ByteArray? - get() = mData.compressedThumbnail - - /** - * Returns the JPEG quality used to generate the image - * or 0 if not found - * - * @return qualityGuess - */ - val qualityGuess : Int - get() = mData.qualityGuess + val thumbnailBitmap : Bitmap? + get() = mData.thumbnailBitmap /** * this gives information about the process used to create the JPEG file. @@ -150,7 +128,7 @@ class ExifInterface { * @return true if the thumbnail is compressed. */ val isThumbnailCompressed : Boolean - get() = mData.hasCompressedThumbnail() + get() = mData.compressedThumbnail != null /** * Decodes the user comment tag into string as specified in the EXIF @@ -173,13 +151,21 @@ class ExifInterface { val latitudeRef = getTagStringValue(TAG_GPS_LATITUDE_REF) val longitude = getTagRationalValues(TAG_GPS_LONGITUDE) val longitudeRef = getTagStringValue(TAG_GPS_LONGITUDE_REF) - if(latitude == null || longitude == null || latitudeRef == null || longitudeRef == null || latitude.size < 3 || longitude.size < 3) { - return null + + return when { + + latitude == null + || longitude == null + || latitudeRef == null + || longitudeRef == null + || latitude.size < 3 + || longitude.size < 3 -> null + + else -> doubleArrayOf( + convertLatOrLongToDouble(latitude, latitudeRef), + convertLatOrLongToDouble(longitude, longitudeRef) + ) } - val latLon = DoubleArray(2) - latLon[0] = convertLatOrLongToDouble(latitude, latitudeRef) - latLon[1] = convertLatOrLongToDouble(longitude, longitudeRef) - return latLon } /** @@ -191,10 +177,10 @@ class ExifInterface { val latitude = getTagRationalValues(TAG_GPS_LATITUDE) val latitudeRef = getTagStringValue(TAG_GPS_LATITUDE_REF) - return if(null == latitude || null == latitudeRef) - null - else - convertRationalLatLonToString(latitude, latitudeRef) + return when { + null == latitude || null == latitudeRef -> null + else -> convertRationalLatLonToString(latitude, latitudeRef) + } } /** @@ -206,10 +192,23 @@ class ExifInterface { val longitude = getTagRationalValues(TAG_GPS_LONGITUDE) val longitudeRef = getTagStringValue(TAG_GPS_LONGITUDE_REF) - return if(null == longitude || null == longitudeRef) - null - else - convertRationalLatLonToString(longitude, longitudeRef) + return when { + null == longitude || null == longitudeRef -> null + else -> convertRationalLatLonToString(longitude, longitudeRef) + } + } + + val altitude : Double? // may null + get() = when(val gpsAltitude = getTagRationalValue(TAG_GPS_ALTITUDE)) { + null -> null + + else -> { + val seaLevel = when(getTagByteValue(TAG_GPS_ALTITUDE_REF)) { + 1.toByte() -> - 1 + else -> 1 + } + gpsAltitude.toDouble() * seaLevel + } } /** @@ -243,10 +242,6 @@ class ExifInterface { return null } - init { - mGPSDateStampFormat.timeZone = TimeZone.getTimeZone("UTC") - } - /** * Given the value from [.TAG_FOCAL_PLANE_RESOLUTION_UNIT] or [.TAG_RESOLUTION_UNIT] * this method will return the corresponding value in millimeters @@ -264,17 +259,11 @@ class ExifInterface { } /** - * Reads the exif tags from a file, clearing this ExifInterface object's - * existing exif tags. - * - * @param inFileName a string representing the filepath to jpeg file. - * @param options bit flag which defines which type of tags to process, see [it.sephiroth.android.library.exif2.ExifInterface.Options] - * @throws java.io.IOException for I/O error - * @see .readExif + * Clears this ExifInterface object's existing exif tags. */ - @Throws(IOException::class) - fun readExif(inFileName : String, options : Int) { - BufferedInputStream(FileInputStream(inFileName)).use { readExif(it, options) } + private fun clearExif() : ExifInterface { + mData = ExifData() + return this } /** @@ -293,39 +282,47 @@ class ExifInterface { * @throws java.io.IOException for I/O error */ @Throws(IOException::class) - fun readExif(inStream : InputStream, options : Int) { + fun readExif(inStream : InputStream, options : Int) : ExifInterface { mData = ExifReader(this).read(inStream, options) + return this } + /** + * Reads the exif tags from a file, clearing this ExifInterface object's + * existing exif tags. + * + * @param inFileName a string representing the filepath to jpeg file. + * @param options bit flag which defines which type of tags to process, see [it.sephiroth.android.library.exif2.ExifInterface.Options] + * @throws java.io.IOException for I/O error + * @see .readExif + */ + @Throws(IOException::class) + fun readExif(inFileName : String, options : Int) : ExifInterface = + BufferedInputStream(FileInputStream(inFileName)).use { readExif(it, options) } + + /** + * Reads the exif tags from a byte array, clearing this ExifInterface + * object's existing exif tags. + * + * @param jpeg a byte array containing a jpeg compressed image. + * @param options bit flag which defines which type of tags to process, see [it.sephiroth.android.library.exif2.ExifInterface.Options] + * @throws java.io.IOException for I/O error + * @see .readExif + */ + @Throws(IOException::class) + fun readExif(jpeg : ByteArray, options : Int) = + ByteArrayInputStream(jpeg).use { readExif(it, options) } + /** * Sets the exif tags, clearing this ExifInterface object's existing exif * tags. * * @param tags a collection of exif tags to set. */ - fun setExif(tags : Collection) { + fun setExif(tags : Collection) : ExifInterface { clearExif() setTags(tags) - } - - /** - * Clears this ExifInterface object's existing exif tags. - */ - private fun clearExif() { - mData = ExifData() - } - - /** - * Puts a collection of ExifTags into this ExifInterface objects's tags. Any - * previous ExifTags with the same TID and IFDs will be removed. - * - * @param tags a Collection of ExifTags. - * @see .setTag - */ - private fun setTags(tags : Collection) { - for(t in tags) { - setTag(t) - } + return this } /** @@ -337,8 +334,19 @@ class ExifInterface { * @return the previous ExifTag with the same TID and IFD or null if none * exists. */ - private fun setTag(tag : ExifTag) : ExifTag? { - return mData.addTag(tag) + private fun setTag(tag : ExifTag) : ExifTag? = + mData.addTag(tag) + + /** + * Puts a collection of ExifTags into this ExifInterface objects's tags. Any + * previous ExifTags with the same TID and IFDs will be removed. + * + * @param tags a Collection of ExifTags. + * @see .setTag + */ + private fun setTags(tags : Collection) : ExifInterface { + for(t in tags) setTag(t) + return this } @Throws(IOException::class) @@ -417,34 +425,17 @@ class ExifInterface { output.close() } + // input is used *ONLY* to read the image uncompressed data + // exif tags are not used here @Throws(IOException::class) fun writeExif(input : Bitmap, dstFilename : String, quality : Int) { Log.i(TAG, "writeExif: $dstFilename") - - // input is used *ONLY* to read the image uncompressed data - // exif tags are not used here - - val out = ByteArrayOutputStream() - input.compress(Bitmap.CompressFormat.JPEG, quality, out) - - val `in` = ByteArrayInputStream(out.toByteArray()) - out.close() - - writeExif(`in`, dstFilename) - } - - /** - * Reads the exif tags from a byte array, clearing this ExifInterface - * object's existing exif tags. - * - * @param jpeg a byte array containing a jpeg compressed image. - * @param options bit flag which defines which type of tags to process, see [it.sephiroth.android.library.exif2.ExifInterface.Options] - * @throws java.io.IOException for I/O error - * @see .readExif - */ - @Throws(IOException::class) - fun readExif(jpeg : ByteArray, options : Int) { - readExif(ByteArrayInputStream(jpeg), options) + ByteArrayOutputStream().use { out -> + input.compress(Bitmap.CompressFormat.JPEG, quality, out) + ByteArrayInputStream(out.toByteArray()).use { inStream -> + writeExif(inStream, dstFilename) + } + } } /** @@ -640,20 +631,6 @@ class ExifInterface { return ExifTag(getTrueTagKey(tagId), type, definedCount, ifdId, hasDefinedCount) } - /** - * Sets the value of an ExifTag if it exists it's default IFD. The value - * must be the correct type and length for that ExifTag. - * - * @param tagId a tag constant, e.g. [.TAG_IMAGE_WIDTH]. - * @param val the value to set. - * @return true if success, false if the ExifTag doesn't exist or the value - * is the wrong type/length. - */ - fun setTagValue(tagId : Int, `val` : Any) : Boolean { - val ifdId = getDefinedTagDefaultIfd(tagId) - return setTagValue(tagId, ifdId, `val`) - } - /** * Sets the value of an ExifTag if it exists in the given IFD. The value * must be the correct type and length for that ExifTag. @@ -665,19 +642,12 @@ class ExifInterface { * is the wrong type/length. * @see .setTagValue */ - private fun setTagValue(tagId : Int, ifdId : Int, tagValue : Any) : Boolean { - return getTag(tagId, ifdId)?.setValueAny(tagValue) ?: false - } - - /** - * Removes the ExifTag for a tag constant from that tag's default IFD. - * - * @param tagId a tag constant, e.g. [.TAG_IMAGE_WIDTH]. - */ - fun deleteTag(tagId : Int) { - val ifdId = getDefinedTagDefaultIfd(tagId) - deleteTag(tagId, ifdId) - } + private fun setTagValue( + tagId : Int, + tagValue : Any, + ifdId : Int = getDefinedTagDefaultIfd(tagId) + ) : Boolean = + getTag(tagId, ifdId)?.setValueAny(tagValue) ?: false /** * Removes the ExifTag for a tag constant from the given IFD. @@ -685,8 +655,12 @@ class ExifInterface { * @param tagId a tag constant, e.g. [.TAG_IMAGE_WIDTH]. * @param ifdId the IFD of the ExifTag to remove. */ - private fun deleteTag(tagId : Int, ifdId : Int) { + private fun deleteTag( + tagId : Int, + ifdId : Int = getDefinedTagDefaultIfd(tagId) + ) : ExifInterface { mData.removeTag(getTrueTagKey(tagId), ifdId) + return this } /** @@ -754,18 +728,16 @@ class ExifInterface { return TAG_NULL } - fun getTagDefinition(tagId : Short, defaultIfd : Int) : Int { - return tagInfo.get(defineTag(defaultIfd, tagId)) - } + fun getTagDefinition(tagId : Short, defaultIfd : Int) : Int = + tagInfo.get(defineTag(defaultIfd, tagId)) private fun getTagDefinitionsForTagId(tagId : Short) : IntArray? { val ifds = IfdData.list val defs = IntArray(ifds.size) var counter = 0 - val infos = tagInfo for(i in ifds) { val def = defineTag(i, tagId) - if(infos.get(def) != DEFINITION_NULL) { + if(tagInfo.get(def) != DEFINITION_NULL) { defs[counter ++] = def } } @@ -773,12 +745,8 @@ class ExifInterface { } - fun getTagDefinitionForTag(tag : ExifTag) : Int { - val type = tag.dataType - val count = tag.componentCount - val ifd = tag.ifd - return getTagDefinitionForTag(tag.tagId, type, count, ifd) - } + fun getTagDefinitionForTag(tag : ExifTag) : Int = + getTagDefinitionForTag(tag.tagId, tag.dataType, tag.componentCount, tag.ifd) private fun getTagDefinitionForTag( tagId : Short, @@ -786,11 +754,8 @@ class ExifInterface { count : Int, ifd : Int ) : Int { - val defs = getTagDefinitionsForTagId(tagId) ?: return TAG_NULL - val infos = tagInfo - var ret = TAG_NULL - for(i in defs) { - val info = infos.get(i) + getTagDefinitionsForTagId(tagId)?.forEach { i -> + val info = tagInfo.get(i) val def_type = getTypeFromInfo(info) val def_count = getComponentCountFromInfo(info) val def_ifds = getAllowedIfdsFromInfo(info) @@ -803,12 +768,14 @@ class ExifInterface { } } } - if(valid_ifd && type == def_type && (count == def_count || def_count == ExifTag.SIZE_UNDEFINED)) { - ret = i - break + if(valid_ifd + && type == def_type + && (count == def_count || def_count == ExifTag.SIZE_UNDEFINED) + ) { + return i } } - return ret + return TAG_NULL } /** @@ -827,16 +794,6 @@ class ExifInterface { // mTagInfo = null // } - /** - * Check if thumbnail exists. - * - * @return true if a compressed thumbnail exists. - */ - fun hasThumbnail() : Boolean { - // TODO: add back in uncompressed strip - return mData.hasCompressedThumbnail() - } - /** * Sets the thumbnail to be a jpeg compressed bitmap. Clears any prior * thumbnail. @@ -914,18 +871,6 @@ class ExifInterface { return true } - /** - * Creates a tag for a defined tag constant in the tag's default IFD. - * - * @param tagId a tag constant, e.g. [.TAG_IMAGE_WIDTH]. - * @param val the tag's value. - * @return an ExifTag object. - */ - fun buildTag(tagId : Int, `val` : Any) : ExifTag? { - val ifdId = getTrueIfd(tagId) - return buildTag(tagId, ifdId, `val`) - } - /** * Creates a tag for a defined tag constant in a given IFD if that IFD is * allowed for the tag. This method will fail anytime the appropriate @@ -937,21 +882,24 @@ class ExifInterface { * @return an ExifTag object or null if one could not be constructed. * @see .buildTag */ - fun buildTag(tagId : Int, ifdId : Int, tagValue : Any?) : ExifTag? { + fun buildTag(tagId : Int, tagValue : Any, ifdId : Int = getTrueIfd(tagId)) : ExifTag? { val info = tagInfo.get(tagId) - if(info == 0 || tagValue == null) { - return null - } - val type = getTypeFromInfo(info) + if(info == 0 || ! isIfdAllowed(info, ifdId)) return null + val definedCount = getComponentCountFromInfo(info) - val hasDefinedCount = definedCount != ExifTag.SIZE_UNDEFINED - if(! isIfdAllowed(info, ifdId)) { - return null + + val t = ExifTag( + tagId = getTrueTagKey(tagId), + dataType = getTypeFromInfo(info), + componentCount = definedCount, + ifd = ifdId, + mHasDefinedDefaultComponentCount = definedCount != ExifTag.SIZE_UNDEFINED + ) + + return when { + t.setValueAny(tagValue) -> t + else -> null } - val t = ExifTag(getTrueTagKey(tagId), type, definedCount, ifdId, hasDefinedCount) - return if(! t.setValueAny(tagValue)) { - null - } else t } /** @@ -2220,6 +2168,8 @@ class ExifInterface { private const val GPS_DATE_FORMAT_STR = "yyyy:MM:dd" private val mGPSDateStampFormat = SimpleDateFormat(GPS_DATE_FORMAT_STR, Locale.ENGLISH) + .apply { timeZone = TimeZone.getTimeZone("UTC") } + private const val DATETIME_FORMAT_STR = "yyyy:MM:dd kk:mm:ss" private val mDateTimeStampFormat = SimpleDateFormat(DATETIME_FORMAT_STR, Locale.ENGLISH) @@ -2227,25 +2177,21 @@ class ExifInterface { * Tags that contain offset markers. These are included in the banned * defines. */ - private val sOffsetTags = HashSet() - - init { - sOffsetTags.add(getTrueTagKey(TAG_GPS_IFD)) - sOffsetTags.add(getTrueTagKey(TAG_EXIF_IFD)) - sOffsetTags.add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT)) - sOffsetTags.add(getTrueTagKey(TAG_INTEROPERABILITY_IFD)) - sOffsetTags.add(getTrueTagKey(TAG_STRIP_OFFSETS)) + private val sOffsetTags = HashSet().apply { + add(getTrueTagKey(TAG_GPS_IFD)) + add(getTrueTagKey(TAG_EXIF_IFD)) + add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT)) + add(getTrueTagKey(TAG_INTEROPERABILITY_IFD)) + add(getTrueTagKey(TAG_STRIP_OFFSETS)) } /** * Tags with definitions that cannot be overridden (banned defines). */ - var sBannedDefines = HashSet(sOffsetTags) - - init { - sBannedDefines.add(getTrueTagKey(TAG_NULL)) - sBannedDefines.add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH)) - sBannedDefines.add(getTrueTagKey(TAG_STRIP_BYTE_COUNTS)) + var sBannedDefines = HashSet(sOffsetTags).apply { + add(getTrueTagKey(TAG_NULL)) + add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH)) + add(getTrueTagKey(TAG_STRIP_BYTE_COUNTS)) } /** @@ -2260,9 +2206,8 @@ class ExifInterface { * [.getTrueTagKey]). * @return true if the TID is that of an offset tag. */ - fun isOffsetTag(tag : Short) : Boolean { - return sOffsetTags.contains(tag) - } + fun isOffsetTag(tag : Short) : Boolean = + sOffsetTags.contains(tag) /** * Returns the Orientation ExifTag value for a given number of degrees. @@ -2311,18 +2256,14 @@ class ExifInterface { * seconds/3600 */ fun convertLatOrLongToDouble(coordinate : Array, reference : String) : Double { - try { - val degrees = coordinate[0].toDouble() - val minutes = coordinate[1].toDouble() - val seconds = coordinate[2].toDouble() - val result = degrees + minutes / 60.0 + seconds / 3600.0 - return if(reference.startsWith("S") || reference.startsWith("W")) { - - result - } else result - } catch(e : ArrayIndexOutOfBoundsException) { - throw IllegalArgumentException() + val degrees = coordinate[0].toDouble() + val minutes = coordinate[1].toDouble() + val seconds = coordinate[2].toDouble() + val result = degrees + minutes / 60.0 + seconds / 3600.0 + return when { + reference.startsWith("S") || reference.startsWith("W") -> - result + else -> result } - } fun getAllowedIfdsFromInfo(info : Int) : IntArray? { @@ -2397,22 +2338,15 @@ class ExifInterface { /** * Returns the default IFD for a tag constant. */ - fun getTrueIfd(tag : Int) : Int { - return tag.ushr(16) - } + fun getTrueIfd(tag : Int) : Int = tag.ushr(16) /** * Returns the TID for a tag constant. */ - fun getTrueTagKey(tag : Int) : Short { - // Truncate - return tag.toShort() - } + fun getTrueTagKey(tag : Int) : Short = tag.toShort() - private fun getFlagsFromAllowedIfds(allowedIfds : IntArray?) : Int { - if(allowedIfds == null || allowedIfds.isEmpty()) { - return 0 - } + private fun getFlagsFromAllowedIfds(allowedIfds : IntArray) : Int { + if(allowedIfds.isEmpty()) return 0 var flags = 0 val ifds = IfdData.list for(i in 0 until IfdData.TYPE_IFD_COUNT) { @@ -2426,20 +2360,14 @@ class ExifInterface { return flags } - private fun getComponentCountFromInfo(info : Int) : Int { - return info and 0x0ffff - } + private fun getComponentCountFromInfo(info : Int) : Int = info and 0x0ffff - private fun getTypeFromInfo(info : Int) : Short { - return (info shr 16 and 0x0ff).toShort() - } + private fun getTypeFromInfo(info : Int) : Short = (info shr 16 and 0x0ff).toShort() /** * Returns the constant representing a tag with a given TID and default IFD. */ - fun defineTag(ifdId : Int, tagId : Short) : Int { - return tagId or (ifdId shl 16) - } + fun defineTag(ifdId : Int, tagId : Short) : Int = tagId or (ifdId shl 16) private fun convertRationalLatLonToString( coord : Array, @@ -2475,8 +2403,7 @@ class ExifInterface { * @param timeZone the target timezone * @return the parsed date */ - fun getDateTime(dateTimeString : String?, timeZone : TimeZone) : Date? { - dateTimeString ?: return null + fun getDateTime(dateTimeString : String, timeZone : TimeZone) : Date? { return try { val formatter = SimpleDateFormat(DATETIME_FORMAT_STR, Locale.ENGLISH) @@ -2489,19 +2416,14 @@ class ExifInterface { } fun isIfdAllowed(info : Int, ifd : Int) : Boolean { - val ifds = IfdData.list val ifdFlags = getAllowedIfdFlagsFromInfo(info) - for(i in ifds.indices) { - if(ifd == ifds[i] && ifdFlags shr i and 1 == 1) { - return true - } + IfdData.list.forEachIndexed { itemIndex, itemId -> + if(ifd == itemId && ifdFlags shr itemIndex and 1 == 1) return true } return false } - private fun getAllowedIfdFlagsFromInfo(info : Int) : Int { - return info.ushr(24) - } + private fun getAllowedIfdFlagsFromInfo(info : Int) : Int = info.ushr(24) private fun toExifLatLong(valueArg : Double) : Array { // convert to the format dd/1 mm/1 ssss/100 @@ -2530,7 +2452,7 @@ class ExifInterface { infix fun Short.shr(bits : Int) : Int = (this.toInt() and 0xffff) shr bits infix fun Short.or(bits : Int) : Int = (this.toInt() and 0xffff) or bits - private fun SparseIntArray.initTagInfo() { + private fun SparseIntArray.initTagInfo() : SparseIntArray { var f : Int @@ -2680,6 +2602,8 @@ class ExifInterface { f = getFlagsFromAllowedIfds(intArrayOf(IfdData.TYPE_IFD_INTEROPERABILITY)) shl 24 put(TAG_INTEROPERABILITY_INDEX, f or (ExifTag.TYPE_ASCII shl 16)) put(TAG_INTEROP_VERSION, f or (ExifTag.TYPE_UNDEFINED shl 16) or 4) + + return this } } diff --git a/exif/src/main/java/it/sephiroth/android/library/exif2/ExifTag.kt b/exif/src/main/java/it/sephiroth/android/library/exif2/ExifTag.kt index ae31336d..75ae4d70 100644 --- a/exif/src/main/java/it/sephiroth/android/library/exif2/ExifTag.kt +++ b/exif/src/main/java/it/sephiroth/android/library/exif2/ExifTag.kt @@ -347,9 +347,9 @@ open class ExifTag internal constructor( * type. * */ - inline fun setValueAny(obj : T) : Boolean { + inline fun setValueAny(obj : T) : Boolean { when(obj) { - null -> return false + // null -> return false is String -> return setValue(obj) is ByteArray -> return setValue(obj) diff --git a/exif/src/test/java/it/sephiroth/android/library/exif2/Test1.kt b/exif/src/test/java/it/sephiroth/android/library/exif2/Test1.kt index 73bd1d29..efd31b11 100644 --- a/exif/src/test/java/it/sephiroth/android/library/exif2/Test1.kt +++ b/exif/src/test/java/it/sephiroth/android/library/exif2/Test1.kt @@ -35,14 +35,12 @@ class Test1 { try { val o = FileInputStream(getFile(fileName)).use { inStream -> ExifInterface() - .apply { - readExif( - inStream, - ExifInterface.Options.OPTION_IFD_0 - or ExifInterface.Options.OPTION_IFD_1 - or ExifInterface.Options.OPTION_IFD_EXIF - ) - } + .readExif( + inStream, + ExifInterface.Options.OPTION_IFD_0 + or ExifInterface.Options.OPTION_IFD_1 + or ExifInterface.Options.OPTION_IFD_EXIF + ) .getTagIntValue(ExifInterface.TAG_ORIENTATION) } Pair(o, null) @@ -54,14 +52,12 @@ class Test1 { try { val o = FileInputStream(getFile(fileName)).use { inStream -> ExifInterface() - .apply { - readExif( - inStream, - ExifInterface.Options.OPTION_IFD_0 - or ExifInterface.Options.OPTION_IFD_1 - or ExifInterface.Options.OPTION_IFD_EXIF - ) - } + .readExif( + inStream, + ExifInterface.Options.OPTION_IFD_0 + or ExifInterface.Options.OPTION_IFD_1 + or ExifInterface.Options.OPTION_IFD_EXIF + ) .thumbnailBytes } Pair(o, null) @@ -69,14 +65,12 @@ class Test1 { Pair(null, ex) } - private fun testNotJpegSub(fileName : String) { - val (o, ex) = getOrientation(fileName) - assertTrue("testNotJpegSub", o == null && ex != null) - if(ex != null) println("exception raised: ${ex::class.java} ${ex.message}") - } - @Test fun testNotJpeg() { + fun testNotJpegSub(fileName : String) { + val (o, ex) = getOrientation(fileName) + assertTrue("testNotJpegSub", o == null && ex != null) + } testNotJpegSub("test.gif") testNotJpegSub("test.png") testNotJpegSub("test.webp") @@ -93,22 +87,28 @@ class Test1 { rvO = getOrientation(fileName) assertEquals(fileName, 6, rvO.first) rvT = getThumbnailBytes(fileName) - assertNull(fileName,rvT.first) + assertNull(fileName, rvT.first) // this file has orientation 1 fileName = "test1.jpg" rvO = getOrientation(fileName) assertEquals(fileName, 1, rvO.first) rvT = getThumbnailBytes(fileName) - assertNull(fileName,rvT.first) + assertNull(fileName, rvT.first) // this file has no orientation, it raises exception. fileName = "test2.jpg" rvO = getOrientation(fileName) - assertNotNull(fileName, rvO.second) // + assertNotNull( + fileName, + rvO.second + ) // rvT = getThumbnailBytes(fileName) - assertNotNull(fileName,rvT.second) // + assertNotNull( + fileName, + rvT.second + ) // }