Passing android Bitmap Data within activity using Intent in Android - android

I hava a Bitmap variable named bmp in Activity1 , and I want to send the bitmap to Activity2
Following is the code I use to pass it with the intent.
Intent in1 = new Intent(this, Activity2.class);
in1.putExtra("image",bmp);
startActivity(in1);
And in Activity2 I try to access the bitmap using the following code
Bundle ex = getIntent().getExtras();
Bitmap bmp2 = ex.getParceable("image");
ImageView result = (ImageView)findViewById(R.Id.imageView1);
result.setImageBitmap(bmp);
The application runs without an exception but it does not give the expected result

Convert it to a Byte array before you add it to the intent, send it out, and decode.
//Convert to byte array
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
Intent in1 = new Intent(this, Activity2.class);
in1.putExtra("image",byteArray);
Then in Activity 2:
byte[] byteArray = getIntent().getByteArrayExtra("image");
Bitmap bmp = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
edit
Thought I should update this with best practice:
In your first activity, you should save the Bitmap to disk then load it up in the next activity. Make sure to recycle your bitmap in the first activity to prime it for garbage collection:
Activity 1:
try {
//Write file
String filename = "bitmap.png";
FileOutputStream stream = this.openFileOutput(filename, Context.MODE_PRIVATE);
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
//Cleanup
stream.close();
bmp.recycle();
//Pop intent
Intent in1 = new Intent(this, Activity2.class);
in1.putExtra("image", filename);
startActivity(in1);
} catch (Exception e) {
e.printStackTrace();
}
In Activity 2, load up the bitmap:
Bitmap bmp = null;
String filename = getIntent().getStringExtra("image");
try {
FileInputStream is = this.openFileInput(filename);
bmp = BitmapFactory.decodeStream(is);
is.close();
} catch (Exception e) {
e.printStackTrace();
}

Sometimes, the bitmap might be too large for encode&decode or pass as a byte array in the intent. This can cause either OOM or a bad UI experience.
I suggest to consider putting the bitmap into a static variable of the new activity (the one that uses it) which will carefully be null when you no longer need it (meaning in onDestroy but only if "isChangingConfigurations" returns false).

Simply we can pass only Uri of the Bitmap instead of passing Bitmap object. If Bitmap object is Big, that will cause memory issue.
FirstActivity.
intent.putExtra("uri", Uri);
From SecondActivity we get back bitmap.
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(),Uri.parse(uri));

Kotlin Code for send Bitmap to another activity by intent:
1- in First Activity :
val i = Intent(this#Act1, Act2::class.java)
var bStream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 50, bStream)
val byteArray = bStream.toByteArray()
i.putExtra("image", byteArray )
startActivity(i)
2- In Activity two (Read the bitmap image) :
var bitmap : Bitmap? =null
if (intent.hasExtra("image")){
//convert to bitmap
val byteArray = intent.getByteArrayExtra("image")
bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
}
3- if you need to set it as background for a view, like ConstraintLayout or... :
if (bitmap != null) {
//Convert bitmap to BitmapDrawable
var bitmapDrawable = BitmapDrawable( resources , bitmap)
root_constraintLayout.backgroundDrawable = bitmapDrawable
}

