Loading AlbumArtworks without OutOfMemoryError - java

I want to load the Album-Artworks into my music app and preview them in a recyclerview. I've tried Googles Developer Guide, but I'm actually loading about 200 Bitmaps, so this doesn't work!
I don't have an idea about how to do that!
Here's my current code:
if (cSong != null && cSong.moveToFirst()) {
do {
int iIDCol = cSong.getColumnIndex(MediaStore.Audio.Media._ID);
int iTitleCol = cSong.getColumnIndex(MediaStore.Audio.Media.TITLE);
int iArtistCol = cSong.getColumnIndex(MediaStore.Audio.Media.ARTIST);
int iAlbumCol = cSong.getColumnIndex(MediaStore.Audio.Media.ALBUM);
int iDurationCol = cSong.getColumnIndex(MediaStore.Audio.Media.DURATION);
int iAlbumIDCol = cSong.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID);
Bitmap bCover = null;
BitmapFactory.Options bOptions = new BitmapFactory.Options();
bOptions.inJustDecodeBounds = true;
//Throws OutOfMemoryError
/*try {
Uri ArtworkUri = Uri.parse("content://media/external/audio/albumart");
Uri uri = ContentUris.withAppendedId(ArtworkUri, iAlbumIDCol);
ParcelFileDescriptor pfd = mContext.getContentResolver().openFileDescriptor(uri, "r");
if (pfd != null) {
FileDescriptor fd = pfd.getFileDescriptor();
BitmapFactory.decodeFileDescriptor(fd, null, bOptions);
bOptions.inSampleSize = calculateInSampleSize(bOptions, 100, 100);
bOptions.inJustDecodeBounds = false;
bCover = BitmapFactory.decodeFileDescriptor(fd, null, bOptions);
pfd = null;
fd = null;
}
}
catch (IOException ioe) {
BitmapFactory.decodeResource(mContext.getResources(), R.drawable.standardartwork, bOptions);
bOptions.inSampleSize = calculateInSampleSize(bOptions, 100, 100);
bOptions.inJustDecodeBounds = false;
bCover = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.standardartwork, bOptions);
}*/
SongList.add(new Song(cSong.getLong(iIDCol), cSong.getString(iTitleCol), cSong.getString(iArtistCol), cSong.getString(iAlbumCol), cSong.getInt(iDurationCol), bCover));
}
while (cSong.moveToNext());
Any my InSampleSize Method:
private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int size = 1;
if (height > reqHeight && width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / size) > reqHeight && (halfWidth / size) > reqWidth) {
size *= 2;
}
}
return size;
}
Thanks!

Holding 200 bitmaps in memory is not a good idea even though they are downscaled. The easiest solution would be saving the Uri to the cover instead of Bitmap and decode a Bitmap only when you need it.
So the parsing code would look like this:
Uri artworkUri = Uri.parse("content://media/external/audio/albumart");
if (cSong != null && cSong.moveToFirst()) {
do {
int iIDCol = cSong.getColumnIndex(MediaStore.Audio.Media._ID);
int iTitleCol = cSong.getColumnIndex(MediaStore.Audio.Media.TITLE);
int iArtistCol = cSong.getColumnIndex(MediaStore.Audio.Media.ARTIST);
int iAlbumCol = cSong.getColumnIndex(MediaStore.Audio.Media.ALBUM);
int iDurationCol = cSong.getColumnIndex(MediaStore.Audio.Media.DURATION);
int iAlbumIDCol = cSong.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID);
Uri coverUri = ContentUris.withAppendedId(artworkUri, iAlbumIDCol);
SongList.add(new Song(cSong.getLong(iIDCol), cSong.getString(iTitleCol), cSong.getString(iArtistCol), cSong.getString(iAlbumCol), cSong.getInt(iDurationCol), coverUri));
}
while (cSong.moveToNext());
And in your RecyclerView.Adapter onBindViewHolder(RecyclerView.ViewHolder holder, int position) method do the decoding:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Bitmap image = decodeBitmap(songsList.get(position).getBitmapUrl());
if (image != null) {
holder.imageView.setImageBitmap(image);
} else {
holder.imageView.setImageResource(R.drawable.standardartwork);
}
}
private Bitmap decodeBitmap(Uri uri) {
ParcelFileDescriptor pfd = mContext.getContentResolver().openFileDescriptor(uri, "r");
try {
if (pfd != null) {
FileDescriptor fd = pfd.getFileDescriptor();
BitmapFactory.decodeFileDescriptor(fd, null, bOptions);
bOptions.inSampleSize = calculateInSampleSize(bOptions, 100, 100);
bOptions.inJustDecodeBounds = false;
return BitmapFactory.decodeFileDescriptor(fd, null, bOptions);
} else {
return null;
}
} catch (IOException ioe) {
return null;
}
}
This will allow you to keep in memory only the bitmaps that you actually have to show on the screen, others will be recycled.
NOTE: The snippets are here just for an illustration how your problem could be solved, but this can reduce performance of your RecyclerView, because decoding is done on the main thread. You won't notice it if your images are rather small, but you'll have to do decoding asynchronously if they are large. In case of large images, consider using libraries for image processing like Picasso or Glide.

