diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/EditActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/EditActivity.kt index c9426fd29..853264d71 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/EditActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/EditActivity.kt @@ -39,6 +39,7 @@ import com.simplemobiletools.gallery.pro.dialogs.OtherAspectRatioDialog import com.simplemobiletools.gallery.pro.dialogs.ResizeDialog import com.simplemobiletools.gallery.pro.dialogs.SaveAsDialog import com.simplemobiletools.gallery.pro.extensions.config +import com.simplemobiletools.gallery.pro.extensions.copyNonDimensionAttributesTo import com.simplemobiletools.gallery.pro.extensions.fixDateTaken import com.simplemobiletools.gallery.pro.extensions.openEditor import com.simplemobiletools.gallery.pro.helpers.* @@ -196,47 +197,47 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener editor_draw_canvas.beGone() val options = RequestOptions() - .skipMemoryCache(true) - .diskCacheStrategy(DiskCacheStrategy.NONE) + .skipMemoryCache(true) + .diskCacheStrategy(DiskCacheStrategy.NONE) Glide.with(this) - .asBitmap() - .load(uri) - .apply(options) - .listener(object : RequestListener { - override fun onLoadFailed(e: GlideException?, model: Any?, target: Target?, isFirstResource: Boolean): Boolean { - if (uri != originalUri) { - uri = originalUri - Handler().post { - loadDefaultImageView() - } + .asBitmap() + .load(uri) + .apply(options) + .listener(object : RequestListener { + override fun onLoadFailed(e: GlideException?, model: Any?, target: Target?, isFirstResource: Boolean): Boolean { + if (uri != originalUri) { + uri = originalUri + Handler().post { + loadDefaultImageView() } - return false + } + return false + } + + override fun onResourceReady(bitmap: Bitmap?, model: Any?, target: Target?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { + val currentFilter = getFiltersAdapter()?.getCurrentFilter() + if (filterInitialBitmap == null) { + loadCropImageView() + bottomCropRotateClicked() } - override fun onResourceReady(bitmap: Bitmap?, model: Any?, target: Target?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { - val currentFilter = getFiltersAdapter()?.getCurrentFilter() - if (filterInitialBitmap == null) { - loadCropImageView() - bottomCropRotateClicked() + if (filterInitialBitmap != null && currentFilter != null && currentFilter.filter.name != getString(R.string.none)) { + default_image_view.onGlobalLayout { + applyFilter(currentFilter) } - - if (filterInitialBitmap != null && currentFilter != null && currentFilter.filter.name != getString(R.string.none)) { - default_image_view.onGlobalLayout { - applyFilter(currentFilter) - } - } else { - filterInitialBitmap = bitmap - } - - if (isCropIntent) { - bottom_primary_filter.beGone() - bottom_primary_draw.beGone() - } - - return false + } else { + filterInitialBitmap = bitmap } - }).into(default_image_view) + + if (isCropIntent) { + bottom_primary_filter.beGone() + bottom_primary_draw.beGone() + } + + return false + } + }).into(default_image_view) } private fun loadCropImageView() { @@ -275,17 +276,17 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener val size = Point() windowManager.defaultDisplay.getSize(size) val options = RequestOptions() - .format(DecodeFormat.PREFER_ARGB_8888) - .skipMemoryCache(true) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .fitCenter() + .format(DecodeFormat.PREFER_ARGB_8888) + .skipMemoryCache(true) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .fitCenter() try { val builder = Glide.with(applicationContext) - .asBitmap() - .load(uri) - .apply(options) - .into(editor_draw_canvas.width, editor_draw_canvas.height) + .asBitmap() + .load(uri) + .apply(options) + .into(editor_draw_canvas.width, editor_draw_canvas.height) val bitmap = builder.get() runOnUiThread { @@ -304,16 +305,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener @TargetApi(Build.VERSION_CODES.N) private fun saveImage() { - var inputStream: InputStream? = null - try { - if (isNougatPlus()) { - inputStream = contentResolver.openInputStream(uri!!) - oldExif = ExifInterface(inputStream!!) - } - } catch (e: Exception) { - } finally { - inputStream?.close() - } + setOldExif() if (crop_image_view.isVisible()) { crop_image_view.getCroppedImageAsync() @@ -354,6 +346,20 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener } } + @TargetApi(Build.VERSION_CODES.N) + private fun setOldExif() { + var inputStream: InputStream? = null + try { + if (isNougatPlus()) { + inputStream = contentResolver.openInputStream(uri!!) + oldExif = ExifInterface(inputStream!!) + } + } catch (e: Exception) { + } finally { + inputStream?.close() + } + } + private fun shareImage() { ensureBackgroundThread { when { @@ -591,17 +597,17 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener val bitmap = try { Glide.with(this) - .asBitmap() - .load(uri).listener(object : RequestListener { - override fun onLoadFailed(e: GlideException?, model: Any?, target: Target?, isFirstResource: Boolean): Boolean { - showErrorToast(e.toString()) - return false - } + .asBitmap() + .load(uri).listener(object : RequestListener { + override fun onLoadFailed(e: GlideException?, model: Any?, target: Target?, isFirstResource: Boolean): Boolean { + showErrorToast(e.toString()) + return false + } - override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target?, dataSource: DataSource?, isFirstResource: Boolean) = false - }) - .submit(thumbnailSize, thumbnailSize) - .get() + override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target?, dataSource: DataSource?, isFirstResource: Boolean) = false + }) + .submit(thumbnailSize, thumbnailSize) + .get() } catch (e: GlideException) { showErrorToast(e) finish() @@ -742,6 +748,8 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener override fun onCropImageComplete(view: CropImageView, result: CropImageView.CropResult) { if (result.error == null) { + setOldExif() + val bitmap = result.bitmap if (isSharingBitmap) { isSharingBitmap = false @@ -862,7 +870,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener try { if (isNougatPlus()) { val newExif = ExifInterface(file.absolutePath) - oldExif?.copyTo(newExif, false) + oldExif?.copyNonDimensionAttributesTo(newExif) } } catch (e: Exception) { } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/ViewPagerActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/ViewPagerActivity.kt index fc15c58c0..232c07f5b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/ViewPagerActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/ViewPagerActivity.kt @@ -986,7 +986,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View if (isNougatPlus()) { val newExif = ExifInterface(file.absolutePath) - oldExif?.copyTo(newExif, false) + oldExif?.copyNonDimensionAttributesTo(newExif) } } catch (e: Exception) { } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/ExifInterface.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/ExifInterface.kt new file mode 100644 index 000000000..6c1ba0b0b --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/ExifInterface.kt @@ -0,0 +1,57 @@ +package com.simplemobiletools.gallery.pro.extensions + +import android.media.ExifInterface +import java.lang.reflect.Field +import java.lang.reflect.Modifier + +fun ExifInterface.copyNonDimensionAttributesTo(destination: ExifInterface) { + val attributes = ExifInterfaceAttributes.AllNonDimensionAttributes + + attributes.forEach { + val value = getAttribute(it) + if (value != null) { + destination.setAttribute(it, value) + } + } + + try { + destination.saveAttributes() + } catch (ignored: Exception) { + } +} + +private class ExifInterfaceAttributes { + companion object { + val AllNonDimensionAttributes = getAllNonDimensionExifAttributes() + + private fun getAllNonDimensionExifAttributes(): List { + val tagFields = ExifInterface::class.java.fields.filter { field -> isExif(field) } + + val excludeAttributes = arrayListOf( + ExifInterface.TAG_IMAGE_LENGTH, + ExifInterface.TAG_IMAGE_WIDTH, + ExifInterface.TAG_PIXEL_X_DIMENSION, + ExifInterface.TAG_PIXEL_Y_DIMENSION, + ExifInterface.TAG_THUMBNAIL_IMAGE_LENGTH, + ExifInterface.TAG_THUMBNAIL_IMAGE_WIDTH, + ExifInterface.TAG_ORIENTATION) + + return tagFields + .map { tagField -> tagField.get(null) as String } + .filter { x -> !excludeAttributes.contains(x) } + .distinct() + } + + private fun isExif(field: Field): Boolean { + return field.type == String::class.java && + isPublicStaticFinal(field.modifiers) && + field.name.startsWith("TAG_") + } + + private const val publicStaticFinal = Modifier.PUBLIC or Modifier.STATIC or Modifier.FINAL + + private fun isPublicStaticFinal(modifiers: Int): Boolean { + return modifiers and publicStaticFinal > 0 + } + } +}