create a singleton class for storing bitmap data
public final class BitmapData {
private static final BitmapData bitmapData = new BitmapData();
private Bitmap bitmap;
private BitmapData() {
}
public static BitmapData getInstance() {
return bitmapData;
}
public Bitmap getBitmap() {
return bitmap;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
in first activity you can set like this.
BitmapData.getInstance().setBitmap(bitmap);
and in second activity
Bitmap bitmap = BitmapData.getInstance().getBitmap();
Note: check null value

We can also solve this without passing data through intent. Just store the image in the memory and in the next Activity just load the image from that location, which can also avoid app crash from passing large bitmap data.
Note: You need not even pass the location path to the intent, remember the path and use it.

I would like to also post a best practices answer for those looking to do this (but may be asking the wrong question).
Instead of passing a bitmap around (which I presume you downloaded from the network, otherwise, you would already have a file reference to it), I recommend using an image loader such as Universal Image Loader to download an image into an ImageView. You can configure it to then cache the image to disk:
DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.considerExifParams(true)
.bitmapConfig(Bitmap.Config.RGB_565)
.build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.defaultDisplayImageOptions(defaultOptions)
.build();
ImageLoader.getInstance().init(config);
Now, just pass the image URL in your intent and use the UIL to load the image. In your newly created activity for example, the image will load instantly because it is loading from the cache - even if your image URL has expired since the download.

Bundle b = new Bundle();
b.putSerializable("Image", Bitmap);
mIntent.putExtras(b);
startActivity(mIntent);

Related

Bitmap too large. Tried All

Guys I am facing this issue since 2 days straight. I want to pick an image from gallery and convert it to Base64 method. I have tried Picasso but my imageview is large. Can you please help me. I tried everything but out of memory is too much for me when converting it to bitmap and then to base64.
BitmapDrawable drawable = (BitmapDrawable) ProfilePic.getDrawable();
yourSelectedIBitmapDrawable drawable = (BitmapDrawable) ProfilePic.getDrawable();
yourSelectedImage = drawable.getBitmap();mage = drawable.getBitmap();
Code which is converting this bitmap to Base64. Is there any possibility of skipping the bitmap and directly converting to Base64
private String encodeToBase64(Bitmap image) {
Bitmap immagex = image;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
immagex.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] b = baos.toByteArray();
String imageEncoded = Base64.encodeToString(b,Base64.DEFAULT);
//Log.e("LOOK", imageEncoded);
return imageEncoded;
}
Profile Pic is name of Imageview.
EDIT: So guyz one of the ways is to use the large heap, but Google says you should not use that unless absolutely necessary. The other one that worked for me is the accepted answer. Now I came up with my own solution. In theory, I am using Picasso to load the image into image view. So what if I can extract the image from the ImageView. Not from URI or path, but from Imageview. This way you have an image which is already reduced by Picasso. Picasso provides Callback to for Success or failure. So on Success, you can access the cache memory of ImageView and extract the Bit map out of it.
I will post the code as an answer shortly. I tried it and even an image of 35Mb originally can be converted to bitmap without Out of memory exception.
So here is my ans: https://stackoverflow.com/a/52125006/6022584
You can try to read the bitmap data with a buffer. Something like that :
private String encodeToBase64(Bitmap image) {
// get an InputStream
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(CompressFormat.PNG, 0, baos);
byte[] bitmapdata = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bitmapdata);
// prepare a buffer to read the inputStream
byte[] buffer = new byte[10 * ONE_KIO]; // ONE_KIO = 1024
int bytesRead;
// prepare the stream to encode in Base64
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Base64OutputStream base64OutputStream = new Base64OutputStream(outputStream, Base64.DEFAULT);
// read the inputStream
while ((bytesRead = bais.read(buffer)) != -1) {
base64OutputStream.write(buffer, 0, bytesRead);
}
base64OutputStream.close();
// get the encoded result string
return outputStream.toString();
}
This is my Code that worked. New Issue is the name of Activity for me
if (requestCode == PICK_IMAGE) {
if(resultCode == RESULT_OK){
//isImageFromGallery = true;
//isImageSelected = true;
ImagePath = data.getData();
Picasso.get()
.load(ImagePath)
.resize(1024,1024)
.onlyScaleDown()
.centerCrop()
.into(picture, new Callback(){
#Override
public void onSuccess() {
BitmapDrawable drawable = (BitmapDrawable) picture.getDrawable();
yourSelectedImage = drawable.getBitmap();
//isImageSelected = true;
Log.d("FileSize",Formatter.formatFileSize(NewIssue.this,
yourSelectedImage.getByteCount()));
}
#Override
public void onError(Exception e) {
Toast.makeText(NewIssue.this, "Could Not Load Image", Toast.LENGTH_SHORT).show();
}
});
}
}

How do I capture photo on Android then display the image in another activity?

