Resize Image to File
fun resizeImageToFile(uri: Uri, size: Int, mimeType: String?, file: File): Boolean{ val request = ImageRequestBuilder.newBuilderWithSource(uri) .setResizeOptions(ResizeOptions(size, size)) .build() val imagePipeline = Fresco.getImagePipeline() val dataSource = imagePipeline.fetchDecodedImage(request, null) // the ResizeOptions in the imageRequest will be ignored for this fetch // val dataSource = imagePipeline.fetchEncodedImage(request, null) // val ref = dataSource.result val ref = DataSources.waitForFinalResult(dataSource) ref?.use { ref -> val image = ref.get() if (image is CloseableBitmap) { val bitmap = image.underlyingBitmap if (mimeType == "image/jpeg" || mimeType == null) { val outputStream = file.outputStream() outputStream.use { outputStream -> bitmap.compress(Bitmap.CompressFormat.JPEG, 85, outputStream) // https://caniuse.com/#feat=webp // bitmap.compress(Bitmap.CompressFormat.WEBP, 85, outputStream) return true } } // TODO - handle other file format } } return false}
Usage
val filePath = ...val file = File(filePath)val outputFile = File(...)if (file.exists()) { val mimeType = MediaUtils.extractMime(filePath) resizeImageToFile(Uri.fromFile(file), 1600, mimeType, outputFile)}
Resize Image to InputStream
fun resizeImageToInputStream(uri: Uri, size: Int, mimeType: String?): InputStream? { val request = ImageRequestBuilder.newBuilderWithSource(uri) .setResizeOptions(ResizeOptions(size, size)) .build() val imagePipeline = Fresco.getImagePipeline() val dataSource = imagePipeline.fetchDecodedImage(request, null) val ref = DataSources.waitForFinalResult(dataSource) ref?.use { ref -> val image = ref.get() if (image is CloseableBitmap) { val bitmap = image.underlyingBitmap if (mimeType == "image/jpeg" || mimeType == null) { val outputStream = ByteArrayOutputStream() // val inputStream = PipedInputStream() // val outputStream = PipedOutputStream(inputStream) outputStream.use { outputStream -> bitmap.compress(Bitmap.CompressFormat.JPEG, 85, outputStream) // https://caniuse.com/#feat=webp // bitmap.compress(Bitmap.CompressFormat.WEBP, 85, outputStream) // toByteArray will trigger copy, thus double memory usage // consider this solution: https://github.com/nickrussler/ByteArrayInOutStream return ByteArrayInputStream(outputStream.toByteArray()) } } // TODO - handle other file format } } return null}
Another solution is via Piped Stream to save memory usage.
fun resizeImageToInputStream(uri: Uri, size: Int, mimeType: String?): InputStream? { val request = ImageRequestBuilder.newBuilderWithSource(uri) .setResizeOptions(ResizeOptions(size, size)) .build() val imagePipeline = Fresco.getImagePipeline() val dataSource = imagePipeline.fetchDecodedImage(request, null) // val ref = dataSource.result val ref = DataSources.waitForFinalResult(dataSource) ref?.use { ref -> val image = ref.get() if (image is CloseableBitmap) { val bitmap = image.underlyingBitmap if (mimeType == "image/jpeg" || mimeType == null) { val inputStream = PipedInputStream() val outputStream = PipedOutputStream(inputStream) // using coroutines: need to launch this in a thread launch(Dispatchers.Default) { outputStream.use { outputStream -> // outputStream will not be written/complete until the inputStream is read bitmap.compress(Bitmap.CompressFormat.JPEG, 85, outputStream) } } return inputStream } } } return null}
NOTE: Refer Android Convert OutputStream to InputStream.