Last active
March 16, 2024 16:01
-
-
Save st235/615b4d92552eccf6af8eed154ad48f2d to your computer and use it in GitHub Desktop.
Loading large bitmaps (https://developer.android.com/topic/performance/graphics/load-bitmap)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package github.com.st235; | |
import android.content.ContentResolver; | |
import android.graphics.Bitmap; | |
import android.graphics.BitmapFactory; | |
import android.graphics.Matrix; | |
import android.net.Uri; | |
import android.util.Log; | |
import androidx.annotation.NonNull; | |
import androidx.annotation.Nullable; | |
import androidx.exifinterface.media.ExifInterface; | |
import java.io.FileNotFoundException; | |
import java.io.IOException; | |
import java.io.InputStream; | |
public class LocalUriLoader { | |
private static final String TAG = "LocalUriLoader"; | |
private static final int MAX_DIMENSION = 1920; | |
@NonNull | |
private final ContentResolver contentResolver; | |
public LocalUriLoader(@NonNull ContentResolver contentResolver) { | |
this.contentResolver = contentResolver; | |
} | |
@Nullable | |
public Bitmap load(@NonNull Uri uri) { | |
try { | |
BitmapFactory.Options options = new BitmapFactory.Options(); | |
InputStream inputStream = contentResolver.openInputStream(uri); | |
if (inputStream == null) { | |
return null; | |
} | |
options.inJustDecodeBounds = true; | |
options.inPreferredConfig = Bitmap.Config.RGB_565; | |
BitmapFactory.decodeStream(inputStream, /* outPadding= */ null, options); | |
inputStream.close(); | |
inputStream = contentResolver.openInputStream(uri); | |
if (inputStream == null) { | |
return null; | |
} | |
options.inSampleSize = calculateInSampleSize(options, /* maxWidth= */ MAX_DIMENSION, | |
/* maxHeight= */ MAX_DIMENSION); | |
options.inJustDecodeBounds = false; | |
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, /* outPadding= */ null, options); | |
inputStream.close(); | |
if (bitmap == null) { | |
return null; | |
} | |
Matrix rotationMatrix = getCorrectBitmapRotation(contentResolver, uri); | |
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), | |
rotationMatrix, true); | |
} catch (FileNotFoundException e) { | |
Log.w(TAG, "Cannot find uri: " + uri, e); | |
return null; | |
} catch (IOException e) { | |
Log.w(TAG, "Disk read/write error." , e); | |
return null; | |
} | |
} | |
private static int calculateInSampleSize(@NonNull BitmapFactory.Options options, | |
int maxWidth, | |
int maxHeight) { | |
int rawHeight = options.outHeight; | |
int rawWidth = options.outWidth; | |
int inSampleSize = 1; | |
if (rawHeight > maxHeight || rawWidth > maxWidth) { | |
int halfHeight = rawHeight / 2; | |
int halfWidth = rawWidth / 2; | |
while (halfHeight / inSampleSize >= maxHeight | |
&& halfWidth / inSampleSize >= maxWidth) { | |
inSampleSize *= 2; | |
} | |
} | |
return inSampleSize; | |
} | |
@NonNull | |
private static Matrix getCorrectBitmapRotation(@NonNull ContentResolver contentResolver, | |
@NonNull Uri uri) { | |
Matrix rotationMatrix = new Matrix(); | |
InputStream inputStream = null; | |
try { | |
inputStream = contentResolver.openInputStream(uri); | |
} catch (FileNotFoundException e) { | |
Log.w(TAG, "Uri not found: " + uri, e); | |
return rotationMatrix; | |
} | |
if (inputStream == null) { | |
return rotationMatrix; | |
} | |
ExifInterface exifInterface; | |
try { | |
exifInterface = new ExifInterface(inputStream); | |
} catch (IOException e) { | |
Log.w(TAG, "Cannot read EXIF for " + uri, e); | |
return rotationMatrix; | |
} | |
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, | |
ExifInterface.ORIENTATION_NORMAL); | |
switch(orientation) { | |
case ExifInterface.ORIENTATION_ROTATE_90: | |
rotationMatrix.postRotate(90f); | |
break; | |
case ExifInterface.ORIENTATION_ROTATE_180: | |
rotationMatrix.postRotate(180f); | |
break; | |
case ExifInterface.ORIENTATION_ROTATE_270: | |
rotationMatrix.postRotate(270f); | |
break; | |
} | |
return rotationMatrix; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MainActivity extends AppCompatActivity { | |
private LocalUriLoader localUriLoader; | |
... | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.main_activity); | |
localUriLoader = new LocalUriLoader(getApplicationContext().getContentResolver()); | |
... | |
} | |
private void processImage(Uri selectedImageUri) { | |
try { | |
sampledBitmap = localUriLoader.load(selectedImageUri); | |
imageView.setImageBitmap(sampledBitmap); | |
} catch (Exception e) { | |
Log.e(TAG, "Exception thrown: ",e); | |
} | |
} | |
... | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment