I am currently using an intent to take a picture, like this:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
intent.putExtra("return-data", true);
startActivityForResult(intent, CAMERA_REQUEST);
But I really need to set the image size as close to a square as possible. So after researching it seems you need to do something like this:
Camera camera = Camera.open();
Parameters params = camera.getParameters();
List<Camera.Size> sizes = params.getSupportedPictureSizes();
// Once you will see the supported Sizes, you can define them with the method :
setPictureSize(int width, int height);
My questions are, do these work together or is it an either/or? Which method works best for my needs?
Again, I have 96px by 96px box for user profile pics. After user takes the picture I want the image to fill entire box without stretching. Is the best way to set size at the point of picture being taken, or alter the imageView or bitmap (or ...?) after the fact? OR, should I just let the users crop the picture and I can define the cropping area dimensions?
Edit: See bounty for updated question.
This code allows me to pick image from gallery. Crop and use my aspect ratio. I did similar code for using camera. After user takes picture, it immediately launches an activity to crop the picture.
Intent photoPickerIntent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
photoPickerIntent.setType("image/*");
photoPickerIntent.putExtra("crop", "true");
photoPickerIntent.putExtra("outputX", 150);
photoPickerIntent.putExtra("outputY", 150);
photoPickerIntent.putExtra("aspectX", 1);
photoPickerIntent.putExtra("aspectY", 1);
photoPickerIntent.putExtra("scale", true);
photoPickerIntent.putExtra(MediaStore.EXTRA_OUTPUT, getTempUri());
photoPickerIntent.putExtra("outputFormat",
Bitmap.CompressFormat.JPEG.toString());
startActivityForResult(photoPickerIntent, RESULT_LOAD_IMAGE);
You can use Bitmap.createScaleBitmap(Bitmap src, int destWidth, int destHeight, boolean filter) to resize a bitmap
Do these work together or is it an either/or? Which method works best for my needs?
No, they do not work together. When you use the camera with an Intent, you are asking the system to take a picture for you (i.e. the user gets prompted with the default camera app and takes a picture or chooses one from gallery).
When you use the second approach, you create your own Camera object, which is much more customizable than the first one.
With the first method you will have to scale the image afterwards, while with the second, you can take the picture directly in the correct size, so the main difference is that the first is controlled by android, and the second by your app directly, so the second method works best for your needs. if you don't want to scale afterwards.
If you're going to scale anyway (read below), then it doesn't matter which approach you use to take the picture, I'd say in that case, use the default app.
Is the best way to set size at the point of picture being taken, or alter the imageView or bitmap (or ...?) after the fact? OR, should I just let the users crop the picture and I can define the cropping area dimensions?
That depends on your needs. In the first case your app alters the picture taken, so you choose which portion of the original picture will be the final 96x96 picture. The problem with this method is that you can accidentally crop/strech/manipulate the image in a wrong -or at least, unexpected- manner for the user (i.e. removing part of their face).
When you use the second method, you are providint the user with the freedom to choose what part of the picture they want.
If you are able to automatically detect the best portion of the original image, you should go with the first method, but as you are actually asking which is the best method, you should really go with the second one, because it provides more flexibility to the end user.
(1) how can it be auto cropped to fit my ImageView (96dp x 96dp),
It seems like you already have a solution for getting the crop correct. If you want to convert density pixel unit to pixel unit that corresponds to the phone, you need to use the
public int dpToPixel(int dp) {
Resources r = getResources();
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics());
}
So you can use following as extra
photoPickerIntent.putExtra("outputX", dpToPixel(96));
photoPickerIntent.putExtra("outputY", dpToPixel(96));
(2) How can I shrink the picture in size (make a new bitmap?). These need to be loaded quickly on ListViews. So instead of a 1MB pic being upload, I need one more like 2,000k.
If you use image that are around the size of 96dp, you don't really need to worry about image sizes. Creating and destroying new bitmaps is usually very dangerous when you try to do multiple of them in an activity. You can easily run into issues such as "Out of Memory" issues. Therefore, it is more advised to use Uri's instead. So, save the uri that you are putting in the intent, and make a list of uris' to display on the listview however you want.
On a imageview, it is setImageURI(Uri uri).
Hope that answers all your questions.
Related
I'm displaying big images in my app and want to crop them. The user can rotate and scale the images and select a region he wants to crop.
How can I crop out a 10000x10000 region, starting at point (1000, 1000) for example from a 20000x20000 image? For loading parts of an image I would use BitmapRegionDecoder but I don't know how to combine them to a new image again. Any ideas?
Rotation is another problem, this won't work with the BitmapRegionDecoder , but I would already be glad to have a solution without rotation...
I would need a memory friendly way that is more than just following:
Bitmap bitmap = loadFullBitmapIntoMemory();
Bitmap cropped = Bitmap.createBitmap(bitmap, 1000, 1000, 10000, 10000);
I want to avoid to load the full image into memory...
I ve created my custom camera on my app.When I press capture button it saves the taken photo where I set it before.
Everything is fine for now. But the problem is the phone saves the photo as phones pixels I mean I want to 600x600 pixel but everyphone saves the picture as its camera defaults.
How can I solve this?
I use this example for my custom camera : link
You must have to re size the bitmap of of your taken picture Like...
Bitmap b = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
profileImage.setImageBitmap(Bitmap.createScaledBitmap(b, 120, 120, false));
then after delete the previous image which one was taken by camera
Whats happen in your case:
1.) always custom camera returns it default preview size you can get your preview and picture size using the code and chooses as depending on your requirement.
Camera.Parameters params = mCamera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
List<Camera.Size> sizes = params.getSupportedPictureSizes()
My intention is to have the user pick an image from the gallery, then have a cropping activity come up. However, I need the rectangle that defines the cropping mask to be locked to a certain dimension and then the user simply repositions it to display a portion of an image.
Any ideas on how this would be done?
Thanks
-T
Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null)
.setType("image/*")
.putExtra("crop", "true")
.putExtra("aspectX", width)
.putExtra("aspectY", height)
.putExtra("outputX", width)
.putExtra("outputY", height)
.putExtra("scale", true)
.putExtra("scaleUpIfNeeded", true)
.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f))
.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
You need to create a custom ImageView class to achieve zooming and panning of an image and can have a fixed rectangle image(transparent) overlaying on this image. And can create sub-bitmap of that bitmap. and save it in a file.
createBitmap(Bitmap source, int x, int y, int width, int height);
This method is used to create a sub-bitmap.
http://blog.sephiroth.it/2011/04/04/imageview-zoom-and-scroll/
After achieving zooming and panning, I am not sure if createBitmap can create sub-bitmap from the visible portion of the image(i.e. part of image wont be visible on the screen when it is zoomed), So try getting the drawingCache() from imageView and create sub-bitmap for the same.
I created a layout where my surface view has been resized from the "original size", I did the following:
ViewGroup.LayoutParams params = mSurfaceView.getLayoutParams();
int mPixels=getResources().getDimensionPixelSize(R.dimen.profile_pic_dimension); //200
params.width=mPixels;
params.height=mPixels;
mSurfaceView.setLayoutParams(params);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
and I obtain a view like this:
http://img412.imageshack.us/img412/9379/layoutp.png
but then.. whenever I take the picture.. it doesn't saves as how I can see it on the view... but instead it saves it normal size like if the view was taking the whole screen (like if the surfaceview was never resized).
I tried using this:
Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback() {
#Override
public void onShutter() {
Camera.Parameters p = mCamera.getParameters();
p.setPictureSize(mSurfaceView.getWidth(), mSurfaceView.getHeight());
mCamera.setParameters(p);
}
};
but still didn't get the image size i wanted to.
You cannot just supply any width and height value when setting the picture (or preview) size. In stead, you'll have to use one of the items from the list of supported sizes, which you can retrieve by calling getSupportedPictureSizes() (there's an equivalent for the preview).
So far I haven't come across any devices that support taking square pictures, so after a 4:3, 16:9, 16:10, or whatever ratio, picture has been taken, you will have to 'cut' out the relevant part yourself, and optionally scale it down to a specific dimension. Probably the most straightforward way to do this, is by creating a new Bitmap as a subset from a source Bitmap (and then optionally scale it down). In order to get the source bitmap, you'll likely need to hook up a PictureCallback to the camera with takePicture(...).
I have a Canvas that i draw text on.
(this is quite advanced i think hope you can follow me)
See attached image below.
The functionality is that I can tap on the screen to change the textsize.
Tap left screen = smaller Font.
Tap right Screen = bigger Font.
I can then also move the text on the screen.
When textsize is ok and i have moved the text where i want it,
Then I want to save it back to the original Bitmap.
I use options.inSampleSize = 4; to initially load the Bitmap
The ImageView that have the Bitmap is of course smaller then the original Image.
Some kind of calculation is needed.
This tends to be quite difficult to do.
I have the options.inSampleSize = 4 Bitmaps Ratio.
It's 0.59, 0.69 something depending on Landscape or portrait.
Im playing around with that to somehow change the new BitmapsetTextSize
to look the same as the ImageView smaller Bitmap.
What could i do here?
I have a feeling that since one never know what size an image have.
I have to somehow scale/constrain the Loaded Bitmap Ratio to a fixed Ratio.
Then i need to using percentage or something to transfer the text location
to the bigger image.
I can kind of do that when it comes to initial
(red small ball on picture) location. Hence, the starting point of the text.
But i dont know how long the text is so im stuck so so speak and asking for advice
One way i tried was to divide paint.getTextSize() with the Ratio something like 0.59. That looked like a solution at first. But the image ratio is not fixed and the Font size is not fixed something else is needed.
Here are two pictures showing the problem.
On phone Bitmap:
The saved new Bitmap:
I'm not 100% clear that I understand what you mean, but here's a go. It sounds like you were close to the right approach. Instead of using a fixed ratio, you need to calculate the ratio that the image is scaled by to fit in the view on the phone, then you can scale the text by the inverse ratio. So in steps:
Measure the width of the original image (height would do just as well, but we just need one dimension)
Measure the width of the scaled image
Calculate ratio (ratio = original / scaled)
Let the user type their text
You can then get the text size using something like: float paintSize = paint.getTextSize();
For rendering on the final image, use paint.setTextSize(paintSize / ratio);.