I am currently working on an application that shows a Bitmap on an ImageView. Now the problem is, whenever trying to show a Bitmap larger than 4096x4096, it simply won't show up, stating that the image is too large to be shown.
For example: I want to load up an image that's 4128x2322 pixels
I to resize it to be smaller than 4096x4096.
I thought about something like this:
Bitmap bitmap;
if(b.getHeight() >= 4096) {
double f = b.getHeight() / 4096;
b = Bitmap.createScaledBitmap(b, (int)(b.getWidth() / f), (int)(b.getHeight() / f), false);
}else if(b.getWidth() >= 4096) {
double f = b.getWidth() / 4096;
b = Bitmap.createScaledBitmap(b, (int)(b.getWidth() / f), (int)(b.getHeight() / f), false);
}
imageview.setImageBitmap(b);
Somehow it won't work...
Any advices on how to scale properly?
Thanks in advance!
I got an intent which takes a picture and returns the image
That image will be stored somewhere else, which you will reference via a File or perhaps a content: Uri.
But to show the taken picture I need to scale it down first
Use BitmapFactory to load the bitmap. Use BitmapFactory.Options and its inSampleSize field to indicate how you want the image to be downsampled. This is covered in the documentation.
There is no device with resolution 4096X4096, your image going to be scaled any way. So instead trying to scale it up just top let the system to scale it down. How about taking the screen size in to calculation and provide the final scale by your self. Not only that you will save space but also improve performance.
Related
I am trying to work on a small requirement which provides users with an option to resize an image to a given percentage. Lets say 75% is the option. Does that mean I should resize the image size to 75% or the resolution of the image to 75%?
Any thoughts on this?
I wanted to use
Bitmap yourBitmap; resized =
Bitmap.createScaledBitmap(yourBitmap,(int)(yourBitmap.getWidth()*0.75),
(int)(yourBitmap.getHeight()*0.75), true);
For the newWidth and newHeight should I blindly pass calculate like above?
I think
image resolution is 100% like 100x100 or 200x200 or 1000x1000
user want to resize it to 75%
I think scaleX, scaleY
so on the end image must be 75% like 75x75 or 150x150 or 750x750
Within the help of Bitmap.createScaledBitmap you can resize your image even without losing your image quality
Bitmap scaledBitmap = Bitmap.createScaledBitmap(unscaledBitmap, wantedWidth, wantedHeight, true);
I hope it will work for you
You can implement as following way.
/* sample code */
Bitmap srcBitmap;
Bitmap destBitmap = Bitmap.createScaledBitmap(srcBitmap, (int)(srcBitmap.getWidth()*0.75), (int)(srcBitmap.getHeight()*0.75), true);
Hopefully...
What you consider to be 75% of an image is up to you. There are several posibilities. A nice variant is to resize to a predetermined size like 1024 for width if landscape and for height if portrait.
All the here suggested techniques can often not be used as they construct a full blown original bitmap first. Often memory for that will not be available.
So scale it down while loading. BitmapFactory will do it for you.
I have a strange behaviour by getting Bitmaps with the methods BitmapFactory.decodeStream(Resources res,int id) and BitmapFactory.decodeFile(String pathName). I want to set a bitmap to my appwidget remoteViews, it is an png image with 319x319px and 32kb, for my understanding, it is a very small image that should be handled easily.
Now, what´s happing is, if I put this image inside my drawables folder and want to load the bitmap with BitmapFactory.decodeResource, the app crashs and I get an error-message that the remoteViews exceeds the max bitmap memory usage.
What I find out is, that there is max memory usage to the following rule (from developer.google.com) :
The total Bitmap memory used by the RemoteViews object cannot exceed that
required to fill the screen 1.5 times, ie.
(screen width x screen height x 4 x 1.5) bytes.
Now to the strange part: If I load the identical image from sd card and decode it with BitmapFactory.decodeFile(), it works. Why is this happening?
The problem I face here is, that I have to set some default images, if no other one is on my folder in sd card. For this, I put them in to my drawables folder. If I scale them down to 119x119px, then it works and I get no error message. But this is very bad quality and looks totally blurred at the widget.
Can anybody explain, what exactly is the difference of the behaviour how the bitmaps are loaded? Is there any automatic scaling function in decodeFile() that is not in decodeResource()?
A part of code or the logcat output is irrelevant, so I don´t post it here, I just can´t understand this behaviour and don´t know how to handle it. Also, I searched a lot about this and read the API, but there is nothing I can find out.
EDIT
For now I fixed this with calculating the bitmap memory usage with the above formular and check the bitmap size like this:
DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
double width = (double) metrics.widthPixels;
double height = (double) metrics.heightPixels;
double maximumUsage = width * height * 4.0 * 1.5;
double maximumImageSizeFaktor = (maximumUsage / 3) / 1.5 / 4;
double maximumImageSize = Math.sqrt(maximumImageSizeFaktor);
int maxSize = (int) maximumImageSize - 10; //just to get sure, minimize it for 10
return maxSize;
Then I know the maximal size for my bitmaps and can downsample or resize it. But this did not answer the strange behaviour.
If BitmapFactory is loading from drawables then it does also some scaling according the device screen. By loading from file that will not happen. If you put your images in assets folder it will not happen either.
It seems that setting a wallpaper on Android just doesn't work in any useful way.
If you get an image from your phone and set it as the wallpaper, it's way too big for the screen
If you resize it (either using a createBitmap() function that allows you to specify size, or the ridiculously useless createScaledBitmap()) it goes all jaggy and out of focus
If you use some freaky hacks to fix the quality of the image, it's better, but still not perfectly clear by any stretch.
If you attempt to get the current wallpaper and set that, it still seems to make it too big. It appears to give you the original image file, forcing you to resize it, which doesn't work.
Now, the phone's internal software is perfectly capable of resizing an image to be smaller with no reduction of quality. Why does it not share this functionality?
WallpaperManager wallpaperManager = WallpaperManager.getInstance(Spinnerz.this);
// gets the image from file, inexplicably upside down.
Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "DCIM/Camera/Zedz.jpg");
// use some rotation to get it on an angle that matches the screen.
Matrix bitmapTransforms = new Matrix();
bitmapTransforms.setRotate(90); // flip back upright
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),bitmapTransforms, false); // create bitmap from bitmap from file, using the rotate matrix
// lets set it exactly to the resolution of my Samsung Galaxy S2: 480x800 pixels.
// This function appears to exist specifically to scale a bitmap object - should do a good job of it!
bitmap = Bitmap.createScaledBitmap(bitmap, 480, 800, false);
wallpaperManager.setBitmap(bitmap);
// result is quite a jaggy image - not suitable as a wallpaper.
PIC:
Try this ,
Display d = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int width = d.getWidth();
int height = d.getHeight();
I am running into a strange issue. I have multiple images in my Android project which I stored as .png files under res\drawable. I was able to easily extract the images at runtime and convert them to a bitmap like this:
Drawable d = getResources().getDrawable(R.drawable.imageId);
Bitmap bitmap = ((BitmapDrawable)d).getBitmap();
This works great and the image gets scaled correctly no matter what screen density the device has. All my images are 200 pixels by 200 pixels and my image layout is configured as 200 dip x 200 dip.
Now, I have stored all images as blobs in an SQlite database due to scalability issues and I am extracting them at runtime and converting to a bitmap like this:
byte[] bb = cursor.getBlob(columnIndex);
Bitmap bitmap = BitmapFactory.decodeByteArray(bb, 0, bb.length);
The image displays fine if the screen density is standard 160 dip. But if the density is any less or more, the image doesn't scale and remains 200 pixels x 200 pixels for 160 dip. So basically, on a smaller screen (120 dip), the image takes more space than it should and on a larger screen (240 dip), it takes less space than it should.
Has anyone else run into this bizarre issue? Any explanation, workaround, solution will be really appreciated.
Thanks much in advance!
Okay, I finally got it to work by using createScaledBitmap().
After creating a bitmap from the blob, I calculate the scaling factor and then calculate the new width and height. I then use those in the createScaledBitmap() function. Here's the code that works:
public static Bitmap getImageFromBlob(byte[] mBlob)
{
byte[] bb = mBlob;
Bitmap b = BitmapFactory.decodeByteArray(bb, 0, bb.length);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int newWidth = b.getWidth()*metrics.densityDpi)/DisplayMetrics.DENSITY_DEFAULT;
int newHeight = b.getHeight()*metrics.densityDpi)/DisplayMetrics.DENSITY_DEFAULT;
return Bitmap.createScaledBitmap(b, newWidth, newHeight, true);
}
This link provided the clue:
difference between methods to scale a bitmap
Use decodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts) and in opts set inDesity to let say 160.
Worked for me, see this. But I have to say, I think SQLite is doing it right, and the android drawable is incorrectly sized.
I am trying to reduce the size of images retrieved form the camera (so ~5-8 mega pixels) down to one a a few smaller sizes (the largest being 1024x768). I Tried the following code but I consistently get an OutOfMemoryError.
Bitmap image = BitmapFactory.decodeStream(this.image, null, opt);
int imgWidth = image.getWidth();
int imgHeight = image.getHeight();
// Constrain to given size but keep aspect ratio
float scaleFactor = Math.min(((float) width) / imgWidth, ((float) height) / imgHeight);
Matrix scale = new Matrix();
scale.postScale(scaleFactor, scaleFactor);
final Bitmap scaledImage = Bitmap.createBitmap(image, 0, 0, imgWidth, imgHeight, scale, false);
image.recycle();
It looks like the OOM happens during the createBitmap. Is there a more memory efficient way to do this? Perhaps something that doesn't require me to load the entire original into memory?
When you decode the bitmap with the BitmapFactory, pass in a BitmapFactory.Options object and specify inSampleSize. This is the best way to save memory when decoding an image.
Here's a sample code Strange out of memory issue while loading an image to a Bitmap object
Are you taking the picture with the camera within your application? If so, you should set the picture size to a smaller one in the first place when they're being captured via android.hardware.Camera.Parameters.setPictureSize
Here is a similar question that I answered and show how to go about dynamically loading the proper image size.
out of memory exception + analyzing hprof file dump