Merge pull request #289 from EveX1/feature/downsize-big-images
Downsize big images
This commit is contained in:
commit
b2b8a38c7b
32 changed files with 120 additions and 18 deletions
|
|
@ -677,6 +677,9 @@ class ThreadActivity : SimpleActivity() {
|
|||
if (compressedUri != null) {
|
||||
attachmentSelections[originalUriString] = AttachmentSelection(compressedUri, false)
|
||||
loadAttachmentPreview(attachmentView, compressedUri)
|
||||
} else {
|
||||
toast(R.string.compress_error)
|
||||
removeAttachment(attachmentView, originalUriString)
|
||||
}
|
||||
checkSendMessageAvailability()
|
||||
attachmentView.thread_attachment_progress.beGone()
|
||||
|
|
@ -690,11 +693,7 @@ class ThreadActivity : SimpleActivity() {
|
|||
val attachmentView = layoutInflater.inflate(R.layout.item_attachment, null).apply {
|
||||
thread_attachments_wrapper.addView(this)
|
||||
thread_remove_attachment.setOnClickListener {
|
||||
thread_attachments_wrapper.removeView(this)
|
||||
attachmentSelections.remove(originalUri)
|
||||
if (attachmentSelections.isEmpty()) {
|
||||
thread_attachments_holder.beGone()
|
||||
}
|
||||
removeAttachment(this, originalUri)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -733,6 +732,14 @@ class ThreadActivity : SimpleActivity() {
|
|||
.into(attachmentView.thread_attachment_preview)
|
||||
}
|
||||
|
||||
private fun removeAttachment(attachmentView: View, originalUri: String) {
|
||||
thread_attachments_wrapper.removeView(attachmentView)
|
||||
attachmentSelections.remove(originalUri)
|
||||
if (attachmentSelections.isEmpty()) {
|
||||
thread_attachments_holder.beGone()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkSendMessageAvailability() {
|
||||
if (thread_type_message.text.isNotEmpty() || (attachmentSelections.isNotEmpty() && !attachmentSelections.values.any { it.isPending })) {
|
||||
thread_send_message.isClickable = true
|
||||
|
|
|
|||
|
|
@ -38,9 +38,19 @@ class ImageCompressor(private val context: Context) {
|
|||
val byteArray = contentResolver.openInputStream(uri)?.readBytes()!!
|
||||
var destinationFile = File(outputDirectory, System.currentTimeMillis().toString().plus(mimeType.getExtensionFromMimeType()))
|
||||
destinationFile.writeBytes(byteArray)
|
||||
val constraint = SizeConstraint(compressSize)
|
||||
while (constraint.isSatisfied(destinationFile).not()) {
|
||||
destinationFile = constraint.satisfy(destinationFile)
|
||||
val sizeConstraint = SizeConstraint(compressSize)
|
||||
val bitmap = loadBitmap(destinationFile)
|
||||
|
||||
// if image weight > * 2 targeted size: cut down resolution by 2
|
||||
if (fileSize > 2 * compressSize) {
|
||||
val resConstraint = ResolutionConstraint(bitmap.width / 2, bitmap.height / 2)
|
||||
while (resConstraint.isSatisfied(destinationFile).not()) {
|
||||
destinationFile = resConstraint.satisfy(destinationFile)
|
||||
}
|
||||
}
|
||||
// do compression
|
||||
while (sizeConstraint.isSatisfied(destinationFile).not()) {
|
||||
destinationFile = sizeConstraint.satisfy(destinationFile)
|
||||
}
|
||||
callback.invoke(context.getMyFileUri(destinationFile))
|
||||
} else {
|
||||
|
|
@ -106,7 +116,11 @@ class ImageCompressor(private val context: Context) {
|
|||
private var iteration: Int = 0
|
||||
|
||||
fun isSatisfied(imageFile: File): Boolean {
|
||||
return imageFile.length() <= maxFileSize || iteration >= maxIteration
|
||||
// If size requirement is not met and maxIteration is reached
|
||||
if(iteration >= maxIteration && imageFile.length() >= maxFileSize) {
|
||||
throw Exception("Unable to compress image to targeted size")
|
||||
}
|
||||
return imageFile.length() <= maxFileSize
|
||||
}
|
||||
|
||||
fun satisfy(imageFile: File): File {
|
||||
|
|
@ -116,4 +130,55 @@ class ImageCompressor(private val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
private inner class ResolutionConstraint(private val width: Int, private val height: Int) {
|
||||
|
||||
private fun decodeSampledBitmapFromFile(imageFile: File, reqWidth: Int, reqHeight: Int): Bitmap {
|
||||
return BitmapFactory.Options().run {
|
||||
inJustDecodeBounds = true
|
||||
BitmapFactory.decodeFile(imageFile.absolutePath, this)
|
||||
|
||||
inSampleSize = calculateInSampleSize(this, reqWidth, reqHeight)
|
||||
|
||||
inJustDecodeBounds = false
|
||||
BitmapFactory.decodeFile(imageFile.absolutePath, this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
|
||||
// Raw height and width of image
|
||||
val (height: Int, width: Int) = options.run { outHeight to outWidth }
|
||||
var inSampleSize = 1
|
||||
|
||||
if (height > reqHeight || width > reqWidth) {
|
||||
|
||||
val halfHeight: Int = height / 2
|
||||
val halfWidth: Int = width / 2
|
||||
|
||||
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
|
||||
// height and width larger than the requested height and width.
|
||||
while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) {
|
||||
inSampleSize *= 2
|
||||
}
|
||||
}
|
||||
|
||||
return inSampleSize
|
||||
}
|
||||
|
||||
fun isSatisfied(imageFile: File): Boolean {
|
||||
return BitmapFactory.Options().run {
|
||||
inJustDecodeBounds = true
|
||||
BitmapFactory.decodeFile(imageFile.absolutePath, this)
|
||||
calculateInSampleSize(this, width, height) <= 1
|
||||
}
|
||||
}
|
||||
|
||||
fun satisfy(imageFile: File): File {
|
||||
return decodeSampledBitmapFromFile(imageFile, width, height).run {
|
||||
determineImageRotation(imageFile, this).run {
|
||||
overWrite(imageFile, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue