I'm new to this forum, so please bear with me and gently point out mistakes if any,
So I'm working on a project where I'm uploading images to server, now I want to limit the size of images, I'm giving an option to "Click image" where my code will open default camera intent and clicks the pic, or "Choose from gallery".
My question is regarding "Click image", Now when user clicks an image, can I preset the image max size which can be clicked?
You can resize your image in onActivityResult method,try following code snippet
public static Bitmap handleSamplingAndRotationBitmap(Context context, Uri selectedImage)
throws IOException {
int MAX_HEIGHT = 1024;
int MAX_WIDTH = 1024;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
InputStream imageStream = context.getContentResolver().openInputStream(selectedImage);
BitmapFactory.decodeStream(imageStream, null, options);
imageStream.close();
options.inSampleSize = calculateInSampleSizes(options, MAX_WIDTH, MAX_HEIGHT);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
imageStream = context.getContentResolver().openInputStream(selectedImage);
Bitmap img = BitmapFactory.decodeStream(imageStream, null, options);
img = rotateImageIfRequired(context, img, selectedImage);
return img;
}
private static int calculateInSampleSizes(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) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee a final image
// with both dimensions larger than or equal to the requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
// This offers some additional logic in case the image has a strange
// aspect ratio. For example, a panorama may have a much larger
// width than height. In these cases the total pixels might still
// end up being too large to fit comfortably in memory, so we should
// be more aggressive with sample down the image (=larger inSampleSize).
final float totalPixels = width * height;
// Anything more than 2x the requested pixels we'll sample down further
final float totalReqPixelsCap = reqWidth * reqHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
inSampleSize++;
}
}
return inSampleSize;
}
private static Bitmap rotateImageIfRequired(Context context, Bitmap img, Uri selectedImage) throws IOException {
InputStream input = context.getContentResolver().openInputStream(selectedImage);
ExifInterface ei;
if (Build.VERSION.SDK_INT > 23)
ei = new ExifInterface(input);
else
ei = new ExifInterface(selectedImage.getPath());
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
return rotateImage(img, 90);
case ExifInterface.ORIENTATION_ROTATE_180:
return rotateImage(img, 180);
case ExifInterface.ORIENTATION_ROTATE_270:
return rotateImage(img, 270);
default:
return img;
}
}
private static Bitmap rotateImage(Bitmap img, int degree) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
img.recycle();
return rotatedImg;
}
you just need invoke handleSamplingAndRotationBitmap method,you'll get a Bitmap which size can be set by yourself.
PS: Case some pictures captured by sumsung's phone 's rotation is incorrect,so we need handle picture's orientation too,hope that can help you.
You can simply get the size of the file. You need to store the image when u take for it. after that u can get size using below code segment
String imagePath = Environment.getExternalStorageDirectory() + "/yourImagefile.png";
File imageFile = new File(imagePath );
long filelength = imageFile .length();
length = filelength/1024;
this length give you size in KB. then you can add if condition like below
if(length>sizeyouwant){
//delete image and toast message with info
if(imageFile.exists()) {
imageFile.delete();
}
Toast.makeText(getApplicationContext(),
"Image is not saved due to image size exceeds limit....",
Toast.LENGTH_SHORT).show();
}
Related
Here is a piece of code that I used to compress Bitmap:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
System.out.println("before: " + bmp.getByteCount());
bmp.compress(Bitmap.CompressFormat.JPEG, 80, baos);
System.out.println("baos: " + baos.toByteArray().length);
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap b = BitmapFactory.decodeStream(new ByteArrayInputStream(baos.toByteArray()),
null, options);
System.out.println("after: " + b.getByteCount());
LogCat output:
12-29 11:45:52.638 18042-18042/com.xxx.yyy I/System.out: before: 653760
12-29 11:45:52.678 18042-18042/com.xxx.yyy I/System.out: baos: 13118
12-29 11:45:52.688 18042-18042/com.xxx.yyy I/System.out: after: 1307520
size of baos seems the size of Bitmap after compressing, but why b.getByteCount() return a larger size than bmp before compressing?
BitmapFactory.Options options = new BitmapFactory.Options();
/*
isSampleSize will reduce your bitmap size.
If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save
memory. The sample size is the number of pixels in either dimension that correspond to a single pixel in the
decoded bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original
and 1/16 the number of pixels. Any value <= 1 is treated the same as 1. Note: the decoder uses a final value based
on powers of 2, any other value will be rounded down to the nearest power of 2.
*/
options.inSampleSize = 2;
Bitmap b = BitmapFactory.decodeStream(new ByteArrayInputStream(baos.toByteArray()), null, options);
System.out.println("after: " + b.getByteCount());
I had Same Problem but i solved using Some Method.i used this method in my Camera App after image Captured.i put my code here.Using it you will try.
My Methods :
public static Bitmap decodeSampledBitmapFromByte(Context context, byte[] bitmapBytes) {
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int reqWidth, reqHeight;
Point point = new Point();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
display.getSize(point);
reqWidth = point.x;
reqHeight = point.y;
} else {
reqWidth = display.getWidth();
reqHeight = display.getHeight();
}
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inMutable = true;
options.inBitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Load & resize the image to be 1/inSampleSize dimensions
// Use when you do not want to scale the image with a inSampleSize that is a power of 2
options.inScaled = true;
options.inDensity = options.outWidth;
options.inTargetDensity = reqWidth * options.inSampleSize;
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false; // If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.
options.inPurgeable = true; // Tell to gc that whether it needs free memory, the Bitmap can be cleared
options.inInputShareable = true; // Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
return BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
int initialInSampleSize = computeInitialSampleSize(options, reqWidth, reqHeight);
int roundedInSampleSize;
if (initialInSampleSize <= 8) {
roundedInSampleSize = 1;
while (roundedInSampleSize < initialInSampleSize) {
// Shift one bit to left
roundedInSampleSize <<= 1;
}
} else {
roundedInSampleSize = (initialInSampleSize + 7) / 8 * 8;
}
return roundedInSampleSize;
}
private static int computeInitialSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final double height = options.outHeight;
final double width = options.outWidth;
final long maxNumOfPixels = reqWidth * reqHeight;
final int minSideLength = Math.min(reqHeight, reqWidth);
int lowerBound = (maxNumOfPixels < 0) ? 1 :
(int) Math.ceil(Math.sqrt(width * height / maxNumOfPixels));
int upperBound = (minSideLength < 0) ? 128 :
(int) Math.min(Math.floor(width / minSideLength),
Math.floor(height / minSideLength));
if (upperBound < lowerBound) {
// return the larger one when there is no overlapping zone.
return lowerBound;
}
if (maxNumOfPixels < 0 && minSideLength < 0) {
return 1;
} else if (minSideLength < 0) {
return lowerBound;
} else {
return upperBound;
}
}
i think u need to Use My method decodeSampledBitmapFromByte() instead of your
method.you need to put all methods in your code.
Using this Code i get same size After compressing.i put my LogCat here.
Hope it will help You...Enjoy.(:
is there a way i can compress an image of 115kb to be 4kb in android Without affecting it size?. just reducing it quality?
i only know of using
BitmapFactory.Options which reduces both size and quality
Bitmap.compress which does not give you options for specifying size in bytes.
public Bitmap compressImage(String imagePath) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
bmp = BitmapFactory.decodeStream(new FileInputStream(imagePath),null, options);
options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight);
options.inJustDecodeBounds = false;
bmp = BitmapFactory.decodeStream(new FileInputStream(imagePath),null, options);
return bmp;
}
public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
final float totalPixels = width * height;
final float totalReqPixelsCap = reqWidth * reqHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
inSampleSize++;
}
return inSampleSize;
}
Image re sizing means you're going to shorten the resolution of the image. suppose user selects a 1000*1000 px image. you're going to convert the image into a 300*300 image. thus image size will be reduced.
And Image compression is lowering the file size of the image without compromising the resolution. Of course lowering file size will affect the quality of the image. There are many compression algorithm available which can reduce the file size without much affecting the image quality.
One handy way I found in here is :
Bitmap original = BitmapFactory.decodeStream(getAssets().open("1024x768.jpg"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
original.compress(Bitmap.CompressFormat.PNG, 100, out);
Bitmap decoded = BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));
Log.e("Original dimensions", original.getWidth()+" "+original.getHeight());
Log.e("Compressed dimensions", decoded.getWidth()+" "+decoded.getHeight());
gives
12-07 17:43:36.333: E/Original dimensions(278): 1024 768 12-07
17:43:36.333: E/Compressed dimensions(278): 1024 768
public static int getSquareCropDimensionForBitmap(Bitmap bitmap)
{
int dimension;
//If the bitmap is wider than it is tall
//use the height as the square crop dimension
if (bitmap.getWidth() >= bitmap.getHeight())
{
dimension = bitmap.getHeight();
}
//If the bitmap is taller than it is wide
//use the width as the square crop dimension
else
{
dimension = bitmap.getWidth();
}
return dimension;
}
int dimension = getSquareCropDimensionForBitmap(bitmap);
System.out.println("before cropped height " + bitmap.getHeight() + "and width: " + bitmap.getWidth());
Bitmap croppedBitmap = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension);
System.out.println("after cropped height "+croppedBitmap.getHeight() +"and width: " + croppedBitmap.getWidth());
it can crop and can reduce size u can specify ur own size
I have wrote this method before I noticed there is a compress method in Bitmap class.
/**
* Calcuate how much to compress the image
* #param options
* #param reqWidth
* #param reqHeight
* #return
*/
public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1; // default to not zoom image
if (height > reqHeight || width > reqWidth) {
final int heightRatio = Math.round((float) height/ (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
/**
* resize image to 480x800
* #param filePath
* #return
*/
public static Bitmap getSmallBitmap(String filePath) {
File file = new File(filePath);
long originalSize = file.length();
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
// Calculate inSampleSize based on a preset ratio
options.inSampleSize = calculateInSampleSize(options, 480, 800);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap compressedImage = BitmapFactory.decodeFile(filePath, options);
return compressedImage;
}
I was wondering, compare to the built in Compress method, should I keep using this one, or switch to use the built in one? what is the difference?
Your method is in line with Loading Large Bitmap guidelines
Large file on disk
Small bitmap in memory
compress() methods converts a large bitmap to a small one:
Large bitmap in memory
Small bitmap on disk (IOStream) (and possibly in different format)
I would use your method if I needed to load bitmap from a file to ImageViews of different sizes.
Basically
What you are doing in the above code is just resizing the image ,which will not loose much of the quality of the image since you use the SampleSize .
compress(Bitmap.CompressFormat format, int quality, OutputStream stream)
It is used when you want to change the imageFormat you have Bitmap.CompressFormat JPEG
Bitmap.CompressFormat PNG Bitmap.CompressFormat WEBP or to reduce the quality of the image using the quality parameter 0 - 100 .
I have an ImageView and I need to getImageResource() based on user GPS position.
There are 6 images and as the distance between 2 points decrease I replace the image with a new resource.
I'm testing the app on the Galaxy S4 and the problem is that after a very small random number of loading the app crashes because of OutOfMemory.
Is there a good way to cache the images? (Maybe I need to load them by using an AsyncTask)
The images are 400x400px png- 24 bit with transparency.
Thank you
Try using this:
public static Bitmap decodeSampledBitmapFromResource(String uri,
int reqWidth, int reqHeight, int orientation) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(uri, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap decodeFile = BitmapFactory.decodeFile(uri, options);
int rotate = 0;
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;
}
Matrix matrix = new Matrix();
// matrix.postScale(scaleWidth, scaleHeight);
matrix.postRotate(rotate);
Bitmap rotatedBitmap = Bitmap.createBitmap(decodeFile, 0, 0,
decodeFile.getWidth(), decodeFile.getHeight(), matrix, true);
return rotatedBitmap;
}
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) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}
Galaxy S4 most likely works with the xxhdpi drawables, so you putting everything in mdpi will have the system scale up your images to match S4's dpi level, hence the OutOfMemory error. Try scaling and placing drawables in their respective folders depending on the dpi (including xhdpi and xxhdpi) and after that maybe optimize your code.
I can successfully convert the given Base64 string to corresponding image in Android.
To test this scenario in my app, I took one image from my drawable folder and convert it into its corresponding Base64 string using this website : Motobit.com. The image that I gave on this website was this:
Its 23X25 pixels in dimension and 46.3KB in size.
Using below code in my Android I am converting this image's Base64 into Image as follows:
byte[] decodedString = Base64.decode(tabData.getString("TabIconImageData"), Base64.DEFAULT);
BitmapFactory.Options options = new Options();
options.inJustDecodeBounds = true;
options.inSampleSize = calculateInSampleSize(options, 500, 500);
options.inJustDecodeBounds = false;
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length,options);
myImageView.setImageBitmap(decodedByte);
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) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height
/ (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
The Base64 string is getting converted successfully in image, but it looks nealy half in the size than of its original image. I want the image of its original size and also in PNG format.
Please guide me for this to resolve.
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Bitmap btm = decodeBase64("Base64 String");
Bitmap bt=Bitmap.createScaledBitmap(btm, btm.getWidth(), btm.getHeight(), false);
company_logo.setImageBitmap(bt);
and this
public static Bitmap decodeBase64(String input)
{
byte[] decodedByte = Base64.decode(input, 0);
return BitmapFactory.decodeByteArray(decodedByte, 0, decodedByte.length);
}