I solved it by using the Library Picasso, which handles the Loading-Process of the Image.
Picasso.with(mContext).load(ImageUri).resize(Width, Height).into(ImageView);

Related

RecyclerView take Image form camera is rotating when show on the list

I have an issue with my code. When I take a photo from my app, it is rotating 90ยบ to show. But, when I choose gallery option to select my photo, it is showing normal.
Can someone help me??
Code bellow:
Adapter.java
public void onBindViewHolder(#NonNull final ProdutosListaViewHolder holder, final int i){
Produto prod = produtos.get(i);
File foto = mPicture.getImageProduto(prod.codProd);
if(foto == null || foto.exists()){
holder.foto.setImageResource(R.drawable.sem_foto_icon);
}else{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeFile(foto.getAbsolutePath(), options);
holder.foto.setImageBitmap(bitmap);
}
}
PictureManager.java
if the camera selected to take the photo
Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
i.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(ctx, ....));
((Activity) ctx).startActivityForResult(i, 999);
if the gallery selected to take the photo
Intent i = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
((Activity) ctx).startActivityForResult(i, 998);
ProductListActivity.java
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==999){
try{
File foto = (new PictureManager(FOTO_PRODUTO, ctx)).getImageProduto(produtoSelecionado.codProd);
if(foto != null){
mProdutosListaAdapter.notifyItemChanged(posicaoSelecionada);
}
}catch(Exception e){
e.printStackTrace();
}
}else if(requestCode==998){
try{
Uri selectedImage = data.getData();
String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = ctx.getContentResolver().query(selectedImage, filePathColumn, null null, null);
cursor.moveToFirst();
int columnIndex = cursor.ColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
File file = new File(picturePath);
int codigo = produtoSelecionado.codProd;
File foto = (new PictureManager(FOTO_PRODUTO, ctx)).salvarFoto(file, codigo, 1);
mProdutosListaAdapter.notifyDataSetChanged();
}
}
}
}
}
Camera always gives you the picture according to camera orientation. I have tried the below code to change orientation
public static Bitmap rotateImageOrientation(String photoFilePath) {
// Create and configure BitmapFactory
BitmapFactory.Options bounds = new BitmapFactory.Options();
bounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(photoFilePath, bounds);
BitmapFactory.Options opts = new BitmapFactory.Options();
Bitmap bm = BitmapFactory.decodeFile(photoFilePath, opts);
// Read EXIF Data
ExifInterface exif = null;
try {
exif = new ExifInterface(photoFilePath);
} catch (IOException e) {
e.printStackTrace();
}
String orientString = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
int orientation = orientString != null ? Integer.parseInt(orientString) : ExifInterface.ORIENTATION_NORMAL;
int rotationAngle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) rotationAngle = 90;
if (orientation == ExifInterface.ORIENTATION_ROTATE_180) rotationAngle = 180;
if (orientation == ExifInterface.ORIENTATION_ROTATE_270) rotationAngle = 270;
// Rotate Bitmap
Matrix matrix = new Matrix();
matrix.setRotate(rotationAngle, (float) bm.getWidth() / 2, (float) bm.getHeight() / 2);
return Bitmap.createBitmap(bm, 0, 0, bounds.outWidth, bounds.outHeight, matrix, true);
// Return result
}

IOException: Resetting to invalid mark in Android Oreo

