I'm trying to display an image having it's absolute path. I came upon this code on stackoverflow which should theoretically work, however I get error Bitmap too big to be uploaded into a texture on most images so I'm looking for another way to do it. Surprisingly there aren't any examples apart from this one on how to do it.
This is what I am trying:
Bitmap myBitmap = BitmapFactory.decodeFile(imagePath);
ImageView image = new ImageView(context);
image.setImageBitmap(myBitmap);
layout.addView(image);
By the way the images I'm working with have been taken with the default camera app so they don't have any uncommon format or size (and can be seen with no problem on the gallery app). How can I add them to my layout?
Just try to resize your image first by using below code and then set it into the ImageView:
public static Drawable GetDrawable(String newFileName)
{
File f;
BitmapFactory.Options o2;
Bitmap drawImage = null;
Drawable d = null;
try
{
f = new File(newFileName);
//decodes image and scales it to reduce memory consumption
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
o.inTempStorage = new byte[16 * 1024];
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
//The new size we want to scale to
final int REQUIRED_SIZE = 150;
//Find the correct scale value. It should be the power of 2.
int scale = 1;
while ((o.outWidth / scale / 2 >= REQUIRED_SIZE) && (o.outHeight / scale / 2 >= REQUIRED_SIZE))
scale *= 2;
//Decode with inSampleSize
o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
drawImage = BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
//Bitmap bmp = pictureDrawableToBitmap((PictureDrawable) drawable);
d = new BitmapDrawable(drawImage);
//drawImage.recycle();
//new BitmapWorkerTask
}
catch (FileNotFoundException e)
{
}
return d;
}
Use the above method as below:
imageView.setImageBitmap(myBitmap);
You might want to use a smaller sample size (inSampleSize) that fits the heap
First, create a bitmap that fits the heap, possibly slightly larger than the one you require
BitmapFactory.Options bounds = new BitmapFactory.Options();
this.bounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, bounds);
if (bounds.outWidth == -1) { // TODO: Error }
int width = bounds.outWidth;
int height = bounds.outHeight;
boolean withinBounds = width <= maxWidth && height <= maxHeight;
if (!withinBounds) {
int newWidth = calculateNewWidth(int width, int height);
float sampleSizeF = (float) width / (float) newWidth;
int sampleSize = Math.round(sampleSizeF);
BitmapFactory.Options resample = new BitmapFactory.Options();
resample.inSampleSize = sampleSize;
bitmap = BitmapFactory.decodeFile(filePath, resample);
}
The second step is to call Bitmap.createScaledBitmap() to create a new bitmap to the exact resolution you require.
Make sure you clean up after the temporary bitmap to reclaim its memory. (Either let the variable go out of scope and let the GC deal with it, or call .recycle() on it if you are loading lots of images and are running tight on memory.)
Related
I am downloading images from web URL and showing on my android application but I am not able to resize my image according to my requirements.
private Bitmap decodeFile(File f) {
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream stream1 = new FileInputStream(f);
BitmapFactory.decodeStream(stream1, null, o);
stream1.close();
//Find the correct scale value. It should be the power of 2.
// Set width/height of recreated image
final int REQUIRED_SIZE = 285;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 1;
height_tmp /= 1;
scale *= 2;
}
//decode with current scale values
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
FileInputStream stream2 = new FileInputStream(f);
Bitmap bitmap = BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
now can any one tell me how can i resize my images to 250*250 px
also thanx in advance
Try and use Picasso library - http://square.github.io/picasso/.
It is fairly easy to use and integrate, and has a resize method doing exactly this.
Picasso.with(context).load(url).resize(250, 250).centerCrop().into(imageView);
you basically put instead of 'url' your url.
I Need to compress the image size after a taken a photo. I want to decrease the size to a maximum of 400K.
So, the average image size after taken the photo is about 3.3MB. I need to compress it to 400K.
What is the best option for this ?
I have tried :
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()));
.
The code below allow me to reduce the size by way of width and height, but not is storage space.
Bitmap bitmap = Bitmap.createScaledBitmap(capturedImage, width, height, true);
i find this sample from https://stackoverflow.com/a/823966/556337, But he does not explain how to make a image of a maxim size of XXX.MB. There is there a way to implement my issue. ?
// Decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// The new size we want to scale to
final int REQUIRED_SIZE=70;
// Find the correct scale value. It should be the power of 2.
int scale = 1;
while(o.outWidth / scale / 2 >= REQUIRED_SIZE &&
o.outHeight / scale / 2 >= REQUIRED_SIZE) {
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
I am working on an android app, which has camera capture and photo uploading feature. If the device has a high resolution camera, the captured image size will be really large (1~3MB or more).
Since the app will need to upload this image to server, I will need to compress the image before uploading. If the camera captured a 1920x1080 full-res photo for example, the ideal output is to keep a 16:9 ratio of the image, compress it to be a 640x360 image to reduce some image quality and make it a smaller size in bytes.
Here is my code (referenced from google):
/**
* this class provide methods that can help compress the image size.
*
*/
public class ImageCompressHelper {
/**
* 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) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
/**
* resize image to 480x800
* #param filePath
* #return
*/
public static Bitmap getSmallBitmap(String filePath) {
File file = new File(filePath);
long originalSize = file.length();
MyLogger.Verbose("Original image size is: " + originalSize + " bytes.");
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);
MyLogger.Verbose("Compressed image size is " + sizeOf(compressedImage) + " bytes");
return compressedImage;
}
The problem with the above code is:
It cannot keep the ratio, the code is forcing the image to resized to 480x800. if user captured a image in another ratio, the image will not look good after compress.
It doesn't functioning well. The code will always change the image size to 7990272byte no matter what the original file size is. If the original image size is pretty small already, it will make it big (my test result to take a picture of my wall, which is pretty much mono-colored):
Original image size is: 990092 bytes.
Compressed image size is 7990272 bytes
I am asking if there's suggestion of a better way to compress photo so it can be uploaded smoothly?
You need to decide on a limit for either your width or height (not both, obviously). Then replace those fixed image sizes with calculated ones, say:
int targetWidth = 640; // your arbitrary fixed limit
int targetHeight = (int) (originalHeight * targetWidth / (double) originalWidth); // casts to avoid truncating
(Add checks and calculation alternatives for landscape / portrait orientation, as needed.)
As #harism also commented: the large size you mentioned is the raw size of that 480x800 bitmap, not the file size, which should be a JPEG in your case. How are you going about saving that bitmap, BTW? Your code doesn't seem to contain the saving part.
See this question here for help on that, with the key being something like:
OutputStream imagefile = new FileOutputStream("/your/file/name.jpg");
// Write 'bitmap' to file using JPEG and 80% quality hint for JPEG:
bitmap.compress(CompressFormat.JPEG, 80, imagefile);
Firstly i check the size of image then i compress image according to size and get compressed bitmap then send that bitmap to server
For Compressed bitmap call below funtion we have to pass image path in below funtion
public Bitmap get_Picture_bitmap(String imagePath) {
long size_file = getFileSize(new File(imagePath));
size_file = (size_file) / 1000;// in Kb now
int ample_size = 1;
if (size_file <= 250) {
System.out.println("SSSSS1111= " + size_file);
ample_size = 2;
} else if (size_file > 251 && size_file < 1500) {
System.out.println("SSSSS2222= " + size_file);
ample_size = 4;
} else if (size_file >= 1500 && size_file < 3000) {
System.out.println("SSSSS3333= " + size_file);
ample_size = 8;
} else if (size_file >= 3000 && size_file <= 4500) {
System.out.println("SSSSS4444= " + size_file);
ample_size = 12;
} else if (size_file >= 4500) {
System.out.println("SSSSS4444= " + size_file);
ample_size = 16;
}
Bitmap bitmap = null;
BitmapFactory.Options bitoption = new BitmapFactory.Options();
bitoption.inSampleSize = ample_size;
Bitmap bitmapPhoto = BitmapFactory.decodeFile(imagePath, bitoption);
ExifInterface exif = null;
try {
exif = new ExifInterface(imagePath);
} catch (IOException e) {
// Auto-generated catch block
e.printStackTrace();
}
int orientation = exif
.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Matrix matrix = new Matrix();
if ((orientation == 3)) {
matrix.postRotate(180);
bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0,
bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix,
true);
} else if (orientation == 6) {
matrix.postRotate(90);
bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0,
bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix,
true);
} else if (orientation == 8) {
matrix.postRotate(270);
bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0,
bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix,
true);
} else {
matrix.postRotate(0);
bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0,
bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix,
true);
}
return bitmap;
}
getFileSize funtion for getting the size of image
public long getFileSize(final File file) {
if (file == null || !file.exists())
return 0;
if (!file.isDirectory())
return file.length();
final List<File> dirs = new LinkedList<File>();
dirs.add(file);
long result = 0;
while (!dirs.isEmpty()) {
final File dir = dirs.remove(0);
if (!dir.exists())
continue;
final File[] listFiles = dir.listFiles();
if (listFiles == null || listFiles.length == 0)
continue;
for (final File child : listFiles) {
result += child.length();
if (child.isDirectory())
dirs.add(child);
}
}
return result;
}
Im trying to glue one bitmap on the right of second. Here is my code:
public static Bitmap getGluedBitmap(File left, File right, int reqWidth, int reqHeight, LruCache<String, Bitmap> mCache)
{
Bitmap lefty = decodeSampledBitmapFromFile(left, reqWidth / 2, reqHeight, 2, mCache);
Bitmap righty = decodeSampledBitmapFromFile(right, reqWidth / 2, reqHeight, 2, mCache);
Bitmap output = Bitmap.createBitmap(reqWidth, reqHeight, Config.ARGB_8888);
Canvas canvas = new Canvas(output);
canvas.drawBitmap(lefty, null, new Rect(0, 0, canvas.getWidth() / 2, canvas.getHeight()), null);
canvas.drawBitmap(righty, null, new Rect(canvas.getWidth() / 2 + 1, 0, canvas.getWidth(), canvas.getHeight()), null);
return output;
}
And here is decodeSampledBitmapFromFile method from Google examples, optimized for my needs:
public static Bitmap decodeSampledBitmapFromFile(File file, int reqWidth, int reqHeight, int state, LruCache<String, Bitmap> mCache) {
String imageKey = String.valueOf(file.getAbsolutePath());
imageKey += state;
Bitmap bitmap = getBitmapFromMemCache(imageKey, mCache);
if (bitmap == null) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file.getAbsolutePath(), options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
boolean done = false;
while(!done)
{
try {
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
done = true;
} catch (OutOfMemoryError e) {
// Ignore. Try again.
}
}
return addBitmapToMemoryCache(imageKey, bitmap, mCache);
}
else
{
return bitmap;
}
}
This method searches picture by key in cache, state is used to cache different versions on picters, i.e. little version, big vertion, etc.
Also, you can see some crooked nails with decoding file, but this step is temporary, and I'll fix this later. All you need to know that this method working 146% correctly.
The problem is: bitmap, that I'm creating with first method is uncorrect, and its not displaying. I mean width and height of this bitmap equals -1 for some reason.
However, width of Bitmap lefty and righty equals -1 too, but I've tryed display those bitmaps and that worked perfectly.
Tell me if I'm merging bitmaps wrong.
Well, the code is absolutelly correct. For some reason, my device cant display the resulting bitmap. I tried to build this code to other device, and it worked perfectly. Thanks for your attention.
I'm resizing an array of Bitmaps to a certain percentage of screen (So looks the same on all devices). Some of the bitmaps are sprites with + 256kb in size (explosions etc).
Obviously the VM is running out of memory once the bitmaps are converted twice, the bitmaps only convert at the beginning of the android application but it's still giving the error.
Can anyone tell me, is there a better, faster, more effcient way to return this peice of code as a bitmap.
Just out of curiosity are bitmap values passed by reference? (As in does the object parameter use the same line of memory for the same object?).
Anyhow's here is z code:
public Bitmap ResizeBitmap(Bitmap bitmap, float s_percentage, int frames, int viewport_width, int viewport_height)
{
float percentage = s_percentage / 100.0f;
float scale = viewport_width / 100 * percentage;
if(viewport_width < viewport_height)
{
scale = viewport_height / 100 * percentage;
}
int newWidth = (int) (bitmap.getWidth() * scale);
int newHeight = (int) (bitmap.getHeight() * scale);
if(newWidth <= 0 || newHeight <= 0)
{
// Extra check, for invalid width/height
Log.e("Function List, Resize Bitmap", "invalid dimension ("+newWidth+"x"+newHeight+")");
return bitmap;
}
//Round up to closet factor of total frames
int rW = (newWidth/frames)+1;
newWidth = rW*frames;
Bitmap newBitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, false);
return newBitmap;
}
To be in VM budget try to scale down your Bitmap like this.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile( filename, options );
options.inJustDecodeBounds = false;
options.inSampleSize = 4;
bitmap = BitmapFactory.decodeFile( filename, options );
if ( bitmap != null ) {
bitmap = Bitmap.createScaledBitmap( bitmap, width, height, false );
}
//Adjust SampleSize to values like 2, 4, 8 etc