Skip to content

Commit

Permalink
Copying exif metadata from original local media to thumbnail file. Fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
savvasdalkitsis committed Jan 18, 2024
1 parent 478ff65 commit f89731f
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import com.savvasdalkitsis.uhuruphotos.feature.media.local.domain.implementation
import com.savvasdalkitsis.uhuruphotos.feature.media.local.domain.implementation.service.model.LocalMediaStoreServiceItem
import com.savvasdalkitsis.uhuruphotos.feature.media.local.domain.implementation.service.model.LocalMediaStoreServiceItem.Photo
import com.savvasdalkitsis.uhuruphotos.feature.media.local.domain.implementation.service.model.LocalMediaStoreServiceItem.Video
import com.savvasdalkitsis.uhuruphotos.feature.media.local.domain.implementation.usecase.BitmapUseCase
import com.savvasdalkitsis.uhuruphotos.foundation.exif.api.usecase.ExifUseCase
import com.savvasdalkitsis.uhuruphotos.foundation.log.api.log
import com.savvasdalkitsis.uhuruphotos.foundation.log.api.runCatchingWithLog
Expand All @@ -64,6 +65,7 @@ class LocalMediaRepository @Inject constructor(
private val exifUseCase: ExifUseCase,
@LocalMediaModule.LocalMediaDateTimeFormat
private val dateTimeFormat: DateTimeFormatter,
private val bitmapUseCase: BitmapUseCase,
) {

fun observeMedia(): Flow<List<LocalMediaItemDetails>> = localMediaItemDetailsQueries.getItems()
Expand Down Expand Up @@ -276,10 +278,12 @@ class LocalMediaRepository @Inject constructor(
private fun Bitmap?.save(item: LocalMediaStoreServiceItem): String? = try {
this?.let { bitmap ->
val file = context.filesDir.subFolder("localThumbnails").subFile("${item.id}.jpg")
val saved = file.outputStream().use {
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, it)
with(bitmapUseCase) {
file.writeBytes(
bitmap.toJpeg().copyExifFrom(item.contentUri)
)
}
return file.absolutePath.takeIf { saved }
return file.absolutePath
}
} catch (e: Exception) {
log(e)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
Copyright 2024 Savvas Dalkitsis
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.savvasdalkitsis.uhuruphotos.feature.media.local.domain.implementation.usecase

import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import com.savvasdalkitsis.uhuruphotos.foundation.exif.api.usecase.ExifUseCase
import com.savvasdalkitsis.uhuruphotos.foundation.log.api.log
import dagger.hilt.android.qualifiers.ApplicationContext
import java.io.ByteArrayOutputStream
import java.io.IOException
import javax.inject.Inject

class BitmapUseCase @Inject constructor(
@ApplicationContext
private val context: Context,
private val exifUseCase: ExifUseCase,
) {
private val resolver get() = context.contentResolver

fun Bitmap.toJpeg(): ByteArray = ByteArrayOutputStream().use {
if (!compress(Bitmap.CompressFormat.JPEG, 95, it)) {
throw IOException("Failed to create JPEG.")
}
it.toByteArray()
}

fun ByteArray.copyExifFrom(
uri: Uri?
): ByteArray = when (uri) {
null -> this
else -> try {
resolver.openInputStream(uri)?.use { original ->
with(exifUseCase) {
copyExifFrom(original)
}
} ?: this
} catch (e: Exception) {
log(e)
this
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ import com.savvasdalkitsis.uhuruphotos.feature.media.local.domain.implementation
import com.savvasdalkitsis.uhuruphotos.foundation.date.api.DateDisplayer
import com.savvasdalkitsis.uhuruphotos.foundation.date.api.module.DateModule.ParsingDateFormat
import com.savvasdalkitsis.uhuruphotos.foundation.date.api.module.DateModule.ParsingDateTimeFormat
import com.savvasdalkitsis.uhuruphotos.foundation.exif.api.usecase.ExifUseCase
import com.savvasdalkitsis.uhuruphotos.foundation.log.api.log
import com.savvasdalkitsis.uhuruphotos.foundation.log.api.runCatchingWithLog
import com.savvasdalkitsis.uhuruphotos.foundation.notification.api.ForegroundNotificationWorker
Expand All @@ -63,10 +62,8 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import org.joda.time.format.DateTimeFormatter
import se.ansman.dagger.auto.AutoBind
import java.io.ByteArrayOutputStream
import java.io.IOException
import javax.inject.Inject

Expand All @@ -86,7 +83,7 @@ class LocalMediaUseCase @Inject constructor(
private val localMediaFolderRepository: LocalMediaFolderRepository,
private val mediaStoreVersionRepository: MediaStoreVersionRepository,
private val workerStatusUseCase: WorkerStatusUseCase,
private val exifUseCase: ExifUseCase,
private val bitmapUseCase: BitmapUseCase,
) : LocalMediaUseCase {

private val apiQPermissions = if (SDK_INT >= Q) {
Expand Down Expand Up @@ -222,7 +219,9 @@ class LocalMediaUseCase @Inject constructor(
false
}
else -> try {
val bytes = bitmap.toJpeg().copyExifFrom(originalFileUri)
val bytes = with(bitmapUseCase) {
bitmap.toJpeg().copyExifFrom(originalFileUri)
}
resolver.openOutputStream(uri)?.use {
it.write(bytes)
} ?: throw IOException("Failed to open output stream.")
Expand All @@ -235,30 +234,6 @@ class LocalMediaUseCase @Inject constructor(
}
}

private fun Bitmap.toJpeg() = ByteArrayOutputStream().use {
if (!compress(Bitmap.CompressFormat.JPEG, 95, it)) {
throw IOException("Failed to create JPEG.")
}
it.toByteArray()
}

private fun ByteArray.copyExifFrom(
uri: Uri?
): ByteArray = when (uri) {
null -> this
else -> try {
resolver.openInputStream(uri)?.use { original ->
with(exifUseCase) {
copyExifFrom(original)
}
} ?: this
} catch (e: Exception) {
log(e)
this
}
}


override suspend fun refreshAll(
onProgressChange: suspend (current: Int, total: Int) -> Unit,
) {
Expand Down

0 comments on commit f89731f

Please sign in to comment.