Working EXIF lossless on Internal & SD

Tested and works on both Internal Storage and External SD cards
This commit is contained in:
Guillaume 2017-11-03 17:01:13 +01:00 committed by GitHub
parent d0e4fd1df7
commit 63d39b589a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -46,8 +46,9 @@ import com.simplemobiletools.gallery.models.Medium
import kotlinx.android.synthetic.main.activity_medium.* import kotlinx.android.synthetic.main.activity_medium.*
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.InputStream
import java.io.OutputStream
import java.util.* import java.util.*
class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, ViewPagerFragment.FragmentListener { class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, ViewPagerFragment.FragmentListener {
@ -454,52 +455,60 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
SaveAsDialog(this, currPath, false) { SaveAsDialog(this, currPath, false) {
Thread({ Thread({
toast(R.string.saving) toast(R.string.saving)
if (it.isJpg() && !isPathOnSD(it)) { val selectedFile = File(it)
if (it == currPath) { val tmpFile = File(filesDir, ".tmp_${it.getFilenameFromPath()}")
rotateFileByExif(it) try {
runOnUiThread { val bitmap = BitmapFactory.decodeFile(currPath)
(getCurrentFragment() as? PhotoFragment)?.refreshBitmap() getFileOutputStream(tmpFile) {
if (it == null) {
toast(R.string.unknown_error_occurred)
deleteFile(tmpFile) {}
return@getFileOutputStream
} }
} else {
copyFile(currPath, it) if (currPath.isJpg()) {
rotateFileByExif(it) saveRotation(getCurrentFile(), tmpFile)
} else {
saveFile(tmpFile, bitmap, it as FileOutputStream)
}
if (tmpFile.length() > 0 && selectedFile.exists()) {
deleteFile(selectedFile) {}
}
copyFile(tmpFile, selectedFile)
scanPath(selectedFile.absolutePath) {}
deleteFile(tmpFile) {} // Not necessary?
toast(R.string.file_saved)
it.flush()
it.close()
mRotationDegrees = 0f
invalidateOptionsMenu()
} }
} else { } catch (e: OutOfMemoryError) {
rotateFileByDegrees(currPath, it) toast(R.string.out_of_memory_error)
deleteFile(tmpFile) {}
} catch (e: Exception) {
showErrorToast(e)
deleteFile(tmpFile) {}
} }
}).start() }).start()
} }
} }
private fun rotateFileByDegrees(sourcePath: String, destinationPath: String) { private fun copyFile(source: File, destination: File) {
val tmpFile = File(File(destinationPath).parent, ".tmp_${destinationPath.getFilenameFromPath()}") var inputStream: InputStream? = null
var out: OutputStream? = null
try { try {
getFileOutputStream(tmpFile) { if (needsStupidWritePermissions(destination.absolutePath)) {
if (it == null) { getFileDocument(destination.parent)
toast(R.string.unknown_error_occurred)
return@getFileOutputStream
}
val bitmap = BitmapFactory.decodeFile(sourcePath)
saveFile(tmpFile, bitmap, it as FileOutputStream)
it.flush()
it.close()
val destination = File(destinationPath)
deleteFile(destination) {
renameFile(tmpFile, destination) {}
}
toast(R.string.file_saved)
mRotationDegrees = 0f
invalidateOptionsMenu()
} }
} catch (e: OutOfMemoryError) { out = getFileOutputStreamSync(destination.absolutePath, source.getMimeType(), getFileDocument(destination.parent))
toast(R.string.out_of_memory_error) inputStream = FileInputStream(source)
deleteFile(tmpFile) {} inputStream.copyTo(out!!)
} catch (e: Exception) { } finally {
showErrorToast(e) inputStream?.close()
deleteFile(tmpFile) {} out?.close()
} }
} }
@ -510,34 +519,13 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
bmp.compress(file.getCompressionFormat(), 90, out) bmp.compress(file.getCompressionFormat(), 90, out)
} }
private fun copyFile(sourcePath: String, destinationPath: String) { private fun saveRotation(input: File, output: File) {
var inputStream: FileInputStream? = null copyFile(input, output)
var outputStream: FileOutputStream? = null val exif = ExifInterface(output.absolutePath)
try { var orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
inputStream = FileInputStream(sourcePath) var orientationDegrees = (degreesForRotation(orientation) + mRotationDegrees) % 360
outputStream = FileOutputStream(destinationPath)
inputStream.copyTo(outputStream)
scanPath(destinationPath) {}
} catch (ignored: FileNotFoundException) {
} finally {
inputStream?.close()
outputStream?.close()
}
}
private fun rotateFileByExif(path: String) {
val exif = ExifInterface(path)
val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
val orientationDegrees = (degreesForRotation(orientation) + mRotationDegrees) % 360
exif.setAttribute(ExifInterface.TAG_ORIENTATION, rotationFromDegrees(orientationDegrees)) exif.setAttribute(ExifInterface.TAG_ORIENTATION, rotationFromDegrees(orientationDegrees))
exif.saveAttributes() exif.saveAttributes()
if (!config.keepLastModified) {
File(getCurrentPath()).setLastModified(System.currentTimeMillis())
}
mRotationDegrees = 0f
invalidateOptionsMenu()
toast(R.string.file_saved)
} }
private fun degreesForRotation(orientation: Int) = when (orientation) { private fun degreesForRotation(orientation: Int) = when (orientation) {