I'm trying to upload an image from phone's gallery to a server. I tried Glide and Picasso library. But it is not showing the selected image in ImageView. So, I'm scaling down the image as mentioned here. This method works fine with most of the phones. But I found that it is not working in OnePlus 5 or 5T (Android - Oxygen: 8.0.0). It is showing following exception. The same code works fine if I take a picture using the camera and upload it.
04-14 16:13:43.207 26947-27295/me.example.app W/System.err: java.io.IOException: Resetting to invalid mark
at java.io.BufferedInputStream.reset(BufferedInputStream.java:450)
at me.example.app .Fragment.ImageUploadFragment.decodeSampledBitmapFromUri(ImageUploadFragment.java:172)
at me.example.app .Fragment.ImageUploadFragment$GetResizedBitmapTask.doInBackground(ImageUploadFragment.java:124)
at me.example.app .Fragment.ImageUploadFragment$GetResizedBitmapTask.doInBackground(ImageUploadFragment.java:105)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
Code for reference:
MainActivity:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_FROM_GALLARY && resultCode == Activity.RESULT_OK){
imageUploadFragment.resizeImage(data.getData(), IMAGE_MAX_DIMENSION);
}
}
....
#Override
public void onBitmapResized(Bitmap resizedBitmap, int maxDimension) {
if (resizedBitmap != null){
Log.i("image", "resized");
imgSelected.setImageBitmap(resizedBitmap);
} else {
Toast.makeText(this, "Something went wrong! Please try again.", Toast.LENGTH_SHORT).show();
}
}
ImageUploadFragment:
public void resizeImage(Uri uri, int maxDimension){
GetResizedBitmapTask getResizedBitmapTask = new GetResizedBitmapTask(maxDimension);
getResizedBitmapTask.execute(uri);
}
#SuppressLint("StaticFieldLeak")
private class GetResizedBitmapTask extends AsyncTask<Uri, Void, Bitmap> {
private int mMaxDimension;
GetResizedBitmapTask(int maxDimension) {
this.mMaxDimension = maxDimension;
}
#Override
protected Bitmap doInBackground(Uri... uris) {
Uri uri = uris[0];
if (uri != null){
Bitmap bitmap;
try {
bitmap = decodeSampledBitmapFromUri(uri, mMaxDimension, mMaxDimension);
return bitmap;
} catch (IOException e) {
e.printStackTrace();
//****this exception I'm getting****
return null;
}
}
return null;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
if (mImageTaskCallbacks != null)
mImageTaskCallbacks.onBitmapResized(bitmap, mMaxDimension);
}
}
public Bitmap decodeSampledBitmapFromUri(Uri imageUri, int reqWidth, int reqHeight) throws IOException{
//gets bytes of data from image file
InputStream inputStream = mContext.getContentResolver().openInputStream(imageUri);
if (inputStream == null){
return null;
}
InputStream bufferedInputStream = new BufferedInputStream(inputStream);
//marks the current position in the InputStream based on the number of bytes remaining to read in the buffer
bufferedInputStream.mark(bufferedInputStream.available());
BitmapFactory.Options options = new BitmapFactory.Options();
//decoder will return null (no bitmap)
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(bufferedInputStream, null, options);
bufferedInputStream.reset();
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
BitmapFactory.decodeStream(bufferedInputStream, null, options);
//****this line of code causing the exception****
bufferedInputStream.reset();
return BitmapFactory.decodeStream(bufferedInputStream, null, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight){
int inSampleSize = 1;
final int width = options.outWidth;
final int height = options.outHeight;
if (width > reqWidth || height > reqHeight){
final int halfWidth = width/2;
final int halfHeight = height/2;
while ((halfWidth/inSampleSize) > reqWidth && (halfHeight/inSampleSize) > reqHeight){
inSampleSize *= 2;
}
}
return inSampleSize;
}
Thank you in advance.

Loading Bitmaps doesn't work correct, while scrolling in RecyclerView

I'm loading the Album-Artworks in my Music-App. Because I couldn't load them on Main-Thread, I'm using Threads, and they get muddled up!
Sometimes the Image isn't loaded in the correct size or it is shown as a brown square. These issues appear if I scroll fast. If I scroll slow, it works!
The important methods of my MusicStore-Class:
public Bitmap getAlbumArtwork(long AlbumID, int Height, int Width) {
ParcelFileDescriptor pfd;
Bitmap bCover = null;
BitmapFactory.Options bOptions = new BitmapFactory.Options();
bOptions.inJustDecodeBounds = true;
try {
Uri ArtworkUri = Uri.parse("content://media/external/audio/albumart");
Uri uri = ContentUris.withAppendedId(ArtworkUri, AlbumID);
pfd = mContext.getContentResolver().openFileDescriptor(uri, "r");
if (pfd != null) {
BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor(), null, bOptions);
bOptions.inSampleSize = calculateInSampleSize(bOptions, Width, Height);
bOptions.inJustDecodeBounds = false;
bCover = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor(), null, bOptions);
pfd.close();
}
}
catch (IOException ioe) {
BitmapFactory.decodeResource(mContext.getResources(), R.drawable.standardartwork, bOptions);
bOptions.inSampleSize = calculateInSampleSize(bOptions, Width, Height);
bOptions.inJustDecodeBounds = false;
bCover = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.standardartwork, bOptions);
}
return bCover;
}
public void setAlbumArtwork(final long AlbumID, final ImageView ArtworkView) {
Thread thArtwork = new Thread(new Runnable() {
#Override
public void run() {
final Bitmap bArtwork = getAlbumArtwork(AlbumID, ArtworkView.getHeight() / 2, ArtworkView.getWidth() / 2);
handler.postDelayed(new Runnable() {
#Override
public void run() {
ArtworkView.setImageBitmap(bArtwork);
threadList.remove(Thread.currentThread());
}
}, 50);
}
});
threadList.add(thArtwork);
thArtwork.start();
}
private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int size = 1;
if (height > reqHeight && width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / size) > reqHeight && (halfWidth / size) > reqWidth) {
size *= 2;
}
}
return size;
}
And my RecyclerViewAdapter:
public class SongRecyclerViewAdapter extends RecyclerView.Adapter<SongRecyclerViewAdapter.Holder> {
private Context mContext;
private Song[] sSongs;
private MusicStore musicStore;
public SongRecyclerViewAdapter(Context context, Song[] songs) {
mContext = context;
sSongs = songs;
musicStore = new MusicStore(mContext);
}
#Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_songview, parent, false);
Holder holder = new Holder(view);
return holder;
}
#Override
public void onBindViewHolder(Holder holder, int position) {
musicStore.setAlbumArtwork(sSongs[position].getAlbumID(), holder.imvSong);
holder.txvSongTitle.setText(sSongs[position].getTitle());
holder.txvSongInfo.setText(sSongs[position].getArtists());
}
#Override
public void onViewDetachedFromWindow(Holder holder) {
}
#Override
public int getItemCount() {
return sSongs != null ? sSongs.length : 0;
}
public class Holder extends RecyclerView.ViewHolder {
LinearLayout linearLayout;
ImageView imvSong;
TextView txvSongTitle;
TextView txvSongInfo;
public Holder(View layout) {
super(layout);
linearLayout = (LinearLayout) layout;
imvSong = (ImageView) layout.findViewById(R.id.imvSong);
txvSongTitle = (TextView) layout.findViewById(R.id.adap_txvSongtitle);
txvSongInfo = (TextView) layout.findViewById(R.id.adap_txvSongInfo);
}
}
}
I'm absolutely open for any other idead to load the Bitmaps correctly!
You could try it out if you want:
https://play.google.com/store/apps/details?id=at.guger.musixs
Thanks!
http://square.github.io/picasso/
The setup and docs are quite simple. You can also passing in the Uri and Picasso will resolve it.
Example
Picasso.with(this).load(uri).into(imageView);
If you can also specify things like width and height, placeholder, and much more.
.resize(width, height).placeholder(placeholderImg)