I'm a beginner in Android, my problem is I can't pass the captured image to another activity for it to be manipulated. My plan is to save the captured photo in byte since i only need it temporarily then pass it to another activity or for the sake of manipulating the image. Is their a way for me to get its "jpg url" without saving to the user's gallery? Thanks in advance.
EDIT: Here are some code from CameraUtility class added with
bitmapPicture = BitmapFactory.decodeByteArray(arg0 , 0, arg0.length);...
try{
//Write File
String filename="bitmap.png";
FileOutputStream stream = getApplicationContext().openFileOutput(filename, Context.MODE_PRIVATE);
// bitmapPicture.compress(Bitmap.CompressFormat.JPEG, 50, stream);
bitmapPicture = BitmapFactory.decodeByteArray(arg0 , 0, arg0.length);
//Cleanup
stream.close();
Toast.makeText(getApplicationContext(), "Saved", Toast.LENGTH_LONG).show();
bitmapPicture.recycle();
//Pop intent
Intent in1 = new Intent(CameraUtility.this, Receiver.class);
in1.putExtra("image", filename);
startActivity(in1);
}catch (Exception e){
e.printStackTrace();
}
Receiver class...
public class Receiver extends AppCompatActivity{
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bitmap bitmapPicture = null;
String filename = getIntent().getStringExtra("image");
try{
FileInputStream is = this.openFileInput(filename);
bitmapPicture = BitmapFactory.decodeStream(is);
is.close();
}catch (Exception e){
e.printStackTrace();
}
setContentView(R.layout.receive_bitmap);
ImageView viewBtimap = findViewById(R.id.bitmapview);
viewBtimap.setImageBitmap(bitmapPicture);
}
EDIT: But now, it doesn't have an error. But the image won't pass on to another activity.
To fix the particular crash, it's enough to add one line to your pictureTaken function:
bitmapPicture = BitmapFactory.decodeByteArray(arg0 , 0, arg0.length);
But this is not the best way to deal with your task.
Instead of converting the picture to PNG, you can save the arg0 byte array as is. It will be a legitimate Jpeg file, and any consumer, including your Receiver activity, can use it with no changes.
Furthermore, you don't need to store the picture as file. Keep the byte array in memory and convert it to bitmap (don't forget to scale it down to match the ImageView dimensions) with BitmapFactory.decodeByteArray().

want to pass image from one activity to another [duplicate]

This question already has answers here:
How to pass image data from one activity to another activity?
(9 answers)
Closed 5 years ago.
I have to transfer the image from one activity to another. In first activity there are two buttons (take photo) and (View Image).User can take photo by pressing (take photo) button and that photo will be transfer to another activity class which can be view by (View Image) button. Help required.
There is another way for doing this. You can convert the Bitmap image and convert into Base 64 and store it in shared preference. In another activity you can reconvert back it into bitmap and use where ever you want.
Bitmap Conversion and Storing into Shared Preference
Bitmap photo = (Bitmap) intent.getParcelableExtra("Your data");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
photo.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
String temp = Base64.encodeToString(b, Base64.DEFAULT);
myPrefsEdit.putString("url", temp);
myPrefsEdit.commit();
Retrieving from Shared Preference and Loading it into an ImageView
String temp = myPrefs.getString("url", "defaultString");
try {
byte[] encodeByte = Base64.decode(temp, Base64.DEFAULT);
Bitmap bitmap = BitmapFactory.decodeByteArray(encodeByte, 0, encodeByte.length);
picture.setImageBitmap(bitmap);
} catch (Exception e) {
e.getMessage();
}

Unable to locate imageview for uploading to parse

Edit: Solved.
I'm trying to upload an image to parse that has been selected from the phone's gallery. However I cannot seem to locate the imageview as it returns null. I think this page: Saving images to Parse has a similar question to what I'm asking but there is no answer to it.
Fragment class:
public void onClick(View view) {
img = (ImageView) rootView.findViewById(R.id.imageView1);
// Locate the image (error is here)
Bitmap bitmap = BitmapFactory.decodeResource(getActivity().getResources(), img);
// Convert it to byte
ByteArrayOutputStream stream = new ByteArrayOutputStream();
// Compress image to lower quality scale 1 - 100
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] image = stream.toByteArray();
//byte[] image = img.getContext().toString().getBytes();
//Bitmap bitmap = BitmapFactory.decodeFile(img);
ParseFile file = new ParseFile("image.jpg", image);
file.saveInBackground();
ParseObject familyTree = new ParseObject("FamilyTree");
familyTree.put("image", file);
familyTree.put("name", etName.getText().toString());
familyTree.put("relation", etRelation.getText().toString());
familyTree.saveInBackground();
Toast.makeText(FamilyTreeFragment2.this.getActivity(), "Saved.", Toast.LENGTH_SHORT).show();
// getFragmentManager().beginTransaction().replace(R.id.container, new FamilyTreeFragment2()).addToBackStack(null).commit();
}
Any help is appreciated. Thank you.
I've managed to find the solution.
Replaced
Bitmap bitmap = BitmapFactory.decodeResource(getActivity().getResources(), img);
with
Bitmap bitmap = ((BitmapDrawable) img.getDrawable()).getBitmap();

