-
-
Notifications
You must be signed in to change notification settings - Fork 240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Correctly close resources in BitmapUtils. #440
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,12 +17,9 @@ import androidx.exifinterface.media.ExifInterface | |
import com.canhub.cropper.CropImageView.RequestSizeOptions | ||
import com.canhub.cropper.common.CommonVersionCheck.isAtLeastQ29 | ||
import com.canhub.cropper.utils.getUriForFile | ||
import java.io.Closeable | ||
import java.io.File | ||
import java.io.FileNotFoundException | ||
import java.io.IOException | ||
import java.io.InputStream | ||
import java.io.OutputStream | ||
import java.lang.ref.WeakReference | ||
import javax.microedition.khronos.egl.EGL10 | ||
import javax.microedition.khronos.egl.EGLConfig | ||
|
@@ -426,23 +423,19 @@ internal object BitmapUtils { | |
compressFormat: CompressFormat, | ||
compressQuality: Int, | ||
customOutputUri: Uri?, | ||
): Uri? { | ||
): Uri { | ||
val newUri = customOutputUri ?: buildUri(context, compressFormat) | ||
var outputStream: OutputStream? = null | ||
try { | ||
outputStream = context.contentResolver.openOutputStream(newUri!!, WRITE_AND_TRUNCATE) | ||
|
||
bitmap.compress(compressFormat, compressQuality, outputStream) | ||
} finally { | ||
closeSafe(outputStream) | ||
return context.contentResolver.openOutputStream(newUri, WRITE_AND_TRUNCATE).use { | ||
bitmap.compress(compressFormat, compressQuality, it) | ||
newUri | ||
} | ||
return newUri | ||
} | ||
|
||
private fun buildUri( | ||
context: Context, | ||
compressFormat: CompressFormat | ||
): Uri? = | ||
): Uri = | ||
try { | ||
val ext = when (compressFormat) { | ||
CompressFormat.JPEG -> ".jpg" | ||
|
@@ -668,16 +661,12 @@ internal object BitmapUtils { | |
*/ | ||
@Throws(FileNotFoundException::class) | ||
private fun decodeImageForOption(resolver: ContentResolver, uri: Uri): BitmapFactory.Options { | ||
var stream: InputStream? = null | ||
return try { | ||
stream = resolver.openInputStream(uri) | ||
return resolver.openInputStream(uri).use { | ||
val options = BitmapFactory.Options() | ||
options.inJustDecodeBounds = true | ||
BitmapFactory.decodeStream(stream, EMPTY_RECT, options) | ||
BitmapFactory.decodeStream(it, EMPTY_RECT, options) | ||
options.inJustDecodeBounds = false | ||
options | ||
} finally { | ||
closeSafe(stream) | ||
} | ||
} | ||
|
||
|
@@ -692,14 +681,12 @@ internal object BitmapUtils { | |
options: BitmapFactory.Options | ||
): Bitmap? { | ||
do { | ||
var stream: InputStream? = null | ||
try { | ||
stream = resolver.openInputStream(uri) | ||
return BitmapFactory.decodeStream(stream, EMPTY_RECT, options) | ||
} catch (e: OutOfMemoryError) { | ||
options.inSampleSize *= 2 | ||
} finally { | ||
closeSafe(stream) | ||
resolver.openInputStream(uri).use { | ||
try { | ||
return BitmapFactory.decodeStream(it, EMPTY_RECT, options) | ||
} catch (e: OutOfMemoryError) { | ||
options.inSampleSize *= 2 | ||
} | ||
} | ||
} while (options.inSampleSize <= 512) | ||
throw CropException.FailedToDecodeImage(uri) | ||
|
@@ -727,21 +714,25 @@ internal object BitmapUtils { | |
rect.width(), rect.height(), reqWidth, reqHeight | ||
) | ||
) | ||
val stream = context.contentResolver.openInputStream(uri) | ||
val decoder = BitmapRegionDecoder.newInstance(stream!!, false) | ||
do { | ||
|
||
context.contentResolver.openInputStream(uri).use { | ||
val decoder = BitmapRegionDecoder.newInstance(it!!, false) | ||
|
||
try { | ||
return BitmapSampled( | ||
decoder!!.decodeRegion(rect, options), | ||
options.inSampleSize | ||
) | ||
} catch (e: OutOfMemoryError) { | ||
options.inSampleSize *= 2 | ||
do { | ||
try { | ||
return BitmapSampled( | ||
decoder!!.decodeRegion(rect, options), | ||
options.inSampleSize | ||
) | ||
} catch (e: OutOfMemoryError) { | ||
options.inSampleSize *= 2 | ||
} | ||
} while (options.inSampleSize <= 512) | ||
Check warning Code scanning / detekt Report magic numbers. Magic number is a numeric literal that is not defined as a constant and hence it's unclear what the purpose of this number is. It's better to declare such numbers as constants and give them a proper name. By default, -1, 0, 1, and 2 are not considered to be magic numbers.
This expression contains a magic number. Consider defining it to a well named constant.
|
||
} finally { | ||
decoder?.recycle() | ||
} | ||
} while (options.inSampleSize <= 512) | ||
|
||
closeSafe(stream) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was no try / catch / finally here |
||
decoder?.recycle() | ||
} | ||
} catch (e: Exception) { | ||
throw CropException.FailedToLoadBitmap(uri, e.message) | ||
} | ||
|
@@ -934,19 +925,6 @@ internal object BitmapUtils { | |
} | ||
} | ||
|
||
/** | ||
* Close the given closeable object (Stream) in a safe way: check if it is null and catch-log | ||
* exception thrown. | ||
* | ||
* @param closeable the closable object to close | ||
*/ | ||
private fun closeSafe(closeable: Closeable?) { | ||
try { | ||
closeable?.close() | ||
} catch (ignored: IOException) { | ||
} | ||
} | ||
|
||
/** | ||
* Holds bitmap instance and the sample size that the bitmap was loaded/cropped with. | ||
*/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this stream closed automatically? I could not find something that guarantee it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you looked at the implementation of
use
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know the use of the keyword
use
either. I just looked it up. This is the given description ofuse
in kotlin.Links for more info
use
documentationuse