Android Studio Camera App Saving to Internal Storage

Currently looking for help on saving images from a camera app to internal storage do to Nexus not having an SD card, our current code saves the photos taken to an SD card folder and the quality is not good.
public class MainActivity extends ActionBarActivity {
private ImageView imageHolder;
private final int requestCode = 20;
public final static String EXTRA_MESSAGE = "com.test1.cam.camapp.MESSAGE";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageHolder = (ImageView)findViewById(R.id.captured_photo);
Button capturedImageButton = (Button)findViewById(R.id.photo_button);
capturedImageButton.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent photoCaptureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(photoCaptureIntent, requestCode);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(this.requestCode == requestCode && resultCode == RESULT_OK){
Bitmap bitmap = (Bitmap)data.getExtras().get("data");
String partFilename = currentDateFormat();
storeCameraPhotoInSDCard(bitmap, partFilename);
// display the image from SD Card to ImageView Control
String storeFilename = "photo_" + partFilename + ".jpg";
Bitmap mBitmap = getImageFileFromSDCard(storeFilename);
imageHolder.setImageBitmap(mBitmap);
}
}
public void showGreetings(View view)
{
String button_text;
button_text = ((Button) view) .getText().toString();
if(button_text.equals("Info"))
{
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
}
else if (button_text.equals("Info"))
{
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
}
}
public void saveImage(Context context, Bitmap b,String name,String extension){
name=name+"."+extension;
FileOutputStream out;
try {
out = context.openFileOutput(name, Context.MODE_PRIVATE);
b.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private String currentDateFormat(){
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HH_mm_ss");
String currentTimeStamp = dateFormat.format(new Date());
return currentTimeStamp;
}
private void storeCameraPhotoInSDCard(Bitmap bitmap, String currentDate){
File outputFile = new File(Environment.getExternalStorageDirectory(), "photo_" + currentDate + ".jpg");
try {
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private Bitmap getImageFileFromSDCard(String filename){
Bitmap bitmap = null;
File imageFile = new File(Environment.getExternalStorageDirectory() + filename);
try {
FileInputStream fis = new FileInputStream(imageFile);
bitmap = BitmapFactory.decodeStream(fis);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return bitmap;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
To improve the image quality you should change compression to PNG, or change the second parameters to 100 (PNG is lossless and will ignore second params).
b.compress(Bitmap.CompressFormat.PNG, 100, out);
To change external into internal just change
File outputFile = new File(Environment.getExternalStorageDirectory(), "photo_" + currentDate + ".jpg");
into
File outputFile = new File(context.getFilesDir(), "photo_" + currentDate + ".jpg");
The image you are trying to save returns you jest the thumbnail of the actual image that is why you are getting low quality image. You should pass the image name to the intent to save the high quality image when it is captured
Following Helper class that I use for image capture may be of some help to you
public class CaptureImageHelper {
private static final int DEFAULT_WIDTH = 1024; // min pixels
private static final int DEFAULT_HEIGHT = 768; // min pixels
private static final String TEMP_IMAGE_NAME = "tempImage";
public static Intent getImageCaptureIntent(Context context, String title) {
Intent chooserIntent = null;
List<Intent> intentList = new ArrayList<>();
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getTempFile(context)));
intentList = addIntentsToList(context, intentList, takePhotoIntent);
if (intentList.size() > 0) {
chooserIntent = Intent.createChooser(intentList.remove(intentList.size() - 1), title);
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new Parcelable[]{}));
}
return chooserIntent;
}
private static File getTempFile(Context context) {
//Note you can change the path here according to your need
File imageFile = new File(Environment.getExternalStorageDirectory(), TEMP_IMAGE_NAME);
imageFile.getParentFile().mkdirs();
return imageFile;
}
private static List<Intent> addIntentsToList(Context context, List<Intent> list, Intent intent) {
List<ResolveInfo> resInfo = context.getPackageManager().queryIntentActivities(intent, 0);
for (ResolveInfo resolveInfo : resInfo) {
String packageName = resolveInfo.activityInfo.packageName;
Intent targetedIntent = new Intent(intent);
targetedIntent.setPackage(packageName);
list.add(targetedIntent);
}
return list;
}
public static Bitmap getImageFromResult(Context context, int resultCode, Intent imageReturnedIntent) {
return getImageFromResult(context, DEFAULT_WIDTH, DEFAULT_HEIGHT, resultCode, imageReturnedIntent);
}
public static Bitmap getImageFromResult(Context context, int width, int height, int resultCode, Intent imageReturnedIntent) {
Bitmap bm = null;
if (resultCode == Activity.RESULT_OK) {
Uri selectedImage;
File imageFile = getTempFile(context);
selectedImage = Uri.fromFile(imageFile);
bm = getImageResized(context, selectedImage, width, height);
int rotation = getRotation(context, selectedImage, true);
bm = rotate(bm, rotation);
}
return bm;
}
private static Bitmap getImageResized(Context context, Uri selectedImage, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
System.gc();
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap actuallyUsableBitmap = null;
AssetFileDescriptor fileDescriptor = null;
try {
fileDescriptor = context.getContentResolver().openAssetFileDescriptor(selectedImage, "r");
} catch (FileNotFoundException e) {
}
if (null != fileDescriptor) {
BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
actuallyUsableBitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options);
}
return actuallyUsableBitmap;
}
private static Bitmap getImageResized(Context context, Uri selectedImage) {
return getImageResized(context, selectedImage, DEFAULT_WIDTH, DEFAULT_HEIGHT);
}
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = 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;
}
private static int getRotation(Context context, Uri imageUri, boolean isCamera) {
int rotation;
if (isCamera) {
rotation = getRotationFromCamera(context, imageUri);
} else {
rotation = getRotationFromGallery(context, imageUri);
}
return rotation;
}
private static int getRotationFromCamera(Context context, Uri imageFile) {
int rotate = 0;
try {
context.getContentResolver().notifyChange(imageFile, null);
ExifInterface exif = new ExifInterface(imageFile.getPath());
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
}
} catch (Exception e) {
e.printStackTrace();
}
return rotate;
}
private static int getRotationFromGallery(Context context, Uri imageUri) {
int orientation = 0;
String[] columns = {MediaStore.Images.Media.ORIENTATION};
Cursor cursor = context.getContentResolver().query(imageUri, columns, null, null, null);
if (null != cursor && cursor.moveToFirst()) {
int orientationColumnIndex = cursor.getColumnIndex(columns[0]);
orientation = cursor.getInt(orientationColumnIndex);
cursor.close();
}
return orientation;
}
private static Bitmap rotate(Bitmap bm, int rotation) {
if (rotation != 0) {
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
return Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
}
return bm;
}
}