how do you pass images (bitmaps) between android activities using bundles?

Suppose I have an activity to select an image from the gallery, and retrieve it as a BitMap, just like the example: here
Now, I want to pass this BitMap to be used in an ImageView for another activity. I am aware bundles can be passed between activities, but how would I store this BitMap into the bundle?
or is there another approach I should take?
I would highly recommend a different approach.
It's possible if you REALLY want to do it, but it costs a lot of memory and is also slow. It might not work if you have an older phone and a big bitmap. You could just pass it as an extra, for example intent.putExtra("data", bitmap). A Bitmap implements Parcelable, so you can put it in an extra. Likewise, a bundle has putParcelable.
If you want to pass it inbetween activities, I would store it in a file. That's more efficient, and less work for you. You can create private files in your data folder using MODE_PRIVATE that are not accessible to any other app.
If you pass it as a Parcelable, you're bound to get a JAVA BINDER FAILURE error. So, the solution is this: If the bitmap is small, like, say, a thumbnail, pass it as a byte array and build the bitmap for display in the next activity. For instance:
in your calling activity...
Intent i = new Intent(this, NextActivity.class);
Bitmap b; // your bitmap
ByteArrayOutputStream bs = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.PNG, 50, bs);
i.putExtra("byteArray", bs.toByteArray());
startActivity(i);
...and in your receiving activity
if(getIntent().hasExtra("byteArray")) {
ImageView previewThumbnail = new ImageView(this);
Bitmap b = BitmapFactory.decodeByteArray(
getIntent().getByteArrayExtra("byteArray"),0,getIntent().getByteArrayExtra("byteArray").length);
previewThumbnail.setImageBitmap(b);
}
As suggested by #EboMike I saved the bitmap in a file named myImage in the internal storage of my application not accessible my other apps. Here's the code of that part:
public String createImageFromBitmap(Bitmap bitmap) {
String fileName = "myImage";//no .png or .jpg needed
try {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
FileOutputStream fo = openFileOutput(fileName, Context.MODE_PRIVATE);
fo.write(bytes.toByteArray());
// remember close file output
fo.close();
} catch (Exception e) {
e.printStackTrace();
fileName = null;
}
return fileName;
}
Then in the next activity you can decode this file myImage to a bitmap using following code:
Bitmap bitmap = BitmapFactory.decodeStream(context
.openFileInput("myImage"));//here context can be anything like getActivity() for fragment, this or MainActivity.this
Note A lot of checking for null and scaling bitmap's is ommited.
Activity
To pass a bitmap between Activites
Intent intent = new Intent(this, Activity.class);
intent.putExtra("bitmap", bitmap);
And in the Activity class
Bitmap bitmap = getIntent().getParcelableExtra("bitmap");
Fragment
To pass a bitmap between Fragments
SecondFragment fragment = new SecondFragment();
Bundle bundle = new Bundle();
bundle.putParcelable("bitmap", bitmap);
fragment.setArguments(bundle);
To receive inside the SecondFragment
Bitmap bitmap = getArguments().getParcelable("bitmap");
Transferring large bitmap (Compress bitmap)
If you are getting failed binder transaction, this means you are exceeding the binder transaction buffer by transferring large element from one activity to another activity.
So in that case you have to compress the bitmap as an byte's array and then uncompress it in another activity, like this
In the FirstActivity
Intent intent = new Intent(this, SecondActivity.class);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPG, 100, stream);
byte[] bytes = stream.toByteArray();
intent.putExtra("bitmapbytes",bytes);
And in the SecondActivity
byte[] bytes = getIntent().getByteArrayExtra("bitmapbytes");
Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Bitmap is Parcelable so you can add using [putExtra(String,Parcelable)][2] method, But not sure it is a best practice, If it is large size data it is better to store in a single place and use from both activities.
[2]: http://developer.android.com/reference/android/content/Intent.html#putExtra(java.lang.String, android.os.Parcelable)
in first.java
Intent i = new Intent(this, second.class);
i.putExtra("uri",uri);
startActivity(i);
in second.java
Bundle bd = getIntent().getExtras();
Uri uri = bd.getParcelable("uri");
Log.e("URI", uri.toString());
try {
Bitmap bitmap = Media.getBitmap(this.getContentResolver(), uri);
imageView.setImageBitmap(bitmap);
}
catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
I had to rescale the bitmap a bit to not exceed the 1mb limit of the transaction binder. You can adapt the 400 the your screen or make it dinamic it's just meant to be an example.
It works fine and the quality is nice.
Its also a lot faster then saving the image and loading it after but you have the size limitation.
public void loadNextActivity(){
Intent confirmBMP = new Intent(this,ConfirmBMPActivity.class);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
Bitmap bmp = returnScaledBMP();
bmp.compress(Bitmap.CompressFormat.JPEG, 100, stream);
confirmBMP.putExtra("Bitmap",bmp);
startActivity(confirmBMP);
finish();
}
public Bitmap returnScaledBMP(){
Bitmap bmp=null;
bmp = tempBitmap;
bmp = createScaledBitmapKeepingAspectRatio(bmp,400);
return bmp;
}
After you recover the bmp in your nextActivity with the following code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_confirmBMP);
Intent intent = getIntent();
Bitmap bitmap = (Bitmap) intent.getParcelableExtra("Bitmap");
}
I hope my answer was somehow helpfull.
Greetings
Write this code from where you want to Intent into next activity.
yourimageView.setDrawingCacheEnabled(true);
Drawable drawable = ((ImageView)view).getDrawable();
Bitmap bitmap = imageView.getDrawingCache();
Intent intent = new Intent(getBaseContext(), NextActivity.class);
intent.putExtra("Image", imageBitmap);
In onCreate Function of NextActivity.class
Bitmap hotel_image;
Intent intent = getIntent();
hotel_image= intent.getParcelableExtra("Image");
You can pass image in short without using bundle like this
This is the code of sender .class file
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher;
Intent intent = new Intent();
Intent.setClass(<Sender_Activity>.this, <Receiver_Activity.class);
Intent.putExtra("Bitmap", bitmap);
startActivity(intent);
and this is receiver class file code.
Bitmap bitmap = (Bitmap)this.getIntent().getParcelableExtra("Bitmap");
ImageView viewBitmap = (ImageView)findViewById(R.id.bitmapview);
viewBitmap.setImageBitmap(bitmap);
No need to compress.
that's it
It's better to save the file in temp/cache folder and pass the file path through intent data as I did it. here is sample code:
from on Button Click (Here bitmapFullScreen is a bitmap data which I have collected from Live Server)
Intent intent = new Intent(context, FullscreenActivity.class);
String fPath = CreateTempFile(bitmapFullScreen);
if(!StringUtils.isEmpty(fPath)) {
intent.putExtra("image", fPath);
startActivity(intent);
}
Function to create a File on Temp/Cache folder
public String CreateTempFile(Bitmap mBitmap) {
File f3 = new File(Environment.getExternalStorageDirectory() + "/inpaint/");
if (!f3.exists())
f3.mkdirs();
OutputStream outStream = null;
SimpleDateFormat dateFormatter;
dateFormatter = new SimpleDateFormat("MMddyyyyhhmmss", Locale.US);
String FN = Environment.getExternalStorageDirectory() + "/inpaint/" + dateFormatter.format(Calendar.getInstance().getTime()) + ".png";
File file = new File(FN);
try {
outStream = new FileOutputStream(file);
mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
outStream.close();
return file.getAbsolutePath();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
2nd File where we need the file
Global var
String FileName = "";
Receive the Intent String data as FilePath to View Image on ImageView
this code will be onCreate
ImageView imgUpload = findViewById(R.id.imgUpload);
try {
if (getIntent().hasExtra("image")) {
FileName = getIntent().getStringExtra("image");
Bitmap b = BitmapFactory.decodeFile(FileName);
imgUpload.setImageBitmap(b);
}
} catch (Exception ex) {
Toast.makeText(context, "Error: " + ex.getMessage(), Toast.LENGTH_LONG).show();
}
After display the Image we need to delete temp file
#Override
public void onBackPressed() {
super.onBackPressed();
try {
File file = new File(FileName);
file.delete();
} catch (Exception ex) {
Toast.makeText(context, "Error: " + ex.getMessage(), Toast.LENGTH_LONG).show();
}
}

Categories

Resources