I want to pass my image from one Activity to another. At first I tried to do this with a base64 String of my image. But this only works for small pictures. It worked with 400 kb but not with 600 kb. Is there a better way to do this? By the way, I don't save the image locally, I get the image from a server, so I don't have a real Drawable.
If you only have the remote URL, then you can directly share it, otherwise you can save the image in the local media store and then share its local URL. Something like:
Bitmap bitmap = ...
String path = MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, "Image Description", null);
Uri uri = Uri.parse(path);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/jpeg");
intent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(intent, "Share Image"));
Even though it is a bit discouraged to pass large "blocks" of data through intents in android (use a singleton or store the image on the internal memory, etc), you can achieve it by doing :
1 - On your Sender Activity
Intent yourIntent = new Intent(YourActivity.this, DestinationActivity.class);
Bitmap bmp; // store the image in your bitmap
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 50, baos);
yourIntent.putExtra("yourImage", baos.toByteArray());
startActivity(yourIntent);
2 - On your Receiver Activity
// parse the intent onCreate()
if(getIntent().hasExtra("yourImage")) {
ImageView iv = new ImageView(this);
Bitmap bmp = BitmapFactory.decodeByteArray(getIntent().getByteArrayExtra("yourImage"), 0, getIntent().getByteArrayExtra("yourImage").length);
iv.setImageBitmap(bmp);
}
It is strongly discouraged that you do it this way because :
1 - There is a memory limit to the passing of data through an intent.
The maximum amount of data you can transfer using an Intent is 500KB (tested on API 10, 16, 19 and 23). check this external reference
Sometimes, the bitmap might be too large for processing, thus leading to OOM (I have experienced this in the past) or cause a bad UI experience.
2 - If your activity crashes by any reason, thus leading to a crash on the application, you will lose the image because it is stored in temporary memory. If you save it internally, you can persist the image even if the application crashes.
General the best practice is to process the image when you need it, store it on a device folder (can be internal or external memory) and later when you need it retrieve it again for more processing. This way you avoid unnecessary memory allocation throughout the application.
Also, you can use third-party libraries like Picasso or Glide. I personally like Glide as it is better in performance than any other.
Related
I have searched online for a tutorial on how to send a bitmap data over to another activity using the putExtra() method in kotlin, but nothing seems to pop up. I do not know how to code in java so all the tutorials and stack overflow threads that talk about converting to a byte array do not help much. Can someone please help me with maybe a solution?
What I did so far (My project is in no regards to this post) is I saved a image using my camera as a bitmap using the code:
val thumbnail : Bitmap = data!!.extras!!.get("data") as Bitmap
(the key word "data" is a intent inside the upper override function (onActivityResult))
This saves a bitmap of the image I took with the camera and now I tried to send it over, using the putExtra() command as so:
var screenSwitch2 = Intent(this#MainActivity,mlscreen::class.java)
screenSwitch2.putExtra("bitmap", thumbnail)
On the other screen "mlscreen" I tried to recover the data using a intent.getStringExtra("bitmap")
val thumbnail = intent.getStringExtra("bitmap")
and then I set my image view in the "mlscreen" using the setImageBitmap method as here:
iv_image.setImageBitmap(thumbnail)
I got the error that I was looking for a bitmap data and not a string data for the method. I knew this would occur though because I had to use intent.getSTRINGExtra which would mean its converting it to a string I presume.
Any help with this would be appreciated! Thanks.
There are 3 ways to do that :
1 - Using Intent (not recommended)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
thumbnail.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
intent.putExtra("image", b);
startActivity(intent);
2 - Using static (not recommended)
public static Bitmap thumbnail;
3 - Using Path (recommended)
Save your Bitmap as an image file in specific folder (make it invisible to the users).
Get the path from the saved file.
Use intent.putExtrat("imagePath",path);.
Use BitmapFactory.decodeFile(filePath); to get the Bitmap from the path.
Remove the path.
I'm developing an application that takes a photo and saves it in Android/data/package/files. I would like to reduce storage used, so I would like to resize the photo before saving it. For the moment I'm calling new intent passing as extra the output path. Is possible to pass also the size wanted or is possible to have the bitmap before saving it?
public void takePicture(View view){
Intent pictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File f = new File(getPath(nameEdit.getText().toString()));
path = f.getAbsolutePath();
pictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
if (pictureIntent.resolveActivity(getPackageManager())!=null){
startActivityForResult(pictureIntent,REQUEST_IMAGE_CAPTURE);
}
}
Is possible to pass also the size wanted
No.
is possible to have the bitmap before saving it?
Not really. You could write your own ContentProvider and use a Uri for that, rather than a file. When the camera app tries saving the content, you would get that information in memory first. However, you will then crash with an OutOfMemoryError, as you will not have enough heap space to hold a full-resolution photo, in all likelihood.
You can use BitmapFactory with inSampleSize set in the BitmapFactory.Options to read in the file once it has been written by the camera, save the resized image as you see fit, then delete the full-resolution image. Or, skip EXTRA_OUTPUT, and you will get a thumbnail image returned to you, obtained by calling getExtra("data") on the Intent passed into onHandleIntent().
My application takes pictures via camera intent. How should I display their small size version in a grid view for viewing purpose. Should I create their thumbnails and store them in cache or external storage Or should I use the thumbnails created by Default Gallery application. My pictures are stored in external storage so I am expecting that Default Gallery Application would make their thumbnails automatically. If yes, then how should I map each image with the thumbnail created by Default Gallery Application.
Well, I have found that Async class could handle the memory usage scenario.
The relevant link is: http://developer.android.com/intl/es/reference/android/os/AsyncTask.html
Well, I have got an answer
public Bitmap getbitpam(String path) {
Bitmap imgthumBitmap = null;
try {
final int THUMBNAIL_SIZE =300 ;
FileInputStream fis = new FileInputStream(path);
imgthumBitmap = BitmapFactory.decodeStream(fis);
imgthumBitmap = Bitmap.createScaledBitmap(imgthumBitmap,
THUMBNAIL_SIZE, THUMBNAIL_SIZE, false);
ByteArrayOutputStream bytearroutstream = new ByteArrayOutputStream();
imgthumBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytearroutstream);
} catch (Exception ex) {
}
return imgthumBitmap;
}
However, this is taking a lot of RAM. I Have also found a strange behavior. That as I am scrolling in grid view, it is taking more RAM. The growth in memory used is cumulative and finally the app is crashing due to Memory_Low exception. Any workaround for it??
Got answer for second problem too:-- Async class.
This is more of a design question. I have a MasterActivity showing a not-so-little preview of an image, and a DetailActivity that should show the image in fullscreen.
Picture is retrieved from server using parse.com services and assigned to ParseImageViews, namely view.setParseFile(file); view.loadInBackground(). Average size is approx. 800x1000px: thus picture is scaled down in master activity, bigger in detail. In both cases I refer to the same 800x1000px file on the backend. Downloading takes some 2s. I do not want to store smaller sizes.
When the user taps a button, I need to pass this Bitmap (ParseFile, objectId, whatever) to DetailActivity, if it was loaded into theMasterActivity.
Option1: Parcelable through Intent
Issue: Binder Transaction Failed
Intent i = new Intent(this, DetailActivity.class);
Bitmap b = ((BitmapDrawable) picture.getDrawable()).getBitmap();
i.putExtra("bitmap", b);
startActivity(i);
Doesn't work, getting Binder Transaction Failed!. It is well documented here on SO (example) that you can't pass objects larger than 1MB (more or less) like that.
Option2: byte[] through Intent
Issue: Binder Transaction Failed
ByteArrayOutputStream stream = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] bytes = stream.toByteArray();
i.putExtra("bitmap", bytes);
As suggested elsewhere I tried to compress the bitmap, but I'm getting the same size error. To avoid transaction limit here I should drop the quality down to 50 or so, and the result is not good to see.
Option3: download the file again in DetailActivity.onCreate()
Issue: OutOfMemoryError
This was a promising option, but didn't work, throwing OOM. My debug opinion is that:
I download the image in MasterActivity;
I launch DetailActivity, while master is still in the backstack;
I download a second instance of the picture, thus going OOM.
I'm stuck at this point. What can I do? If both activities could share the same Bitmap instance, I could avoid OOM.
Simply put I need to capture image using camera and upload it to facebook via my android application. And I successfully did that. The problem is when the photo posted in facebook, it's just too small and in low resolution while the image I took is in high resolution.
I understand that: in order to upload to facebook, i need to convert the captured image which is in bitmap format into byte array. So i have method for that:
public static byte[] convertBitmapToByteArray(Bitmap bm){
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bm.compress(CompressFormat.PNG, 100, bos);
byte[] bitmapdata = bos.toByteArray();
return bitmapdata;
}
Then to upload the image to facebook, i have code below where byteData is byte array I converted from bitmap image using the method above.
parameters.putString("message", "Test");
parameters.putByteArray("source", byteData);
String facebookResponse = facebookInstance.request(albumId+"/photos",parameters,"POST");
return facebookResponse;
I am pretty sure the problem is my convertBitmapToByteArray method since the method is to compress the bitmap image and turn it into byte array, and this made my image into low resolution image. However I can't seem to find the way to upload the image without converting it into byte array first. Any solution for me?
Alright even this thread is old, i found out the answer. It's not the problem of CompressFormant.JPEG or CompressFormat.JPG. Simply put, intent in android isn't designed to carry big data like image from activity through activity. I need to save the image from intent to sd card first before able to pull it out from there. It's my solution.