Saving an image with its thumb and showing on imageView android

I am trying to save an image taken from camera and then storing it on sdCard along with its Thumb also showing this thumb on an imageView.
However it gives error at Null pointer
imageBitmap = Bitmap.createScaledBitmap(imageBitmap, 40, 40, false);
What is wrong?
{
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
try
{
if (title.getText().toString().equals(""))
{
displayAlert("Please Input Title First","Error!");
}
else
{
Integer val = myMisc.miscId ;
String fileName = "image" + "_" + title.getText().toString()+"_" + val.toString();
photo = this.createFile(fileName, ".jpg");
myMisc.filename = photo.getAbsolutePath();
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
startActivityForResult(intent, RESULT_CAMERA_SELECT);
}
}
catch(Exception e)
{
Log.v("Error", "Can't create file to take picture!");
displayAlert("Can't create file to take picture!","SDCard Error!");
}
}
public synchronized void onActivityResult(final int requestCode, int resultCode, final Intent data)
{
if (resultCode == Activity.RESULT_OK)
{
if (requestCode == RESULT_CAMERA_SELECT)
{
try
{
saveImage();
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
public void saveImage() throws IOException
{
try
{
FileInputStream is2 = new FileInputStream(photo);
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap imageBitmap = BitmapFactory.decodeStream(is2, null, options);
options.inSampleSize = calculateInSampleSize(options, 40, 40);
options.inJustDecodeBounds = false;
imageBitmap = BitmapFactory.decodeStream(is2 ,null, options);
imageBitmap = Bitmap.createScaledBitmap(imageBitmap, 40, 40, false);
Integer val = myMisc.miscId;
String fileName = ".thumbImage" + "_" + title.getText().toString()+ "_" + val.toString();
photo = this.createFile(fileName, ".jpg");
myMisc.thumbFileName = photo.getAbsolutePath();
try {
FileOutputStream out = new FileOutputStream(photo);
imageBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
} catch (Exception e) {
e.printStackTrace();
}
is2.close();
Uri uri = Uri.fromFile(photo);
photo = null;
imageBitmap = null;
imageView.setImageURI(uri);
}catch(Exception e)
{
displayAlert("Can't create file to take picture!","SD Card Error");
}
}
It's probably because of the decodeStream method.
Bitmap imageBitmap = BitmapFactory.decodeStream(is2, null, options);
You parsed null at the when it asks for a Rectangle and when you tried to create a scaled bitmap it was not valid.
i found my error Bitmap imageBitmap = BitmapFactory.decodeStream(is2, null, options); decoding twice

Categories

Resources