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.
Related
In my app user can take picture from camera intent , then I save this image as full size image
not thumbnail. Then what I want to do is use this saved image to compress it and send it over to server.
The image size from camera intent is around 7-8 MB and resolution of 5664x4248.
The requirements is to achieve is image of same size and quality of whatsapp which is 40-80KB
I tried different solution but I couldn't achieve the same good quality and size.
For this I used id.zelory:compressor:2.1.1 library
Any Idea?
Here I call this method after saving the image to resize it
private File customCompressImage (File imgFile) {
String destinationDirectoryPath= Environment.getExternalStorageDirectory().getPath() + "/Pictures/";
try {
return new CustomCompressor(context)
.setMaxWidth(612)
.setMaxHeight(816)
.setQuality(80)
.setCompressFormat(Bitmap.CompressFormat.JPEG)
.setDestinationDirectoryPath(destinationDirectoryPath)
.compressToFile(imgFile);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
CompressImage
static File compressImage(File imageFile, int reqWidth, int reqHeight, Bitmap.CompressFormat compressFormat, int quality, String destinationPath) throws IOException {
FileOutputStream fileOutputStream = null;
File file = new File(destinationPath).getParentFile();
if (!file.exists()) {
file.mkdirs();
}
try {
fileOutputStream = new FileOutputStream(destinationPath);
// write the compressed bitmap at the destination specified by destinationPath.
decodeSampledBitmapFromFile(imageFile, reqWidth, reqHeight).compress(compressFormat, quality, fileOutputStream);
} finally {
if (fileOutputStream != null) {
fileOutputStream.flush();
fileOutputStream.close();
}
}
return new File(destinationPath);
}
static Bitmap decodeSampledBitmapFromFile(File imageFile, int reqWidth, int reqHeight) throws IOException {
// First decode with inJustDecodeBounds=true to check dimensions
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap scaledBitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);
//check the rotation of the image and display it properly
ExifInterface exif;
exif = new ExifInterface(imageFile.getAbsolutePath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
} else if (orientation == 3) {
matrix.postRotate(180);
} else if (orientation == 8) {
matrix.postRotate(270);
}
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
return scaledBitmap;
}
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) {
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;
}
I tried passing different max width and height and quality and I never achived both small size and good quality
You can try this piece of code.
public static Bitmap getCompressed( Bitmap imageBitmap) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
return imageBitmap;
}
// 100 is quality,
change it according to your need
#End User shouldn't it be like this instead (that's at least what I get from reading the documentation):
public static Bitmap getCompressed(Bitmap imageBitmap) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
if (!imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out))
throw new IllegalStateException("Unable to compress image");
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
return BitmapFactory.decodeStream(in);
}
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 downloading an image and i want to display it in a RelativeLayout as background. However since android has so man different screens, i am finding it difficult to resize the image according to screen size.
Here is my layout
[Top Bar]
[Relative Layout] ..width= fill_parent , height = wrap_content
[ListView]
In my resizing i am using this code
bitmap = Utilities.decodeSampledBitmap(in, imageView.getWidth(), imageView.getWidth());
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;
}
public static Bitmap decodeSampledBitmap(InputStream in, int reqWidth, int reqHeight)
{
if (in != null)
{
byte[] image;
try {
image = readFully(in);
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
BitmapFactory.decodeByteArray(image, 0, image.length, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeByteArray(image, 0, image.length, options);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
else
return null;
}
However these are still stretching images and only in hdpi it seems something better, ldpi is worse, mdpi seems fine , xhdpi is bad too. Stetching is effecting. I can't fix the size of RelativeLayout or Use ImageView because It will then show space between Image and ListView..
What method should I adopt.
I suggest you not using the background image, but use ImageView and set his ScaleType to meet your needs.
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.)
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