Skip to content

Commit

Permalink
Merge pull request #142 from Team-Motivoo/feat/bitmap-resize
Browse files Browse the repository at this point in the history
[Feat] 비트맵 리사이징
  • Loading branch information
Jokwanhee committed Apr 19, 2024
2 parents 15f0ddb + a995e0b commit 65aeccd
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package sopt.motivoo.data.repository

import android.graphics.Bitmap
import okhttp3.RequestBody.Companion.toRequestBody
import sopt.motivoo.data.datasource.remote.HomeDataSource
import sopt.motivoo.data.model.request.home.RequestMissionTodayDto
import sopt.motivoo.domain.entity.error.ResponseHandler
Expand All @@ -10,7 +9,7 @@ import sopt.motivoo.domain.entity.home.MissionChoiceData
import sopt.motivoo.domain.entity.home.MissionImageData
import sopt.motivoo.domain.error.UserErrorHandler
import sopt.motivoo.domain.repository.HomeRepository
import java.io.ByteArrayOutputStream
import sopt.motivoo.util.BitmapRequestBody
import javax.inject.Inject

class HomeRepositoryImpl @Inject constructor(
Expand Down Expand Up @@ -53,9 +52,7 @@ class HomeRepositoryImpl @Inject constructor(
}

override suspend fun uploadPhoto(url: String, bitmap: Bitmap): Unit? = try {
val outputStream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 80, outputStream)
val requestBody = outputStream.toByteArray().toRequestBody()
val requestBody = BitmapRequestBody(bitmap).create(50)
homeDataSource.uploadPhoto(url, requestBody)
} catch (e: Exception) {
null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ import sopt.motivoo.R
import sopt.motivoo.databinding.BottomSheetHomeBinding
import sopt.motivoo.presentation.home.HomePictureState
import sopt.motivoo.presentation.home.viewmodel.HomeViewModel
import sopt.motivoo.util.BitmapUtil
import sopt.motivoo.util.Constants.S3_BUCKET_NAME
import sopt.motivoo.util.UriManager
import sopt.motivoo.util.extension.createUriToBitmap

@AndroidEntryPoint
class HomeBottomSheetFragment : BottomSheetDialogFragment() {
Expand All @@ -39,6 +39,7 @@ class HomeBottomSheetFragment : BottomSheetDialogFragment() {
private val viewModel: HomeViewModel by viewModels()

var pictureUri: Uri? = null
private lateinit var bitmapUtil: BitmapUtil

private val isCameraPermissionResult =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
Expand All @@ -60,8 +61,10 @@ class HomeBottomSheetFragment : BottomSheetDialogFragment() {
registerForActivityResult(ActivityResultContracts.TakePicture()) { isSuccess ->
if (isSuccess) {
binding.pvLoading.visibility = View.VISIBLE
pictureUri?.let {
viewModel.getMissionImage(S3_BUCKET_NAME, requireContext().createUriToBitmap(it))
pictureUri?.let { uri ->
bitmapUtil.createUriToBitmap(uri, size = 2)?.let { bitmap ->
viewModel.getMissionImage(S3_BUCKET_NAME, bitmap)
}
}
}
}
Expand Down Expand Up @@ -92,6 +95,7 @@ class HomeBottomSheetFragment : BottomSheetDialogFragment() {

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bitmapUtil = BitmapUtil(requireContext())
setLayoutSize()
collectHomePictureState()
onClickTakePicture()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,36 @@ import sopt.motivoo.R
import sopt.motivoo.databinding.DialogHomePhotoBinding
import sopt.motivoo.presentation.home.HomePictureState
import sopt.motivoo.presentation.home.viewmodel.HomeViewModel
import sopt.motivoo.util.BitmapUtil
import sopt.motivoo.util.Constants.S3_BUCKET_NAME
import sopt.motivoo.util.binding.BindingDialogFragment
import sopt.motivoo.util.extension.createUriToBitmap
import sopt.motivoo.util.extension.showToast

@AndroidEntryPoint
class HomePhotoDialogFragment :
BindingDialogFragment<DialogHomePhotoBinding>(R.layout.dialog_home_photo) {

private val viewModel: HomeViewModel by viewModels()
private lateinit var photoUri: Uri
private lateinit var bitmapUtil: BitmapUtil

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setLayoutSizeRatio(widthPercent = 1f, heightPercent = 1f)
bitmapUtil = BitmapUtil(requireContext())

val safeArgs: HomePhotoDialogFragmentArgs by navArgs()
photoUri = safeArgs.photoUri

binding.ivPhoto.load(photoUri)

binding.tvConfirm.setOnClickListener {
binding.pvLoading.visibility = View.VISIBLE
viewModel.getMissionImage(
S3_BUCKET_NAME,
requireContext().createUriToBitmap(safeArgs.photoUri)
)
bitmapUtil.createUriToBitmap(photoUri, size = 2)?.let { bitmap ->
binding.pvLoading.visibility = View.VISIBLE
viewModel.getMissionImage(
S3_BUCKET_NAME, bitmap
)
} ?: requireContext().showToast("createUriToBitmap is null")
}

viewLifecycleOwner.lifecycleScope.launch {
Expand Down
24 changes: 24 additions & 0 deletions app/src/main/java/sopt/motivoo/util/BitmapRequestBody.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package sopt.motivoo.util

import android.graphics.Bitmap
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.ByteArrayOutputStream

class BitmapRequestBody(private val bitmap: Bitmap) {

/**
* byte size = output.toByteArray().size
*/
fun create(quality: Int = 100): RequestBody {
val output = ByteArrayOutputStream()
try {
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, output)
} catch (e: Exception) {
e.message
} finally {
output.close()
}
return output.toByteArray().toRequestBody()
}
}
92 changes: 92 additions & 0 deletions app/src/main/java/sopt/motivoo/util/BitmapUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package sopt.motivoo.util

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ImageDecoder
import android.graphics.Matrix
import android.media.ExifInterface
import android.net.Uri
import android.os.Build
import android.provider.MediaStore

class BitmapUtil(private val context: Context) {
private fun loadOrientation(uri: Uri): Int {
var orientation = 0
val stream = context.contentResolver.openInputStream(uri) ?: return 0
try {
val exifInterface = ExifInterface(stream)
orientation = exifInterface.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL
)
} catch (e: Exception) {
e.message
} finally {
stream.close()
}
return orientation
}

/**
* @param bounds : if ture, assign bitmap in memory. if false, no assign bitmap in memory
* @param size : return image ratio
*/
private fun decodeUriToBitmap(uri: Uri, bounds: Boolean = false, size: Int = 1): Bitmap? {
var bitmap: Bitmap? = null
val options = BitmapFactory.Options().apply {
inJustDecodeBounds = bounds
inSampleSize = size
}

val stream = context.contentResolver.openInputStream(uri)
try {
bitmap = BitmapFactory.decodeStream(stream, null, options)
} catch (e: Exception) {
e.message
} finally {
stream?.close()
}

return bitmap
}

private fun rotateBitmap(orientation: Int, bitmap: Bitmap?): Bitmap? = when (orientation) {
ExifInterface.ORIENTATION_ROTATE_90 -> rotateImage(bitmap, 90f)
ExifInterface.ORIENTATION_ROTATE_180 -> rotateImage(bitmap, 180f)
ExifInterface.ORIENTATION_ROTATE_270 -> rotateImage(bitmap, 270f)
else -> bitmap
}

private fun rotateImage(bitmap: Bitmap?, angle: Float): Bitmap? {
val matrix = Matrix().apply { postRotate(angle) }
return bitmap?.let {
Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
}
}

/**
* Use BitmapFactory Bitmap Resize
*/
fun createUriToBitmap(uri: Uri, bounds: Boolean = false, size: Int = 1): Bitmap? {
val orientation = loadOrientation(uri)
val bitmap = decodeUriToBitmap(uri, bounds, size)

return rotateBitmap(orientation, bitmap)
}

/**
* Use ImageDecoder Bitmap Resize, easy convert uri to bitmap
*/
fun createUriToBitmap(uri: Uri): Bitmap =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val source =
ImageDecoder.createSource(context.contentResolver, uri)
ImageDecoder.decodeBitmap(source)
} else {
MediaStore.Images.Media.getBitmap(
context.contentResolver,
uri
)
}
}
16 changes: 0 additions & 16 deletions app/src/main/java/sopt/motivoo/util/extension/ContextExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@ import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.ImageDecoder
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.ImageView
Expand Down Expand Up @@ -92,18 +88,6 @@ fun Context.sendNotification(
}.build()
}

fun Context.createUriToBitmap(photoUri: Uri): Bitmap =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val source =
ImageDecoder.createSource(contentResolver, photoUri)
ImageDecoder.decodeBitmap(source)
} else {
MediaStore.Images.Media.getBitmap(
contentResolver,
photoUri
)
}

fun Context.checkNetworkState(): Boolean {
val connectivityManager =
this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
Expand Down

0 comments on commit 65aeccd

Please sign in to comment.