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().
Related
I'm trying to implement camera app with certain features. I need to take a picture using phone's camera and then manipulate that image. However, I don't need to save the picture to the file, I only need to get some "data" from the picture. Is there a way to take picture and then immediately load it as bitmap or do I need to at least save it, read it and then delete it.
I read this tutorial: https://developer.android.com/training/camera/photobasics.html, but saving and deleting images seems heavy on processor, so I'd like to avoid it if I can. Ty
As Saiteja Prasadam notes, if you skip EXTRA_OUTPUT on ACTION_IMAGE_CAPTURE, you will get a thumbnail Bitmap back via getExtra("data").
Beyond that, you can work with the camera APIs directly (e.g., android.hardware.Camera).
You could try creating a ContentProvider that supports writing to a memory buffer instead of a file, then use a content: Uri pointing to that provider in EXTRA_OUTPUT. Getting this to work correctly, and without fragmenting your heap space, may be difficult or impossible.
Overall, bear in mind that you might not have heap space for a full-resolution image anyway. I do not know what "some "data" from the picture" means, exactly, but if it depends upon loading the whole image into RAM, you are going to have challenges implementing that.
Here is the relevant API documentation:
https://developer.android.com/reference/android/hardware/Camera.html#takePicture(android.hardware.Camera.ShutterCallback,%20android.hardware.Camera.PictureCallback,%20android.hardware.Camera.PictureCallback,%20android.hardware.Camera.PictureCallback)
void takePicture (Camera.ShutterCallback shutter,
Camera.PictureCallback raw,
Camera.PictureCallback postview,
Camera.PictureCallback jpeg)
shutter: the callback for image capture moment, or null
raw: the callback for raw (uncompressed) image data, or null
postview: callback with postview image data, may be null
jpeg: the callback for JPEG image data, or null
Start Intent
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
Activity Result
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAMERA_REQUEST && resultCode == RESULT_OK) {
Bitmap photo = (Bitmap) data.getExtras().get("data");
}
}
Note: This thumbnail image from "data" might be good for an icon, but not a lot more. Dealing with a full-sized image takes a bit more work.
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.
I am working with a customizable database with pictures. Right now I am taking pictures as it is from the sdcard and encoding it in base64 String and then putting it in the database. but whenever I am trying decoding it and showing it in my view, I am getting Out of memory error. Can any one one tell me what is the best procedure to do it? Shall I change the size of the pictures before encoding it?
I want to re-size all of the pictures into 512*512.
Image to Base64 is very heavy operation in android. Consider saving the images on the external/internal memory and save the file path in the sqlite database.
You can convert your image to byte array then store values in sql by using BLOB type and vice versa.
As you mentioned you want to resize the images to 512*512, you can scale the image using below code,
Create bitmap from captured image and then use below line
Bitmap resizedBitmap = Bitmap.createScaledBitmap(myBitmap, 512, 512, false);
It will give you a smaller image, you can also consider compressing the image to reduce in size,
OutputStream imagefile = new FileOutputStream("/your/file/name.jpg");
// Write 'bitmap' to file using JPEG and 50% quality hint for JPEG:
bitmap.compress(CompressFormat.JPEG, 50, imagefile);
Now, you have two options,
Save the scaled and compressed image into a file and save the path of that file in db. (Better way)
Convert the scaled and compressed image to base64 string and save in db.
Althought base64 is , as many answers said, a heavy operation for android, if done properly, it should not be a problem.
There are many reasons a bitmap could be required to be saved to a DB , (photo of a invoice ticket, for example?), and this is the way i do it.
first, create a new , smaller bitmap like #Swapnil commented.
and second, correctly use the bitmap transformation methods, i've been using these (look below) two so far and haven't had any memory issue on many different devices.
link to my BitmapUtils transformation methods
I want to capture photo and also save it to my sdcard using android camera.I know its easy but I want to store image in low resolution without telling user go to setting and set low resolution manually.
What i am gonna write is not good practice to do code but it may full-fill your requirement
capture image as you do with normally using android default camera .
check the path of that image which just now captured .
reduce quality of that image as per requirement using BitmapFactory.Options calss and store in bitmap object
delete that original image which captured by default camera
save that bitmap object to SD Card where old image was located with same file name and path
I know this is very late but this is for the people who might read this question now , you can use this following code :
Camera.Parameters parameters = mcamera.getParameters();
List<Camera.Size> sizes = parameters.getSupportedPictureSizes();
Camera.Size size = sizes.get(sizes.size()-1);
Log.d("Parth","Size : "+size.height+","+size.width);
Log.d("Parth","Sizes:"+sizes.toString());
parameters.setPictureSize(size.width,size.height);
mcamera.setParameters(parameters);
Implement a camera app by yourself. Use BitmapFactory to decode raw data. Via BitmapFactory.Options, you can set any resolution you want.
Use this to capture image :
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.ACTION_IMAGE_CAPTURE, preinsertedUri);
Don't use MediaStore.EXTRA_OUTPUT because the image will be big size if you use EXTRA_OUTPUT
It looks like in camera image capture, one can only capture either thumbnail or full image but not both in one pass because
public void startCamera() {
...
camera.putExtra("output", imageUri); (step 1)
...
needs to be declared before
...
startActivityForResult(camera, IMAGE_CAPTURE); (step 2)
...
Bundle extras = camera.getExtras();
mImageBitmap = (Bitmap) extras.get("data");
imageView.setImageBitmap(mImageBitmap);
...
But once "onActivityResult" returns, the full image is already saved into imageUri and the buffer cleared. But to capture the thumbnail of an image taken, the code needs to be executed after "startActivityForResult". The problem is the image buffer is cleared once the image is saved in step 2. To capture the image thumbnail, one will need to skip saving the full image in step 1 in order to capture the thumbnail image in step 2.
I can use an alternative to save the full image, reload the full image into bitmap, scale the image into a thumbnail size and resave the image but it seems to be redundant. Any idea if I can do both in one pass?
Check out MediaStore.Images.Thumbnails, and specifically getThumbnail (near the bottom): http://developer.android.com/reference/android/provider/MediaStore.Images.Thumbnails.html .
If that doesn't work, yes, you will have to manually re-scale and save the thumbnail yourself.